mirror of
https://github.com/Melledy/Nebula.git
synced 2025-12-12 20:34:36 +01:00
- Added ban module - Added Ban and Unban commands, supporting banning and unbanning players through various command parameters. - Added timestamp formatting method in Utils utility class for displaying ban expiration times - Introduced PlayerErrorCode enum defining various error codes including ErrBan - Added dual ban checking for both IP and user during player login - Optimized login failure responses to provide specific error reasons and parameters
341 lines
9.6 KiB
Java
341 lines
9.6 KiB
Java
package emu.nebula.util;
|
|
|
|
import java.io.File;
|
|
import java.net.InetAddress;
|
|
import java.net.InetSocketAddress;
|
|
import java.net.ServerSocket;
|
|
import java.time.Instant;
|
|
import java.time.LocalDate;
|
|
import java.time.YearMonth;
|
|
import java.time.ZoneId;
|
|
import java.time.format.DateTimeFormatter;
|
|
import java.time.temporal.ChronoUnit;
|
|
import java.util.Base64;
|
|
import java.util.List;
|
|
import java.util.concurrent.ThreadLocalRandom;
|
|
|
|
import emu.nebula.GameConstants;
|
|
import it.unimi.dsi.fastutil.ints.IntList;
|
|
|
|
public class Utils {
|
|
private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray();
|
|
|
|
public static final Object EMPTY_OBJECT = new Object();
|
|
public static final int[] EMPTY_INT_ARRAY = new int[0];
|
|
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
|
|
|
|
public static String bytesToHex(byte[] bytes) {
|
|
return bytesToHex(bytes, 0);
|
|
}
|
|
|
|
public static String bytesToHex(byte[] bytes, int offset) {
|
|
if (bytes == null || (bytes.length - offset) <= 0) return "";
|
|
char[] hexChars = new char[(bytes.length - offset) * 2];
|
|
for (int j = offset; j < bytes.length; j++) {
|
|
int v = bytes[j] & 0xFF;
|
|
int h = j - offset;
|
|
hexChars[h * 2] = HEX_ARRAY[v >>> 4];
|
|
hexChars[h * 2 + 1] = HEX_ARRAY[v & 0x0F];
|
|
}
|
|
return new String(hexChars);
|
|
}
|
|
|
|
public static byte[] hexToBytes(String s) {
|
|
int len = s.length();
|
|
byte[] data = new byte[len / 2];
|
|
for (int i = 0; i < len; i += 2) {
|
|
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
|
|
+ Character.digit(s.charAt(i+1), 16));
|
|
}
|
|
return data;
|
|
}
|
|
|
|
public static String capitalize(String s) {
|
|
StringBuilder sb = new StringBuilder(s);
|
|
sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
|
|
return sb.toString();
|
|
}
|
|
|
|
public static String lowerCaseFirstChar(String s) {
|
|
StringBuilder sb = new StringBuilder(s);
|
|
sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* Creates a string with the path to a file.
|
|
* @param path The path to the file.
|
|
* @return A path using the operating system's file separator.
|
|
*/
|
|
public static String toFilePath(String path) {
|
|
return path.replace("/", File.separator);
|
|
}
|
|
|
|
/**
|
|
* Checks if a file exists on the file system.
|
|
* @param path The path to the file.
|
|
* @return True if the file exists, false otherwise.
|
|
*/
|
|
public static boolean fileExists(String path) {
|
|
return new File(path).exists();
|
|
}
|
|
|
|
/**
|
|
* Creates a folder on the file system.
|
|
* @param path The path to the folder.
|
|
* @return True if the folder was created, false otherwise.
|
|
*/
|
|
public static boolean createFolder(String path) {
|
|
return new File(path).mkdirs();
|
|
}
|
|
|
|
public static long getCurrentSeconds() {
|
|
return Math.floorDiv(System.currentTimeMillis(), 1000);
|
|
}
|
|
|
|
public static int getMinAdvanceForLevel(int level) {
|
|
return Math.max(Math.min((int) ((level - 1) / 10D), 8), 0);
|
|
}
|
|
|
|
/**
|
|
* Parses the string argument as a signed decimal integer. Returns a 0 if the string argument is not an integer.
|
|
*/
|
|
public static int parseSafeInt(String s) {
|
|
if (s == null) {
|
|
return 0;
|
|
}
|
|
|
|
int i = 0;
|
|
|
|
try {
|
|
i = Integer.parseInt(s);
|
|
} catch (Exception e) {
|
|
i = 0;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
/**
|
|
* Parses the string argument as a signed decimal long. Returns a 0 if the string argument is not a long.
|
|
*/
|
|
public static long parseSafeLong(String s) {
|
|
if (s == null) {
|
|
return 0;
|
|
}
|
|
|
|
long i = 0;
|
|
|
|
try {
|
|
i = Long.parseLong(s);
|
|
} catch (Exception e) {
|
|
i = 0;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
/**
|
|
* Add 2 integers without overflowing
|
|
*/
|
|
public static int safeAdd(int a, int b) {
|
|
return safeAdd(a, b, Integer.MAX_VALUE, 0);
|
|
}
|
|
|
|
public static int safeAdd(int a, int b, long max, long min) {
|
|
long sum = (long) a + (long) b;
|
|
|
|
if (sum > max) {
|
|
return (int) max;
|
|
} else if (sum < min) {
|
|
return (int) min;
|
|
}
|
|
|
|
return (int) sum;
|
|
}
|
|
|
|
/**
|
|
* Subtract 2 integers without overflowing
|
|
*/
|
|
public static int safeSubtract(int a, int b) {
|
|
return safeSubtract(a, b, Integer.MAX_VALUE, Integer.MIN_VALUE);
|
|
}
|
|
|
|
public static int safeSubtract(int a, int b, long max, long min) {
|
|
long sum = (long) a - (long) b;
|
|
|
|
if (sum > max) {
|
|
return (int) max;
|
|
} else if (sum < min) {
|
|
return (int) min;
|
|
}
|
|
|
|
return (int) sum;
|
|
}
|
|
|
|
public static double generateRandomDouble() {
|
|
return ThreadLocalRandom.current().nextDouble();
|
|
}
|
|
|
|
public static int randomRange(int min, int max) {
|
|
return ThreadLocalRandom.current().nextInt(min, max + 1);
|
|
}
|
|
|
|
public static boolean randomChance(double chance) {
|
|
if (chance <= 0D) {
|
|
return false;
|
|
}
|
|
|
|
return ThreadLocalRandom.current().nextDouble() < chance;
|
|
}
|
|
|
|
public static int randomElement(int[] array) {
|
|
return array[ThreadLocalRandom.current().nextInt(0, array.length)];
|
|
}
|
|
|
|
public static <T> T randomElement(List<T> list) {
|
|
return randomElement(list, false);
|
|
}
|
|
|
|
public static <T> T randomElement(List<T> list, boolean remove) {
|
|
int index = ThreadLocalRandom.current().nextInt(0, list.size());
|
|
var object = list.get(index);
|
|
|
|
if (remove) {
|
|
list.remove(index);
|
|
}
|
|
|
|
return object;
|
|
}
|
|
|
|
public static int randomElement(IntList list) {
|
|
return list.getInt(ThreadLocalRandom.current().nextInt(0, list.size()));
|
|
}
|
|
|
|
public static int randomElement(IntList list, boolean remove) {
|
|
int index = ThreadLocalRandom.current().nextInt(0, list.size());
|
|
int object = list.getInt(index);
|
|
|
|
if (remove) {
|
|
list.removeInt(index);
|
|
}
|
|
|
|
return object;
|
|
}
|
|
|
|
/**
|
|
* Checks if an integer array contains a value
|
|
* @param array
|
|
* @param value The value to check for
|
|
*/
|
|
public static boolean arrayContains(int[] array, int value) {
|
|
for (int i = 0; i < array.length; i++) {
|
|
if (array[i] == value) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static boolean arrayContains(Integer[] array, int value) {
|
|
for (Integer element : array) {
|
|
if (element != null && element.equals(value)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static boolean arrayContains(List<Integer> list, int value) {
|
|
for (Integer element : list) {
|
|
if (element.equals(value)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static int[] convertListToIntArray(List<Integer> list) {
|
|
// Create an int array with the same size as the list
|
|
int[] intArray = new int[list.size()];
|
|
|
|
// Iterate over the list and populate the int array
|
|
for (int i = 0; i < list.size(); i++) {
|
|
intArray[i] = list.get(i);
|
|
}
|
|
|
|
return intArray;
|
|
}
|
|
|
|
/**
|
|
* Base64 encodes a given byte array.
|
|
* @param toEncode An array of bytes.
|
|
* @return A base64 encoded string.
|
|
*/
|
|
public static String base64Encode(byte[] toEncode) {
|
|
return Base64.getEncoder().encodeToString(toEncode);
|
|
}
|
|
|
|
/**
|
|
* Base64 decodes a given string.
|
|
* @param toDecode A base64 encoded string.
|
|
* @return An array of bytes.
|
|
*/
|
|
public static byte[] base64Decode(String toDecode) {
|
|
return Base64.getDecoder().decode(toDecode);
|
|
}
|
|
|
|
/**
|
|
* Checks if a port is open on a given host.
|
|
*
|
|
* @param host The host to check.
|
|
* @param port The port to check.
|
|
* @return True if the port is open, false otherwise.
|
|
*/
|
|
public static boolean isPortOpen(String host, int port) {
|
|
try (var serverSocket = new ServerSocket()) {
|
|
serverSocket.setReuseAddress(false);
|
|
serverSocket.bind(new InetSocketAddress(InetAddress.getByName(host), port), 1);
|
|
return true;
|
|
} catch (Exception ex) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get amount of weeks since this epoch day. Each week starts on monday.
|
|
* @param epochDays
|
|
* @return
|
|
*/
|
|
public static int getWeeks(long epochDays) {
|
|
return (int) Math.floor((epochDays + 3) / 7D);
|
|
}
|
|
|
|
/**
|
|
* Get amount of months since this epoch day.
|
|
* @param epochDays
|
|
* @return
|
|
*/
|
|
public static int getMonths(long epochDays) {
|
|
var begin = LocalDate.ofEpochDay(0);
|
|
var date = LocalDate.ofEpochDay(epochDays);
|
|
return (int) ChronoUnit.MONTHS.between(begin, date);
|
|
}
|
|
|
|
public static int getDaysOfMonth(long epochDays) {
|
|
var date = LocalDate.ofEpochDay(epochDays);
|
|
var month = YearMonth.of(date.getYear(), date.getMonthValue());
|
|
return month.lengthOfMonth();
|
|
}
|
|
|
|
public static String formatTimestamp(long timestamp) {
|
|
return Instant.ofEpochMilli(timestamp)
|
|
.atZone(GameConstants.UTC_ZONE)
|
|
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
|
}
|
|
|
|
public static String formatTimestamp(long timestamp, String pattern) {
|
|
return Instant.ofEpochMilli(timestamp)
|
|
.atZone(GameConstants.UTC_ZONE)
|
|
.format(DateTimeFormatter.ofPattern(pattern));
|
|
}
|
|
}
|