commit ee06da5fb672578c1348b80777af5fa05f8e249e Author: lax1dude Date: Fri May 3 17:27:39 2024 -0700 bungee impl half completed diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/BitmapFile.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/BitmapFile.java new file mode 100644 index 0000000..9db1c07 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/BitmapFile.java @@ -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 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 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; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDConfiguration.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDConfiguration.java new file mode 100644 index 0000000..36c2d07 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDConfiguration.java @@ -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> messages = new HashMap(); + public final Map messagePools = new HashMap(); + public final Map 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); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDConnectionAdapter.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDConnectionAdapter.java new file mode 100644 index 0000000..1b8eac6 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDConnectionAdapter.java @@ -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 getPlayerList(); + int[] getBitmap(); + int getOnlinePlayers(); + int getMaxPlayers(); + String getSubType(); + + void setLine1(String p); + void setLine2(String p); + void setPlayerList(List 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 getDefaultOnlinePlayersList(int maxLen); + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDConnectionUpdater.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDConnectionUpdater.java new file mode 100644 index 0000000..edd5109 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDConnectionUpdater.java @@ -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 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 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; + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDLoggerAdapter.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDLoggerAdapter.java new file mode 100644 index 0000000..75ed523 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDLoggerAdapter.java @@ -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); + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDUtils.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDUtils.java new file mode 100644 index 0000000..197a137 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/EaglerMOTDUtils.java @@ -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(); + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/MessagePool.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/MessagePool.java new file mode 100644 index 0000000..ceccbe9 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/MessagePool.java @@ -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 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(); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/MessagePoolEntry.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/MessagePoolEntry.java new file mode 100644 index 0000000..09def8f --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/MessagePoolEntry.java @@ -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 { + + 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 frames; + + public MessagePoolEntry(int interval, int timeout, boolean random, boolean shuffle, float weight, String next, List 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); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/bungee/EaglerMOTDConnectionBungee.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/bungee/EaglerMOTDConnectionBungee.java new file mode 100644 index 0000000..ab4c3fa --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/bungee/EaglerMOTDConnectionBungee.java @@ -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 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 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 getDefaultOnlinePlayersList(int maxLen) { + Collection ppl = BungeeCord.getInstance().getPlayers(); + List 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; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/bungee/EaglerMOTDListenerBungee.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/bungee/EaglerMOTDListenerBungee.java new file mode 100644 index 0000000..2826558 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/bungee/EaglerMOTDListenerBungee.java @@ -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) { + + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/bungee/EaglerMOTDPluginBungee.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/bungee/EaglerMOTDPluginBungee.java new file mode 100644 index 0000000..9b38b38 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/bungee/EaglerMOTDPluginBungee.java @@ -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 motdConnections = new LinkedList(); + +} diff --git a/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/default_frames.json b/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/default_frames.json new file mode 100644 index 0000000..65a0500 --- /dev/null +++ b/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/default_frames.json @@ -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" + } +} \ No newline at end of file diff --git a/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/default_messages.json b/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/default_messages.json new file mode 100644 index 0000000..cefd9c1 --- /dev/null +++ b/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/default_messages.json @@ -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" + } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/default_queries.json b/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/default_queries.json new file mode 100644 index 0000000..c522042 --- /dev/null +++ b/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/default_queries.json @@ -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" + } + } +} \ No newline at end of file diff --git a/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/server-icons-test.png b/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/server-icons-test.png new file mode 100644 index 0000000..e1440d1 Binary files /dev/null and b/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/eaglermotd/server-icons-test.png differ diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..180e0c1 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -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 \ No newline at end of file