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
+ * Gets a substring from the specified String avoiding exceptions.
+ *
+ * A negative start position can be used to start/end
+ * The returned substring starts with the character in the
+ * If n
+ * characters from the end of the String.
+ * 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.
+ * 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 extends ZipEntry> 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