diff --git a/src/main/java/pw/yumc/YumCore/kit/EntityKit.java b/src/main/java/pw/yumc/YumCore/kit/EntityKit.java new file mode 100644 index 0000000..8949bb3 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/kit/EntityKit.java @@ -0,0 +1,423 @@ +package pw.yumc.YumCore.kit; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import com.comphenix.protocol.utility.MinecraftFields; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.wrappers.WrappedDataWatcher; + +import pw.yumc.YumCore.utils.ReflectUtil; + +public class EntityKit { + + private static Method _mGetNavigation; + private static Method _mA3 = null; + private static Method _mA2 = null; + private static Method _mA1 = null; + + private static Field _fgoalSelector; + private static Field _ftargetSelector; + + private final static Class _cControllerMove = MinecraftReflection.getMinecraftClass("ControllerMove"); + private final static Class _cPathEntity = MinecraftReflection.getMinecraftClass("PathEntity"); + private final static Class _cEntityInsentient = MinecraftReflection.getMinecraftClass("EntityInsentient"); + private final static Class _cPathfinderGoalSelector = MinecraftReflection.getMinecraftClass("PathfinderGoalSelector"); + + private static Method _mPlayerList_MoveToWorld = null; + private static Method _mPlayerConnection_Teleport = null; + private static Field _fWorldServer_dimension = null; + + static { + try { + _mGetNavigation = _cEntityInsentient.getMethod("getNavigation"); + _fgoalSelector = _cEntityInsentient.getDeclaredField("goalSelector"); + _fgoalSelector.setAccessible(true); + _ftargetSelector = _cEntityInsentient.getDeclaredField("targetSelector"); + _ftargetSelector.setAccessible(true); + + ReflectUtil.getMethodByNameAndParams(_cEntityInsentient, "getControllerMove"); + ReflectUtil.getDeclaredMethodByParams(_cControllerMove, double.class, double.class, double.class, double.class).get(0); + + final Class cc = MinecraftReflection.getMinecraftClass("NavigationAbstract"); + for (final Method method : cc.getDeclaredMethods()) { + final Class[] parmeters = method.getParameterTypes(); + switch (parmeters.length) { + case 1: { + if (parmeters[0] == double.class) { + _mA1 = method; + } + break; + } + case 2: { + if (parmeters[0] == _cPathEntity.getClass() && parmeters[1] == double.class) { + _mA2 = method; + } + break; + } + case 3: { + if (parmeters[0] == double.class && parmeters[1] == double.class && parmeters[2] == double.class) { + _mA3 = method; + } + break; + } + } + } + } catch (final Exception ex) { + ex.printStackTrace(); + } + try { + _mPlayerList_MoveToWorld = ReflectUtil + .getDeclaredMethodByParamsAndType(MinecraftReflection.getPlayerListClass(), + MinecraftReflection.getEntityPlayerClass(), + MinecraftReflection.getEntityPlayerClass(), + Integer.TYPE, + Boolean.TYPE, + Location.class, + Boolean.TYPE) + .get(0); + } catch (final Exception ex) { + ex.printStackTrace(); + } + } + + /** + * 通过ID获取实体 + * + * @param entityId + * 实体ID + * @return 实体 + */ + public static Entity getEntityById(final int entityId) { + for (final World world : Bukkit.getWorlds()) { + for (final Entity entity : world.getEntities()) { + if (entity.getEntityId() == entityId) { + return entity; + } + } + } + return null; + } + + /** + * 判断实体是否在水里 + * + * @param ent + * 实体 + * @return 结果 + */ + public static boolean inWater(final Entity ent) { + return ent.getLocation().getBlock().getTypeId() == 8 || ent.getLocation().getBlock().getTypeId() == 9; + } + + /** + * 判断实体是否隐藏 + * + * @param entity + * 实体 + * @return 是否隐藏 + */ + public static boolean isInvisible(final Entity entity) { + final Object ent = ReflectUtil.getHandle(entity); + try { + return (boolean) ent.getClass().getMethod("isInvisible").invoke(ent); + } catch (final Exception e) { + } + return false; + } + + /** + * 实体是否在地上 + * + * @param ent + * 实体 + * @return 结果 + */ + public static boolean isOnGround(final Entity ent) { + return ent.isOnGround(); + } + + /** + * 判断是否为禁摩状态 + * + * @param entity + * 实体 + * @return 结果 + */ + public static boolean isSilence(final Entity entity) { + return WrappedDataWatcher.getEntityWatcher(entity).getByte(4) == 1; + } + + /** + * 判断实体是否在方块上 + * + * @param entity + * 实体 + * @return 结果 + */ + public static boolean onBlock(final Entity entity) { + // Side Standing + double xMod = entity.getLocation().getX() % 1; + if (entity.getLocation().getX() < 0) { + xMod += 1; + } + + double zMod = entity.getLocation().getZ() % 1; + if (entity.getLocation().getZ() < 0) { + zMod += 1; + } + + int xMin = 0; + int xMax = 0; + int zMin = 0; + int zMax = 0; + + if (xMod < 0.3) { + xMin = -1; + } + if (xMod > 0.7) { + xMax = 1; + } + + if (zMod < 0.3) { + zMin = -1; + } + if (zMod > 0.7) { + zMax = 1; + } + + for (int x = xMin; x <= xMax; x++) { + for (int z = zMin; z <= zMax; z++) { + // Standing on SOMETHING + if (entity.getLocation().add(x, -0.5, z).getBlock().getType() != Material.AIR && !entity.getLocation().add(x, -0.5, z).getBlock().isLiquid()) { + return true; + } + + // Inside a Lillypad + if (entity.getLocation().add(x, 0, z).getBlock().getType() == Material.WATER_LILY) { + return true; + } + + // Fences/Walls + final Material beneath = entity.getLocation().add(x, -1.5, z).getBlock().getType(); + if (entity.getLocation().getY() % 0.5 == 0 && (beneath == Material.FENCE || beneath == Material.FENCE_GATE || beneath == Material.NETHER_FENCE || beneath == Material.COBBLE_WALL)) { + return true; + } + } + } + + return false; + } + + /** + * 解析实体类型 + * + * @param str + * 实体名称 + * @return {@link EntityType} + */ + public static EntityType parseEntityType(final String str) { + EntityType type = null; + if (str != null) { + type = EntityType.fromName(str); + if (type == null) { + try { + type = EntityType.valueOf(str.toUpperCase()); + } catch (final Exception e) { + } + } + } + return type; + } + + /** + * 移除全局选择器 + * + * @param entity + * 实体 + */ + public static void removeGoalSelectors(final Entity entity) { + try { + if (_fgoalSelector == null) { + _fgoalSelector = _cEntityInsentient.getDeclaredField("goalSelector"); + _fgoalSelector.setAccessible(true); + } + final Object creature = ReflectUtil.getHandle(entity); + if (_cEntityInsentient.isInstance(creature)) { + final Object world = ReflectUtil.getHandle(entity.getWorld()); + final Object methodProfiler = world.getClass().getField("methodProfiler").get(world); + final Object goalSelector = _cPathfinderGoalSelector.getConstructor(methodProfiler.getClass()).newInstance(methodProfiler); + _fgoalSelector.set(creature, goalSelector); + } + } catch (final Exception e) { + e.printStackTrace(); + } + } + + /** + * 隐藏实体 + * + * @param entity + * 实体 + * @param invisible + * 是否隐藏 + */ + public static void setInvisible(final Entity entity, final boolean invisible) { + final Object ent = ReflectUtil.getHandle(entity); + try { + ent.getClass().getMethod("setInvisible", boolean.class).invoke(ent, invisible); + } catch (final Exception e) { + } + } + + /** + * 设置实体为静默状态 + * + * @param entity + * 实体 + * @param silence + * 是否静默 + */ + public static void setSilence(final Entity entity, final boolean silence) { + final byte value = (byte) (silence ? 1 : 0); + final WrappedDataWatcher watcher = WrappedDataWatcher.getEntityWatcher(entity); + watcher.setObject(4, value); + } + + /** + * 静默传送, 不触发事件 + * + * @param entity + * @param to + */ + public static void teleportQuietly(final Entity entity, final Location to) { + if (!(entity instanceof Player)) { + entity.teleport(to); + } else { + if (entity.getWorld().equals(to.getWorld())) { + final Object playerConnection = MinecraftFields.getPlayerConnection((Player) entity); + if (_mPlayerConnection_Teleport == null) { + _mPlayerConnection_Teleport = ReflectUtil.getMethodByNameAndParams(playerConnection.getClass(), "teleport", Location.class); + } + try { + _mPlayerConnection_Teleport.invoke(playerConnection, to); + } catch (final Exception ex) { + ex.printStackTrace(); + } + } else { + final Object toWorldServer = ReflectUtil.getHandle(to.getWorld()); + final Object server = ReflectUtil.getHandle(Bukkit.getServer()); + if (_fWorldServer_dimension == null) { + for (final Field field : ReflectUtil.getFieldByType(toWorldServer.getClass(), Integer.TYPE)) { + final int modifier = field.getModifiers(); + if (Modifier.isFinal(modifier) && Modifier.isPublic(modifier)) { + _fWorldServer_dimension = field; + } + } + } + try { + _mPlayerList_MoveToWorld.invoke(server, ReflectUtil.getHandle(entity), (int) _fWorldServer_dimension.get(toWorldServer), true, to, true); + } catch (final Exception e) { + e.printStackTrace(); + } + } + } + } + + /** + * 让实体升高/降低 + * + * @param ent + * @param speed + * 速度 + * @param yAdd + * Y轴加减 + * @param yMax + * Y轴最大值 + * @param groundBoost + * 当实体在地上的时候,会稍微抬起一些 + */ + public static void velocity(final Entity ent, final double speed, final double yAdd, final double yMax, final boolean groundBoost) { + velocity(ent, ent.getLocation().getDirection(), speed, false, 0.0D, yAdd, yMax, groundBoost); + } + + /** + * 让实体升高/降低 + * + * @param ent + * @param vec + * 坐标 + * @param speed + * 速度 + * @param ySet + * 是否设置Y轴初始值 + * @param yBase + * Y轴初始值 + * @param yAdd + * Y轴加减 + * @param yMax + * Y轴最大值 + * @param groundBoost + * 当实体在地上的时候,会稍微抬起一些 + */ + public static void velocity(final Entity ent, final Vector vec, final double speed, final boolean ySet, final double yBase, final double yAdd, final double yMax, final boolean groundBoost) { + if ((Double.isNaN(vec.getX())) || (Double.isNaN(vec.getY())) || (Double.isNaN(vec.getZ())) || (vec.length() == 0.0D)) { + return; + } + + if (ySet) { + vec.setY(yBase); + } + + vec.normalize(); + vec.multiply(speed); + + vec.setY(vec.getY() + yAdd); + + if (vec.getY() > yMax) { + vec.setY(yMax); + } + if ((groundBoost) && (ent.isOnGround())) { + vec.setY(vec.getY() + 0.2D); + } + + ent.setFallDistance(0.0F); + ent.setVelocity(vec); + } + + public static void walkTo(final Entity entity, final Location location) { + if (entity == null || location == null) { + return; + } + final Object nmsEntityEntity = ReflectUtil.getHandle(entity); + if (!_cEntityInsentient.isInstance(nmsEntityEntity)) { + entity.teleport(location); + return; + } + try { + final Object oFollowerNavigation = _mGetNavigation.invoke(nmsEntityEntity); + + final Object path = _mA3.invoke(oFollowerNavigation, location.getX(), location.getY(), location.getZ()); + if (path != null) { + _mA2.invoke(oFollowerNavigation, path, 1D); + _mA1.invoke(oFollowerNavigation, 2D); + } + if (location.distance(entity.getLocation()) > 20) { + entity.teleport(location); + } + } catch (final Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/pw/yumc/YumCore/kit/HashKit.java b/src/main/java/pw/yumc/YumCore/kit/HashKit.java new file mode 100644 index 0000000..c22de5c --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/kit/HashKit.java @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package pw.yumc.YumCore.kit; + +import java.security.MessageDigest; + +public class HashKit { + + private static java.security.SecureRandom random = new java.security.SecureRandom(); + + /** + * 生成种子 + *

+ * md5 128bit 16bytes + *

+ * sha1 160bit 20bytes + *

+ * sha256 256bit 32bytes + *

+ * sha384 384bit 48bites + *

+ * sha512 512bit 64bites + *

+ * + * @param numberOfBytes + * 数字比特 + * @return 种子字串 + */ + public static String generateSalt(final int numberOfBytes) { + final byte[] salt = new byte[numberOfBytes]; + random.nextBytes(salt); + return toHex(salt); + } + + /** + * 字符串加密 + * + * @param algorithm + * 算法 + * @param srcStr + * 字符串 + * @return 加密后的字符串 + */ + public static String hash(final String algorithm, final String srcStr) { + try { + final StringBuilder result = new StringBuilder(); + final MessageDigest md = MessageDigest.getInstance(algorithm); + final byte[] bytes = md.digest(srcStr.getBytes("utf-8")); + for (final byte b : bytes) { + final String hex = Integer.toHexString(b & 0xFF); + if (hex.length() == 1) { + result.append("0"); + } + result.append(hex); + } + return result.toString(); + } catch (final Exception e) { + throw new RuntimeException(e); + } + } + + /** + * MD5加密 + * + * @param srcStr + * 字符串 + * @return 加密后的字符串 + */ + public static String md5(final String srcStr) { + return hash("MD5", srcStr); + } + + /** + * sha1加密 + * + * @param srcStr + * 字符串 + * @return 加密后的字符串 + */ + public static String sha1(final String srcStr) { + return hash("SHA-1", srcStr); + } + + /** + * sha256加密 + * + * @param srcStr + * 字符串 + * @return 加密后的字符串 + */ + public static String sha256(final String srcStr) { + return hash("SHA-256", srcStr); + } + + /** + * sha384加密 + * + * @param srcStr + * 字符串 + * @return 加密后的字符串 + */ + public static String sha384(final String srcStr) { + return hash("SHA-384", srcStr); + } + + /** + * sha512加密 + * + * @param srcStr + * 字符串 + * @return 加密后的字符串 + */ + public static String sha512(final String srcStr) { + return hash("SHA-512", srcStr); + } + + /** + * Byte转字符串 + * + * @param bytes + * Byte数组 + * @return 字符串 + */ + private static String toHex(final byte[] bytes) { + final StringBuilder result = new StringBuilder(); + for (final byte b : bytes) { + final String hex = Integer.toHexString(b & 0xFF); + if (hex.length() == 1) { + result.append("0"); + } + result.append(hex); + } + return result.toString(); + } +} diff --git a/src/main/java/pw/yumc/YumCore/kit/HttpKit.java b/src/main/java/pw/yumc/YumCore/kit/HttpKit.java new file mode 100644 index 0000000..e5db631 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/kit/HttpKit.java @@ -0,0 +1,354 @@ +/** + * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package pw.yumc.YumCore.kit; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Map; +import java.util.Map.Entry; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +/** + * HttpKit + */ +public class HttpKit { + + private static final String GET = "GET"; + + private static final String POST = "POST"; + + private static final String CHARSET = "UTF-8"; + + private static final SSLSocketFactory sslSocketFactory = initSSLSocketFactory(); + private static final TrustAnyHostnameVerifier trustAnyHostnameVerifier = new HttpKit.TrustAnyHostnameVerifier(); + + private HttpKit() { + } + + /** + * Get 方法获取HTML + * + * @param url + * 网址 + * @return 网页HTML + */ + public static String get(final String url) { + return get(url, null, null); + } + + /** + * Get 方法获取HTML + * + * @param url + * 网址 + * @param queryParas + * 查询参数 + * @return 网页HTML + */ + public static String get(final String url, final Map queryParas) { + return get(url, queryParas, null); + } + + /** + * Get 方法获取HTML + * + * @param url + * 网址 + * @param queryParas + * 查询参数 + * @param headers + * 头信息 + * @return 网页HTML + */ + public static String get(final String url, final Map queryParas, final Map headers) { + HttpURLConnection conn = null; + try { + conn = getHttpConnection(buildUrlWithQueryString(url, queryParas), GET, headers); + conn.connect(); + return readResponseString(conn); + } catch (final Exception e) { + throw new RuntimeException(e); + } finally { + if (conn != null) { + conn.disconnect(); + } + } + } + + /** + * Post 获取网页 + * + * @param url + * 网址 + * @param queryParas + * 参数 + * @param data + * 数据 + * @return 网页HTML + */ + public static String post(final String url, final Map queryParas, final String data) { + return post(url, queryParas, data, null); + } + + /** + * Post 获取网页 + * + * @param url + * 网址 + * @param queryParas + * 参数 + * @param data + * 数据 + * @param headers + * 头信息 + * @return 网页HTML + */ + public static String post(final String url, final Map queryParas, final String data, final Map headers) { + HttpURLConnection conn = null; + try { + conn = getHttpConnection(buildUrlWithQueryString(url, queryParas), POST, headers); + conn.connect(); + + final OutputStream out = conn.getOutputStream(); + out.write(data.getBytes(CHARSET)); + out.flush(); + out.close(); + + return readResponseString(conn); + } catch (final Exception e) { + throw new RuntimeException(e); + } finally { + if (conn != null) { + conn.disconnect(); + } + } + } + + /** + * Get 方法获取HTML + * + * @param url + * 网址 + * @param data + * 查询参数 + * @return 网页HTML + */ + public static String post(final String url, final String data) { + return post(url, null, data, null); + } + + /** + * Get 方法获取HTML + * + * @param url + * 网址 + * @param data + * 查询参数 + * @param headers + * 头信息 + * @return 网页HTML + */ + public static String post(final String url, final String data, final Map headers) { + return post(url, null, data, headers); + } + + /** + * 构建查询串为字符串 + * + * @param url + * 网址 + * @param queryParas + * 参数 + * @return 构建后的地址 + */ + private static String buildUrlWithQueryString(final String url, final Map queryParas) { + if (queryParas == null || queryParas.isEmpty()) { + return url; + } + + final StringBuilder sb = new StringBuilder(url); + boolean isFirst; + if (url.indexOf("?") == -1) { + isFirst = true; + sb.append("?"); + } else { + isFirst = false; + } + + for (final Entry entry : queryParas.entrySet()) { + if (isFirst) { + isFirst = false; + } else { + sb.append("&"); + } + + final String key = entry.getKey(); + String value = entry.getValue(); + if (StrKit.notBlank(value)) { + try { + value = URLEncoder.encode(value, CHARSET); + } catch (final UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + sb.append(key).append("=").append(value); + } + return sb.toString(); + } + + /** + * 获得HTTP链接 + * + * @param url + * 地址 + * @param method + * 方法 + * @param headers + * 头信息 + * @return HTTP链接 + * @throws IOException + * @throws NoSuchAlgorithmException + * @throws NoSuchProviderException + * @throws KeyManagementException + */ + private static HttpURLConnection getHttpConnection(final String url, final String method, final Map headers) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException { + final URL _url = new URL(url); + final HttpURLConnection conn = (HttpURLConnection) _url.openConnection(); + if (conn instanceof HttpsURLConnection) { + ((HttpsURLConnection) conn).setSSLSocketFactory(sslSocketFactory); + ((HttpsURLConnection) conn).setHostnameVerifier(trustAnyHostnameVerifier); + } + + conn.setRequestMethod(method); + conn.setDoOutput(true); + conn.setDoInput(true); + + conn.setConnectTimeout(19000); + conn.setReadTimeout(19000); + + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36"); + + if (headers != null && !headers.isEmpty()) { + for (final Entry entry : headers.entrySet()) { + conn.setRequestProperty(entry.getKey(), entry.getValue()); + } + } + + return conn; + } + + /** + * 获得SSL安全套接字 + * + * @return 安全套接字工厂 + */ + private static SSLSocketFactory initSSLSocketFactory() { + try { + final TrustManager[] tm = { new HttpKit.TrustAnyTrustManager() }; + final SSLContext sslContext = SSLContext.getInstance("TLS", "SunJSSE"); + sslContext.init(null, tm, new java.security.SecureRandom()); + return sslContext.getSocketFactory(); + } catch (final Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 从连接读取HTML + * + * @param conn + * HTTP连接 + * @return 字符串 + */ + private static String readResponseString(final HttpURLConnection conn) { + final StringBuilder sb = new StringBuilder(); + InputStream inputStream = null; + try { + inputStream = conn.getInputStream(); + final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, CHARSET)); + String line = null; + while ((line = reader.readLine()) != null) { + sb.append(line).append("\n"); + } + return sb.toString(); + } catch (final Exception e) { + throw new RuntimeException(e); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (final IOException e) { + e.printStackTrace(); + } + } + } + } + + /** + * https 域名校验 + * + * @author 喵♂呜 + * @since 2016年4月1日 下午10:36:01 + */ + private static class TrustAnyHostnameVerifier implements HostnameVerifier { + @Override + public boolean verify(final String hostname, final SSLSession session) { + return true; + } + } + + /** + * https 证书管理 + * + * @author 喵♂呜 + * @since 2016年4月1日 下午10:36:05 + */ + private static class TrustAnyTrustManager implements X509TrustManager { + @Override + public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + } +} diff --git a/src/main/java/pw/yumc/YumCore/kit/StrKit.java b/src/main/java/pw/yumc/YumCore/kit/StrKit.java index 0c366fc..65d12ff 100644 --- a/src/main/java/pw/yumc/YumCore/kit/StrKit.java +++ b/src/main/java/pw/yumc/YumCore/kit/StrKit.java @@ -1,5 +1,10 @@ package pw.yumc.YumCore.kit; +import java.util.Collection; + +import org.apache.commons.lang.Validate; +import org.bukkit.ChatColor; + /** * 字符串工具类 * @@ -7,9 +12,20 @@ package pw.yumc.YumCore.kit; * @since 2016年9月14日 上午1:02:23 */ public class StrKit { + private static final String EMPTY = ""; + private StrKit() { } + /** + * @param string + * 源字串 + * @return 颜色转化后的字串 + */ + public static String color(final String string) { + return ChatColor.translateAlternateColorCodes('&', string); + } + /** * 转移数组后获取字符串 * @@ -29,6 +45,44 @@ public class StrKit { return ret; } + /** + * Copies all elements from the iterable collection of originals to the + * collection provided. + * + * @param + * the collection of strings + * @param token + * String to search for + * @param originals + * An iterable collection of strings to filter. + * @param collection + * The collection to add matches to + * @return the collection provided that would have the elements copied + * into + * @throws UnsupportedOperationException + * if the collection is immutable + * and originals contains a string which starts with the specified + * search string. + * @throws IllegalArgumentException + * if any parameter is is null + * @throws IllegalArgumentException + * if originals contains a null element. + * Note: the collection may be modified before this is thrown + */ + public static > T copyPartialMatches(final String token, final Iterable originals, final T collection) throws UnsupportedOperationException, IllegalArgumentException { + Validate.notNull(token, "Search token cannot be null"); + Validate.notNull(collection, "Collection cannot be null"); + Validate.notNull(originals, "Originals cannot be null"); + + for (final String string : originals) { + if (startsWithIgnoreCase(string, token)) { + collection.add(string); + } + } + + return collection; + } + /** * @param str * 字串 @@ -38,6 +92,35 @@ public class StrKit { return str == null || str.isEmpty(); } + /** + * 转化数组为字符串 + * + * @param arr + * 数组 + * @return 字符串 + */ + public static String join(final Object[] arr) { + return join(arr, EMPTY); + } + + /** + * 转化数组为字符串 + * + * @param arr + * 数组 + * @param split + * 分割符 + * @return 字符串 + */ + public static String join(final Object[] arr, final String split) { + final StringBuffer str = new StringBuffer(); + for (final Object s : arr) { + str.append(s.toString()); + str.append(split); + } + return str.length() > split.length() ? str.toString().substring(0, str.length() - split.length()) : str.toString(); + } + /** * @param str * 字串 @@ -46,4 +129,107 @@ public class StrKit { public static boolean notBlank(final String str) { return str != null && !str.isEmpty(); } + + /** + * This method uses a region to check case-insensitive equality. This + * means the internal array does not need to be copied like a + * toLowerCase() call would. + * + * @param string + * String to check + * @param prefix + * Prefix of string to compare + * @return true if provided string starts with, ignoring case, the prefix + * provided + * @throws NullPointerException + * if prefix is null + * @throws IllegalArgumentException + * if string is null + */ + public static boolean startsWithIgnoreCase(final String string, final String prefix) throws IllegalArgumentException, NullPointerException { + Validate.notNull(string, "Cannot check a null string for a match"); + if (string.length() < prefix.length()) { + return false; + } + return string.regionMatches(true, 0, prefix, 0, prefix.length()); + } + + /** + *

+ * Gets a substring from the specified String avoiding exceptions. + *

+ * + *

+ * A negative start position can be used to start/end n + * characters from the end of the String. + *

+ * + *

+ * The returned substring starts with the character in the start + * position and ends before the end position. All position counting is + * zero-based -- i.e., to start at the beginning of the string use + * start = 0. Negative start and end positions can be used to + * specify offsets relative to the end of the String. + *

+ * + *

+ * If start is not strictly to the left of end, "" + * is returned. + *

+ * + *
+     * StringUtils.substring(null, *, *)    = null
+     * StringUtils.substring("", * ,  *)    = "";
+     * StringUtils.substring("abc", 0, 2)   = "ab"
+     * StringUtils.substring("abc", 2, 0)   = ""
+     * StringUtils.substring("abc", 2, 4)   = "c"
+     * StringUtils.substring("abc", 4, 6)   = ""
+     * StringUtils.substring("abc", 2, 2)   = ""
+     * StringUtils.substring("abc", -2, -1) = "b"
+     * StringUtils.substring("abc", -4, 2)  = "ab"
+     * 
+ * + * @param str + * the String to get the substring from, may be null + * @param start + * the position to start from, negative means + * count back from the end of the String by this many characters + * @param end + * the position to end at (exclusive), negative means + * count back from the end of the String by this many characters + * @return substring from start position to end positon, + * null if null String input + */ + public static String substring(final String str, int start, int end) { + if (str == null) { + return null; + } + + // handle negatives + if (end < 0) { + end = str.length() + end; // remember end is negative + } + if (start < 0) { + start = str.length() + start; // remember start is negative + } + + // check length next + if (end > str.length()) { + end = str.length(); + } + + // if start is greater than end, return "" + if (start > end) { + return EMPTY; + } + + if (start < 0) { + start = 0; + } + if (end < 0) { + end = 0; + } + + return str.substring(start, end); + } } diff --git a/src/main/java/pw/yumc/YumCore/kit/ZipKit.java b/src/main/java/pw/yumc/YumCore/kit/ZipKit.java new file mode 100644 index 0000000..3e874bc --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/kit/ZipKit.java @@ -0,0 +1,70 @@ +package pw.yumc.YumCore.kit; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +/** + * ZIP操作类 + * + * @since 2016年7月19日 上午10:24:06 + * @author 喵♂呜 + */ +public class ZipKit { + /** + * 获取文件真实名称 + * + * @param name + * 名称 + * @return + */ + public static String getRealName(final String name) { + return new File(name).getName(); + } + + /** + * @param zipFile + * zip文件 + * @param destPath + * 解压目录 + * @throws ZipException + * ZIP操作异常 + * @throws IOException + * IO异常 + */ + public static void unzip(final File zipFile, final File destPath) throws ZipException, IOException { + unzip(zipFile, destPath, null); + } + + /** + * @param zipFile + * zip文件 + * @param destPath + * 解压目录 + * @param ext + * 解压后缀 + * @throws ZipException + * ZIP操作异常 + * @throws IOException + * IO异常 + */ + public static void unzip(final File zipFile, final File destPath, final String ext) throws ZipException, IOException { + final ZipFile zipObj = new ZipFile(zipFile); + final Enumeration e = zipObj.entries(); + while (e.hasMoreElements()) { + final ZipEntry entry = e.nextElement(); + final File destinationFilePath = new File(destPath, getRealName(entry.getName())); + if (entry.isDirectory() || (ext != null && !destinationFilePath.getName().endsWith(ext))) { + continue; + } + destinationFilePath.getParentFile().mkdirs(); + Files.copy(zipObj.getInputStream(entry), destinationFilePath.toPath(), StandardCopyOption.REPLACE_EXISTING); + } + zipObj.close(); + } +} diff --git a/src/main/java/pw/yumc/YumCore/misc/L10N.java b/src/main/java/pw/yumc/YumCore/misc/L10N.java deleted file mode 100644 index 7a739ee..0000000 --- a/src/main/java/pw/yumc/YumCore/misc/L10N.java +++ /dev/null @@ -1,141 +0,0 @@ -package pw.yumc.YumCore.misc; - -import java.util.HashMap; -import java.util.Map; - -import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; -import org.bukkit.material.SpawnEgg; - -import pw.yumc.YumCore.bukkit.Log; -import pw.yumc.YumCore.config.FileConfig; -import pw.yumc.YumCore.config.YumConfig; - -/** - * 本地化工具类 - * - * @since 2015年12月14日 下午1:33:52 - * @author 喵♂呜 - */ -public class L10N { - private static String CONFIG_NAME = "Item_zh_CN.yml"; - private static FileConfig custom; - private static Map content; - - static { - content = new HashMap<>(); - Log.info("异步初始化本地化工具..."); - load(); - } - - private L10N() { - } - - /** - * 获取物品完整汉化名称(包括原版) - * - * @param i - * 物品实体 - * @return 物品名称 - */ - public static final String getFullName(final ItemStack i) { - return getItemName(getItemType(i)) + (i.hasItemMeta() && i.getItemMeta().hasDisplayName() ? "§r(" + i.getItemMeta().getDisplayName() + "§r)" : ""); - } - - /** - * 获取物品汉化名称 - * - * @param i - * 物品实体 - * @return 物品名称 - */ - public static final String getItemName(final ItemStack i) { - return getItemName(getItemType(i)); - } - - /** - * 获取物品汉化名称(优先显示名称) - * - * @param i - * 物品实体 - * @return 物品名称 - */ - public static final String getName(final ItemStack i) { - return i.hasItemMeta() && i.getItemMeta().hasDisplayName() ? i.getItemMeta().getDisplayName() : getItemName(getItemType(i)); - } - - /** - * 重载LocalUtil - */ - public static void reload() { - Log.info("异步重载本地化工具..."); - content.clear(); - load(); - } - - /** - * 获取物品汉化名称 - * - * @param iname - * 物品类型名称 - * @return 物品名称 - */ - private static final String getItemName(final String iname) { - String aname = content.get(iname); - if (aname == null) { - aname = iname; - if (custom != null) { - custom.set(iname, iname); - custom.save(); - } - } - return aname; - } - - /** - * 获取物品类型名称 - * - * @param i - * 物品实体 - * @return 物品类型 - */ - private static final String getItemType(final ItemStack i) { - String name = i.getType().name(); - String dura = ""; - if (i.getType() == Material.MONSTER_EGG) { - name = ((SpawnEgg) i.getData()).getSpawnedType().name(); - } else { - final int dur = i.getDurability(); - dura = (i.getMaxStackSize() != 1 && dur != 0) ? Integer.toString(dur) : ""; - } - return (name + (dura.isEmpty() ? "" : "-" + dura)).toUpperCase(); - } - - /** - * 载入数据 - */ - private static void load() { - new Thread(new Runnable() { - @SuppressWarnings("unchecked") - @Override - public void run() { - try { - final Map local = YumConfig.getLocal(CONFIG_NAME).getContentMap(); - final Map remote = YumConfig.getRemote(CONFIG_NAME).getContentMap(); - if (local != null) { - Log.info("本地汉化文件词条数量: " + local.size()); - content.putAll(local); - } - if (remote != null) { - Log.info("远程汉化文件词条数量: " + remote.size()); - content.putAll(remote); - } - Log.info("本地化工具初始化完毕..."); - } catch (final Exception e) { - Log.warning(String.format("本地化工具初始化失败: %s %s", e.getClass().getName(), e.getMessage())); - Log.debug(CONFIG_NAME, e); - } - } - }).start(); - } -}