From ab3ed6bebe9b81d5e11a60001cc2e4e8a8fa2bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9D=8F=E9=BB=91?= Date: Sat, 6 Jul 2019 00:17:54 +0800 Subject: [PATCH] Taboolib 5.0 fully refactored & Not a plugin now. --- build.gradle | 13 +- src/main/resources/Addons/TabooLibDeprecated | Bin 427084 -> 0 bytes src/main/resources/Language2/Language2.yml | 125 -- src/main/resources/Language2/zh_CN.yml | 66 - src/main/resources/TLM/CommandChanger.yml | 14 - src/main/resources/TLM/Kits.yml | 34 - src/main/resources/TLM/TimeCycle.yml | 35 - src/main/resources/bungee.yml | 5 - src/main/resources/config.yml | 55 +- .../{hikarisettings.yml => datasource.yml} | 0 src/main/resources/items.yml | 51 - src/main/resources/lang/internal.yml | 6 +- src/main/resources/lang/zh_CN.yml | 513 +---- src/main/resources/module.yml | 10 - src/main/resources/motd.txt | 10 - src/main/resources/plugin.yml | 14 - src/main/resources/translateuuid.yml | 11 - src/main/resources/version | 1 + .../scala/com/ilummc/tlib/ExampleMain.java | 114 -- src/main/scala/com/ilummc/tlib/TLib.java | 137 -- .../com/ilummc/tlib/annotations/Logger.java | 16 - .../tlib/annotations/PluginInstance.java | 13 - .../com/ilummc/tlib/annotations/TConfig.java | 29 - .../tlib/annotations/TLocalePlugin.java | 11 - .../tlib/annotations/clr/CommandHandler.java | 17 - .../tlib/annotations/clr/CommandHandlers.java | 14 - .../com/ilummc/tlib/annotations/clr/Sub.java | 14 - .../ilummc/tlib/annotations/db/Database.java | 11 - .../tlib/annotations/db/DatabasePassword.java | 4 - .../tlib/annotations/db/DatabaseType.java | 4 - .../tlib/annotations/db/DatabaseUrl.java | 4 - .../tlib/annotations/db/DatabaseUser.java | 4 - .../ilummc/tlib/annotations/db/SQLTable.java | 14 - .../scala/com/ilummc/tlib/bean/Property.java | 43 - .../ilummc/tlib/bean/PropertyTypeAdaptor.java | 16 - .../ilummc/tlib/clr/CommandLineResolver.java | 7 - .../com/ilummc/tlib/config/TLibConfig.java | 59 - src/main/scala/com/ilummc/tlib/db/Pool.java | 63 - .../com/ilummc/tlib/db/TLibDataSource.java | 35 - .../ilummc/tlib/dependency/TDependency.java | 80 - .../tlib/dependency/TDependencyLoader.java | 32 - .../com/ilummc/tlib/filter/TLoggerFilter.java | 102 - .../tlib/filter/TLoggerFilterHandler.java | 13 - .../tlib/filter/impl/FilterConfiguration.java | 28 - .../filter/impl/FilterExceptionMirror.java | 119 -- .../impl/FilterInvalidPluginLoader.java | 18 - .../ilummc/tlib/inject/TConfigInjector.java | 143 -- .../tlib/inject/TDependencyInjector.java | 188 -- .../ilummc/tlib/inject/TPluginManager.java | 231 --- .../scala/com/ilummc/tlib/nms/ActionBar.java | 47 - .../ilummc/tlib/resources/TLocaleLoader.java | 169 -- .../ilummc/tlib/resources/TLocaleSender.java | 37 - src/main/scala/com/ilummc/tlib/util/IO.java | 18 - .../scala/com/ilummc/tlib/util/Strings.java | 48 - .../tlibscala/runtime/RichOfflinePlayer.scala | 30 - .../ilummc/tlibscala/runtime/RichPlayer.scala | 68 - .../bstats => io/izzel/taboolib}/Metrics.java | 18 +- .../scala/io/izzel/taboolib/PluginLoader.java | 109 ++ .../scala/io/izzel/taboolib/TabooLib.java | 137 ++ .../scala/io/izzel/taboolib/TabooLibAPI.java | 91 + .../io/izzel/taboolib/TabooLibLoader.java | 159 ++ src/main/scala/io/izzel/taboolib/Version.java | 57 + .../command}/TabooLibExecuteCommand.java | 67 +- .../command}/TabooLibLocaleCommand.java | 16 +- .../command}/TabooLibPluginCommand.java | 54 +- .../taboolib/listener/ListenerNetWork.java | 9 +- .../listener/ListenerPlayerCommand.java | 59 + .../taboolib/listener/ListenerPlayerJump.java | 9 +- .../izzel/taboolib/locale}/TLocale.java | 33 +- .../taboolib/locale}/TLocaleInstance.java | 18 +- .../izzel/taboolib/locale/TLocaleSender.java | 19 + .../taboolib/locale}/TLocaleSerialize.java | 2 +- .../locale}/type/TLocaleActionBar.java | 11 +- .../taboolib/locale}/type/TLocaleBook.java | 22 +- .../taboolib/locale}/type/TLocaleBossBar.java | 19 +- .../taboolib/locale}/type/TLocaleJson.java | 31 +- .../taboolib/locale}/type/TLocaleSound.java | 18 +- .../taboolib/locale}/type/TLocaleText.java | 10 +- .../taboolib/locale}/type/TLocaleTitle.java | 9 +- .../module/ai}/PathfinderCreator.java | 2 +- .../module/ai}/PathfinderExecutor.java | 2 +- .../izzel/taboolib/module/ai}/SimpleAi.java | 2 +- .../taboolib/module/ai}/SimpleAiSelector.java | 14 +- .../internal/InternalPathfinderCreator.java | 6 +- .../internal/InternalPathfinderExecutor.java | 25 +- .../taboolib/module/command}/TCommand.java | 3 +- .../module/command}/TCommandHandler.java | 110 +- .../module/command/base}/BaseMainCommand.java | 56 +- .../module/command/base}/BaseSubCommand.java | 6 +- .../module/command/base}/CommandArgument.java | 4 +- .../module/command/base}/CommandField.java | 2 +- .../module/command/base}/CommandRegister.java | 2 +- .../module/command/base}/CommandTab.java | 2 +- .../module/command/base}/CommandType.java | 2 +- .../command/lite}/CompleterCommand.java | 4 +- .../module/command/lite}/CompleterTab.java | 2 +- .../command/lite}/SimpleCommandBuilder.java | 38 +- .../taboolib/module/compat/EconomyHook.java | 55 + .../module/compat/PermissionHook.java | 39 + .../module}/compat/PlaceholderHook.java | 6 +- .../module/compat/WorldGuardHook.java} | 8 +- .../taboolib/module/config/TConfig.java} | 58 +- .../module/config}/TConfigWatcher.java | 7 +- .../module/dependency}/Dependencies.java | 2 +- .../module/dependency}/Dependency.java | 4 +- .../module/dependency/TDependency.java | 62 + .../dependency/TDependencyInjector.java | 40 + .../taboolib/module/inject}/Container.java | 2 +- .../module/inject}/PlayerContainer.java | 2 +- .../module/inject}/PlayerContainerLoader.java | 15 +- .../taboolib/module/inject}/TFunction.java | 2 +- .../module/inject}/TFunctionLoader.java | 12 +- .../taboolib/module}/inject/TInject.java | 2 +- .../module}/inject/TInjectLoader.java | 30 +- .../taboolib/module}/inject/TInjectTask.java | 2 +- .../taboolib/module/inject}/TListener.java | 2 +- .../module/inject}/TListenerHandler.java | 49 +- .../taboolib/module/inject}/TSchedule.java | 2 +- .../module/inject}/TScheduleData.java | 2 +- .../module/inject}/TScheduleLoader.java | 30 +- .../taboolib/module/item}/ItemBuilder.java | 26 +- .../io/izzel/taboolib/module/item/Items.java | 286 +++ .../module/item/inventory}/ClickEvent.java | 2 +- .../module/item/inventory}/ClickListener.java | 4 +- .../item/inventory/ClickListenerOffhand.java} | 6 +- .../module/item/inventory}/ClickTask.java | 2 +- .../module/item/inventory}/ClickType.java | 2 +- .../module/item/inventory}/CloseTask.java | 2 +- .../module/item/inventory}/MenuBuilder.java | 8 +- .../module/item/inventory}/MenuHolder.java | 2 +- .../module/lite}/SimpleClassVisitor.java | 2 +- .../taboolib/module/lite}/SimpleCounter.java | 2 +- .../taboolib/module/lite/SimpleEquip.java} | 14 +- .../taboolib/module/lite}/SimpleI18n.java | 33 +- .../taboolib/module/lite}/SimpleIterator.java | 2 +- .../module/lite}/SimpleMethodVisitor.java | 2 +- .../module/lite}/SimpleReflection.java | 2 +- .../module/lite}/SimpleVersionControl.java | 16 +- .../taboolib/module}/logger/TLogger.java | 96 +- .../module/logger}/TLoggerManager.java | 3 +- .../izzel/taboolib/module}/mysql/IColumn.java | 2 +- .../izzel/taboolib/module}/mysql/IHost.java | 2 +- .../module}/mysql/builder/SQLColumn.java | 6 +- .../mysql/builder/SQLColumnOption.java | 2 +- .../module}/mysql/builder/SQLColumnType.java | 2 +- .../module}/mysql/builder/SQLExecutor.java | 2 +- .../module}/mysql/builder/SQLHost.java | 10 +- .../module}/mysql/builder/SQLTable.java | 20 +- .../mysql/builder/query/RunnableQuery.java | 6 +- .../mysql/builder/query/RunnableUpdate.java | 6 +- .../mysql/builder/query/TaskResult.java | 2 +- .../mysql/builder/query/TaskStatement.java | 2 +- .../module}/mysql/hikari/HikariHandler.java | 39 +- .../module}/mysql/hikari/MapDataSource.java | 4 +- .../module/mysql/lite}/SQLiteColumn.java | 6 +- .../mysql/lite}/SQLiteColumnOption.java | 2 +- .../module/mysql/lite}/SQLiteColumnType.java | 2 +- .../module/mysql/lite}/SQLiteHost.java | 4 +- .../taboolib/module}/nms/NMSHandler.java | 15 +- .../taboolib/module}/nms/NMSHandlerImpl.java | 79 +- .../taboolib/module}/nms/nbt/NBTBase.java | 2 +- .../taboolib/module}/nms/nbt/NBTCompound.java | 2 +- .../taboolib/module}/nms/nbt/NBTList.java | 7 +- .../taboolib/module}/nms/nbt/NBTType.java | 2 +- .../module}/packet/TPacketHandler.java | 10 +- .../module}/packet/TPacketListener.java | 2 +- .../packet/channel/ChannelExecutor.java | 4 +- .../channel/InternalChannelExecutor.java | 4 +- .../module}/serialize/DoNotSerialize.java | 2 +- .../module}/serialize/TSerializable.java | 2 +- .../serialize/TSerializeCollection.java | 2 +- .../module}/serialize/TSerializeCustom.java | 2 +- .../module}/serialize/TSerializeMap.java | 2 +- .../module}/serialize/TSerializer.java | 13 +- .../module}/serialize/TSerializerElement.java | 2 +- .../serialize/TSerializerElementGeneral.java | 6 +- .../module}/serialize/TSerializerExample.java | 6 +- .../module}/tellraw/TellrawCreator.java | 14 +- .../taboolib/module}/tellraw/TellrawJson.java | 32 +- .../module}/tellraw/TellrawVersion.java | 2 +- .../tellraw/internal/AbstractTellraw.java | 4 +- .../tellraw/internal/InternalTellraw.java | 23 +- .../origin/book}/BookAchievement.java | 2 +- .../taboolib/origin/book}/BookFormatter.java | 33 +- .../taboolib/origin/book}/BookReflection.java | 12 +- .../origin/book}/action/ClickAction.java | 4 +- .../origin/book}/action/HoverAction.java | 14 +- .../origin/book}/builder/BookBuilder.java | 10 +- .../origin/book}/builder/PageBuilder.java | 18 +- .../origin/book}/builder/TextBuilder.java | 11 +- .../origin/client}/TabooLibClient.java | 40 +- .../origin/client}/TabooLibServer.java | 20 +- .../origin/client}/TabooLibSettings.java | 2 +- .../origin/client}/packet/Packet.java | 2 +- .../origin/client}/packet/PacketParser.java | 7 +- .../client}/packet/PacketSerializer.java | 15 +- .../origin/client}/packet/PacketType.java | 2 +- .../origin/client}/packet/PacketValue.java | 2 +- .../client}/packet/impl/PacketAlive.java | 8 +- .../client}/packet/impl/PacketCommand.java | 10 +- .../client}/packet/impl/PacketEmpty.java | 6 +- .../client}/packet/impl/PacketHeartbeat.java | 9 +- .../client}/packet/impl/PacketJoin.java | 10 +- .../client}/packet/impl/PacketMessage.java | 13 +- .../client}/packet/impl/PacketQuit.java | 12 +- .../client}/server/ClientConnection.java | 14 +- .../taboolib/origin}/cronus/CronusParser.java | 6 +- .../taboolib/origin}/cronus/CronusUtils.java | 4 +- .../origin}/cronus/bukkit/ItemStack.java | 8 +- .../origin}/cronus/bukkit/Location.java | 2 +- .../origin}/cronus/util/StringExpression.java | 8 +- .../origin}/cronus/util/StringNumber.java | 2 +- .../origin/database/PlayerDataManager.java | 95 + .../origin/database/PluginDataManager.java | 86 + .../origin/event}/PlayerJumpEvent.java | 2 +- .../origin/event}/PlayerLoadedEvent.java | 2 +- .../izzel/taboolib/origin/lite/Boards.java} | 185 +- .../izzel/taboolib/origin/lite/Catchers.java | 70 + .../izzel/taboolib/origin/lite/Effects.java | 967 ++++++++++ .../izzel/taboolib/origin/lite/Logs.java} | 26 +- .../izzel/taboolib/origin/lite/Numbers.java | 48 + .../izzel/taboolib/origin/lite/Scripts.java} | 9 +- .../izzel/taboolib/origin/lite/Servers.java | 47 + .../io/izzel/taboolib/origin/lite/Sounds.java | 117 ++ .../izzel/taboolib/origin/lite/Weights.java} | 8 +- .../origin/lite/cooldown/Cooldown.java | 72 + .../origin/lite/cooldown/Cooldowns.java | 47 + .../origin}/plugin/PluginLoadState.java | 2 +- .../origin}/plugin/PluginLoadStateType.java | 2 +- .../origin}/plugin/PluginUnloadState.java | 2 +- .../taboolib/origin}/plugin/PluginUtils.java | 22 +- .../taboolib/origin/tag}/TagDataHandler.java | 68 +- .../taboolib/origin/tag}/TagPlayerData.java | 10 +- .../izzel/taboolib/origin/tag}/TagUtils.java | 4 +- .../taboolib/plugin/InternalJavaPlugin.java | 10 + .../izzel/taboolib/plugin/InternalPlugin.java | 139 ++ .../taboolib/plugin/InternalPluginLoader.java | 59 + .../izzel/taboolib/util/ArrayUtil.java} | 25 +- .../scala/io/izzel/taboolib/util/Files.java | 297 +++ .../izzel/taboolib/util/IO.java} | 23 +- .../tlib => io/izzel/taboolib}/util/Ref.java | 18 +- .../izzel/taboolib/util/Reflection.java} | 6 +- .../izzel/taboolib/util/Strings.java} | 77 +- .../izzel/taboolib/util/Times.java} | 6 +- .../izzel/taboolib/util/Variables.java} | 16 +- .../izzel/taboolib}/util/asm/AsmAnalyser.java | 2 +- .../taboolib}/util/asm/AsmClassLoader.java | 2 +- .../util/asm/AsmClassTransformer.java | 2 +- .../taboolib/util}/chat/BaseComponent.java | 25 +- .../util}/chat/BaseComponentSerializer.java | 6 +- .../izzel/taboolib/util/chat}/ChatColor.java | 2 +- .../taboolib/util/chat}/ChatMessageType.java | 2 +- .../izzel/taboolib/util}/chat/ClickEvent.java | 2 +- .../taboolib/util}/chat/ComponentBuilder.java | 3 +- .../util}/chat/ComponentSerializer.java | 6 +- .../izzel/taboolib/util}/chat/HoverEvent.java | 2 +- .../taboolib/util}/chat/TextComponent.java | 4 +- .../util}/chat/TextComponentSerializer.java | 4 +- .../util}/chat/TranslatableComponent.java | 4 +- .../chat/TranslatableComponentSerializer.java | 4 +- .../util}/eagletdl/AlreadyStartException.java | 2 +- .../util}/eagletdl/CompleteEvent.java | 2 +- .../util}/eagletdl/ConnectedEvent.java | 2 +- .../DoNotSupportMultipleThreadException.java | 2 +- .../util}/eagletdl/EagletHandler.java | 2 +- .../taboolib/util}/eagletdl/EagletTask.java | 8 +- .../taboolib/util}/eagletdl/ErrorEvent.java | 2 +- .../util}/eagletdl/HashNotMatchException.java | 2 +- .../taboolib/util}/eagletdl/HashUtil.java | 2 +- .../util}/eagletdl/ProgressEvent.java | 2 +- .../util}/eagletdl/RetryFailedException.java | 2 +- .../util}/eagletdl/SingleThreadDownload.java | 2 +- .../util}/eagletdl/SplitDownload.java | 2 +- .../taboolib/util}/eagletdl/StartEvent.java | 2 +- .../lzzel}/tlibscala/AsyncTask.scala | 2 +- .../lzzel}/tlibscala/Example.scala | 11 +- .../lzzel}/tlibscala/Implicits.scala | 4 +- .../lzzel}/tlibscala/Prelude.scala | 4 +- .../lzzel}/tlibscala/ScalaTaskExecutor.scala | 3 +- .../ilummc => io/lzzel}/tlibscala/Task.scala | 2 +- .../tlibscala/runtime/RichLocation.scala | 2 +- .../tlibscala/runtime/RichOfflinePlayer.scala | 28 + .../lzzel/tlibscala/runtime/RichPlayer.scala | 40 + .../lzzel}/tlibscala/runtime/RichVector.scala | 7 +- src/main/scala/me/skymc/taboolib/Main.java | 269 --- .../scala/me/skymc/taboolib/TabooLib.java | 169 -- .../me/skymc/taboolib/TabooLibDatabase.java | 128 -- .../me/skymc/taboolib/TabooLibLoader.java | 305 --- .../skymc/taboolib/anvil/AnvilContainer.java | 29 - .../taboolib/anvil/AnvilContainerAPI.java | 44 - .../anvil/AnvilContainerGenerator.java | 142 -- .../skymc/taboolib/bungee/TabooLibBungee.java | 11 - .../skymc/taboolib/cloud/TCloudCommand.java | 250 --- .../me/skymc/taboolib/cloud/TCloudLoader.java | 133 -- .../taboolib/cloud/expansion/Expansion.java | 118 -- .../cloud/expansion/ExpansionType.java | 10 - .../commands/TabooLibMainCommand.java | 883 --------- .../commands/internal/TBaseCommand.java | 20 - .../commands/internal/plugin/TLibLocale.java | 33 - .../taboolib/common/json/TJsonArray.java | 350 ---- .../taboolib/common/json/TJsonObject.java | 253 --- .../taboolib/common/loader/Instantiable.java | 18 - .../common/loader/InstantiableLoader.java | 86 - .../taboolib/database/GlobalDataManager.java | 415 ---- .../taboolib/database/PlayerDataManager.java | 262 --- .../taboolib/events/CustomBookOpenEvent.java | 81 - .../taboolib/events/TPluginEnableEvent.java | 28 - .../taboolib/events/TPluginLoadEvent.java | 28 - .../itag/AsyncPlayerReceiveNameTagEvent.java | 85 - .../itag/PlayerReceiveNameTagEvent.java | 57 - .../exception/PlayerOfflineException.java | 10 - .../exception/PluginNotFoundException.java | 10 - .../skymc/taboolib/fileutils/ConfigUtils.java | 212 --- .../skymc/taboolib/fileutils/FileUtils.java | 481 ----- .../skymc/taboolib/inventory/ItemUtils.java | 493 ----- .../inventory/builder/MenuBuilder.java | 71 - .../builder/menu/MenuBuilderCallable.java | 10 - .../builder/menu/MenuBuilderEvent.java | 48 - .../builder/menu/MenuBuilderHolder.java | 50 - .../builder/menu/MenuBuilderItem.java | 26 - .../builder/menu/MenuBuilderListener.java | 49 - .../me/skymc/taboolib/itagapi/TagPacket.java | 134 -- .../listener/ListenerPlayerCommand.java | 104 - .../listener/ListenerPlayerJoinAndQuit.java | 33 - .../taboolib/listener/ListenerPlugin.java | 106 -- .../taboolib/listener/TListenerCommand.java | 9 - .../me/skymc/taboolib/particle/EffLib.java | 1677 ----------------- .../taboolib/particle/pack/ParticleData.java | 77 - .../taboolib/particle/pack/ParticlePack.java | 40 - .../taboolib/particle/pack/ParticleType.java | 11 - .../skymc/taboolib/playerdata/DataUtils.java | 154 -- .../taboolib/scoreboard/SimpleScoreboard.java | 216 --- .../me/skymc/taboolib/sound/SoundPack.java | 94 - .../me/skymc/taboolib/sound/SoundUtils.java | 43 - .../me/skymc/taboolib/update/UpdateTask.java | 136 -- 335 files changed, 4225 insertions(+), 12881 deletions(-) delete mode 100644 src/main/resources/Addons/TabooLibDeprecated delete mode 100644 src/main/resources/Language2/Language2.yml delete mode 100644 src/main/resources/Language2/zh_CN.yml delete mode 100644 src/main/resources/TLM/CommandChanger.yml delete mode 100644 src/main/resources/TLM/Kits.yml delete mode 100644 src/main/resources/TLM/TimeCycle.yml delete mode 100644 src/main/resources/bungee.yml rename src/main/resources/{hikarisettings.yml => datasource.yml} (100%) delete mode 100644 src/main/resources/items.yml delete mode 100644 src/main/resources/module.yml delete mode 100644 src/main/resources/motd.txt delete mode 100644 src/main/resources/plugin.yml delete mode 100644 src/main/resources/translateuuid.yml create mode 100644 src/main/resources/version delete mode 100644 src/main/scala/com/ilummc/tlib/ExampleMain.java delete mode 100644 src/main/scala/com/ilummc/tlib/TLib.java delete mode 100644 src/main/scala/com/ilummc/tlib/annotations/Logger.java delete mode 100644 src/main/scala/com/ilummc/tlib/annotations/PluginInstance.java delete mode 100644 src/main/scala/com/ilummc/tlib/annotations/TConfig.java delete mode 100644 src/main/scala/com/ilummc/tlib/annotations/TLocalePlugin.java delete mode 100644 src/main/scala/com/ilummc/tlib/annotations/clr/CommandHandler.java delete mode 100644 src/main/scala/com/ilummc/tlib/annotations/clr/CommandHandlers.java delete mode 100644 src/main/scala/com/ilummc/tlib/annotations/clr/Sub.java delete mode 100644 src/main/scala/com/ilummc/tlib/annotations/db/Database.java delete mode 100644 src/main/scala/com/ilummc/tlib/annotations/db/DatabasePassword.java delete mode 100644 src/main/scala/com/ilummc/tlib/annotations/db/DatabaseType.java delete mode 100644 src/main/scala/com/ilummc/tlib/annotations/db/DatabaseUrl.java delete mode 100644 src/main/scala/com/ilummc/tlib/annotations/db/DatabaseUser.java delete mode 100644 src/main/scala/com/ilummc/tlib/annotations/db/SQLTable.java delete mode 100644 src/main/scala/com/ilummc/tlib/bean/Property.java delete mode 100644 src/main/scala/com/ilummc/tlib/bean/PropertyTypeAdaptor.java delete mode 100644 src/main/scala/com/ilummc/tlib/clr/CommandLineResolver.java delete mode 100644 src/main/scala/com/ilummc/tlib/config/TLibConfig.java delete mode 100644 src/main/scala/com/ilummc/tlib/db/Pool.java delete mode 100644 src/main/scala/com/ilummc/tlib/db/TLibDataSource.java delete mode 100644 src/main/scala/com/ilummc/tlib/dependency/TDependency.java delete mode 100644 src/main/scala/com/ilummc/tlib/dependency/TDependencyLoader.java delete mode 100644 src/main/scala/com/ilummc/tlib/filter/TLoggerFilter.java delete mode 100644 src/main/scala/com/ilummc/tlib/filter/TLoggerFilterHandler.java delete mode 100644 src/main/scala/com/ilummc/tlib/filter/impl/FilterConfiguration.java delete mode 100644 src/main/scala/com/ilummc/tlib/filter/impl/FilterExceptionMirror.java delete mode 100644 src/main/scala/com/ilummc/tlib/filter/impl/FilterInvalidPluginLoader.java delete mode 100644 src/main/scala/com/ilummc/tlib/inject/TConfigInjector.java delete mode 100644 src/main/scala/com/ilummc/tlib/inject/TDependencyInjector.java delete mode 100644 src/main/scala/com/ilummc/tlib/inject/TPluginManager.java delete mode 100644 src/main/scala/com/ilummc/tlib/nms/ActionBar.java delete mode 100644 src/main/scala/com/ilummc/tlib/resources/TLocaleLoader.java delete mode 100644 src/main/scala/com/ilummc/tlib/resources/TLocaleSender.java delete mode 100644 src/main/scala/com/ilummc/tlib/util/IO.java delete mode 100644 src/main/scala/com/ilummc/tlib/util/Strings.java delete mode 100644 src/main/scala/com/ilummc/tlibscala/runtime/RichOfflinePlayer.scala delete mode 100644 src/main/scala/com/ilummc/tlibscala/runtime/RichPlayer.scala rename src/main/scala/{me/skymc/taboolib/bstats => io/izzel/taboolib}/Metrics.java (97%) create mode 100644 src/main/scala/io/izzel/taboolib/PluginLoader.java create mode 100644 src/main/scala/io/izzel/taboolib/TabooLib.java create mode 100644 src/main/scala/io/izzel/taboolib/TabooLibAPI.java create mode 100644 src/main/scala/io/izzel/taboolib/TabooLibLoader.java create mode 100644 src/main/scala/io/izzel/taboolib/Version.java rename src/main/scala/{me/skymc/taboolib/commands => io/izzel/taboolib/command}/TabooLibExecuteCommand.java (66%) rename src/main/scala/{me/skymc/taboolib/commands/locale => io/izzel/taboolib/command}/TabooLibLocaleCommand.java (89%) rename src/main/scala/{me/skymc/taboolib/commands/plugin => io/izzel/taboolib/command}/TabooLibPluginCommand.java (81%) rename src/main/scala/{me/skymc => io/izzel}/taboolib/listener/ListenerNetWork.java (59%) create mode 100644 src/main/scala/io/izzel/taboolib/listener/ListenerPlayerCommand.java rename src/main/scala/{me/skymc => io/izzel}/taboolib/listener/ListenerPlayerJump.java (88%) rename src/main/scala/{com/ilummc/tlib/resources => io/izzel/taboolib/locale}/TLocale.java (86%) rename src/main/scala/{com/ilummc/tlib/resources => io/izzel/taboolib/locale}/TLocaleInstance.java (87%) create mode 100644 src/main/scala/io/izzel/taboolib/locale/TLocaleSender.java rename src/main/scala/{com/ilummc/tlib/resources => io/izzel/taboolib/locale}/TLocaleSerialize.java (98%) rename src/main/scala/{com/ilummc/tlib/resources => io/izzel/taboolib/locale}/type/TLocaleActionBar.java (85%) rename src/main/scala/{com/ilummc/tlib/resources => io/izzel/taboolib/locale}/type/TLocaleBook.java (84%) rename src/main/scala/{com/ilummc/tlib/resources => io/izzel/taboolib/locale}/type/TLocaleBossBar.java (79%) rename src/main/scala/{com/ilummc/tlib/resources => io/izzel/taboolib/locale}/type/TLocaleJson.java (90%) rename src/main/scala/{com/ilummc/tlib/resources => io/izzel/taboolib/locale}/type/TLocaleSound.java (75%) rename src/main/scala/{com/ilummc/tlib/resources => io/izzel/taboolib/locale}/type/TLocaleText.java (93%) rename src/main/scala/{com/ilummc/tlib/resources => io/izzel/taboolib/locale}/type/TLocaleTitle.java (92%) rename src/main/scala/{me/skymc/taboolib/common/pathfinder => io/izzel/taboolib/module/ai}/PathfinderCreator.java (75%) rename src/main/scala/{me/skymc/taboolib/common/pathfinder => io/izzel/taboolib/module/ai}/PathfinderExecutor.java (97%) rename src/main/scala/{me/skymc/taboolib/common/pathfinder => io/izzel/taboolib/module/ai}/SimpleAi.java (87%) rename src/main/scala/{me/skymc/taboolib/common/pathfinder => io/izzel/taboolib/module/ai}/SimpleAiSelector.java (61%) rename src/main/scala/{me/skymc/taboolib/common/pathfinder => io/izzel/taboolib/module/ai}/internal/InternalPathfinderCreator.java (84%) rename src/main/scala/{me/skymc/taboolib/common/pathfinder => io/izzel/taboolib/module/ai}/internal/InternalPathfinderExecutor.java (88%) rename src/main/scala/{me/skymc/taboolib/commands/internal => io/izzel/taboolib/module/command}/TCommand.java (88%) rename src/main/scala/{me/skymc/taboolib/commands/internal => io/izzel/taboolib/module/command}/TCommandHandler.java (58%) rename src/main/scala/{me/skymc/taboolib/commands/internal => io/izzel/taboolib/module/command/base}/BaseMainCommand.java (74%) rename src/main/scala/{me/skymc/taboolib/commands/internal => io/izzel/taboolib/module/command/base}/BaseSubCommand.java (88%) rename src/main/scala/{me/skymc/taboolib/commands/internal/type => io/izzel/taboolib/module/command/base}/CommandArgument.java (94%) rename src/main/scala/{me/skymc/taboolib/commands/internal/type => io/izzel/taboolib/module/command/base}/CommandField.java (89%) rename src/main/scala/{me/skymc/taboolib/commands/internal/type => io/izzel/taboolib/module/command/base}/CommandRegister.java (88%) rename src/main/scala/{me/skymc/taboolib/commands/internal/type => io/izzel/taboolib/module/command/base}/CommandTab.java (77%) rename src/main/scala/{me/skymc/taboolib/commands/internal/type => io/izzel/taboolib/module/command/base}/CommandType.java (66%) rename src/main/scala/{me/skymc/taboolib/commands/builder/type => io/izzel/taboolib/module/command/lite}/CompleterCommand.java (63%) rename src/main/scala/{me/skymc/taboolib/commands/builder/type => io/izzel/taboolib/module/command/lite}/CompleterTab.java (84%) rename src/main/scala/{me/skymc/taboolib/commands/builder => io/izzel/taboolib/module/command/lite}/SimpleCommandBuilder.java (82%) create mode 100644 src/main/scala/io/izzel/taboolib/module/compat/EconomyHook.java create mode 100644 src/main/scala/io/izzel/taboolib/module/compat/PermissionHook.java rename src/main/scala/{com/ilummc/tlib => io/izzel/taboolib/module}/compat/PlaceholderHook.java (87%) rename src/main/scala/{me/skymc/taboolib/support/SupportWorldGuard.java => io/izzel/taboolib/module/compat/WorldGuardHook.java} (94%) rename src/main/scala/{me/skymc/taboolib/common/configuration/TConfiguration.java => io/izzel/taboolib/module/config/TConfig.java} (57%) rename src/main/scala/{com/ilummc/tlib/inject => io/izzel/taboolib/module/config}/TConfigWatcher.java (93%) rename src/main/scala/{com/ilummc/tlib/annotations => io/izzel/taboolib/module/dependency}/Dependencies.java (86%) rename src/main/scala/{com/ilummc/tlib/annotations => io/izzel/taboolib/module/dependency}/Dependency.java (81%) create mode 100644 src/main/scala/io/izzel/taboolib/module/dependency/TDependency.java create mode 100644 src/main/scala/io/izzel/taboolib/module/dependency/TDependencyInjector.java rename src/main/scala/{me/skymc/taboolib/common/playercontainer => io/izzel/taboolib/module/inject}/Container.java (88%) rename src/main/scala/{me/skymc/taboolib/common/playercontainer => io/izzel/taboolib/module/inject}/PlayerContainer.java (87%) rename src/main/scala/{me/skymc/taboolib/common/playercontainer => io/izzel/taboolib/module/inject}/PlayerContainerLoader.java (84%) rename src/main/scala/{me/skymc/taboolib/common/function => io/izzel/taboolib/module/inject}/TFunction.java (90%) rename src/main/scala/{me/skymc/taboolib/common/function => io/izzel/taboolib/module/inject}/TFunctionLoader.java (82%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/inject/TInject.java (89%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/inject/TInjectLoader.java (84%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/inject/TInjectTask.java (84%) rename src/main/scala/{me/skymc/taboolib/listener => io/izzel/taboolib/module/inject}/TListener.java (94%) rename src/main/scala/{me/skymc/taboolib/listener => io/izzel/taboolib/module/inject}/TListenerHandler.java (77%) rename src/main/scala/{me/skymc/taboolib/common/schedule => io/izzel/taboolib/module/inject}/TSchedule.java (90%) rename src/main/scala/{me/skymc/taboolib/common/schedule => io/izzel/taboolib/module/inject}/TScheduleData.java (92%) rename src/main/scala/{me/skymc/taboolib/common/schedule => io/izzel/taboolib/module/inject}/TScheduleLoader.java (69%) rename src/main/scala/{me/skymc/taboolib/inventory/builder => io/izzel/taboolib/module/item}/ItemBuilder.java (88%) create mode 100644 src/main/scala/io/izzel/taboolib/module/item/Items.java rename src/main/scala/{me/skymc/taboolib/inventory/builder/v2 => io/izzel/taboolib/module/item/inventory}/ClickEvent.java (95%) rename src/main/scala/{me/skymc/taboolib/inventory/builder/v2 => io/izzel/taboolib/module/item/inventory}/ClickListener.java (96%) rename src/main/scala/{me/skymc/taboolib/inventory/builder/v2/ClickListener1_9.java => io/izzel/taboolib/module/item/inventory/ClickListenerOffhand.java} (78%) rename src/main/scala/{me/skymc/taboolib/inventory/builder/v2 => io/izzel/taboolib/module/item/inventory}/ClickTask.java (70%) rename src/main/scala/{me/skymc/taboolib/inventory/builder/v2 => io/izzel/taboolib/module/item/inventory}/ClickType.java (66%) rename src/main/scala/{me/skymc/taboolib/inventory/builder/v2 => io/izzel/taboolib/module/item/inventory}/CloseTask.java (78%) rename src/main/scala/{me/skymc/taboolib/inventory/builder/v2 => io/izzel/taboolib/module/item/inventory}/MenuBuilder.java (95%) rename src/main/scala/{me/skymc/taboolib/inventory/builder/v2 => io/izzel/taboolib/module/item/inventory}/MenuHolder.java (90%) rename src/main/scala/{me/skymc/taboolib/common/versioncontrol => io/izzel/taboolib/module/lite}/SimpleClassVisitor.java (97%) rename src/main/scala/{me/skymc/taboolib/common/util => io/izzel/taboolib/module/lite}/SimpleCounter.java (95%) rename src/main/scala/{me/skymc/taboolib/inventory/TEquipment.java => io/izzel/taboolib/module/lite/SimpleEquip.java} (80%) rename src/main/scala/{me/skymc/taboolib/common/util => io/izzel/taboolib/module/lite}/SimpleI18n.java (72%) rename src/main/scala/{me/skymc/taboolib/common/util => io/izzel/taboolib/module/lite}/SimpleIterator.java (96%) rename src/main/scala/{me/skymc/taboolib/common/versioncontrol => io/izzel/taboolib/module/lite}/SimpleMethodVisitor.java (98%) rename src/main/scala/{me/skymc/taboolib/common/util => io/izzel/taboolib/module/lite}/SimpleReflection.java (99%) rename src/main/scala/{me/skymc/taboolib/common/versioncontrol => io/izzel/taboolib/module/lite}/SimpleVersionControl.java (88%) rename src/main/scala/{com/ilummc/tlib => io/izzel/taboolib/module}/logger/TLogger.java (67%) rename src/main/scala/{com/ilummc/tlib/inject => io/izzel/taboolib/module/logger}/TLoggerManager.java (88%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/IColumn.java (77%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/IHost.java (95%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/builder/SQLColumn.java (96%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/builder/SQLColumnOption.java (90%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/builder/SQLColumnType.java (98%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/builder/SQLExecutor.java (94%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/builder/SQLHost.java (93%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/builder/SQLTable.java (82%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/builder/query/RunnableQuery.java (96%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/builder/query/RunnableUpdate.java (93%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/builder/query/TaskResult.java (79%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/builder/query/TaskStatement.java (80%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/hikari/HikariHandler.java (78%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/module}/mysql/hikari/MapDataSource.java (88%) rename src/main/scala/{me/skymc/taboolib/mysql/sqlite => io/izzel/taboolib/module/mysql/lite}/SQLiteColumn.java (96%) rename src/main/scala/{me/skymc/taboolib/mysql/sqlite => io/izzel/taboolib/module/mysql/lite}/SQLiteColumnOption.java (91%) rename src/main/scala/{me/skymc/taboolib/mysql/sqlite => io/izzel/taboolib/module/mysql/lite}/SQLiteColumnType.java (92%) rename src/main/scala/{me/skymc/taboolib/mysql/sqlite => io/izzel/taboolib/module/mysql/lite}/SQLiteHost.java (93%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/nms/NMSHandler.java (71%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/nms/NMSHandlerImpl.java (82%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/nms/nbt/NBTBase.java (98%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/nms/nbt/NBTCompound.java (98%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/nms/nbt/NBTList.java (96%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/nms/nbt/NBTType.java (90%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/packet/TPacketHandler.java (87%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/packet/TPacketListener.java (88%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/packet/channel/ChannelExecutor.java (96%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/packet/channel/InternalChannelExecutor.java (89%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/serialize/DoNotSerialize.java (89%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/serialize/TSerializable.java (94%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/serialize/TSerializeCollection.java (89%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/serialize/TSerializeCustom.java (89%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/serialize/TSerializeMap.java (88%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/serialize/TSerializer.java (96%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/serialize/TSerializerElement.java (81%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/serialize/TSerializerElementGeneral.java (97%) rename src/main/scala/{me/skymc/taboolib/common => io/izzel/taboolib/module}/serialize/TSerializerExample.java (93%) rename src/main/scala/{me/skymc/taboolib/json => io/izzel/taboolib/module}/tellraw/TellrawCreator.java (71%) rename src/main/scala/{me/skymc/taboolib/json => io/izzel/taboolib/module}/tellraw/TellrawJson.java (89%) rename src/main/scala/{me/skymc/taboolib/json => io/izzel/taboolib/module}/tellraw/TellrawVersion.java (76%) rename src/main/scala/{me/skymc/taboolib/json => io/izzel/taboolib/module}/tellraw/internal/AbstractTellraw.java (82%) rename src/main/scala/{me/skymc/taboolib/json => io/izzel/taboolib/module}/tellraw/internal/InternalTellraw.java (88%) rename src/main/scala/{me/skymc/taboolib/bookformatter => io/izzel/taboolib/origin/book}/BookAchievement.java (98%) rename src/main/scala/{me/skymc/taboolib/bookformatter => io/izzel/taboolib/origin/book}/BookFormatter.java (52%) rename src/main/scala/{me/skymc/taboolib/bookformatter => io/izzel/taboolib/origin/book}/BookReflection.java (97%) rename src/main/scala/{me/skymc/taboolib/bookformatter => io/izzel/taboolib/origin/book}/action/ClickAction.java (96%) rename src/main/scala/{me/skymc/taboolib/bookformatter => io/izzel/taboolib/origin/book}/action/HoverAction.java (93%) rename src/main/scala/{me/skymc/taboolib/bookformatter => io/izzel/taboolib/origin/book}/builder/BookBuilder.java (91%) rename src/main/scala/{me/skymc/taboolib/bookformatter => io/izzel/taboolib/origin/book}/builder/PageBuilder.java (82%) rename src/main/scala/{me/skymc/taboolib/bookformatter => io/izzel/taboolib/origin/book}/builder/TextBuilder.java (81%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/TabooLibClient.java (74%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/TabooLibServer.java (85%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/TabooLibSettings.java (97%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/packet/Packet.java (92%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/packet/PacketParser.java (92%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/packet/PacketSerializer.java (89%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/packet/PacketType.java (87%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/packet/PacketValue.java (90%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/packet/impl/PacketAlive.java (66%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/packet/impl/PacketCommand.java (72%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/packet/impl/PacketEmpty.java (64%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/packet/impl/PacketHeartbeat.java (70%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/packet/impl/PacketJoin.java (64%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/packet/impl/PacketMessage.java (70%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/packet/impl/PacketQuit.java (76%) rename src/main/scala/{me/skymc/taboolib/socket => io/izzel/taboolib/origin/client}/server/ClientConnection.java (84%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/origin}/cronus/CronusParser.java (95%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/origin}/cronus/CronusUtils.java (98%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/origin}/cronus/bukkit/ItemStack.java (93%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/origin}/cronus/bukkit/Location.java (98%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/origin}/cronus/util/StringExpression.java (94%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/origin}/cronus/util/StringNumber.java (98%) create mode 100644 src/main/scala/io/izzel/taboolib/origin/database/PlayerDataManager.java create mode 100644 src/main/scala/io/izzel/taboolib/origin/database/PluginDataManager.java rename src/main/scala/{me/skymc/taboolib/events => io/izzel/taboolib/origin/event}/PlayerJumpEvent.java (95%) rename src/main/scala/{me/skymc/taboolib/events => io/izzel/taboolib/origin/event}/PlayerLoadedEvent.java (93%) rename src/main/scala/{me/skymc/taboolib/scoreboard/ScoreboardUtil.java => io/izzel/taboolib/origin/lite/Boards.java} (56%) create mode 100644 src/main/scala/io/izzel/taboolib/origin/lite/Catchers.java create mode 100644 src/main/scala/io/izzel/taboolib/origin/lite/Effects.java rename src/main/scala/{me/skymc/taboolib/fileutils/TLogs.java => io/izzel/taboolib/origin/lite/Logs.java} (86%) create mode 100644 src/main/scala/io/izzel/taboolib/origin/lite/Numbers.java rename src/main/scala/{me/skymc/taboolib/javascript/ScriptHandler.java => io/izzel/taboolib/origin/lite/Scripts.java} (88%) create mode 100644 src/main/scala/io/izzel/taboolib/origin/lite/Servers.java create mode 100644 src/main/scala/io/izzel/taboolib/origin/lite/Sounds.java rename src/main/scala/{me/skymc/taboolib/object/WeightCollection.java => io/izzel/taboolib/origin/lite/Weights.java} (93%) create mode 100644 src/main/scala/io/izzel/taboolib/origin/lite/cooldown/Cooldown.java create mode 100644 src/main/scala/io/izzel/taboolib/origin/lite/cooldown/Cooldowns.java rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/origin}/plugin/PluginLoadState.java (91%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/origin}/plugin/PluginLoadStateType.java (90%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/origin}/plugin/PluginUnloadState.java (90%) rename src/main/scala/{me/skymc/taboolib => io/izzel/taboolib/origin}/plugin/PluginUtils.java (93%) rename src/main/scala/{me/skymc/taboolib/itagapi => io/izzel/taboolib/origin/tag}/TagDataHandler.java (64%) rename src/main/scala/{me/skymc/taboolib/itagapi => io/izzel/taboolib/origin/tag}/TagPlayerData.java (87%) rename src/main/scala/{me/skymc/taboolib/itagapi => io/izzel/taboolib/origin/tag}/TagUtils.java (95%) create mode 100644 src/main/scala/io/izzel/taboolib/plugin/InternalJavaPlugin.java create mode 100644 src/main/scala/io/izzel/taboolib/plugin/InternalPlugin.java create mode 100644 src/main/scala/io/izzel/taboolib/plugin/InternalPluginLoader.java rename src/main/scala/{me/skymc/taboolib/string/ArrayUtils.java => io/izzel/taboolib/util/ArrayUtil.java} (74%) create mode 100644 src/main/scala/io/izzel/taboolib/util/Files.java rename src/main/scala/{me/skymc/taboolib/common/io/IOUtils.java => io/izzel/taboolib/util/IO.java} (74%) rename src/main/scala/{com/ilummc/tlib => io/izzel/taboolib}/util/Ref.java (93%) rename src/main/scala/{me/skymc/taboolib/methods/ReflectionUtils.java => io/izzel/taboolib/util/Reflection.java} (99%) rename src/main/scala/{me/skymc/taboolib/string/StringUtils.java => io/izzel/taboolib/util/Strings.java} (67%) rename src/main/scala/{me/skymc/taboolib/timeutil/TimeFormatter.java => io/izzel/taboolib/util/Times.java} (93%) rename src/main/scala/{me/skymc/taboolib/string/VariableFormatter.java => io/izzel/taboolib/util/Variables.java} (88%) rename src/main/scala/{com/ilummc/tlib => io/izzel/taboolib}/util/asm/AsmAnalyser.java (96%) rename src/main/scala/{com/ilummc/tlib => io/izzel/taboolib}/util/asm/AsmClassLoader.java (93%) rename src/main/scala/{com/ilummc/tlib => io/izzel/taboolib}/util/asm/AsmClassTransformer.java (99%) rename src/main/scala/{com/ilummc/tlib/bungee/api => io/izzel/taboolib/util}/chat/BaseComponent.java (93%) rename src/main/scala/{com/ilummc/tlib/bungee => io/izzel/taboolib/util}/chat/BaseComponentSerializer.java (95%) rename src/main/scala/{com/ilummc/tlib/bungee/api => io/izzel/taboolib/util/chat}/ChatColor.java (99%) rename src/main/scala/{com/ilummc/tlib/bungee/api => io/izzel/taboolib/util/chat}/ChatMessageType.java (81%) rename src/main/scala/{com/ilummc/tlib/bungee/api => io/izzel/taboolib/util}/chat/ClickEvent.java (96%) rename src/main/scala/{com/ilummc/tlib/bungee/api => io/izzel/taboolib/util}/chat/ComponentBuilder.java (99%) rename src/main/scala/{com/ilummc/tlib/bungee => io/izzel/taboolib/util}/chat/ComponentSerializer.java (89%) rename src/main/scala/{com/ilummc/tlib/bungee/api => io/izzel/taboolib/util}/chat/HoverEvent.java (94%) rename src/main/scala/{com/ilummc/tlib/bungee/api => io/izzel/taboolib/util}/chat/TextComponent.java (98%) rename src/main/scala/{com/ilummc/tlib/bungee => io/izzel/taboolib/util}/chat/TextComponentSerializer.java (89%) rename src/main/scala/{com/ilummc/tlib/bungee/api => io/izzel/taboolib/util}/chat/TranslatableComponent.java (98%) rename src/main/scala/{com/ilummc/tlib/bungee => io/izzel/taboolib/util}/chat/TranslatableComponentSerializer.java (90%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/AlreadyStartException.java (61%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/CompleteEvent.java (89%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/ConnectedEvent.java (92%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/DoNotSupportMultipleThreadException.java (65%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/EagletHandler.java (68%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/EagletTask.java (99%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/ErrorEvent.java (88%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/HashNotMatchException.java (61%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/HashUtil.java (98%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/ProgressEvent.java (97%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/RetryFailedException.java (85%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/SingleThreadDownload.java (97%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/SplitDownload.java (98%) rename src/main/scala/{com/ilummc => io/izzel/taboolib/util}/eagletdl/StartEvent.java (82%) rename src/main/scala/{com/ilummc => io/lzzel}/tlibscala/AsyncTask.scala (94%) rename src/main/scala/{com/ilummc => io/lzzel}/tlibscala/Example.scala (67%) rename src/main/scala/{com/ilummc => io/lzzel}/tlibscala/Implicits.scala (87%) rename src/main/scala/{com/ilummc => io/lzzel}/tlibscala/Prelude.scala (95%) rename src/main/scala/{com/ilummc => io/lzzel}/tlibscala/ScalaTaskExecutor.scala (94%) rename src/main/scala/{com/ilummc => io/lzzel}/tlibscala/Task.scala (94%) rename src/main/scala/{com/ilummc => io/lzzel}/tlibscala/runtime/RichLocation.scala (93%) create mode 100644 src/main/scala/io/lzzel/tlibscala/runtime/RichOfflinePlayer.scala create mode 100644 src/main/scala/io/lzzel/tlibscala/runtime/RichPlayer.scala rename src/main/scala/{com/ilummc => io/lzzel}/tlibscala/runtime/RichVector.scala (71%) delete mode 100644 src/main/scala/me/skymc/taboolib/Main.java delete mode 100644 src/main/scala/me/skymc/taboolib/TabooLib.java delete mode 100644 src/main/scala/me/skymc/taboolib/TabooLibDatabase.java delete mode 100644 src/main/scala/me/skymc/taboolib/TabooLibLoader.java delete mode 100644 src/main/scala/me/skymc/taboolib/anvil/AnvilContainer.java delete mode 100644 src/main/scala/me/skymc/taboolib/anvil/AnvilContainerAPI.java delete mode 100644 src/main/scala/me/skymc/taboolib/anvil/AnvilContainerGenerator.java delete mode 100644 src/main/scala/me/skymc/taboolib/bungee/TabooLibBungee.java delete mode 100644 src/main/scala/me/skymc/taboolib/cloud/TCloudCommand.java delete mode 100644 src/main/scala/me/skymc/taboolib/cloud/TCloudLoader.java delete mode 100644 src/main/scala/me/skymc/taboolib/cloud/expansion/Expansion.java delete mode 100644 src/main/scala/me/skymc/taboolib/cloud/expansion/ExpansionType.java delete mode 100644 src/main/scala/me/skymc/taboolib/commands/TabooLibMainCommand.java delete mode 100644 src/main/scala/me/skymc/taboolib/commands/internal/TBaseCommand.java delete mode 100644 src/main/scala/me/skymc/taboolib/commands/internal/plugin/TLibLocale.java delete mode 100644 src/main/scala/me/skymc/taboolib/common/json/TJsonArray.java delete mode 100644 src/main/scala/me/skymc/taboolib/common/json/TJsonObject.java delete mode 100644 src/main/scala/me/skymc/taboolib/common/loader/Instantiable.java delete mode 100644 src/main/scala/me/skymc/taboolib/common/loader/InstantiableLoader.java delete mode 100644 src/main/scala/me/skymc/taboolib/database/GlobalDataManager.java delete mode 100644 src/main/scala/me/skymc/taboolib/database/PlayerDataManager.java delete mode 100644 src/main/scala/me/skymc/taboolib/events/CustomBookOpenEvent.java delete mode 100644 src/main/scala/me/skymc/taboolib/events/TPluginEnableEvent.java delete mode 100644 src/main/scala/me/skymc/taboolib/events/TPluginLoadEvent.java delete mode 100644 src/main/scala/me/skymc/taboolib/events/itag/AsyncPlayerReceiveNameTagEvent.java delete mode 100644 src/main/scala/me/skymc/taboolib/events/itag/PlayerReceiveNameTagEvent.java delete mode 100644 src/main/scala/me/skymc/taboolib/exception/PlayerOfflineException.java delete mode 100644 src/main/scala/me/skymc/taboolib/exception/PluginNotFoundException.java delete mode 100644 src/main/scala/me/skymc/taboolib/fileutils/ConfigUtils.java delete mode 100644 src/main/scala/me/skymc/taboolib/fileutils/FileUtils.java delete mode 100644 src/main/scala/me/skymc/taboolib/inventory/ItemUtils.java delete mode 100644 src/main/scala/me/skymc/taboolib/inventory/builder/MenuBuilder.java delete mode 100644 src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderCallable.java delete mode 100644 src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderEvent.java delete mode 100644 src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderHolder.java delete mode 100644 src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderItem.java delete mode 100644 src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderListener.java delete mode 100644 src/main/scala/me/skymc/taboolib/itagapi/TagPacket.java delete mode 100644 src/main/scala/me/skymc/taboolib/listener/ListenerPlayerCommand.java delete mode 100644 src/main/scala/me/skymc/taboolib/listener/ListenerPlayerJoinAndQuit.java delete mode 100644 src/main/scala/me/skymc/taboolib/listener/ListenerPlugin.java delete mode 100644 src/main/scala/me/skymc/taboolib/listener/TListenerCommand.java delete mode 100644 src/main/scala/me/skymc/taboolib/particle/EffLib.java delete mode 100644 src/main/scala/me/skymc/taboolib/particle/pack/ParticleData.java delete mode 100644 src/main/scala/me/skymc/taboolib/particle/pack/ParticlePack.java delete mode 100644 src/main/scala/me/skymc/taboolib/particle/pack/ParticleType.java delete mode 100644 src/main/scala/me/skymc/taboolib/playerdata/DataUtils.java delete mode 100644 src/main/scala/me/skymc/taboolib/scoreboard/SimpleScoreboard.java delete mode 100644 src/main/scala/me/skymc/taboolib/sound/SoundPack.java delete mode 100644 src/main/scala/me/skymc/taboolib/sound/SoundUtils.java delete mode 100644 src/main/scala/me/skymc/taboolib/update/UpdateTask.java diff --git a/build.gradle b/build.gradle index 6c2683c..cc8f684 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { id 'com.github.johnrengelman.shadow' version '4.0.4' } group = 'me.skymc' -version = '4.86' +version = '5.0' sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -28,14 +28,11 @@ dependencies { exclude(module: 'log4j') } compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.8' - shadow group: 'com.zaxxer', name: 'HikariCP', version: '3.1.0' - shadow group: 'org.javalite', name: 'activejdbc', version: '2.0' compile group: 'org.ow2.asm', name: 'asm', version: '7.0-beta' compile group: 'com.google.code.gson', name: 'gson', version: '2.7' - shadow group: 'com.h2database', name: 'h2', version: '1.4.197' - shadow group: 'me.clip', name: 'placeholderapi', version: '2.8.4' - shadow group: 'net.objecthunter', name: 'exp4j', version: '0.4.8' + shadow group: 'com.zaxxer', name: 'HikariCP', version: '3.1.0' shadow group: 'org.scala-lang', name: 'scala-library', version: '2.12.8' + shadow group: 'me.clip', name: 'placeholderapi', version: '2.8.4' shadow fileTree(dir: 'libs', includes: ['*.jar']) } @@ -48,11 +45,11 @@ processResources { inputs.property "version", project.version from(sourceSets.main.resources.srcDirs) { - include 'plugin.yml' + include 'version' expand 'version': project.version } from(sourceSets.main.resources.srcDirs) { - exclude 'plugin.yml' + exclude 'version' } } \ No newline at end of file diff --git a/src/main/resources/Addons/TabooLibDeprecated b/src/main/resources/Addons/TabooLibDeprecated deleted file mode 100644 index e7a08a302b2cc117f4d0298daa41f2d56cfaec05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 427084 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%0DW5>p@Q_V7XmfX2b?Ul^s^ejTt(w7;mgugP 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 z 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

SIh1UTl@IH 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' -- '<@1> | <@1> 单行重复变量' -- '<@1> | <@2> 单行不同变量' -- '@option:1' -- ' text: 文本' -- ' command: 执行命令' -- ' showtext: 显示文本' -- '@option:2' -- ' text: 测试' -- ' command: 执行命令' -- ' showtext: 显示文本' - -# JSON2 -JSON-NEW: -- '[json2]' -- '新 <@1> 内容 - 1' -- '新 <@1> 内容 - 2' -- '@option:1' -- ' text: JSON' -- ' showtext: 展示文本' diff --git a/src/main/resources/Language2/zh_CN.yml b/src/main/resources/Language2/zh_CN.yml deleted file mode 100644 index 09527b0..0000000 --- a/src/main/resources/Language2/zh_CN.yml +++ /dev/null @@ -1,66 +0,0 @@ -COMMAND-ERROR: '&8[&3&lTLM&8] &4指令错误' -COMMAND-HELP: -- '' -- '&b&l----- &3&lTaooLibraryModule Commands &b&l-----' -- '' -- '&f /tlm kit list &6- &e列出所有礼包' -- '&f /tlm kit reward &8[&7名称] &8<&7名称&8> &6- &e领取礼包' -- '&f /tlm kit reset &8[&7名称] &8<&7玩家&8> &6- &e刷新礼包' -- '' -- '&f /tlm inv list &6- &e列出所有保存的背包' -- '&f /tlm inv info &8[&7名称] &6- &e查看保存背包' -- '&f /tlm inv save &8[&7名称] &6- &e保存当前背包' -- '&f /tlm inv paste &8[&7名称] &8<&7玩家&8> &8<&7-b|a&8> &6- &e覆盖背包' -- '&f /tlm inv delete &8[&7名称] &6- &e删除保存背包' -- '' -- '&f /tlm list &6- &e列出所有模块' -- '' -- '&f /tlm reload &8[&7模块名|TLM|ALL&8] &6- &e列出所有模块' -- '' - -# 3.58 增加 -NOPERMISSION-HELP: '&8[&3&lTLM&8] &4你没有权限列出帮助命令' -NOPERMISSION-LIST: '&8[&3&lTLM&8] &4你没有权限这么做' -NOPERMISSION-RELOAD: '&8[&3&lTLM&8] &4你没有权限这么做' -NOPERMISSION-KIT-REWARD: '&8[&3&lTLM&8] &4你没有权限这么做' -NOPERMISSION-KIT-RESET: '&8[&3&lTLM&8] &4你没有权限这么做' - -# 3.60 新增 -NOPERMISSION-KIT-LIST: '&8[&3&lTLM&8] &4你没有权限这么做' -NOPERMISSION-INV: '&8[&3&lTLM&8] &4你没有权限这么做' - -# 3.59 增加 -KIT-EMPTY: '&8[&3&lTLM&8] &4参数错误' -KIT-NAME: '&8[&3&lTLM&8] &4请输入正确的礼包名称' -KIT-DISABLE: '&8[&3&lTLM&8] &4该模块尚未在配置文件中启用' -KIT-NOTFOUND: '&8[&3&lTLM&8] &4礼包 &c$kit &4不存在' -KIT-OFFLINE: '&8[&3&lTLM&8] &4玩家 &c$name &4不在线' -KIT-CONSOLE: '&8[&3&lTLM&8] &4后台不允许输入这个指令' -KIT-COOLDOWN: '&8[&3&lTLM&8] &4礼包 &c$kit &4正在冷却中' -KIT-DISPOSABLE: '&8[&3&lTLM&8] &4礼包 &c$kit &4只能领取一次' -KIT-RESET-ALL: '&8[&3&lTLM&8] &7礼包 &f$kit &7已刷新' -KIT-RESET-PLAYER: '&8[&3&lTLM&8] &7玩家 &f$player &7的礼包 &f$kit &7已刷新' -KIT-SUCCESS: '&8[&3&lTLM&8] &7礼包 &f$kit &7已领取' -KIT-PLACEHOLDER: - 0: '&4模块未启用' - 1: '&4礼包不存在' - 2: '&8已领取' - 3: '&a可领取' - 4: '&4冷却中' - 5: '&4无权限' - -# 3.60 新增 -KIT-LIST: '&8[&3&lTLM&8] &7当前礼包: &f$kits' - -# 3.60 增加 -INV-EMPTY: '&8[&3&lTLM&8] &4参数错误' -INV-DISABLE: '&8[&3&lTLM&8] &4该模块尚未在配置文件中启用' -INV-CONSOLE: '&8[&3&lTLM&8] &4该命令不允许控制台执行' -INV-NAME: '&8[&3&lTLM&8] &4请输入正确的背包名称' -INV-LIST: '&8[&3&lTLM&8] &7当前已保存背包: &f$name' -INV-NOTFOUND: '&8[&3&lTLM&8] &4背包 &c$name &4不存在' -INV-INFO-TITLE: '背包信息: $name' -INV-SAVE: '&8[&3&lTLM&8] &7背包 &f$name &7已保存!' -INV-OFFLINE: '&8[&3&lTLM&8] &4玩家 &c$name &4不在线' -INV-PASTE: '&8[&3&lTLM&8] &7背包 &f$name &7已覆盖到玩家 &f$player&7!' -INV-DELETE: '&8[&3&lTLM&8] &4背包 &c$name &4已删除' \ No newline at end of file diff --git a/src/main/resources/TLM/CommandChanger.yml b/src/main/resources/TLM/CommandChanger.yml deleted file mode 100644 index 353fbeb..0000000 --- a/src/main/resources/TLM/CommandChanger.yml +++ /dev/null @@ -1,14 +0,0 @@ -# 指令配置 -Commands: - # 配置序号(不可重复) - test: - # 输入命令 - Input: '/kit' - # 替换命令 - Replace: '/tlm kit' - # 替换模式(省略默认全部) - # ---------- # - # CONSOLE = 后台 - # PLAYER = 玩家 - # ---------- # - ReplaceMode: 'PLAYER' \ No newline at end of file diff --git a/src/main/resources/TLM/Kits.yml b/src/main/resources/TLM/Kits.yml deleted file mode 100644 index 00d7e81..0000000 --- a/src/main/resources/TLM/Kits.yml +++ /dev/null @@ -1,34 +0,0 @@ -# 礼包配置 -Kits: - # 礼包名 - kit_name: - # 礼包刷新时间 - # ---------- # - # 1d = 1天 - # 1h = 1小时 - # 1m = 1分钟 - # 1s = 1秒钟 - # 时间之间用 ";" 分隔, 例如 1小时30分钟 = "1h;30m" - # ---------- # - Cooldown: '1d' - - # 背包空间不足时物品是否掉落 - FullDrop: true - - # 是否只能领取一次 - Disposable: false - - # 礼包领取权限 - Permission: 'taboolib.kit.kit_name' - - # 礼包领取权限提示 - Permission-message: '&4你没有权限领取这个礼包' - - # 礼包内容 - # 空格左侧为物品名,右侧为物品数量 - Items: - - 'UnlimitSword 1' - - # 礼包命令 - Commands: - - 'say $player 领取了礼包 kit_name!' \ No newline at end of file diff --git a/src/main/resources/TLM/TimeCycle.yml b/src/main/resources/TLM/TimeCycle.yml deleted file mode 100644 index 6a4e5a8..0000000 --- a/src/main/resources/TLM/TimeCycle.yml +++ /dev/null @@ -1,35 +0,0 @@ -# 时间检查器 -TimeCycle: - # 检查器名称 - cycle_name: - # 检查器周期 - # ---------- # - # 1d = 1天 - # 1h = 1小时 - # 1m = 1分钟 - # 1s = 1秒钟 - # 时间之间用 ";" 分隔, 例如 1小时30分钟 = "1h;30m" - # ---------- # - Cycle: '1d' - - # 更新配置 - UpdateCommand: - - 'say 检查器 cycle_name 更新!' - - # 初始化配置 - Initialise: - # 初始化时间 - # 特殊时间 - # - DAY_OF_WEEK = 本周第几天 (最小:1) - # - DAY_OF_MONTH = 本月第几天 (最小:1) - InitialiseDate: - # 初始化时将小时设置为 0 - - 'HOUR_OF_DAY=0' - # 初始化时将分钟设置为 0 - - 'MINUTE=0' - # 初始化时将秒钟设置为 0 - - 'SECOND=0' - - # 初始化命令 - InitialiseCommand: - - 'say 检查器 cycle_name 初始化完成!' \ No newline at end of file diff --git a/src/main/resources/bungee.yml b/src/main/resources/bungee.yml deleted file mode 100644 index 1ac27bb..0000000 --- a/src/main/resources/bungee.yml +++ /dev/null @@ -1,5 +0,0 @@ -name: TabooLib -main: me.skymc.taboolib.bungee.TabooLibBungee -version: ${project.version} - -author: [lzzelAliz, 坏黑] \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 24aa81e..af131cc 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,8 +1,3 @@ -# 权限不足时提示 -NO-PERMISSION-MESSAGE: '&f&l(&4&l?&f&l) &c你没有权利这么做' -# 不满足条件时提示 -NO-CLAIM-MESSAGE: '&f&l(&4&l?&f&l) &c你现在还不能这么做 &7(%s%&7)' - # 数据储存地址 # 该配置将在启用数据库储存时失效 DATAURL: @@ -10,8 +5,6 @@ DATAURL: PLAYER-DATA: 'plugins/TabooLib/playerdata/' # 插件数据 SERVER-DATA: 'plugins/TabooLib/serverdata/' - # 物品数据(来自 ItemSave 插件) - ITEMDIR: 'plugins/Skript/scripts/config/item.yml' # 语言文件相关设置 LOCALE: @@ -24,13 +17,6 @@ LOCALE: # 如果需要开启仍然可以在语言文件中加入 papi: true USE_PAPI: false -# 是否注入 PluginManager,关闭后可能会导致部分功能出错。 -PLUGIN-INJECTOR: - ENABLE: true - # 检测下面的插件并自动关闭注入 - DISABLE-ON-PLUGIN-EXISTS: - - LuckPerms - # 是否在当前服务器启用交流网终端 # 启用后将会收到大量调试信息, 不建议使用 SERVER: false @@ -44,18 +30,6 @@ TABLIST-SORT: true # 玩家列表(TAB-API)是否自动清理没有成员的队伍 TABLIST-AUTO-CLEAN-TEAM: true -# 是否启用发包(禁用后会影响 tagDisplay() 方法的使用) -TABLIST-PACKET: true - -# 是否启用更新检测 -UPDATE-CHECK: true - -# 是否启用自动更新 -UPDATE-DOWNLOAD: false - -# 是否启用附属插件异常拦截 -EXCEPTION-MIRROR: true - # 是否在关闭服务器时清理玩家数据 # 该配置将在启用数据库储存时失效 DELETE-DATA: false @@ -68,31 +42,4 @@ DELETE-VARIABLE: false # 是否以 UUID 的形式创建玩家数据 # 不建议开启!除非用 TabooLib 储存的插件支持新版储存方式! -ENABLE-UUID: false - -# 是否隐藏保存数据的提示 -HIDE-NOTIFY: true - -# 数据库信息 -# 该功能在当前版本下无法使用,请勿启用 -MYSQL: - # 是否启用数据库 - ENABLE: false - # 数据库地址 - HOST: 'localhost' - # 数据库端口 - PORT: 3306 - # 数据库用户 - USER: root - # 数据库密码 - PASSWORD: '' - # 数据库名称 - DATABASE: 'test' - # 数据表前缀 - PREFIX: 'taboolib' - -# 全局变量信息 -PluginData: - # 检查更新间隔(单位:秒) - # 检查变量是否被其他服务器更新 - CHECK-DELAY: 5 \ No newline at end of file +ENABLE-UUID: false \ No newline at end of file diff --git a/src/main/resources/hikarisettings.yml b/src/main/resources/datasource.yml similarity index 100% rename from src/main/resources/hikarisettings.yml rename to src/main/resources/datasource.yml diff --git a/src/main/resources/items.yml b/src/main/resources/items.yml deleted file mode 100644 index 665d8f2..0000000 --- a/src/main/resources/items.yml +++ /dev/null @@ -1,51 +0,0 @@ -UnlimitSword: - material: DIAMOND_SWORD - name: '&b&nUnlimitSword' - lore: - - '' - - '&8&oAn sword of infinitely durable' - - '&8&oAnd hide attributes lore' - - '' - flags: - - HIDE_ATTRIBUTES - nbt: - Unbreakable: 1 - -ColorLeather: - material: LEATHER_CHESTPLATE - name: '&aLe&2at&3he&4r C&5he&6st&7pl&8at&9e' - lore: - - '' - - '&8&oA chestplate of colored' - - '&8&oAnd enchanted with &7DURABILITY I' - - '' - enchants: - DURABILITY: 1 - color: 255-0-0 - -SpeedPotion: - material: POTION - name: '&1&nSpeed Potion' - lore: - - '' - - '&8&oA potion of &7SPEED I' - - '&8&oAnd not have Particles' - - '' - potions: - SPEED: 200-5 - -KingsAxe: - material: GOLD_AXE - name: '&e&nKingsAxe' - lore: - - '' - - '&6&o100 damage !!!' - - '&6&o30% speed !!!' - - '' - - '&e&oA knife a pupil !!!' - - '' - attributes: - mainhand: - damage: 100 - speed: 30% - \ No newline at end of file diff --git a/src/main/resources/lang/internal.yml b/src/main/resources/lang/internal.yml index fb41bc9..942640e 100644 --- a/src/main/resources/lang/internal.yml +++ b/src/main/resources/lang/internal.yml @@ -1,8 +1,6 @@ -TRY-LOADING-LANG: '插件 {0} 尝试加载 {1} 作为语言文件' -SUCCESS-LOADING-LANG-NORMAL: '成功加载 {0} 插件的 {1} 语言文件, 共 {2} 项' -SUCCESS-LOADING-LANG-UPDATE: '成功加载 {0} 插件的 {1} 语言文件, 共 {2} 项, 及 {3} 项新条目' +SUCCESS-LOADING-LANG-NORMAL: '成功为 {0} 加载 {1} 语言文件, 共 {2} 项' +SUCCESS-LOADING-LANG-UPDATE: '成功为 {0} 加载 {1} 语言文件, 共 {2} 项, 及 {3} 项新条目' ERROR-LOADING-LANG: '加载 {0} 插件的语言文件时发生异常:{1}' -RELOADING-LANG: '正在重新载入 {0} 插件的语言文件' FETCH-LOCALE-ERROR: '语言文件获取失败:{0}' SEND-LOCALE-ERROR: '语言文件发送失败:{0}' LOCALE-ERROR-REASON: '原因:{0}' diff --git a/src/main/resources/lang/zh_CN.yml b/src/main/resources/lang/zh_CN.yml index 0be6abc..55f73af 100644 --- a/src/main/resources/lang/zh_CN.yml +++ b/src/main/resources/lang/zh_CN.yml @@ -1,21 +1,3 @@ -TLIB: - INJECTION-SUCCESS: '注入成功' - INJECTION-FAILED: - - '注入失败' - - '&c提前加载依赖于 TabooLib 的所有插件的相关功能' - INJECTION-DISABLED: - - '关闭注入' - - '&c提前加载依赖于 TabooLib 的所有插件的相关功能' - LOAD-FAIL-OFFLINE: - - '**********************************************' - - '** TabooLib-{0} 无法在您的服务器上使用' - - '**' - - '** 您的服务器尚未连接互联网导致本插件无法正常载入' - - '** 请使用离线版本或是手动下载依赖库文件' - - '**' - - '** 详情查阅: https://github.com/Bkm016/TabooLib' - - '**********************************************' - DEPENDENCY: DOWNLOAD-OFFLINE: '已启用离线模式, 将不会下载第三方依赖库' DOWNLOAD-CONNECTED: ' 正在下载 {0} 大小 {1}' @@ -27,38 +9,7 @@ DEPENDENCY: PLUGIN-AUTOLOAD-FAIL: '{0} 所依赖的插件 {1} 尝试自动加载失败,请尝试手动下载' PLUGIN-LOAD-SUCCESS: ' {0} 请求的插件 {1} 加载成功' PLUGIN-LOAD-FAIL: ' {0} 请求的插件 {1} 加载失败' - LOADING-START: '正在加载 {0} 插件所需的依赖' -# LIBRARY-LOAD-SUCCESS: ' {0} 请求的库文件 {1} 加载成功' LIBRARY-LOAD-FAIL: ' {0} 请求的库文件 {1} 加载失败' - LOAD-COMPLETE: '依赖加载完成' -# LOAD-CLASSES: '&7缓存 &f{0} &7插件的 &f{1} &7个类耗时&f {2} &7毫秒.' - -CONFIG: - LOAD-FAIL-NO-ANNOTATION: '插件 {0} 的配置类 {1} 加载失败:没有 @Config 注解' - LOAD-FAIL: '插件 {0} 的配置类 {1} 加载失败:没有 @Config 注解' - LOAD-FAIL-NO-FILE: '插件 {0} 的配置类 {1} 加载失败:没有 @Config 注解或文件不存在' - LOAD-SUCCESS: '插件 {0} 的 {1} 配置文件成功加载' - SAVE-FAIL-NO-ANNOTATION: '插件 {0} 的配置类 {1} 序列化失败:没有 @Config 注解' - SAVE-FAIL: '插件 {0} 的配置类 {1} 加载失败:没有 @Config 注解' - SAVE-SUCCESS: '插件 {0} 的配置 {1} 已保存' - RELOAD-SUCCESS: '插件 {0} 的配置 {1} 成功重载' - RELOAD-FAIL: '插件 {0} 的配置 {1} 成功重载' - LISTEN-START: '开始监听 {0} 插件的 {1} 配置文件' - -NOTIFY: - ERROR-SERVER-KEY: '&4检测到本服序列号与其他服务器相同, 已重新生成!' - ERROR-CONNECTION-FAIL: '&4数据库连接失败, 请检查配置是否正确!' - SUCCESS-LOADED: - - '§7插件载入完成!' - - '§7插件作者: §f{0}' - - '§7插件版本: §f{1}' - - '§7游戏版本: §f{2}' - SUCCESS-DISABLE: - - '&c插件已卸载, 感谢您使用&4禁忌书库' - - '&c插件作者: &4坏黑' - FAIL-DISABLE: - - '&c插件尚未启动完成, 已跳过卸载代码' - - '&c插件作者: &4坏黑' LOCALE: TITLE-SEND-TO-NON-PLAYER: '该语言类型只能发送给玩家:{0}' @@ -74,27 +25,10 @@ MISC: FIELD-COPY-FAILED: '拷贝 {0} 对象失败' FIELD-COPY-ERROR: '拷贝 {0} 对象出错:{1}' -#COOLDOWNPACK: -# PACK-REGISTER: '注册冷却包: {0}, 时间: {1} 秒 ({2})' -# PACK-REGISTER-ANONYMOUS: '注册冷却包: {0}, 时间: {1} 秒 (匿名注册)' -# PACK-UNREGISTER: '注销冷却包: {0} (主动注销)' -# PACK-UNREGISTER-AUTO: '注销冷却包: {0} (自动注销)' - -GLOBAL-DATAMANAGER: - ERROR-CHECK-VARIABLE: '&4变量 &c{0} &4载入异常: &c{1}' - SUCCESS-LOADED-VARIABLE: '&7从数据库中获取 &f{0} &7个变量, 耗时: &f{1} &7(ms)' - PLAYER-DATAMANAGER: - ERROR-STORAGE-SQL: '不允许在储存模式为数据库的情况下获取离线玩家数据' ERROR-PLAYER-DATA: '&4玩家 &c{0} &4的数据载入出现异常: &c{1}' SUCCESS-SAVE-DATA: '&7保存 &f{0} &7条玩家数据, 耗时: &f{1} &7(ms)' -ENTITY-UTILS: - NOTFOUND-PROTOCOLLIB: '缺少前置插件 ProtocolLib' - -FILE-UTILS: - FAIL-LOAD-CONFIGURATION: '&4配置文件载入失败!, 插件: &c{0}&4, 文件: &c{1}' - DATA-UTILS: SUCCESS-SAVE-DATA: '&7保存 &f{0} &7条插件数据, 耗时: &f{1} &7(ms)' FAIL-SAVE-FILE: '&4文件 &c{0}&4 保存失败, 原因: &c{1}' @@ -106,53 +40,14 @@ ITEM-UTILS: FAIL-LOAD-POTION: '&c{0} &4不是一个有效的药水名称, 输入 &c/tlib potions&4 查看所有药水' FAIL-LOAD-FLAG: '&c{0} &4不是一个有效的标签名称, 输入 &c/tlib flags&4 查看所有标签' FAIL-SAVE-EXISTS: '无法载入载入物品 &4{0}&c, 因为它已经存在了' -# SUCCESS-LOAD-CACHES: '&7载入 &f{0} &7项缓存物品' -# SUCCESS-LOAD-NAMES: '&7载入 &f{0} &7项物品名称' EMPTY-ITEM: '空' -LANGUAGE2: - FAIL-NOTFOUND-FILE: '语言文件 {0} 不存在' - -TIMECYCLE: - FAIL-CYCLE-EXISTS: '注册周期管理器 &8{0}&c 失败, 原因: &4名称重复' - -UPDATETASK: - VERSION-FAIL: '&4更新记录获取失败, 请检查网络连接!' - VERSION-LATEST: '&7插件已是最新版, 无需更新!' - VERSION-OUTDATED: - - '&8####################################################' - - '&7 检测到有新的版本更新!' - - '&7 当前版本: &f{0}' - - '&7 最新版本: &f{1}' - - '&7 下载地址: &fhttp://www.mcbbs.net/thread-773065-1-1.html' - - '&7 开源地址: &fhttps://github.com/Bkm016/TabooLib/' - - '&8####################################################' - -MYSQL-CONNECTION: - FAIL-CONNECT: '&4数据库 &c{0} &4连接失败, 原因: &c{0}' - FAIL-NOTFOUND-DRIVE: '&7驱动器获取失败, 无法连接到数据库' - FAIL-NOTFOUND-CONNECTION: '&7警告! 数据库尚未连接, 请检查配置文件后重启服务器! ({0})' - FAIL-COMMAND-NORMAL: '&4数据库命令执行出错, 错误原因: &c{0}' - FAIL-COMMAND-DETAIL: '&4数据库命令执行出错, 错误代码: &c{0}&4, 错误原因: &c{1}' - FAIL-EXECUTE-TASK: '异步任务失败, 执行方式改为同步执行' - SUCCESS-REGISTERED: '&7插件 &f{0}&7 注册新的数据库连接' - SUCCESS-REGISTERED-EXISTS: '&7插件 &f{0}&7 引用插件 &f{1}&7 注册的数据库连接' - SUCCESS-REGISTERED-LISTENER: '&7启动数据库连接监控' - SUCCESS-CONNECTION-CANCEL: '已停止插件 &f{0}&7 的 &f{1}&7 条数据库连接' - NOTIFY-CONNECTING: '&7正在连接数据库, 地址: &f{0}' - NOTIFY-CONNECTED: '&7数据库连接成功 ({0}ms)' - MYSQL-HIKARI: CREATE-SUCCESS: '&7插件 &f{0}&7 注册新的数据库连接: &f{1}' CREATE-EXISTS: '&7插件 &f{0}&7 引用插件 &f{1}&7 注册的数据库连接' CLOSE-SUCCESS: '&7插件 &f{0} &7注册的数据库连接 &f{1} &7已被注销!' CLOSE-FAIL: '&7插件 &f{0} &7注册的数据库连接正在被 &f{1} &7个插件使用, 无法注销!' -TABOOLIB-MODULE: - SUCCESS-LOADED: '&7载入 &f{0} &7个 &fTLM &7模块' - FAIL-LOADED: '&4模块载入异常: &c{0}&4, 模块: &c{1}&4, 位于: &c{2}' - FAIL-RUNTIME: '&4模块运行异常: &c{0}&4, 模块: &c{1}&4, 位于: &c{2}' - COMMANDS: GLOBAL: ONLY-PLAYER: '&8[&3&lTabooLib&8] &4控制台无法这么做' @@ -169,9 +64,7 @@ COMMANDS: - '&8[&3&lTabooLib&8] &7指令 &f{0} &7不存在' - '&8[&3&lTabooLib&8] &7你可能想要:' - '&8[&3&lTabooLib&8] &7{1}' - COMMAND-CREATE-FAILED: '&7插件 &f{0} &7的 &f{1} &7命令注册失败: &c{2}' -# COMMAND-CREATE: '&7自动为插件 &f{0} &7的 &f{1} &7命令注册到服务器' -# COMMAND-REGISTER: '&7自动为插件 &f{0} &7的 &f{1} &7命令注册 &f{2} &7条子命令' + COMMAND-CREATE-FAILED: '&c插件 &7{0} &c的 &7{1} &c命令注册失败: &7{2}' COMMAND-HELP: ' §f/{0} {1} {2}§6- §e{3}' COMMAND-HELP-EMPTY: ' §f/{0} {1} {2}' COMMAND-ARGUMENT: '§7<§8{0}§7>' @@ -179,285 +72,6 @@ COMMANDS: PARAMETER: UNKNOWN: '&8[&3&lTabooLib&8] &4指令错误' INSUFFICIENT: '&8[&3&lTabooLib&8] &4参数不足' - RELOAD: - LOADING: '&8[&3&lTabooLib&8] &7重载中...' - SUCCESS-NORMAL: '&8[&3&lTabooLib&8] &7重载成功' - SUCCESS-ELAPSED-TIME: '&8[&3&lTabooLib&8] &7重载成功, 耗时: &f{0} ms' - TABOOLIB: - COMMAND-TITLE: '&e&l----- &6&lTabooLib Commands &e&l-----' - SAVE: - DESCRIPTION: '载入插件' - ARGUMENTS: - 0: '名称' - INVALID-NAME: '&8[&3&lTabooLib&8] &4请输入正确的名称' - INVALID-ITEM: '&8[&3&lTabooLib&8] &4请手持正确的物品' - INVALID-ITEM-FINAL-EXISTS: '&8[&3&lTabooLib&8] &4该名称所对应的物品保存于固定物品库中, 无法覆盖' - GUIDE-EXISTS: '&8[&3&lTabooLib&8] &4你有一个正在进行的聊天引导, 请完成后在这么做' - GUIDE-BEFORE: '&8[&3&lTabooLib&8] &7物品 &f{0}&7 已存在, 如果你想要覆盖它, 请在聊天框中输入 "&fYES&7"' - GUIDE-QUIT: '&8[&3&lTabooLib&8] &7退出引导' - SUCCESS: '&8[&3&lTabooLib&8] &7物品 &f{0} &7已替换' - ITEM: - DESCRIPTION: '给予玩家物品' - ARGUMENTS: - 0: '名称' - 1: '玩家' - 2: '数量' - INVALID-NAME: '&8[&3&lTabooLib&8] &4请输入正确的名称' - INVALID-ITEM: '&8[&3&lTabooLib&8] &4物品 &c{0} &4不存在' - INVALID-PLAYER: '&8[&3&lTabooLib&8] &4玩家 &c{0} &4不在线' - INVALID-NUMBER: '&8[&3&lTabooLib&8] &4数量必须大于0' - SUCCESS: '&8[&3&lTabooLib&8] &7物品已发送至玩家 &f{0} &7的背包中' - ITEMRELOAD: - DESCRIPTION: '重载物品缓存' - SUCCESS-RELOAD: '&8[&3&lTabooLib&8] &7重载成功' - VARIABLE: - DESCRIPTION: - GET: '查看变量' - SET: '设置变量' - ARGUMENTS: - GET: - 0: '-s|-a' - 1: '键' - SET: - 0: '-s|-a' - 1: '键' - 2: '值' - WRITE-ERROR-TYPE: '&8[&3&lTabooLib&8] &4请输入正确的写入方式: &c-s&4、&c-a' - WRITE-SUCCESS: '&8[&3&lTabooLib&8] &7写入完成, 耗时: &f{0} &7(ms)' - READ-ERROR-TYPE: '&8[&3&lTabooLib&8] &4请输入正确的写入方式: &c-s&4、&c-a' - READ-RESULT: '&8[&3&lTabooLib&8] &7变量 &f{0} &7的值为: &f{1}' - READ-SUCCESS: '&8[&3&lTabooLib&8] &7写入完成, 耗时: &f{0} &7(ms)' - IMPORTDATA: - DESCRIPTION: '&4向数据库导入本地数据 &8(该操作将会清空数据库)' - CLEARING: '&8[&3&lTabooLib&8] &7正在清空数据库...' - EMPTYDATA: '&8[&3&lTabooLib&8] &4没有玩家数据可以导入' - IMPORTING-START: '&8[&3&lTabooLib&8] &7开始导入 &f{0} &7项玩家数据' - IMPORTING-PROGRESS: '&8[&3&lTabooLib&8] &7导入玩家数据: &f{0} &7进度: &f{1}/{2}' - SUCCESS: '&8[&3&lTabooLib&8] &7导入完成' - UPDATEPLUGIN: - DESCRIPTION: '&4更新插件 &8(谨防非正规途径的插件获取方式)' - UPDATE-NOT-FOUND: '&8[&3&lTabooLib&8] &7插件已是最新版, 无需更新!' - UPDATE-NOT-FOUND-SIZE: '&8[&3&lTabooLib&8] &4文件长度获取失败.' - UPDATE-NOT-SUPPORT: '&8[&3&lTabooLib&8] &4您的服务器不支持在线更新!' - UPDATE-SUCCESS: '&8[&3&lTabooLib&8] &7最新版下载完成, 服务器即将重启!' - UPDATE-FAILED: '&8[&3&lTabooLib&8] &4最新版下载失败.' - FILE-NOT-FOUND: '&8[&3&lTabooLib&8] &4尚未寻找到插件文件.' - PLAYER-ONLINE: '&8[&3&lTabooLib&8] &4服务器有玩家在线无法更新插件.' - ARGUMENTS: - 0: '-f' - PLAYERTAG: - DESCRIPTION: - DISPLAY: '设置玩家展示名称' - PREFIX: '设置玩家头顶前缀' - SUFFIX: '设置玩家头顶后缀' - DELETE: '删除玩家称号数据' - ARGUMENTS: - DISPLAY: - 0: '玩家' - 1: '文本' - PREFIX: - 0: '玩家' - 1: '文本' - SUFFIX: - 0: '玩家' - 1: '文本' - DELETE: - 0: '玩家' - INVALID-PLAYER: '&8[&3&lTabooLib&8] &4玩家 &c{0} &4不在线' - SUCCESS-DISPLAY-SET: '&8[&3&lTabooLib&8] &7设置玩家 &f{0} &7的名称为 &f{1}' - SUCCESS-PREFIX-SET: '&8[&3&lTabooLib&8] &7设置玩家 &f{0} &7的前缀为 &f{1}' - SUCCESS-SUFFIX-SET: '&8[&3&lTabooLib&8] &7设置玩家 &f{0} &7的后缀为 &f{1}' - SUCCESS-DELETE: '&8[&3&lTabooLib&8] &7删除玩家 &f{0} &7的称号数据' - LAGSERVER: - DESCRIPTION: '休眠主线程' - ARGUMENTS: - 0: '毫秒' - INVALID-TIME: '&8[&3&lTabooLib&8] &4休眠时间不可超过 &c30000 &4毫秒' - START: '&8[&3&lTabooLib&8] &7线程休眠开始.' - STOP: '&8[&3&lTabooLib&8] &7线程休眠结束.' - INFO: - DESCRIPTION: '查看物品信息' - INVALID-ITEM: '&8[&3&lTabooLib&8] &4请手持正确的物品' - ITEM-INFO: - - ==: JSON - text: - - '' - - '&b&l----- &3&lItemStack Info &b&l-----' - - '' - - '&7 - 物品材质: &f<{0}@type>' - - '&7 - 物品名称: &f<{1}@name>' - - '&7 - 物品序号: &f<{2}@id>' - - '&7 - 物品数据: &f' - - '' - args: - type: - hover: '&f点击复制' - suggest: '{0}' - name: - hover: '&f点击复制' - suggest: '{1}' - id: - hover: '&f点击复制' - suggest: '{2}' - nbt: - hover: '{3}' - ITEMLIST: - DESCRIPTION: '查看所有物品' - MENU: - TITLE: '物品库 {0}' - NEXT: '&f上一页' - BACK: '&f下一页' - LORE: - - '' - - '&f&m ' - - '&f序列号: &8{0}' - SOUNDS: - DESCRIPTION: '查看所有音效' - MENU: - TITLE: '音效库 {0}' - NEXT: '&f上一页' - BACK: '&f下一页' - LORE: - - '' - - '&fQ键: &70 音调' - - '&f左键: &71 音调' - - '&f右键: &72 音调' - - '&f中键: &7复制名称' - RESULT: - SEARCH: - - '&7查询名称: &f{0}' - - '&7查询结果: &f{1}' - COPY: - - ==: JSON - text: '&7点击复制: <&f&n{0}@sound>' - args: - sound: - hover: 点击复制音效 - suggest: '{0}' - TIMECYCLE: - DESCRIPTION: - LIST: '列出所有时间检查器' - INFO: '查询检查器信息' - RESET: '初始化时间检查器' - UPDATE: '更新时间检查器' - ARGUMENTS: - INFO: - 0: '名称' - RESET: - 0: '名称' - UPDATE: - 0: '名称' - INVALID-CYCLE: '&8[&3&lTabooLib&8] &4检查器 &c{0} &4不存在' - CYCLE-UPDATE: '&8[&3&lTabooLib&8] &7检查器 &f{0} &7已更新' - CYCLE-RESET: '&8[&3&lTabooLib&8] &7检查器 &f{0} &7初始化完成' - CYCLE-INFO: - - '' - - '&b&l----- &3&lTimeCycle Info &b&l-----' - - '' - - ' &f- &7注册周期: &f{0}' - - ' &f- &7注册插件: &f{1}' - - ' &f- &7上次刷新时间: &f{2}' - - ' &f- &7下次刷新时间: &f{3}' - - '' - LIST: - HEAD: - - '' - - '&b&l----- &3&lTimeCycle List &b&l-----' - - '' - BODY: - - ==: JSON - text: ' &7- &f{0} <&8(点击复制)@copy>' - args: - copy: - hover: '&f点击复制' - suggest: '{0}' - FOOT: - - '' - ATTRIBUTES: - DESCRIPTION: '查看所有属性' - HEAD: - - '' - - '&b&l----- &3&lItemStack Attributes &b&l-----' - - '' - BODY: - - ==: JSON - text: ' &7- &f{0} <&8(点击复制)@copy>' - args: - copy: - hover: '&f点击复制' - suggest: '{0}' - FOOT: - - '' - ENCHANTS: - DESCRIPTION: '查看所有附魔' - HEAD: - - '' - - '&b&l----- &3&lItemStack Enchantments &b&l-----' - - '' - BODY: - - ==: JSON - text: ' &7- &f{0}. {1} <&8(点击复制)@copy>' - args: - copy: - hover: '&f点击复制' - suggest: '{1}' - FOOT: - - '' - POTIONS: - DESCRIPTION: '查看所有药水' - HEAD: - - '' - - '&b&l----- &3&lItemStack PotionEffects &b&l-----' - - '' - BODY: - - ==: JSON - text: ' &7- &f{0}. {1} <&8(点击复制)@copy>' - args: - copy: - hover: '&f点击复制' - suggest: '{1}' - FOOT: - - '' - FLAGS: - DESCRIPTION: '查看所有标签' - HEAD: - - '' - - '&b&l----- &3&lItemStack Flags &b&l-----' - - '' - BODY: - - ==: JSON - text: ' &7- &f{0} <&8(点击复制)@copy>' - args: - copy: - hover: '&f点击复制' - suggest: '{0}' - FOOT: - - '' - SLOTS: - DESCRIPTION: '查看所有部位' - HEAD: - - '' - - '&b&l----- &3&lItemStack Slots &b&l-----' - - '' - BODY: - - ==: JSON - text: ' &7- &f{0} <&8(点击复制)@copy>' - args: - copy: - hover: '&f点击复制' - suggest: '{0}' - FOOT: - - '' - LANGUAGE2: - INVALID-PLAYER: '&8[&3&lTabooLib&8] &4玩家 &c{0} &4不在线' - SUCCESS-SEND: '&8[&3&lTabooLib&8] &7信息已发送, 耗时&f: {0}' - HELP: - - '' - - '&e&l----- &6&lLanguage2 Commands &e&l-----' - - '' - - '&f /{0} send &8[&7玩家/ALL&8] &8[&7语言&8] &8<&7变量&8> &6- &e发送语言提示' - - '&f /{0} reload &6- &e重载语言库' - - '' TLOCALE: COMMAND-TITLE: '&e&l----- &6&lTabooLibLoacle Commands &e&l-----' SEND: @@ -517,15 +131,6 @@ COMMANDS: INVALID-PLUGIN: '&8[&3&lTabooLib&8] &4插件 &c{0} &4不存在' INVALID-PLUGIN-IGNORED: '&8[&3&lTabooLib&8] &4插件 &c{0} &4无法操作' TRY-RELOAD: '&8[&3&lTabooLib&8] &7尝试重载插件...' - TRANSLATE-UUID: - COMMAND-TITLE: '&e&l----- &6&lTranslateUUID Commands &e&l-----' - IMPORTLOCAL: - DESCRIPTION: '导入本地数据到数据库' - DISABLED: '&8[&3&lTabooLib&8] &4该功能尚未启用' - SUCCESS: '&8[&3&lTabooLib&8] &7请求已发送, 详细信息请查看控制台' - RELOAD: - DESCRIPTION: '重载配置及数据库' - SUCCESS: '&8[&3&lTabooLib&8] &7请求已发送, 详细信息请查看控制台' TEXECUTE: COMMAND-TITLE: '&e&l----- &6&lTabooLibExecute Commands &e&l-----' CHAT: @@ -566,81 +171,6 @@ COMMANDS: 0: '目录' 1: '内容' SUCCESS: '&8[&3&lTabooLib&8] &7写入完成.' - TCLOUD: - COMMAND-TITLE: '&e&l----- &6&lTabooLibCloud Commands &e&l-----' - REFRESH: - DESCRIPTION: '刷新扩展列表' - SUCCESS: '&8[&3&lTabooLib&8] &7请求已发送. &8(详细信息请在控制台查看)' - STATUS: - DESCRIPTION: '查看扩展统计' - STATUS: - - '&8[&3&lTabooLib&8] &7当前总共 &f{0} &7项扩展被 &fTCLOUD &7录入, 其中包含:' - - '&8[&3&lTabooLib&8] &7内置扩展 &f{1} &7项' - - '&8[&3&lTabooLib&8] &7插件扩展 &f{2} &7项' - CONNECT-FAILED: '&8[&3&lTabooLib&8] &c尚未获取扩展列表.' - INFO: - DESCRIPTION: '查看扩展信息' - ARGUMENTS: - 0: '名称' - EXPANSION-NOT-FOUND: '&8[&3&lTabooLib&8] &c扩展 &4{0} &c不存在.' - EXPANSION-INFO: - - '&8[&3&lTabooLib&8] &7扩展 &f{0} &7信息:' - - '&8[&3&lTabooLib&8] &7作者 &f{1}' - - '&8[&3&lTabooLib&8] &7版本 &f{2}' - - '&8[&3&lTabooLib&8] &7描述 &f{3}' - - '&8[&3&lTabooLib&8] &7最后更新时间 &f{4}' - - '&8[&3&lTabooLib&8] &7最后更新内容 &f{5}' - EXPANSION-INFO-DETAIL: - 0: '&8[&3&lTabooLib&8] &7详细描述' - 1: '&8[&3&lTabooLib&8] &7- &f{0}' - DOWNLOAD: - DESCRIPTION: '下载扩展' - ARGUMENTS: - 0: '名称' - EXPANSION-NOT-FOUND: '&8[&3&lTabooLib&8] &c扩展 &4{0} &c不存在.' - EXPANSION-EXISTS: '&8[&3&lTabooLib&8] &c扩展 &4{0} &c已存在.' - EXPANSION-VERSION: '&8[&3&lTabooLib&8] &c扩展 &4{0} &c需要 &4TabooLib v{1}&c 版本才可以使用!' - DOWNLOAD-START: - - '&8[&3&lTabooLib&8] &7扩展 &f{0} &7开始下载:' - - '&8[&3&lTabooLib&8] &7地址 &f{1}' - DOWNLOAD-SUCCESS: '&8[&3&lTabooLib&8] &7扩展 &f{0} &7下载完成, 请重启服务器.' - UPDATE: - DESCRIPTION: '更新扩展' - ARGUMENTS: - 0: '名称' - EXPANSION-NOT-FOUND: '&8[&3&lTabooLib&8] &c扩展 &4{0} &c不存在.' - EXPANSION-NOT-EXISTS: '&8[&3&lTabooLib&8] &c扩展 &4{0} &c尚未下载.' - EXPANSION-NO-UPDATE: '&8[&3&lTabooLib&8] &7扩展 &f{0} &7已是最新版本.' - EXPANSION-VERSION: '&8[&3&lTabooLib&8] &c扩展 &4{0} &c需要 &4TabooLib v{1}&c 版本才可以使用!' - UPDATE-START: - - '&8[&3&lTabooLib&8] &7扩展 &f{0} &7开始更新:' - - '&8[&3&lTabooLib&8] &7版本 &f{1}' - - '&8[&3&lTabooLib&8] &7地址 &f{2}' - UPDATE-SUCCESS: '&8[&3&lTabooLib&8] &7扩展 &f{0} &7更新完成, 请重启服务器.' - LIST: - DESCRIPTION: '查看扩展列表' - ARGUMENTS: - 0: 'PLUGINS/INTERNAL' - 1: '页数' - INVALID-TYPE: - 0: '&8[&3&lTabooLib&8] &c错误的扩展类型. &4(PLUGINS、INTERNAL)' - 1: '&8[&3&lTabooLib&8] &c错误的页数.' - LIST-HEAD: - - '' - - '&e&l----- &6&lTabooLibCloud Expansions : &f{0} &6&l: &f{1}/{2} &e&l-----' - - '' - LIST-EXPANSION: - 0: ' &f{0}. &8{1} &7{2}' - 1: ' &f{0}. &c{1} &7{2}' - 2: ' &f{0}. &a{1} &7{2}' - LIST-BOTTOM: - - '' - - ' &f> &8[未安装] &a[已安装] &c[可更新]' - - '' - -DATABASE: - CONNECTION-ESTABLISHED: '成功连接到 {0} 数据库,连接池大小 {1}' - CONNECTION-ERROR: '连接到数据库错误:{0}' COMMUNICATION: FAILED-LOAD-SETTINGS: '§8[§3§lTabooLibClient§8] &4配置载入失败: {0}' @@ -657,43 +187,4 @@ UTIL: DOWNLOAD-CONNECTED: '开始下载文件 {0} 大小 {1}' DOWNLOAD-PROGRESS: ' 下载速度 {0} 进度 {1}' DOWNLOAD-SUCCESS: '下载 {0} 完成!' - DOWNLOAD-FAILED: '下载 {0} 失败!' - -TCLOUD: - LIST-LOAD-SUCCESS: '载入 &fTCLOUD &7扩展列表完成! 耗时 &f{0} &7毫秒' - LIST-LOAD-FAILED: '载入 &4{0} &c扩展数据失败: &4{1}' - LIST-PARSE-FAILED: '读取 &4TCLOUD &c扩展列表失败: &4{0}' - LIST-CONNECT-FAILED: '获取 &4TCLOUD &c扩展列表失败!' - -TFILTER: - EXCEPTION-MIRROR: - EVENT: - HEAD: - - '&c插件 &4{0} &c执行事件时出现异常! &7(处理耗时: {1}ms)' - - '&c异常事件: &4{2}' - - '&c异常类型: &4{3}' - - '&c异常内容: &4{4}' - - '&c异常位置:' - STACK-TRACE: '&7 {0}. &4{1}' - COMMAND: - HEAD: - - '&c插件 &4{0} &c执行命令时出现异常! &7(处理耗时: {1}ms)' - - '&c异常命令: &4{2}' - - '&c异常类型: &4{3}' - - '&c异常内容: &4{4}' - - '&c异常位置:' - STACK-TRACE: '&7 {0}. &4{1}' - SCHEDULE: - HEAD: - - '&c插件 &4{0} &c执行任务时出现异常! &7(处理耗时: {1}ms)' - - '&c异常类型: &4{2}' - - '&c异常内容: &4{3}' - - '&c异常位置:' - STACK-TRACE: '&7 {0}. &4{1}' - OTHER: - HEAD: - - '&c插件 &4{0} &c运行时出现异常! &7(处理耗时: {1}ms)' - - '&c异常类型: &4{2}' - - '&c异常内容: &4{3}' - - '&c异常位置:' - STACK-TRACE: '&7 {0}. &4{1}' \ No newline at end of file + DOWNLOAD-FAILED: '下载 {0} 失败!' \ No newline at end of file diff --git a/src/main/resources/module.yml b/src/main/resources/module.yml deleted file mode 100644 index ccd6800..0000000 --- a/src/main/resources/module.yml +++ /dev/null @@ -1,10 +0,0 @@ -# 语言文件 -Language: 'zh_CN' - -# 启用模块 -# 该配置需要重启服务器才会生效 -EnableModule: -#- 'Kits' -#- 'TimeCycle' -#- 'CommandChanger' -#- 'InventorySave' \ No newline at end of file diff --git a/src/main/resources/motd.txt b/src/main/resources/motd.txt deleted file mode 100644 index 2d271a9..0000000 --- a/src/main/resources/motd.txt +++ /dev/null @@ -1,10 +0,0 @@ -§r -§r -§b________ §b______ §f______§8___________ -§b___ __/§3_____ §b___ /§3_____________§f___ /§8___(_)__ /_ -§b__ / §3_ __ `/§b_ __ \§3 __ \ __ \§f_ / §8__ /__ __ \ -§b_ / §3/ /_/ /§b_ /_/ /§3 /_/ / /_/ /§f /___§8 / _ /_/ / -§b/_/ §3\__,_/ §b/_.___/§3\____/\____/§f/_____/§8_/ /_.___/ -§r - §8version §f{0} -§r \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml deleted file mode 100644 index 5432566..0000000 --- a/src/main/resources/plugin.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: TabooLib -main: me.skymc.taboolib.Main -version: ${version} -api-version: 1.13 - -authors: -- 坏黑 -- lzzelAliz - -softdepend: -- Vault -- PlaceholderAPI -- Skript -- MassiveLag \ No newline at end of file diff --git a/src/main/resources/translateuuid.yml b/src/main/resources/translateuuid.yml deleted file mode 100644 index 3e15dbb..0000000 --- a/src/main/resources/translateuuid.yml +++ /dev/null @@ -1,11 +0,0 @@ -# 是否启用 -Enable: false - -# 数据库地址 -Database: - host: 'localhost' - port: '3306' - user: 'root' - password: '' - database: 'test' - table: 'taboolib_translate_uuid_database' \ No newline at end of file diff --git a/src/main/resources/version b/src/main/resources/version new file mode 100644 index 0000000..e78e522 --- /dev/null +++ b/src/main/resources/version @@ -0,0 +1 @@ +${version} \ No newline at end of file diff --git a/src/main/scala/com/ilummc/tlib/ExampleMain.java b/src/main/scala/com/ilummc/tlib/ExampleMain.java deleted file mode 100644 index b6426a6..0000000 --- a/src/main/scala/com/ilummc/tlib/ExampleMain.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.ilummc.tlib; - -import com.ilummc.tlib.annotations.TConfig; -import com.ilummc.tlib.bean.Property; -import org.bukkit.Bukkit; -import org.bukkit.plugin.java.JavaPlugin; - -import java.lang.management.GarbageCollectorMXBean; -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryMXBean; -import java.util.concurrent.TimeUnit; - -@TConfig(name = "cfg.yml", charset = "GBK") -public class ExampleMain extends JavaPlugin { - - private Property update = Property.of(false); - - public static void main(String[] args) { - MemoryMXBean bean = ManagementFactory.getMemoryMXBean(); - System.out.println(bean.getHeapMemoryUsage().toString()); - System.out.println(bean.getNonHeapMemoryUsage().toString()); - for (int i = 0; i < 10; i++) { - for (GarbageCollectorMXBean mxBean : ManagementFactory.getGarbageCollectorMXBeans()) { - System.out.println(mxBean.getName()); - System.out.println(mxBean.getCollectionCount()); - System.out.println(mxBean.getCollectionTime()); - for (String s : mxBean.getMemoryPoolNames()) { - System.out.println(s); - } - System.out.println(mxBean.getObjectName().toString()); - } - System.gc(); - } - for (String s : ManagementFactory.getRuntimeMXBean().getInputArguments()) { - System.out.println(s); - } - } - - @Override - public void onEnable() { - update.addListener(((oldVal, newVal) -> { - Bukkit.getLogger().info("配置项 enableUpdate 的值由 " + oldVal + " 变为了 " + newVal); - if (newVal) { - Updater.start(); - } else { - Updater.stop(); - } - })); - } - - private static class Updater { - public static void start() { - - } - - public static void stop() { - - } - } - - private static class CD { - - final long start, period; - final TimeUnit unit; - final Runnable onStart, onFinish, onTimer; - - CD(long start, long period, TimeUnit unit, Runnable onStart, Runnable onFinish, Runnable onTimer) { - this.start = start; - this.period = period; - this.unit = unit; - this.onStart = onStart; - this.onFinish = onFinish; - this.onTimer = onTimer; - } - - public static void main(String[] args) { - CD.builder().setOnStart(() -> { - }).setOnFinish(() -> { - }).setOnTimer(1000, TimeUnit.MILLISECONDS, () -> { - }).build(); - } - - public static CdBuilder builder() { - return new CdBuilder(); - } - - private static class CdBuilder { - private long start, period; - private TimeUnit unit; - private Runnable onStart, onFinish, onTimer; - - public CdBuilder setOnStart(Runnable runnable) { - this.onStart = runnable; - return this; - } - - public CdBuilder setOnFinish(Runnable runnable) { - this.onFinish = runnable; - return this; - } - - public CdBuilder setOnTimer(long period, TimeUnit timeUnit, Runnable runnable) { - this.period = period; - this.unit = timeUnit; - this.onTimer = runnable; - return this; - } - - public CD build() { - return new CD(start, period, unit, onStart, onFinish, onTimer); - } - } - } -} diff --git a/src/main/scala/com/ilummc/tlib/TLib.java b/src/main/scala/com/ilummc/tlib/TLib.java deleted file mode 100644 index ad11ca0..0000000 --- a/src/main/scala/com/ilummc/tlib/TLib.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.ilummc.tlib; - -import com.ilummc.tlib.annotations.Dependency; -import com.ilummc.tlib.compat.PlaceholderHook; -import com.ilummc.tlib.config.TLibConfig; -import com.ilummc.tlib.db.Pool; -import com.ilummc.tlib.inject.TConfigWatcher; -import com.ilummc.tlib.inject.TDependencyInjector; -import com.ilummc.tlib.inject.TPluginManager; -import com.ilummc.tlib.logger.TLogger; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.resources.TLocaleLoader; -import com.ilummc.tlib.util.IO; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.fileutils.FileUtils; -import me.skymc.taboolib.plugin.PluginUtils; -import org.bukkit.Bukkit; -import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.configuration.file.YamlConfiguration; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.nio.charset.Charset; -import java.util.Arrays; - -@Dependency(type = Dependency.Type.LIBRARY, maven = "com.zaxxer:HikariCP:3.1.0") -@Dependency(type = Dependency.Type.LIBRARY, maven = "org.slf4j:slf4j-api:1.7.25") -@Dependency(type = Dependency.Type.LIBRARY, maven = "org.javalite:activejdbc:2.0") -@Dependency(type = Dependency.Type.LIBRARY, maven = "org.javalite:javalite-common:2.0") -@Dependency(type = Dependency.Type.LIBRARY, maven = "org.javalite:app-config:2.0") -@Dependency(type = Dependency.Type.LIBRARY, maven = "org.codehaus.jackson:jackson-mapper-asl:1.9.13") -@Dependency(type = Dependency.Type.LIBRARY, maven = "org.codehaus.jackson:jackson-core-asl:1.9.13") -@Dependency(type = Dependency.Type.LIBRARY, maven = "jaxen:jaxen:1.1.6") -@Dependency(type = Dependency.Type.LIBRARY, maven = "dom4j:dom4j:1.6.1") -@Dependency(type = Dependency.Type.LIBRARY, maven = "xml-apis:xml-apis:1.0.b2") -@Dependency(type = Dependency.Type.LIBRARY, maven = "org.ehcache:ehcache:3.5.2") -@Dependency(type = Dependency.Type.LIBRARY, maven = "com.h2database:h2:1.4.197") -public class TLib { - - private static TLib tLib; - private static YamlConfiguration internalLanguage; - private TLogger logger = new TLogger("§8[§3§lTabooLib§8][§r{1}§8] §f{2}", Main.getInst(), TLogger.FINE); - private TLibConfig config; - private TConfigWatcher configWatcher = new TConfigWatcher(); - private File libsFolder; - - private TLib() { - libsFolder = new File(Main.getInst().getDataFolder(), "/libs"); - if (!libsFolder.exists()) { - libsFolder.mkdirs(); - } - try { - String yamlText = new String(IO.readFully(FileUtils.getResource("lang/internal.yml")), Charset.forName("utf-8")); - internalLanguage = new YamlConfiguration(); - internalLanguage.loadFromString(yamlText); - } catch (IOException | InvalidConfigurationException ignored) { - } - } - - public static void init() { - tLib = new TLib(); - - TLocaleLoader.init(); - PlaceholderHook.init(); - TLocaleLoader.load(Main.getInst(), false); - } - - public static void initPost() { - TDependencyInjector.inject(Main.getInst(), TLib.getTLib()); - try { - Pool.init(); - } catch (Throwable ignored) { - } - } - - public static void unload() { - try { - Pool.unload(); - } catch (Throwable ignored) { - } - tLib.getConfigWatcher().unregisterAll(); - TDependencyInjector.eject(Main.getInst(), tLib); - - } - - public static void injectPluginManager() { - if (!tLib.isInjectEnabled() || tLib.isBlackListPluginExists()) { - TLocale.Logger.warn("TLIB.INJECTION-DISABLED"); - Arrays.stream(Bukkit.getPluginManager().getPlugins()).filter(plugin -> plugin != Main.getInst()).forEach(plugin -> TDependencyInjector.inject(plugin, plugin)); - return; - } - try { - Field field = Bukkit.getServer().getClass().getDeclaredField("pluginManager"); - field.setAccessible(true); - field.set(Bukkit.getServer(), new TPluginManager()); - TLocale.Logger.info("TLIB.INJECTION-SUCCESS"); - } catch (NoSuchFieldException | IllegalAccessException | IllegalArgumentException ignored) { - TLocale.Logger.error("TLIB.INJECTION-FAILED"); - Arrays.stream(Bukkit.getPluginManager().getPlugins()).filter(plugin -> !TabooLib.isTabooLib(plugin)).forEach(plugin -> TDependencyInjector.inject(plugin, plugin)); - } - } - - public static TLib getTLib() { - return tLib; - } - - public static YamlConfiguration getInternalLanguage() { - return internalLanguage; - } - - public TLogger getLogger() { - return logger; - } - - public TLibConfig getConfig() { - return config; - } - - public TConfigWatcher getConfigWatcher() { - return configWatcher; - } - - public File getLibsFolder() { - return libsFolder; - } - - public boolean isInjectEnabled() { - return Main.getInst().getConfig().getBoolean("PLUGIN-INJECTOR.ENABLE", true); - } - - public boolean isBlackListPluginExists() { - return Main.getInst().getConfig().getStringList("PLUGIN-INJECTOR.DISABLE-ON-PLUGIN-EXISTS").stream().anyMatch(PluginUtils::isPluginExists); - } - -} diff --git a/src/main/scala/com/ilummc/tlib/annotations/Logger.java b/src/main/scala/com/ilummc/tlib/annotations/Logger.java deleted file mode 100644 index da9456a..0000000 --- a/src/main/scala/com/ilummc/tlib/annotations/Logger.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.ilummc.tlib.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface Logger { - - String value() default "[{0}|{1}§f] {2}"; - - int level() default com.ilummc.tlib.logger.TLogger.INFO; - -} diff --git a/src/main/scala/com/ilummc/tlib/annotations/PluginInstance.java b/src/main/scala/com/ilummc/tlib/annotations/PluginInstance.java deleted file mode 100644 index 9e10b55..0000000 --- a/src/main/scala/com/ilummc/tlib/annotations/PluginInstance.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.ilummc.tlib.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface PluginInstance { - - String value(); -} diff --git a/src/main/scala/com/ilummc/tlib/annotations/TConfig.java b/src/main/scala/com/ilummc/tlib/annotations/TConfig.java deleted file mode 100644 index 3a28756..0000000 --- a/src/main/scala/com/ilummc/tlib/annotations/TConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.ilummc.tlib.annotations; - -import com.ilummc.tlib.util.Ref; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.lang.reflect.Modifier; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface TConfig { - - String name() default "config.yml"; - - boolean fromJar() default false; - - boolean saveOnExit() default false; - - boolean readOnly() default true; - - String charset() default "UTF-8"; - - boolean listenChanges() default false; - - int excludeModifiers() default Modifier.STATIC | Modifier.TRANSIENT | Ref.ACC_SYNTHETIC | Ref.ACC_BRIDGE; - -} diff --git a/src/main/scala/com/ilummc/tlib/annotations/TLocalePlugin.java b/src/main/scala/com/ilummc/tlib/annotations/TLocalePlugin.java deleted file mode 100644 index 40f6ce6..0000000 --- a/src/main/scala/com/ilummc/tlib/annotations/TLocalePlugin.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.ilummc.tlib.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface TLocalePlugin { -} diff --git a/src/main/scala/com/ilummc/tlib/annotations/clr/CommandHandler.java b/src/main/scala/com/ilummc/tlib/annotations/clr/CommandHandler.java deleted file mode 100644 index c38a610..0000000 --- a/src/main/scala/com/ilummc/tlib/annotations/clr/CommandHandler.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.ilummc.tlib.annotations.clr; - -import java.lang.annotation.*; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -@Repeatable(CommandHandlers.class) -public @interface CommandHandler { - - /** - * Name of the command - * - * @return Name of the command - */ - String value(); - -} diff --git a/src/main/scala/com/ilummc/tlib/annotations/clr/CommandHandlers.java b/src/main/scala/com/ilummc/tlib/annotations/clr/CommandHandlers.java deleted file mode 100644 index 34cfb32..0000000 --- a/src/main/scala/com/ilummc/tlib/annotations/clr/CommandHandlers.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.ilummc.tlib.annotations.clr; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface CommandHandlers { - - CommandHandler[] value(); - -} diff --git a/src/main/scala/com/ilummc/tlib/annotations/clr/Sub.java b/src/main/scala/com/ilummc/tlib/annotations/clr/Sub.java deleted file mode 100644 index 2ee6e27..0000000 --- a/src/main/scala/com/ilummc/tlib/annotations/clr/Sub.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.ilummc.tlib.annotations.clr; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface Sub { - - String value(); - -} diff --git a/src/main/scala/com/ilummc/tlib/annotations/db/Database.java b/src/main/scala/com/ilummc/tlib/annotations/db/Database.java deleted file mode 100644 index cdf2b49..0000000 --- a/src/main/scala/com/ilummc/tlib/annotations/db/Database.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.ilummc.tlib.annotations.db; - -public @interface Database { - - boolean sharedPool() default true; - - int poolSize() default 8; - - Class configClass(); - -} diff --git a/src/main/scala/com/ilummc/tlib/annotations/db/DatabasePassword.java b/src/main/scala/com/ilummc/tlib/annotations/db/DatabasePassword.java deleted file mode 100644 index 6f42c90..0000000 --- a/src/main/scala/com/ilummc/tlib/annotations/db/DatabasePassword.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.ilummc.tlib.annotations.db; - -public @interface DatabasePassword { -} diff --git a/src/main/scala/com/ilummc/tlib/annotations/db/DatabaseType.java b/src/main/scala/com/ilummc/tlib/annotations/db/DatabaseType.java deleted file mode 100644 index 48070ca..0000000 --- a/src/main/scala/com/ilummc/tlib/annotations/db/DatabaseType.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.ilummc.tlib.annotations.db; - -public @interface DatabaseType { -} diff --git a/src/main/scala/com/ilummc/tlib/annotations/db/DatabaseUrl.java b/src/main/scala/com/ilummc/tlib/annotations/db/DatabaseUrl.java deleted file mode 100644 index 056dd25..0000000 --- a/src/main/scala/com/ilummc/tlib/annotations/db/DatabaseUrl.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.ilummc.tlib.annotations.db; - -public @interface DatabaseUrl { -} diff --git a/src/main/scala/com/ilummc/tlib/annotations/db/DatabaseUser.java b/src/main/scala/com/ilummc/tlib/annotations/db/DatabaseUser.java deleted file mode 100644 index b8ab435..0000000 --- a/src/main/scala/com/ilummc/tlib/annotations/db/DatabaseUser.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.ilummc.tlib.annotations.db; - -public @interface DatabaseUser { -} diff --git a/src/main/scala/com/ilummc/tlib/annotations/db/SQLTable.java b/src/main/scala/com/ilummc/tlib/annotations/db/SQLTable.java deleted file mode 100644 index 543d3f2..0000000 --- a/src/main/scala/com/ilummc/tlib/annotations/db/SQLTable.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.ilummc.tlib.annotations.db; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface SQLTable { - - String value(); - -} diff --git a/src/main/scala/com/ilummc/tlib/bean/Property.java b/src/main/scala/com/ilummc/tlib/bean/Property.java deleted file mode 100644 index 66f3950..0000000 --- a/src/main/scala/com/ilummc/tlib/bean/Property.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.ilummc.tlib.bean; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.BiConsumer; - -public class Property { - - private Property(T value) { - this.value = value; - } - - private List> consumers; - - private T value; - - public void set(T value) { - if (value != this.value) { - if (consumers != null) { - for (BiConsumer consumer : consumers) { - consumer.accept(this.value, value); - } - } - this.value = value; - } - } - - public T get() { - return value; - } - - public void addListener(BiConsumer consumer) { - if (consumers == null) { - consumers = new ArrayList<>(); - } - consumers.add(consumer); - } - - public static Property of(T value) { - return new Property<>(value); - } - -} diff --git a/src/main/scala/com/ilummc/tlib/bean/PropertyTypeAdaptor.java b/src/main/scala/com/ilummc/tlib/bean/PropertyTypeAdaptor.java deleted file mode 100644 index f802433..0000000 --- a/src/main/scala/com/ilummc/tlib/bean/PropertyTypeAdaptor.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.ilummc.tlib.bean; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonParseException; - -import java.lang.reflect.Type; - -public class PropertyTypeAdaptor implements JsonDeserializer { - - @Override - public Property deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException { - return null; - } -} diff --git a/src/main/scala/com/ilummc/tlib/clr/CommandLineResolver.java b/src/main/scala/com/ilummc/tlib/clr/CommandLineResolver.java deleted file mode 100644 index 5341f28..0000000 --- a/src/main/scala/com/ilummc/tlib/clr/CommandLineResolver.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.ilummc.tlib.clr; - -public class CommandLineResolver { - - - -} diff --git a/src/main/scala/com/ilummc/tlib/config/TLibConfig.java b/src/main/scala/com/ilummc/tlib/config/TLibConfig.java deleted file mode 100644 index 9ecb9de..0000000 --- a/src/main/scala/com/ilummc/tlib/config/TLibConfig.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.ilummc.tlib.config; - -import com.ilummc.tlib.annotations.TConfig; - -import java.util.HashMap; -import java.util.Map; - -/** - * @author sky - * @since 2018-04-22 14:31:11 - */ -@TConfig(name = "tlib.yml") -public class TLibConfig { - - private String dataSourceClassName; - - private String jdbcUrl = "jdbc:h2:file:~/plugins/TabooLib/h2"; - - private String driverClassName; - - private String username = ""; - - private String password = ""; - - private int maximumPoolSize = 4; - - private Map settings = new HashMap() {{ - put("cachePrepStmts", true); - put("useServerPrepStmts", true); - }}; - - public String getDataSourceClassName() { - return dataSourceClassName; - } - - public String getJdbcUrl() { - return jdbcUrl; - } - - public String getDriverClassName() { - return driverClassName; - } - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } - - public int getMaximumPoolSize() { - return maximumPoolSize; - } - - public Map getSettings() { - return settings; - } -} diff --git a/src/main/scala/com/ilummc/tlib/db/Pool.java b/src/main/scala/com/ilummc/tlib/db/Pool.java deleted file mode 100644 index 82ccbfc..0000000 --- a/src/main/scala/com/ilummc/tlib/db/Pool.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.ilummc.tlib.db; - -import com.ilummc.tlib.TLib; -import com.ilummc.tlib.resources.TLocale; -import org.javalite.activejdbc.Base; - -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -public final class Pool extends ThreadPoolExecutor { - - private static final AtomicInteger number = new AtomicInteger(1); - - private static final Pool singleton = new Pool(); - - private final TLibDataSource dataSource; - - private Pool() { - super(TLib.getTLib().getConfig().getMaximumPoolSize(), - TLib.getTLib().getConfig().getMaximumPoolSize(), - 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); - try { - dataSource = new TLibDataSource(); - this.setThreadFactory(r -> new Thread(() -> { - Base.open(dataSource.getDataSource()); - r.run(); - }, "TabooLib-DbPool-" + number.getAndIncrement())); - prestartAllCoreThreads(); - TLocale.sendToConsole("DATABASE.CONNECTION-ESTABLISHED", dataSource.getDataSource().getConnection().getMetaData().getDatabaseProductName(), - String.valueOf(TLib.getTLib().getConfig().getMaximumPoolSize())); - } catch (Exception e) { - TLocale.sendToConsole("DATABASE.CONNECTION-ERROR", e.toString()); - throw new RuntimeException(); - } - } - - public static void run(Runnable runnable) { - instance().execute(runnable); - } - - public static void init() { - - } - - public static void unload() { - instance().dataSource.disconnect(); - instance().shutdown(); - } - - public static Pool instance() { - return singleton; - } - - @Override - protected void afterExecute(Runnable r, Throwable t) { - if (t != null) { - Base.close(); - } - } - -} diff --git a/src/main/scala/com/ilummc/tlib/db/TLibDataSource.java b/src/main/scala/com/ilummc/tlib/db/TLibDataSource.java deleted file mode 100644 index 734b0be..0000000 --- a/src/main/scala/com/ilummc/tlib/db/TLibDataSource.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.ilummc.tlib.db; - -import com.ilummc.tlib.TLib; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; -import org.javalite.activejdbc.Base; - -import javax.sql.DataSource; -import java.util.Properties; - -public class TLibDataSource { - - private final HikariDataSource dataSource; - - TLibDataSource() { - Properties properties = new Properties(); - properties.put("jdbcUrl", TLib.getTLib().getConfig().getJdbcUrl()); - properties.put("username", TLib.getTLib().getConfig().getUsername()); - properties.put("password", TLib.getTLib().getConfig().getPassword()); - properties.put("dataSourceClassName", TLib.getTLib().getConfig().getDataSourceClassName()); - properties.put("driverClassName", TLib.getTLib().getConfig().getDriverClassName()); - TLib.getTLib().getConfig().getSettings().forEach((k, v) -> properties.put("dataSource." + k, v)); - dataSource = new HikariDataSource(new HikariConfig(properties)); - Base.open(dataSource); - } - - public DataSource getDataSource() { - return dataSource; - } - - public void disconnect() { - Base.close(); - } - -} diff --git a/src/main/scala/com/ilummc/tlib/dependency/TDependency.java b/src/main/scala/com/ilummc/tlib/dependency/TDependency.java deleted file mode 100644 index 1ed290e..0000000 --- a/src/main/scala/com/ilummc/tlib/dependency/TDependency.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.ilummc.tlib.dependency; - -import com.ilummc.eagletdl.EagletTask; -import com.ilummc.eagletdl.ProgressEvent; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.Main; - -import java.io.File; -import java.util.concurrent.atomic.AtomicBoolean; - -public class TDependency { - - // 阿里 http://maven.aliyun.com/nexus/content/groups/public - // Maven Central - public static final String MAVEN_REPO = "http://repo1.maven.org/maven2"; - - /** - * 请求一个插件作为依赖,这个插件将会在所有已经添加的 Jenkins 仓库、Maven 仓库寻找 - *

- * 阻塞线程进行下载/加载 - * - * @param args 插件名称,下载地址(可选) - * @return 是否成功加载了依赖 - */ - public static boolean requestPlugin(String... args) { - return false; - } - - /** - * 请求一个库作为依赖,这个库将会在 Maven Central、oss.sonatype 以及自定义的 Maven 仓库寻找 - *

- * 阻塞线程进行下载/加载 - * - * @param type 依赖名,格式为 groupId:artifactId:version - * @return 是否成功加载库,如果加载成功,插件将可以任意调用使用的类 - */ - public static boolean requestLib(String type, String repo, String url) { - if (type.matches(".*:.*:.*")) { - String[] arr = type.split(":"); - File file = new File(Main.getInst().getDataFolder(), "/libs/" + String.join("-", arr) + ".jar"); - if (file.exists()) { - TDependencyLoader.addToPath(Main.getInst(), file); - return true; - } else { - if (downloadMaven(repo, arr[0], arr[1], arr[2], file, url)) { - TDependencyLoader.addToPath(Main.getInst(), file); - return true; - } else { - return false; - } - } - } - return false; - } - - private static boolean downloadMaven(String url, String groupId, String artifactId, String version, File target, String dl) { - if (Main.isOfflineVersion()) { - TLocale.Logger.warn("DEPENDENCY.DOWNLOAD-OFFLINE"); - return false; - } - AtomicBoolean failed = new AtomicBoolean(false); - String link = dl.length() == 0 ? url + "/" + groupId.replace('.', '/') + "/" + artifactId + "/" + version + "/" + artifactId + "-" + version + ".jar" : dl; - new EagletTask() - .url(link) - .file(target) - .setThreads(1) - .setOnError(event -> event.getException().printStackTrace()) - .setOnConnected(event -> TLocale.Logger.info("DEPENDENCY.DOWNLOAD-CONNECTED", String.join(":", new String[] {groupId, artifactId, version}), ProgressEvent.format(event.getContentLength()))) - .setOnProgress(event -> TLocale.Logger.info("DEPENDENCY.DOWNLOAD-PROGRESS", event.getSpeedFormatted(), event.getPercentageFormatted())) - .setOnComplete(event -> { - if (event.isSuccess()) { - TLocale.Logger.info("DEPENDENCY.DOWNLOAD-SUCCESS", String.join(":", new String[] {groupId, artifactId, version})); - } else { - failed.set(true); - TLocale.Logger.error("DEPENDENCY.DOWNLOAD-FAILED", String.join(":", new String[] {groupId, artifactId, version}), link, target.getName()); - } - }).start().waitUntil(); - return !failed.get(); - } -} diff --git a/src/main/scala/com/ilummc/tlib/dependency/TDependencyLoader.java b/src/main/scala/com/ilummc/tlib/dependency/TDependencyLoader.java deleted file mode 100644 index 3c52502..0000000 --- a/src/main/scala/com/ilummc/tlib/dependency/TDependencyLoader.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.ilummc.tlib.dependency; - -import org.bukkit.plugin.Plugin; - -import java.io.File; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; - -public class TDependencyLoader { - - public static synchronized void addToPath(Plugin plugin, URL url) { - try { - Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); - method.setAccessible(true); - method.invoke(plugin.getClass().getClassLoader(), url); - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } - } - - public static synchronized void addToPath(Plugin plugin, File file) { - try { - addToPath(plugin, file.toURI().toURL()); - } catch (MalformedURLException e) { - e.printStackTrace(); - } - } - -} diff --git a/src/main/scala/com/ilummc/tlib/filter/TLoggerFilter.java b/src/main/scala/com/ilummc/tlib/filter/TLoggerFilter.java deleted file mode 100644 index e83cfd3..0000000 --- a/src/main/scala/com/ilummc/tlib/filter/TLoggerFilter.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.ilummc.tlib.filter; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.ilummc.tlib.filter.impl.FilterConfiguration; -import com.ilummc.tlib.filter.impl.FilterInvalidPluginLoader; -import me.skymc.taboolib.TabooLib; -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.logging.Filter; -import java.util.logging.LogRecord; -import java.util.logging.Logger; - -/** - * @author Bkm016 - * @since 2018-04-22 - */ -public class TLoggerFilter implements Filter { - - private Filter filter; - private Logger logger; - private static List handlers = Lists.newLinkedList(); - private static Map pluginFilter = Maps.newHashMap(); - private static TLoggerFilter globalFilter; - private static String playerConnectionName; - - static { - handlers.add(new FilterConfiguration()); - handlers.add(new FilterInvalidPluginLoader()); - // handlers.add(new FilterExceptionMirror()); - } - - public static void preInit() { - inject(new TLoggerFilter(), Bukkit.getLogger()); - inject(new TLoggerFilter(), TabooLib.instance().getLogger()); - try { - playerConnectionName = Class.forName("net.minecraft.server." + TabooLib.getVersion() + ".PlayerConnection").getName(); - } catch (Exception ignored) { - } - } - - public static void postInit() { - Arrays.stream(Bukkit.getPluginManager().getPlugins()).filter(TabooLib::isDependTabooLib).forEach(plugin -> inject(new TLoggerFilter(), plugin.getLogger())); - } - - public static void inject0() { - inject(new TLoggerFilter(), Logger.getLogger(playerConnectionName)); - } - - public static void inject(TLoggerFilter filter, Logger logger) { - if (!(logger.getFilter() instanceof TLoggerFilter)) { - try { - filter.filter = logger.getFilter(); - filter.logger = logger; - logger.setFilter(filter); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - public static void eject(Plugin plugin) { - try { - if (plugin.getLogger().getFilter() instanceof TLoggerFilter) { - ((TLoggerFilter) plugin.getLogger().getFilter()).filter = null; - ((TLoggerFilter) plugin.getLogger().getFilter()).logger = null; - plugin.getLogger().setFilter(null); - } - } catch (Throwable t) { - t.printStackTrace(); - } - } - - public static TLoggerFilter getGlobalFilter() { - return globalFilter; - } - - public static Map getPluginFilter() { - return pluginFilter; - } - - public static List getHandlers() { - return handlers; - } - - public Filter getFilter() { - return filter; - } - - public Logger getLogger() { - return logger; - } - - @Override - public boolean isLoggable(LogRecord e) { - return handlers.stream().allMatch(filter -> filter.isLoggable(e)) && (filter == null || filter.isLoggable(e)); - } -} diff --git a/src/main/scala/com/ilummc/tlib/filter/TLoggerFilterHandler.java b/src/main/scala/com/ilummc/tlib/filter/TLoggerFilterHandler.java deleted file mode 100644 index 9e4ef1b..0000000 --- a/src/main/scala/com/ilummc/tlib/filter/TLoggerFilterHandler.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.ilummc.tlib.filter; - -import java.util.logging.LogRecord; - -/** - * @Author 坏黑 - * @Since 2018-11-29 11:42 - */ -public abstract class TLoggerFilterHandler { - - abstract public boolean isLoggable(LogRecord e); - -} diff --git a/src/main/scala/com/ilummc/tlib/filter/impl/FilterConfiguration.java b/src/main/scala/com/ilummc/tlib/filter/impl/FilterConfiguration.java deleted file mode 100644 index b476822..0000000 --- a/src/main/scala/com/ilummc/tlib/filter/impl/FilterConfiguration.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.ilummc.tlib.filter.impl; - -import com.ilummc.tlib.filter.TLoggerFilterHandler; - -import java.util.Arrays; -import java.util.logging.LogRecord; - -/** - * @Author 坏黑 - * @Since 2018-11-29 11:47 - */ -public class FilterConfiguration extends TLoggerFilterHandler { - - @Override - public boolean isLoggable(LogRecord e) { - if (String.valueOf(e.getMessage()).contains("Cannot load configuration from stream")) { - StackTraceElement[] elements = Thread.currentThread().getStackTrace(); - for (StackTraceElement element : elements) { - if (element.getClassName().contains("ConfigUtils")) { - // Bukkit 拦截异常?我再扔一个 - System.out.println(Arrays.asList(e.getParameters())); - } - } - return false; - } - return true; - } -} diff --git a/src/main/scala/com/ilummc/tlib/filter/impl/FilterExceptionMirror.java b/src/main/scala/com/ilummc/tlib/filter/impl/FilterExceptionMirror.java deleted file mode 100644 index db01569..0000000 --- a/src/main/scala/com/ilummc/tlib/filter/impl/FilterExceptionMirror.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.ilummc.tlib.filter.impl; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import com.ilummc.tlib.filter.TLoggerFilterHandler; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; -import org.bukkit.command.CommandException; -import org.bukkit.event.EventException; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.List; -import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.LogRecord; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * @Author 坏黑 - * @Since 2018-11-29 11:42 - */ -public class FilterExceptionMirror extends TLoggerFilterHandler { - - interface ArgumentsCallback { - - String[] run(); - } - - private static Pattern patternEvent = Pattern.compile("Could not pass event (.+?) to (.+?)"); - private static Pattern patternCommand = Pattern.compile("Unhandled exception executing command '(.+?)' in plugin (.+?)"); - - /** - * 判断是否为调度器异常 - */ - public boolean isScheduleException(LogRecord log) { - return String.valueOf(log.getMessage()).contains("generated an exception"); - } - - /** - * 是否为可捕捉异常 - */ - public boolean isValidException(Throwable throwable) { - return throwable.getCause() != null && throwable.getCause().getStackTrace() != null && throwable.getCause().getStackTrace().length > 0; - } - - /** - * 向控制台打印捕捉到的异常 - * - * @param stackTraceElements 堆栈 - * @param message 信息类型 - * @param args 信息参数 - * @return 是否成功捕捉并打印 - */ - public boolean printException(AtomicReference plugin, StackTraceElement[] stackTraceElements, String message, ArgumentsCallback args) { - Set plugins = Sets.newHashSet(); - List stackTraces = Lists.newLinkedList(); - for (StackTraceElement stack : stackTraceElements) { - try { - plugins.add(JavaPlugin.getProvidingPlugin(Class.forName(stack.getClassName()))); - stackTraces.add(stack); - } catch (Exception ignored) { - } - } - if (!plugins.isEmpty() && plugins.stream().allMatch(p -> TabooLib.isTabooLib(p) || TabooLib.isDependTabooLib(p))) { - plugin.set(plugins.iterator().next()); - TLocale.Logger.error("TFILTER.EXCEPTION-MIRROR." + message + ".HEAD", args.run()); - for (int i = 0; i < stackTraces.size(); i++) { - StackTraceElement stack = stackTraces.get(i); - TLocale.Logger.error("TFILTER.EXCEPTION-MIRROR." + message + ".STACK-TRACE", String.valueOf(i), stack.toString()); - } - return true; - } - return false; - } - - @Override - public boolean isLoggable(LogRecord e) { - if (!Main.getInst().getConfig().getBoolean("EXCEPTION-MIRROR", true) || e.getThrown() == null) { - return true; - } - // 是否为调度器异常 - if (isScheduleException(e)) { - long time = System.currentTimeMillis(); - AtomicReference plugin = new AtomicReference<>(); - return !printException(plugin, e.getThrown().getStackTrace(), "SCHEDULE", () -> new String[] {plugin.get().getName(), String.valueOf(System.currentTimeMillis() - time), e.getThrown().getClass().getSimpleName(), String.valueOf(e.getThrown().getMessage())}); - } - // 是否为其他可捕捉异常 - else if (isValidException(e.getThrown())) { - // 事件异常 - if (e.getThrown() instanceof EventException) { - Matcher matcher = patternEvent.matcher(e.getMessage()); - if (matcher.find()) { - long time = System.currentTimeMillis(); - AtomicReference plugin = new AtomicReference<>(); - return !printException(plugin, e.getThrown().getCause().getStackTrace(), "EVENT", () -> new String[] {plugin.get().getName(), String.valueOf(System.currentTimeMillis() - time), matcher.group(1), e.getThrown().getCause().getClass().getSimpleName(), String.valueOf(e.getThrown().getCause().getMessage())}); - } - } - // 命令异常 - else if (e.getThrown() instanceof CommandException) { - Matcher matcher = patternCommand.matcher(e.getThrown().getMessage()); - if (matcher.find()) { - long time = System.currentTimeMillis(); - AtomicReference plugin = new AtomicReference<>(); - return !printException(plugin, e.getThrown().getCause().getStackTrace(), "COMMAND", () -> new String[] {plugin.get().getName(), String.valueOf(System.currentTimeMillis() - time), matcher.group(1), e.getThrown().getCause().getClass().getSimpleName(), String.valueOf(e.getThrown().getCause().getMessage())}); - } - } - // 其他异常 - else { - long time = System.currentTimeMillis(); - AtomicReference plugin = new AtomicReference<>(); - return !printException(plugin, e.getThrown().getCause().getStackTrace(), "OTHER", () -> new String[] {plugin.get().getName(), String.valueOf(System.currentTimeMillis() - time), e.getThrown().getCause().getClass().getSimpleName(), String.valueOf(e.getThrown().getCause().getMessage())}); - } - } - return true; - } -} diff --git a/src/main/scala/com/ilummc/tlib/filter/impl/FilterInvalidPluginLoader.java b/src/main/scala/com/ilummc/tlib/filter/impl/FilterInvalidPluginLoader.java deleted file mode 100644 index e93cdf8..0000000 --- a/src/main/scala/com/ilummc/tlib/filter/impl/FilterInvalidPluginLoader.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.ilummc.tlib.filter.impl; - -import com.ilummc.tlib.filter.TLoggerFilterHandler; - -import java.util.logging.LogRecord; - -/** - * @Author 坏黑 - * @Since 2018-11-29 11:47 - */ -public class FilterInvalidPluginLoader extends TLoggerFilterHandler { - - @Override - public boolean isLoggable(LogRecord e) { - // 屏蔽插件加载器注入导致的警告信息 - return !String.valueOf(e.getMessage()).contains("Enabled plugin with unregistered PluginClassLoader"); - } -} diff --git a/src/main/scala/com/ilummc/tlib/inject/TConfigInjector.java b/src/main/scala/com/ilummc/tlib/inject/TConfigInjector.java deleted file mode 100644 index d7f788d..0000000 --- a/src/main/scala/com/ilummc/tlib/inject/TConfigInjector.java +++ /dev/null @@ -1,143 +0,0 @@ -package com.ilummc.tlib.inject; - -import com.google.common.io.Files; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.ilummc.tlib.annotations.TConfig; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.fileutils.ConfigUtils; -import org.apache.commons.lang3.Validate; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.Plugin; -import org.yaml.snakeyaml.DumperOptions; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.nio.charset.Charset; -import java.util.HashMap; -import java.util.Map; - -public class TConfigInjector { - - public static void fixUnicode(YamlConfiguration configuration) { - try { - Field field = YamlConfiguration.class.getDeclaredField("yamlOptions"); - field.setAccessible(true); - field.set(configuration, NoUnicodeDumperOption.INSTANCE); - } catch (NoSuchFieldException | IllegalAccessException e) { - e.printStackTrace(); - } - } - - private static final class NoUnicodeDumperOption extends DumperOptions { - - private static final NoUnicodeDumperOption INSTANCE = new NoUnicodeDumperOption(); - - @Override - public void setAllowUnicode(boolean allowUnicode) { - super.setAllowUnicode(false); - } - - @Override - public boolean isAllowUnicode() { - return false; - } - - @Override - public void setLineBreak(LineBreak lineBreak) { - super.setLineBreak(LineBreak.getPlatformLineBreak()); - } - } - - public static Object loadConfig(Plugin plugin, Class clazz) { - try { - TConfig config = clazz.getAnnotation(TConfig.class); - Validate.notNull(config); - File file = new File(plugin.getDataFolder(), config.name()); - if (!file.exists()) { - if (config.fromJar()) { - plugin.saveResource(config.name(), true); - } else { - saveConfig(plugin, clazz.newInstance()); - } - } - Object obj = unserialize(plugin, clazz); - if (config.readOnly()) { - saveConfig(plugin, obj); - } - return obj; - } catch (NullPointerException e) { - TLocale.Logger.warn("CONFIG.LOAD-FAIL-NO-ANNOTATION", plugin.toString(), clazz.getSimpleName()); - } catch (Exception e) { - TLocale.Logger.warn("CONFIG.LOAD-FAIL", plugin.toString(), clazz.getSimpleName()); - } - return null; - } - - public static void reloadConfig(Plugin plugin, Object object) { - try { - TConfig config = object.getClass().getAnnotation(TConfig.class); - Validate.notNull(config); - File file = new File(plugin.getDataFolder(), config.name()); - Map map = ConfigUtils.confToMap(ConfigUtils.loadYaml(plugin, file)); - Object obj = ConfigUtils.mapToObj(map, object); - if (config.readOnly()) { - saveConfig(plugin, obj); - } - } catch (NullPointerException e) { - TLocale.Logger.warn("CONFIG.LOAD-FAIL-NO-ANNOTATION", plugin.toString(), object.getClass().getSimpleName()); - } catch (Exception e) { - TLocale.Logger.warn("CONFIG.LOAD-FAIL", plugin.toString(), object.getClass().getSimpleName()); - } - } - - public static Object unserialize(Plugin plugin, Class clazz) { - try { - TConfig config = clazz.getAnnotation(TConfig.class); - Validate.notNull(config); - return ConfigUtils.confToObj( - ConfigUtils.mapToConf( - ConfigUtils.yamlToMap( - Files.toString(new File(plugin.getDataFolder(), config.name()), Charset.forName(config.charset())))), clazz); - } catch (NullPointerException e) { - TLocale.Logger.warn("CONFIG.LOAD-FAIL-NO-FILE", plugin.toString(), clazz.getSimpleName()); - return null; - } catch (Exception e) { - try { - return clazz.newInstance(); - } catch (InstantiationException | IllegalAccessException e1) { - TLocale.Logger.warn("CONFIG.LOAD-FAIL", plugin.toString(), clazz.getSimpleName()); - return null; - } - } - } - - public static Map serialize(Plugin plugin, Object object) { - try { - TConfig config = object.getClass().getAnnotation(TConfig.class); - Validate.notNull(config); - return ConfigUtils.objToMap(ConfigUtils.objToConf(object).getValues(false), config.excludeModifiers()); - } catch (NullPointerException e) { - TLocale.Logger.warn("CONFIG.SAVE-FAIL-NO-ANNOTATION", plugin.toString(), object.getClass().getSimpleName()); - } catch (Exception e) { - TLocale.Logger.warn("CONFIG.SAVE-FAIL", plugin.toString(), object.getClass().getSimpleName()); - } - return null; - } - - public static void saveConfig(Plugin plugin, Object object) throws IOException, NullPointerException { - TConfig config = object.getClass().getAnnotation(TConfig.class); - Validate.notNull(config); - Gson gson = new GsonBuilder().disableHtmlEscaping().create(); - Map map = gson.fromJson(gson.toJson(object), HashMap.class); - YamlConfiguration configuration = (YamlConfiguration) ConfigUtils.mapToConf(map); - File target = new File(plugin.getDataFolder(), config.name()); - if (!target.exists()) { - target.createNewFile(); - } - byte[] arr = configuration.saveToString().getBytes(config.charset()); - Files.write(arr, target); - } - -} diff --git a/src/main/scala/com/ilummc/tlib/inject/TDependencyInjector.java b/src/main/scala/com/ilummc/tlib/inject/TDependencyInjector.java deleted file mode 100644 index 448fa29..0000000 --- a/src/main/scala/com/ilummc/tlib/inject/TDependencyInjector.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.ilummc.tlib.inject; - -import com.ilummc.tlib.TLib; -import com.ilummc.tlib.annotations.*; -import com.ilummc.tlib.dependency.TDependency; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.resources.TLocaleLoader; -import com.ilummc.tlib.util.Ref; -import me.skymc.taboolib.TabooLib; -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.java.JavaPlugin; - -import java.io.File; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; - -/** - * @author Izzel_Aliz - */ -public class TDependencyInjector { - - private static List injected = new ArrayList<>(); - - static void injectOnEnable(Plugin plugin) { - inject(plugin, plugin); - } - - static void ejectOnDisable(Plugin plugin) { - eject(plugin, plugin); - } - - public static boolean injected(Plugin plugin) { - return injected.contains(plugin.getName()); - } - - public static void inject(Plugin plugin, Object o) { - if (!injected.contains(plugin.getName())) { - injected.add(plugin.getName()); - TLocaleLoader.load(plugin, true); - injectDependencies(plugin, o); - injectLogger(plugin, o); - injectConfig(plugin, o); - injectPluginInstance(plugin, o); - } - } - - public static void eject(Plugin plugin, Object o) { - try { - injected.remove(plugin.getName()); - ejectConfig(plugin, o); - } catch (Throwable ignored) { - } - } - - public static Dependency[] getDependencies(Object o) { - Dependency[] dependencies = new Dependency[0]; - Dependencies d = o.getClass().getAnnotation(Dependencies.class); - if (d != null) { - dependencies = d.value(); - } - Dependency d2 = o.getClass().getAnnotation(Dependency.class); - if (d2 != null) { - dependencies = new Dependency[] {d2}; - } - return dependencies; - } - - private static void ejectConfig(Plugin plugin, Object o) { - for (Field field : Ref.getDeclaredFields(o.getClass())) { - TConfig config; - if ((config = field.getType().getAnnotation(TConfig.class)) != null && config.saveOnExit()) { - try { - field.setAccessible(true); - TConfigInjector.saveConfig(plugin, field.get(o)); - TLocale.Logger.info("CONFIG.SAVE-SUCCESS", plugin.toString(), config.name()); - } catch (Exception e) { - TLocale.Logger.warn("CONFIG.SAVE-FAIL", plugin.toString(), config.name()); - e.printStackTrace(); - } - } - } - } - - private static void injectConfig(Plugin plugin, Object o) { - for (Field field : Ref.getDeclaredFields(o.getClass())) { - try { - TConfig config; - if ((config = field.getType().getAnnotation(TConfig.class)) != null) { - field.setAccessible(true); - Object obj = TConfigInjector.loadConfig(plugin, field.getType()); - if (obj != null) { - TLocale.Logger.info("CONFIG.LOAD-SUCCESS", plugin.toString(), config.name()); - field.set(o, obj); - if (config.listenChanges()) { - TLocale.Logger.info("CONFIG.LISTEN-START", plugin.toString(), config.name()); - TLib.getTLib().getConfigWatcher().addOnListen( - new File(plugin.getDataFolder(), config.name()), - obj, - object -> { - try { - TConfigInjector.reloadConfig(plugin, object); - TLocale.Logger.info("CONFIG.RELOAD-SUCCESS", plugin.toString(), config.name()); - } catch (Exception ignored) { - TLocale.Logger.warn("CONFIG.RELOAD-FAIL", plugin.toString(), config.name()); - } - } - ); - } - } - } - } catch (Exception ignored) { - } - } - } - - private static void injectLogger(Plugin plugin, Object o) { - for (Field field : Ref.getDeclaredFields(o.getClass())) { - try { - Logger logger; - if ((logger = field.getAnnotation(Logger.class)) != null) { - field.getType().asSubclass(com.ilummc.tlib.logger.TLogger.class); - com.ilummc.tlib.logger.TLogger tLogger = new com.ilummc.tlib.logger.TLogger(logger.value(), plugin, logger.level()); - if (!field.isAccessible()) { - field.setAccessible(true); - } - field.set(o, tLogger); - TLoggerManager.setDefaultLogger(plugin, tLogger); - } - } catch (Exception ignored2) { - } - } - } - - private static void injectPluginInstance(Plugin plugin, Object o) { - for (Field field : Ref.getDeclaredFields(o.getClass())) { - try { - PluginInstance instance; - if ((instance = field.getAnnotation(PluginInstance.class)) != null) { - if (!field.isAccessible()) { - field.setAccessible(true); - } - field.getType().asSubclass(JavaPlugin.class); - Plugin pl; - if ((pl = Bukkit.getPluginManager().getPlugin(instance.value())) == null) { - if (!TDependency.requestPlugin(instance.value())) { - TLocale.Logger.warn("PLUGIN-AUTOLOAD-FAIL", plugin.getName(), instance.value()); - return; - } else { - pl = Bukkit.getPluginManager().getPlugin(instance.value()); - } - } - if (pl != null) { - field.set(o, pl); - } - } - } catch (Exception ignored) { - } - } - } - - private static void injectDependencies(Plugin plugin, Object o) { - Dependency[] dependencies = getDependencies(o); - if (dependencies.length != 0) { - TLocale.Logger.info("DEPENDENCY.LOADING-START", plugin.getName()); - for (Dependency dependency : dependencies) { - if (dependency.type() == Dependency.Type.PLUGIN) { - if (TDependency.requestPlugin(dependency.plugin())) { - TabooLib.debug(" Loaded " + dependency.plugin() + " (" + plugin.getName() + ")"); -// TLocale.Logger.info("DEPENDENCY.PLUGIN-LOAD-SUCCESS", plugin.getName(), dependency.plugin()); - } else { - TLocale.Logger.warn("DEPENDENCY.PLUGIN-LOAD-FAIL", plugin.getName(), dependency.plugin()); - } - } - if (dependency.type() == Dependency.Type.LIBRARY) { - if (TDependency.requestLib(dependency.maven(), dependency.mavenRepo(), dependency.url())) { - TabooLib.debug(" Loaded " + String.join(":", dependency.maven()) + " (" + plugin.getName() + ")"); -// TLocale.Logger.info("DEPENDENCY.LIBRARY-LOAD-SUCCESS", plugin.getName(), String.join(":", dependency.maven())); - } else { - TLocale.Logger.warn("DEPENDENCY.LIBRARY-LOAD-FAIL", plugin.getName(), String.join(":", dependency.maven())); - } - } - } - TLocale.Logger.info("DEPENDENCY.LOAD-COMPLETE"); - } - } -} diff --git a/src/main/scala/com/ilummc/tlib/inject/TPluginManager.java b/src/main/scala/com/ilummc/tlib/inject/TPluginManager.java deleted file mode 100644 index 31a5849..0000000 --- a/src/main/scala/com/ilummc/tlib/inject/TPluginManager.java +++ /dev/null @@ -1,231 +0,0 @@ -package com.ilummc.tlib.inject; - -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.Main; -import org.bukkit.Bukkit; -import org.bukkit.Server; -import org.bukkit.command.SimpleCommandMap; -import org.bukkit.event.Event; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.permissions.Permissible; -import org.bukkit.permissions.Permission; -import org.bukkit.plugin.*; - -import java.io.File; -import java.lang.reflect.Field; -import java.util.*; -import java.util.regex.Pattern; - -@SuppressWarnings("unused") -public class TPluginManager implements PluginManager { - - private static TPluginManager singleton; - private final PluginManager instance; - private final Main main = (Main) Main.getInst(); - private static File updateDirectory = null; - private Server server; - private Map fileAssociations = new HashMap<>(); - private List plugins = new ArrayList<>(); - private Map lookupNames = new HashMap<>(); - private SimpleCommandMap commandMap; - private Map permissions = new HashMap<>(); - private Map> defaultPerms = new LinkedHashMap<>(); - private Map> permSubs = new HashMap<>(); - private Map> defSubs = new HashMap<>(); - private boolean useTimings = false; - private List delayedDisable = new ArrayList<>(); - - public static void delayDisable(Plugin plugin) { - if (!singleton.delayedDisable.contains(plugin)) { - singleton.delayedDisable.add(plugin); - } - } - - public TPluginManager() { - instance = Bukkit.getPluginManager(); - // clone all Field in SimplePluginManager - cloneField("updateDirectory"); - cloneField("server"); - cloneField("fileAssociations"); - cloneField("plugins"); - cloneField("lookupNames"); - cloneField("commandMap"); - cloneField("permissions"); - cloneField("defaultPerms"); - cloneField("permSubs"); - cloneField("defSubs"); - cloneField("useTimings"); - singleton = this; - } - - private void cloneField(String bukkitName) { - try { - Field bukkitField = instance.getClass().getDeclaredField(bukkitName); - Field thisFiled = this.getClass().getDeclaredField(bukkitName); - if (bukkitField == null || thisFiled == null) { - TLocale.Logger.warn("MISC.FIELD-COPY-FAILED", bukkitName); - return; - } - bukkitField.setAccessible(true); - thisFiled.setAccessible(true); - thisFiled.set(this, bukkitField.get(instance)); - } catch (Exception e) { - TLocale.Logger.error("MISC.FIELD-COPY-ERROR", bukkitName, e.toString()); - } - } - - @Override - public void registerInterface(Class aClass) throws IllegalArgumentException { - instance.registerInterface(aClass); - } - - @Override - public Plugin getPlugin(String s) { - return instance.getPlugin(s); - } - - @Override - public Plugin[] getPlugins() { - return instance.getPlugins(); - } - - @Override - public boolean isPluginEnabled(String s) { - return instance.isPluginEnabled(s); - } - - @Override - public boolean isPluginEnabled(Plugin plugin) { - return instance.isPluginEnabled(plugin); - } - - @Override - public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException { - return instance.loadPlugin(file); - } - - @Override - public Plugin[] loadPlugins(File file) { - return instance.loadPlugins(file); - } - - @Override - public void disablePlugins() { - for (Plugin plugin : getPlugins()) { - if (plugin != main && !delayedDisable.contains(plugin)) { - disablePlugin(plugin); - } - } - Collections.reverse(delayedDisable); - delayedDisable.forEach(singleton::disablePlugin); - disablePlugin(main); - } - - @Override - public void clearPlugins() { - instance.clearPlugins(); - } - - @Override - public void callEvent(Event event) throws IllegalStateException { - instance.callEvent(event); - } - - @Override - public void registerEvents(Listener listener, Plugin plugin) { - instance.registerEvents(listener, plugin); - } - - @Override - public void registerEvent(Class aClass, Listener listener, EventPriority eventPriority, EventExecutor eventExecutor, Plugin plugin) { - instance.registerEvent(aClass, listener, eventPriority, eventExecutor, plugin); - } - - @Override - public void registerEvent(Class aClass, Listener listener, EventPriority eventPriority, EventExecutor eventExecutor, Plugin plugin, boolean b) { - instance.registerEvent(aClass, listener, eventPriority, eventExecutor, plugin, b); - } - - @Override - public void enablePlugin(Plugin plugin) { - TDependencyInjector.injectOnEnable(plugin); - instance.enablePlugin(plugin); - } - - @Override - public void disablePlugin(Plugin plugin) { - TDependencyInjector.ejectOnDisable(plugin); - instance.disablePlugin(plugin); - } - - @Override - public Permission getPermission(String s) { - return instance.getPermission(s); - } - - @Override - public void addPermission(Permission permission) { - instance.addPermission(permission); - } - - @Override - public void removePermission(Permission permission) { - instance.removePermission(permission); - } - - @Override - public void removePermission(String s) { - instance.removePermission(s); - } - - @Override - public Set getDefaultPermissions(boolean b) { - return instance.getDefaultPermissions(b); - } - - @Override - public void recalculatePermissionDefaults(Permission permission) { - instance.recalculatePermissionDefaults(permission); - } - - @Override - public void subscribeToPermission(String s, Permissible permissible) { - instance.subscribeToPermission(s, permissible); - } - - @Override - public void unsubscribeFromPermission(String s, Permissible permissible) { - instance.unsubscribeFromPermission(s, permissible); - } - - @Override - public Set getPermissionSubscriptions(String s) { - return instance.getPermissionSubscriptions(s); - } - - @Override - public void subscribeToDefaultPerms(boolean b, Permissible permissible) { - instance.subscribeToDefaultPerms(b, permissible); - } - - @Override - public void unsubscribeFromDefaultPerms(boolean b, Permissible permissible) { - instance.unsubscribeFromDefaultPerms(b, permissible); - } - - @Override - public Set getDefaultPermSubscriptions(boolean b) { - return instance.getDefaultPermSubscriptions(b); - } - - @Override - public Set getPermissions() { - return instance.getPermissions(); - } - - @Override - public boolean useTimings() { - return instance.useTimings(); - } -} diff --git a/src/main/scala/com/ilummc/tlib/nms/ActionBar.java b/src/main/scala/com/ilummc/tlib/nms/ActionBar.java deleted file mode 100644 index 46e3edc..0000000 --- a/src/main/scala/com/ilummc/tlib/nms/ActionBar.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.ilummc.tlib.nms; - -import com.ilummc.tlib.util.asm.AsmClassTransformer; -import me.skymc.taboolib.TabooLib; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -public abstract class ActionBar { - - private static ActionBar instance; - - static { - if (TabooLib.getVerint() > 11100) { - instance = (ActionBar) AsmClassTransformer.builder().from(Impl_1_12.class).fromVersion("v1_12_R1") - .toVersion(Bukkit.getServer().getClass().getName().split("\\.")[3]).build().transform(); - } else { - instance = (ActionBar) AsmClassTransformer.builder().from(Impl_1_8.class).fromVersion("v1_8_R3") - .toVersion(Bukkit.getServer().getClass().getName().split("\\.")[3]).build().transform(); - } - } - - public static void sendActionBar(Player player, String text) { - instance.send(player, text); - } - - public abstract void send(Player player, String text); - - public static class Impl_1_8 extends ActionBar { - - @Override - public void send(Player player, String text) { - net.minecraft.server.v1_8_R3.ChatComponentText component = new net.minecraft.server.v1_8_R3.ChatComponentText(text); - net.minecraft.server.v1_8_R3.PacketPlayOutChat packet = new net.minecraft.server.v1_8_R3.PacketPlayOutChat(component, (byte) 2); - ((org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } - } - - public static class Impl_1_12 extends ActionBar { - - @Override - public void send(Player player, String text) { - net.minecraft.server.v1_12_R1.ChatComponentText component = new net.minecraft.server.v1_12_R1.ChatComponentText(text); - net.minecraft.server.v1_12_R1.PacketPlayOutChat packet = new net.minecraft.server.v1_12_R1.PacketPlayOutChat(component, net.minecraft.server.v1_12_R1.ChatMessageType.a((byte) 2)); - ((org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); - } - } -} diff --git a/src/main/scala/com/ilummc/tlib/resources/TLocaleLoader.java b/src/main/scala/com/ilummc/tlib/resources/TLocaleLoader.java deleted file mode 100644 index 98f9a99..0000000 --- a/src/main/scala/com/ilummc/tlib/resources/TLocaleLoader.java +++ /dev/null @@ -1,169 +0,0 @@ -package com.ilummc.tlib.resources; - -import com.ilummc.tlib.TLib; -import com.ilummc.tlib.annotations.TLocalePlugin; -import com.ilummc.tlib.logger.TLogger; -import com.ilummc.tlib.resources.type.*; -import com.ilummc.tlib.util.IO; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboocode.TabooCodeLang; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.fileutils.ConfigUtils; -import me.skymc.taboolib.fileutils.FileUtils; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.configuration.serialization.ConfigurationSerialization; -import org.bukkit.plugin.Plugin; - -import java.io.File; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -public class TLocaleLoader { - - private static final Map map = new ConcurrentHashMap<>(); - - public static void init() { - ConfigurationSerialization.registerClass(TLocaleText.class, "TEXT"); - ConfigurationSerialization.registerClass(TLocaleJson.class, "JSON"); - ConfigurationSerialization.registerClass(TLocaleBook.class, "BOOK"); - ConfigurationSerialization.registerClass(TLocaleSound.class, "SOUND"); - ConfigurationSerialization.registerClass(TLocaleTitle.class, "TITLE"); - ConfigurationSerialization.registerClass(TLocaleBossBar.class, "BAR"); - ConfigurationSerialization.registerClass(TLocaleActionBar.class, "ACTION"); - } - - public static void sendTo(Plugin plugin, String path, CommandSender sender, String... args) { - TabooLib.debug(plugin, "TLocaleLoader.sendTo: " + plugin + ", path: " + path + ", sender: " + sender + ", args: " + Arrays.asList(args)); - if (Bukkit.isPrimaryThread()) { - Optional.ofNullable(map.get(plugin.getName())).ifPresent(localeInstance -> localeInstance.sendTo(path, sender, args)); - } else { - synchronized (TLocaleLoader.class) { - Optional.ofNullable(map.get(plugin.getName())).ifPresent(localeInstance -> localeInstance.sendTo(path, sender, args)); - } - } - } - - public static String asString(Plugin plugin, String path, String... args) { - TabooLib.debug(plugin, "TLocaleLoader.asString: " + plugin.getName() + ", path: " + path + ", args: " + Arrays.asList(args)); - TLocaleInstance tLocaleInstance = map.get(plugin.getName()); - if (tLocaleInstance != null) { - return tLocaleInstance.asString(path, args); - } else { - return ""; - } - } - - public static List asStringList(Plugin plugin, String path, String... args) { - TabooLib.debug(plugin, "TLocaleLoader.asStringList: " + plugin + ", path: " + path + ", args: " + Arrays.asList(args)); - TLocaleInstance tLocaleInstance = map.get(plugin.getName()); - if (tLocaleInstance != null) { - return tLocaleInstance.asStringList(path, args); - } else { - return Collections.emptyList(); - } - } - - /** - * 载入语言文件 - * - * @param plugin 载入插件 - * @param isCover 是否覆盖 - */ - public static void load(Plugin plugin, boolean isCover) { - try { - if (isLoadLocale(plugin, isCover)) { - // 获取文件 - File localeFile = getLocaleFile(plugin); - if (localeFile == null) { - return; - } - - // 加载文件 - infoLogger("TRY-LOADING-LANG", plugin.getName(), localeFile.getName()); - YamlConfiguration localeConfiguration = ConfigUtils.loadYaml(plugin, localeFile); - YamlConfiguration localeConfigurationAtStream = getLocaleAtStream(plugin, localeFile); - - // 载入配置 - loadPluginLocale(plugin, localeFile, localeConfiguration, localeConfigurationAtStream); - - // 注册监听 - TLib.getTLib().getConfigWatcher().removeListener(localeFile); - TLib.getTLib().getConfigWatcher().addListener(localeFile, null, obj -> { - infoLogger("RELOADING-LANG", plugin.getName()); - loadPluginLocale(plugin, localeFile, ConfigUtils.loadYaml(plugin, localeFile), getLocaleAtStream(plugin, localeFile)); - }); - } - } catch (Exception e) { - errorLogger("ERROR-LOADING-LANG", plugin.getName(), e.toString() + "\n" + e.getStackTrace()[0].toString()); - } - } - - public static boolean isLocaleLoaded(Plugin plugin) { - return map.containsKey(plugin.getName()); - } - - public static boolean isDependWithTabooLib(Plugin plugin) { - return plugin.getClass().getAnnotation(TLocalePlugin.class) != null || plugin.getDescription().getDepend().contains(Main.getInst().getName()) || plugin.getDescription().getSoftDepend().contains(Main.getInst().getName()); - } - - public static List getLocalePriority() { - return Main.getInst().getConfig().contains("LOCALE.PRIORITY") ? Main.getInst().getConfig().getStringList("LOCALE.PRIORITY") : Collections.singletonList("zh_CN"); - } - - private static boolean isLoadLocale(Plugin plugin, boolean isCover) { - return (isCover || !isLocaleLoaded(plugin)) && (plugin.equals(Main.getInst()) || isDependWithTabooLib(plugin)); - } - - private static void infoLogger(String path, String... args) { - TLogger.getGlobalLogger().info(Strings.replaceWithOrder(TLib.getInternalLanguage().getString(path), args)); - } - - private static void errorLogger(String path, String... args) { - TLogger.getGlobalLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString(path), args)); - } - - private static File getLocaleFile(Plugin plugin) { - releaseLocales(plugin); - return getLocalePriority().stream().map(localeName -> new File(plugin.getDataFolder(), "lang/" + localeName + ".yml")).filter(File::exists).findFirst().orElse(null); - } - - private static void releaseLocales(Plugin plugin) { - getLocalePriority().stream().filter(localeName -> !new File(plugin.getDataFolder(), "lang/" + localeName + ".yml").exists() && plugin.getResource("lang/" + localeName + ".yml") != null).forEach(localeName -> plugin.saveResource("lang/" + localeName + ".yml", true)); - } - - private static TLocaleInstance getLocaleInstance(Plugin plugin) { - TLocaleInstance instance = new TLocaleInstance(plugin); - map.put(plugin.getName(), instance); - return instance; - } - - private static YamlConfiguration getLocaleAtStream(Plugin plugin, File localeFile) { - InputStream localeInputSteam = FileUtils.getResource(plugin, "lang/" + localeFile.getName()); - try { - String yamlText = new String(IO.readFully(localeInputSteam), Charset.forName("utf-8")); - YamlConfiguration yaml = new YamlConfiguration(); - yaml.loadFromString(yamlText); - return yaml; - } catch (Exception ignored) { - return null; - } - } - - private static void loadPluginLocale(Plugin plugin, File localeFile, YamlConfiguration localeConfiguration, YamlConfiguration localeConfigurationAtStream) { - TLocaleInstance localeInstance = getLocaleInstance(plugin); - if (localeConfigurationAtStream != null) { - localeInstance.load(localeConfigurationAtStream); - } - localeInstance.load(localeConfiguration); - if (localeInstance.getLatestUpdateNodes().get() <= 0) { - infoLogger("SUCCESS-LOADING-LANG-NORMAL", plugin.getName(), localeFile.getName().split("\\.")[0], String.valueOf(localeInstance.size())); - } else { - infoLogger("SUCCESS-LOADING-LANG-UPDATE", plugin.getName(), localeFile.getName().split("\\.")[0], String.valueOf(localeInstance.size()), String.valueOf(localeInstance.getLatestUpdateNodes().get())); - } - } -} diff --git a/src/main/scala/com/ilummc/tlib/resources/TLocaleSender.java b/src/main/scala/com/ilummc/tlib/resources/TLocaleSender.java deleted file mode 100644 index 6d75fd4..0000000 --- a/src/main/scala/com/ilummc/tlib/resources/TLocaleSender.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ilummc.tlib.resources; - -import org.bukkit.command.CommandSender; - -import java.util.List; - -/** - * @Author sky - * @Since 2018-05-12 13:58 - */ -public interface TLocaleSender { - - /** - * 发送信息 - * - * @param sender 发送目标 - * @param args 参数 - */ - void sendTo(CommandSender sender, String... args); - - /** - * 获取文本 - * - * @param args 参数 - * @return 文本 - */ - String asString(String... args); - - /** - * 获取文本集合 - * - * @param args 参数 - * @return 文本集合 - */ - List asStringList(String... args); - -} diff --git a/src/main/scala/com/ilummc/tlib/util/IO.java b/src/main/scala/com/ilummc/tlib/util/IO.java deleted file mode 100644 index 92d4d16..0000000 --- a/src/main/scala/com/ilummc/tlib/util/IO.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.ilummc.tlib.util; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; - -public class IO { - - public static byte[] readFully(InputStream inputStream) throws IOException { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - byte[] buf = new byte[1024]; - int len = 0; - while ((len = inputStream.read(buf)) > 0) { - stream.write(buf, 0, len); - } - return stream.toByteArray(); - } -} diff --git a/src/main/scala/com/ilummc/tlib/util/Strings.java b/src/main/scala/com/ilummc/tlib/util/Strings.java deleted file mode 100644 index 40207d0..0000000 --- a/src/main/scala/com/ilummc/tlib/util/Strings.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.ilummc.tlib.util; - -public class Strings { - - public static boolean isBlank(String var) { - return var == null || var.trim().isEmpty(); - } - - public static boolean isEmpty(CharSequence var) { - return var == null || var.length() == 0; - } - - /** - * 优化过的 String#replace,比默认快了大概 5 倍 - * - * @param template 模板替换文件 - * @param args 替换的参数 - * @return 替换好的字符串 - */ - public static String replaceWithOrder(String template, Object... args) { - if (args.length == 0 || template.length() == 0) { - return template; - } - char[] arr = template.toCharArray(); - StringBuilder stringBuilder = new StringBuilder(template.length()); - for (int i = 0; i < arr.length; i++) { - if (arr[i] == '{' && Character.isDigit(arr[Math.min(i + 1, arr.length - 1)]) - && arr[Math.min(i + 1, arr.length - 1)] - '0' < args.length - && arr[Math.min(i + 2, arr.length - 1)] == '}') { - stringBuilder.append(args[arr[i + 1] - '0']); - i += 2; - } else { - stringBuilder.append(arr[i]); - } - } - return stringBuilder.toString(); - } - - // ********************************* - // - // Deprecated - // - // ********************************* - - public static String replaceWithOrder(String template, String... args) { - return replaceWithOrder(template, (Object[]) args); - } -} diff --git a/src/main/scala/com/ilummc/tlibscala/runtime/RichOfflinePlayer.scala b/src/main/scala/com/ilummc/tlibscala/runtime/RichOfflinePlayer.scala deleted file mode 100644 index fa3d7f1..0000000 --- a/src/main/scala/com/ilummc/tlibscala/runtime/RichOfflinePlayer.scala +++ /dev/null @@ -1,30 +0,0 @@ -package com.ilummc.tlibscala.runtime - -import me.skymc.taboolib.Main -import me.skymc.taboolib.economy.EcoUtils -import me.skymc.taboolib.inventory.builder.ItemBuilder -import org.bukkit.OfflinePlayer -import org.bukkit.inventory.ItemStack - -class RichOfflinePlayer(private val offlinePlayer: OfflinePlayer) { - - def getSkullItem: ItemStack = new ItemBuilder(offlinePlayer).build() - - def getMoney: Double = EcoUtils.get(offlinePlayer) - - def withdraw(x: Double): Boolean = Main.getEconomy.withdrawPlayer(offlinePlayer, x).transactionSuccess - - def deposit(x: Double): Boolean = Main.getEconomy.depositPlayer(offlinePlayer, x).transactionSuccess - - def hasMoney(x: Double): Boolean = Main.getEconomy.has(offlinePlayer, x) - -} - - -object RichOfflinePlayer { - - implicit def player2rich(player: OfflinePlayer): RichOfflinePlayer = new RichOfflinePlayer(player) - - implicit def rich2player(player: RichOfflinePlayer): OfflinePlayer = player.offlinePlayer - -} \ No newline at end of file diff --git a/src/main/scala/com/ilummc/tlibscala/runtime/RichPlayer.scala b/src/main/scala/com/ilummc/tlibscala/runtime/RichPlayer.scala deleted file mode 100644 index 448a8b7..0000000 --- a/src/main/scala/com/ilummc/tlibscala/runtime/RichPlayer.scala +++ /dev/null @@ -1,68 +0,0 @@ -package com.ilummc.tlibscala.runtime - -import com.ilummc.tlib.resources.TLocale -import me.skymc.taboolib.anvil.AnvilContainerAPI -import me.skymc.taboolib.display.{ActionUtils, TitleUtils} -import me.skymc.taboolib.permission.PermissionUtils -import me.skymc.taboolib.player.PlayerUtils -import me.skymc.taboolib.scoreboard.ScoreboardUtil -import me.skymc.taboolib.sign.SignUtils -import org.bukkit.block.Block -import org.bukkit.entity.Player - -import scala.collection.JavaConverters._ - -class RichPlayer(private val player: Player) extends RichOfflinePlayer(player) { - - def sendActionBar(x: String): Unit = ActionUtils.send(player, x) - - def getFishTicks: Int = PlayerUtils.getFishingTicks(PlayerUtils.getPlayerHookedFish(player)) - - def setFishTicks(x: Int): Unit = PlayerUtils.setFishingTicks(PlayerUtils.getPlayerHookedFish(player), x) - - def resetData(): Unit = PlayerUtils.resetData(player, false) - - def resetData(scoreboard: Boolean): Unit = PlayerUtils.resetData(player, scoreboard) - - def displaySidebar(title: String, elements: Map[String, Integer]): Unit = ScoreboardUtil.rankedSidebarDisplay(player, title, mapAsJavaMap(elements)) - - def displaySidebarUnranked(title: String, elements: Array[String]): Unit = ScoreboardUtil.unrankedSidebarDisplay(player, elements: _*) - - def displaySidebarUnranked(title: String, elements: List[String]): Unit = ScoreboardUtil.unrankedSidebarDisplay(player, elements: _*) - - def displaySidebarUnranked(title: String, elements: String*): Unit = ScoreboardUtil.unrankedSidebarDisplay(player, elements: _*) - - def openSign(block: Block): Unit = SignUtils.openSign(player, block) - - def openSign(lines: Array[String], id: String): Unit = SignUtils.openSign(player, lines, id) - - //todo TagDataHandler - - def addPermission(perm: String): Unit = PermissionUtils.addPermission(player, perm) - - def removePermission(perm: String): Unit = PermissionUtils.removePermission(player, perm) - - def sendTitle(title: String, subtitle: String, fadein: Int, stay: Int, fadeout: Int): Unit = TitleUtils.sendTitle(player, title, subtitle, fadein, stay, fadeout) - - def sendTitle(p: Player, title: String, fadeint: Int, stayt: Int, fadeoutt: Int, subtitle: String, fadeinst: Int, stayst: Int, fadeoutst: Int): Unit = TitleUtils.sendTitle(p, title, fadeint, stayt, fadeoutt, subtitle, fadeinst, stayst, fadeoutst) - - def openAnvil(): Unit = AnvilContainerAPI.openAnvil(player) - - def sendLocalizedMessage(node: String, params: String*): Unit = TLocale.sendTo(player, node, params: _*) - - def locale(node: String, params: String*): Unit = sendLocalizedMessage(node, params: _*) - - def <<(text: String): RichPlayer = { - player.sendMessage(text) - this - } - -} - -object RichPlayer { - - implicit def player2rich(player: Player): RichPlayer = new RichPlayer(player) - - implicit def rich2player(player: RichPlayer): Player = player.player - -} diff --git a/src/main/scala/me/skymc/taboolib/bstats/Metrics.java b/src/main/scala/io/izzel/taboolib/Metrics.java similarity index 97% rename from src/main/scala/me/skymc/taboolib/bstats/Metrics.java rename to src/main/scala/io/izzel/taboolib/Metrics.java index 89db7bf..89d46af 100644 --- a/src/main/scala/me/skymc/taboolib/bstats/Metrics.java +++ b/src/main/scala/io/izzel/taboolib/Metrics.java @@ -1,11 +1,11 @@ -package me.skymc.taboolib.bstats; +package io.izzel.taboolib; import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.ServicePriority; -import org.bukkit.plugin.java.JavaPlugin; import org.json.simple.JSONArray; import org.json.simple.JSONObject; @@ -55,7 +55,7 @@ public class Metrics { } // The plugin - private final JavaPlugin plugin; + private final Plugin plugin; // A list with all custom charts private final List charts = new ArrayList<>(); @@ -65,7 +65,7 @@ public class Metrics { * * @param plugin The plugin which stats should be submitted. */ - public Metrics(JavaPlugin plugin) { + public Metrics(Plugin plugin) { if (plugin == null) { throw new IllegalArgumentException("Plugin cannot be null!"); } @@ -78,27 +78,17 @@ public class Metrics { // Check if the config file exists if (!config.isSet("serverUuid")) { - // Add default values config.addDefault("enabled", true); // Every server gets it's unique random id. config.addDefault("serverUuid", UUID.randomUUID().toString()); // Should failed request be logged? config.addDefault("logFailedRequests", false); - - // Inform the server owners about bStats - config.options().header( - "bStats collects some data for plugin authors like how many servers are using their plugins.\n" + - "To honor their work, you should not disable it.\n" + - "This has nearly no effect on the server performance!\n" + - "Check out https://bStats.org/ to learn more :)" - ).copyDefaults(true); try { config.save(configFile); } catch (IOException ignored) { } } - // Load the data serverUUID = config.getString("serverUuid"); logFailedRequests = config.getBoolean("logFailedRequests", false); diff --git a/src/main/scala/io/izzel/taboolib/PluginLoader.java b/src/main/scala/io/izzel/taboolib/PluginLoader.java new file mode 100644 index 0000000..2d997c2 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/PluginLoader.java @@ -0,0 +1,109 @@ +package io.izzel.taboolib; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import io.izzel.taboolib.locale.TLocaleLoader; +import io.izzel.taboolib.module.command.TCommandHandler; +import io.izzel.taboolib.module.config.TConfig; +import io.izzel.taboolib.module.config.TConfigWatcher; +import io.izzel.taboolib.module.dependency.TDependencyInjector; +import io.izzel.taboolib.module.inject.TListenerHandler; +import io.izzel.taboolib.module.mysql.IHost; +import io.izzel.taboolib.module.mysql.hikari.HikariHandler; +import io.izzel.taboolib.origin.database.PluginDataManager; +import org.bukkit.plugin.Plugin; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * @Author 坏黑 + * @Since 2019-07-05 15:14 + */ +public abstract class PluginLoader { + + private static List registerLoader = Lists.newArrayList(); + private static Set plugins = Sets.newHashSet(); + + static { + registerLoader.add(new PluginLoader() { + + @Override + public void onLoading(Plugin plugin) { + // 加载语言文件 + TLocaleLoader.load(plugin, false); + // 注入依赖 + TDependencyInjector.inject(plugin, plugin.getClass()); + // 读取插件类 + TabooLibLoader.setupClasses(plugin); + // 加载插件类 + TabooLibLoader.getPluginClassSafely(plugin).forEach(c -> TabooLibLoader.preLoadClass(plugin, c)); + } + + @Override + public void onStarting(Plugin plugin) { + // 加载监听器 + TListenerHandler.setupListener(plugin); + // 加载插件类 + TabooLibLoader.getPluginClassSafely(plugin).forEach(c -> TabooLibLoader.postLoadClass(plugin, c)); + // 注册插件命令 + TCommandHandler.registerCommand(plugin); + } + + @Override + public void onActivated(Plugin plugin) { + // 注册监听器 + TListenerHandler.registerListener(plugin); + } + + @Override + public void onStopping(Plugin plugin) { + // 注销监听器 + TListenerHandler.cancelListener(plugin); + // 储存插件数据 + PluginDataManager.saveAllCaches(plugin, true); + // 注销数据库连接 + Sets.newHashSet(HikariHandler.getDataSource().keySet()).stream().filter(IHost::isAutoClose).forEach(HikariHandler::closeDataSource); + // 释放文检动态读取 + Optional.ofNullable(TConfig.getFiles().remove(plugin.getName())).ifPresent(files -> files.forEach(file -> TConfigWatcher.getInst().removeListener(file))); + } + }); + } + + public void onLoading(Plugin plugin) { + } + + public void onStarting(Plugin plugin) { + } + + public void onActivated(Plugin plugin) { + } + + public void onStopping(Plugin plugin) { + } + + public static void addPlugin(Plugin plugin) { + plugins.add(plugin.getName()); + } + + public static void load(Plugin plugin) { + registerLoader.forEach(loader -> loader.onLoading(plugin)); + } + + public static void start(Plugin plugin) { + registerLoader.forEach(loader -> loader.onStarting(plugin)); + } + + public static void active(Plugin plugin) { + registerLoader.forEach(loader -> loader.onActivated(plugin)); + } + + public static void stop(Plugin plugin) { + registerLoader.forEach(loader -> loader.onStopping(plugin)); + } + + public static boolean isPlugin(Plugin plugin) { + return plugins.contains(plugin.getName()); + } +} diff --git a/src/main/scala/io/izzel/taboolib/TabooLib.java b/src/main/scala/io/izzel/taboolib/TabooLib.java new file mode 100644 index 0000000..e02c10b --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/TabooLib.java @@ -0,0 +1,137 @@ +package io.izzel.taboolib; + +import io.izzel.taboolib.locale.TLocaleLoader; +import io.izzel.taboolib.module.config.TConfig; +import io.izzel.taboolib.module.config.TConfigWatcher; +import io.izzel.taboolib.module.dependency.Dependency; +import io.izzel.taboolib.module.logger.TLogger; +import io.izzel.taboolib.module.mysql.hikari.HikariHandler; +import io.izzel.taboolib.module.nms.NMSHandler; +import io.izzel.taboolib.origin.database.PlayerDataManager; +import io.izzel.taboolib.origin.database.PluginDataManager; +import io.izzel.taboolib.plugin.InternalPlugin; +import io.izzel.taboolib.util.Files; +import io.izzel.taboolib.util.IO; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.util.NumberConversions; + +import java.io.File; +import java.nio.charset.Charset; +import java.util.concurrent.Executors; + +/** + * @Author 坏黑 + * @Since 2019-07-05 10:39 + *

+ * 注意与 TabooLib4.x 版本的兼容 + * 可能存在同时运行的情况 + */ +@Dependency(type = Dependency.Type.LIBRARY, maven = "org.slf4j:slf4j-api:1.7.25", url = "https://skymc.oss-cn-shanghai.aliyuncs.com/libs/org.slf4j-slf4j-api-1.7.25.jar") +@Dependency(type = Dependency.Type.LIBRARY, maven = "com.zaxxer:HikariCP:3.1.0", url = "https://skymc.oss-cn-shanghai.aliyuncs.com/libs/com.zaxxer-HikariCP-3.1.0.jar") +@Dependency(type = Dependency.Type.LIBRARY, maven = "org.scala-lang:scala-library:2.12.8", url = "https://skymc.oss-cn-shanghai.aliyuncs.com/libs/scala-library-2.12.8.jar") +public class TabooLib { + + private static TabooLib inst = new TabooLib(); + private static TLogger logger; + private static TConfig config; + private static double version; + + // 第三方依赖下载位置 + private File libsFolder; + private File playerDataFolder; + private File serverDataFolder; + + // 内部语言文件 + private YamlConfiguration internal = new YamlConfiguration(); + + public TabooLib() { + // 创建配置 + inst = this; + logger = TLogger.getUnformatted("TabooLib"); + config = TConfig.create(getPlugin(), "config.yml"); + libsFolder = Files.folder("plugins/TabooLib/libs"); + playerDataFolder = Files.folder(config.getString("DATAURL.PLAYER-DATA")); + serverDataFolder = Files.folder(config.getString("DATAURL.SERVER-DATA")); + // 加载版本号 + try { + version = NumberConversions.toDouble(IO.readFully(Files.getResource("version"), Charset.forName("utf-8"))); + } catch (Throwable t) { + t.printStackTrace(); + } + // 加载内部语言文件 + try { + internal.loadFromString(IO.readFully(Files.getResource("lang/internal.yml"), Charset.forName("utf-8"))); + } catch (Throwable t) { + t.printStackTrace(); + } + // 加载 TabooLib 语言文件 + TLocaleLoader.load(getPlugin(), false); + // 加载 TabooLib + TabooLibLoader.init(); + // 创建 TabooLib 插件数据 + PluginDataManager.addPluginData("TabooLib", null); + PluginDataManager.addPluginData("TabooLibrary", null); + // 创建线程检测服务器是否关闭 + Executors.newSingleThreadExecutor().submit(() -> { + while (NMSHandler.getHandler().isRunning()) { + } + // 关闭连接池 + HikariHandler.closeDataSourceForce(); + // 保存数据 + PlayerDataManager.saveAllPlayers(false, true); + PluginDataManager.saveAllCaches(); + // 插件关闭 + PluginLoader.stop(getPlugin()); + // 清理数据 + if (config.getBoolean("DELETE-DATA")) { + Files.deepDelete(getPlayerDataFolder()); + } + }); + } + + public void cancel() { + TConfigWatcher.getInst().unregisterAll(); + } + + public static InternalPlugin getPlugin() { + return InternalPlugin.getPlugin(); + } + + // ********************************* + // + // Getter and Setter + // + // ********************************* + + public static TabooLib getInst() { + return inst; + } + + public static TLogger getLogger() { + return logger; + } + + public static TConfig getConfig() { + return config; + } + + public static double getVersion() { + return version; + } + + public File getLibsFolder() { + return libsFolder; + } + + public File getPlayerDataFolder() { + return playerDataFolder; + } + + public File getServerDataFolder() { + return serverDataFolder; + } + + public YamlConfiguration getInternal() { + return internal; + } +} diff --git a/src/main/scala/io/izzel/taboolib/TabooLibAPI.java b/src/main/scala/io/izzel/taboolib/TabooLibAPI.java new file mode 100644 index 0000000..3b17d32 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/TabooLibAPI.java @@ -0,0 +1,91 @@ +package io.izzel.taboolib; + +import io.izzel.taboolib.module.nms.NMSHandler; +import io.izzel.taboolib.origin.database.PluginDataManager; +import io.izzel.taboolib.util.Strings; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.server.ServerCommandEvent; +import org.bukkit.plugin.Plugin; + +/** + * @Author 坏黑 + * @Since 2019-07-05 14:31 + */ +public class TabooLibAPI { + + private static boolean bukkit; + private static boolean originLoaded; + + static { + try { + // 判断是否基于 Bukkit 运行 + bukkit = Class.forName("org.bukkit.Bukkit") != null; + // 获取 TabooLib4.x 版本是否载入 + originLoaded = Bukkit.getPluginManager().getPlugin("TabooLib") != null; + } catch (Exception ignored) { + } + } + + public static boolean isBukkit() { + return bukkit; + } + + public static boolean isOriginLoaded() { + return originLoaded; + } + + public static boolean isDependTabooLib(Plugin plugin) { + return PluginLoader.isPlugin(plugin); + } + + public static double[] getTPS() { + return NMSHandler.getHandler().getTPS(); + } + + public static boolean isDebug() { + return PluginDataManager.getPluginData("TabooLibrary", TabooLib.getPlugin()).getBoolean("debug"); + } + + public static void setDebug(boolean debug) { + PluginDataManager.getPluginData("TabooLibrary", TabooLib.getPlugin()).set("debug", debug); + } + + public static void debug(String... args) { + debug(TabooLib.getPlugin(), args); + } + + public static void debug(Plugin plugin, String... args) { + if (!isDebug()) { + return; + } + for (String line : args) { + Bukkit.getConsoleSender().sendMessage("§4[" + plugin.getName() + "][DEBUG] §c" + line); + } + } + + public static boolean dispatchCommand(CommandSender sender, String command) { + try { + if ((sender instanceof Player)) { + PlayerCommandPreprocessEvent e = new PlayerCommandPreprocessEvent((Player) sender, "/" + command); + Bukkit.getPluginManager().callEvent(e); + if (e.isCancelled() || Strings.isBlank(e.getMessage()) || !e.getMessage().startsWith("/")) { + return false; + } + return Bukkit.dispatchCommand(e.getPlayer(), e.getMessage().substring(1)); + } else { + ServerCommandEvent e = new ServerCommandEvent(sender, command); + Bukkit.getPluginManager().callEvent(e); + if (e.isCancelled() || Strings.isBlank(e.getCommand())) { + return false; + } + return Bukkit.dispatchCommand(e.getSender(), e.getCommand()); + } + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } +} diff --git a/src/main/scala/io/izzel/taboolib/TabooLibLoader.java b/src/main/scala/io/izzel/taboolib/TabooLibLoader.java new file mode 100644 index 0000000..322821e --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/TabooLibLoader.java @@ -0,0 +1,159 @@ +package io.izzel.taboolib; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import io.izzel.taboolib.module.dependency.TDependencyInjector; +import io.izzel.taboolib.module.inject.TSchedule; +import io.izzel.taboolib.origin.client.TabooLibClient; +import io.izzel.taboolib.origin.client.TabooLibServer; +import io.izzel.taboolib.origin.database.PlayerDataManager; +import io.izzel.taboolib.origin.database.PluginDataManager; +import io.izzel.taboolib.util.Files; +import io.izzel.taboolib.util.Reflection; +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @Author 坏黑 + * @Since 2019-07-05 15:30 + */ +public class TabooLibLoader { + + static Map> pluginClasses = Maps.newHashMap(); + static List loaders = Lists.newArrayList(); + + @TSchedule(period = 20 * 60, async = true) + static void save() { + PluginDataManager.saveAllCaches(); + PlayerDataManager.saveAllCaches(true, false); + } + + @TSchedule + static void start() { + PluginLoader.active(TabooLib.getPlugin()); + // 通讯网络服务器 + if (TabooLib.getConfig().getBoolean("SERVER")) { + TabooLibServer.main(new String[0]); + } + // 通讯网络客户端 + TabooLibClient.init(); + } + + static void init() { + // 加载依赖 + TDependencyInjector.inject("TabooLib", TabooLib.class); + // 插件统计 + Metrics metrics = new Metrics(TabooLib.getPlugin()); + metrics.addCustomChart(new Metrics.SingleLineChart("plugins_using_taboolib", () -> Math.toIntExact(Arrays.stream(Bukkit.getPluginManager().getPlugins()).filter(TabooLibAPI::isDependTabooLib).count()))); + // 读取插件类 + setupClasses(TabooLib.getPlugin()); + // 读取加载器 + pluginClasses.get("TabooLib").stream().filter(TabooLibLoader::isLoader).forEach(pluginClass -> { + try { + loaders.add((Loader) Reflection.instantiateObject(pluginClass)); + } catch (Exception e) { + e.printStackTrace(); + } + loaders.sort(Comparator.comparingInt(Loader::priority)); + }); + // 加载插件 + PluginLoader.load(TabooLib.getPlugin()); + PluginLoader.start(TabooLib.getPlugin()); + } + + public static Optional> getPluginClasses(Plugin plugin) { + return Optional.ofNullable(pluginClasses.get(plugin.getName())); + } + + public static List getPluginClassSafely(Plugin plugin) { + List classes = pluginClasses.get(plugin.getName()); + return classes == null ? new ArrayList<>() : new ArrayList<>(classes); + } + + static boolean isLoader(Class pluginClass) { + return !Loader.class.equals(pluginClass) && Loader.class.isAssignableFrom(pluginClass); + } + + static void setupClasses(Plugin plugin) { + try { + long time = System.currentTimeMillis(); + List classes; + IgnoreClasses annotation = plugin.getClass().getAnnotation(IgnoreClasses.class); + if (annotation != null) { + classes = Files.getClasses(plugin, annotation.value()); + } else { + classes = Files.getClasses(plugin); + } + if (plugin.getName().equals("TabooLib")) { + classes = classes.stream().filter(c -> c.getName().startsWith("io.izzel")).collect(Collectors.toList()); + } + TabooLibAPI.debug("Saved " + classes.size() + " classes (" + plugin.getName() + ") (" + (System.currentTimeMillis() - time) + "ms)"); + pluginClasses.put(plugin.getName(), classes); + } catch (Exception ignored) { + } + } + + static void preLoadClass(Plugin plugin, Class loadClass) { + loaders.forEach(loader -> { + try { + loader.preLoad(plugin, loadClass); + } catch (NoClassDefFoundError ignore) { + } catch (Throwable e) { + e.printStackTrace(); + } + }); + } + + static void postLoadClass(Plugin plugin, Class loadClass) { + loaders.forEach(loader -> { + try { + loader.postLoad(plugin, loadClass); + } catch (NoClassDefFoundError ignore) { + } catch (Throwable e) { + e.printStackTrace(); + } + }); + } + + static void unloadClass(Plugin plugin, Class loadClass) { + loaders.forEach(loader -> { + try { + loader.unload(plugin, loadClass); + } catch (NoClassDefFoundError ignore) { + } catch (Throwable e) { + e.printStackTrace(); + } + }); + } + + public interface Loader { + + default void preLoad(org.bukkit.plugin.Plugin plugin, Class loadClass) { + } + + default void postLoad(org.bukkit.plugin.Plugin plugin, Class loadClass) { + } + + default void unload(Plugin plugin, Class cancelClass) { + } + + default int priority() { + return 0; + } + } + + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + public @interface IgnoreClasses { + + String[] value(); + + } +} diff --git a/src/main/scala/io/izzel/taboolib/Version.java b/src/main/scala/io/izzel/taboolib/Version.java new file mode 100644 index 0000000..38d0fee --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/Version.java @@ -0,0 +1,57 @@ +package io.izzel.taboolib; + +import org.bukkit.Bukkit; + +/** + * @Author 坏黑 + * @Since 2019-07-05 14:42 + */ +public enum Version { + + v1_7(10700), v1_8(10800), v1_9(10900), v1_10(11000), v1_11(11100), v1_12(11200), v1_13(11300), v1_14(11400), vNull(0); + + private int versionInt; + + Version(int versionInt) { + this.versionInt = versionInt; + } + + public int getVersionInt() { + return versionInt; + } + + public static boolean isAfter(Version in) { + return getCurrentVersion().getVersionInt() >= in.getVersionInt(); + } + + public static boolean isBefore(Version in) { + return getCurrentVersion().getVersionInt() < in.getVersionInt(); + } + + public static String getBukkitVersion() { + return Bukkit.getServer().getClass().getName().split("\\.")[3]; + } + + public static Version getCurrentVersion() { + String nmsVersion = getBukkitVersion(); + if (nmsVersion.startsWith("v1_7")) { + return v1_7; + } else if (nmsVersion.startsWith("v1_8")) { + return v1_8; + } else if (nmsVersion.startsWith("v1_9")) { + return v1_9; + } else if (nmsVersion.startsWith("v1_10")) { + return v1_10; + } else if (nmsVersion.startsWith("v1_11")) { + return v1_11; + } else if (nmsVersion.startsWith("v1_12")) { + return v1_12; + } else if (nmsVersion.startsWith("v1_13")) { + return v1_13; + } else if (nmsVersion.startsWith("v1_14")) { + return v1_14; + } else { + return vNull; + } + } +} \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/commands/TabooLibExecuteCommand.java b/src/main/scala/io/izzel/taboolib/command/TabooLibExecuteCommand.java similarity index 66% rename from src/main/scala/me/skymc/taboolib/commands/TabooLibExecuteCommand.java rename to src/main/scala/io/izzel/taboolib/command/TabooLibExecuteCommand.java index e380cde..000728b 100644 --- a/src/main/scala/me/skymc/taboolib/commands/TabooLibExecuteCommand.java +++ b/src/main/scala/io/izzel/taboolib/command/TabooLibExecuteCommand.java @@ -1,19 +1,17 @@ -package me.skymc.taboolib.commands; +package io.izzel.taboolib.command; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.commands.internal.BaseMainCommand; -import me.skymc.taboolib.commands.internal.BaseSubCommand; -import me.skymc.taboolib.commands.internal.TCommand; -import me.skymc.taboolib.commands.internal.type.CommandArgument; -import me.skymc.taboolib.commands.internal.type.CommandRegister; -import me.skymc.taboolib.string.ArrayUtils; +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.module.command.base.BaseMainCommand; +import io.izzel.taboolib.module.command.base.BaseSubCommand; +import io.izzel.taboolib.module.command.TCommand; +import io.izzel.taboolib.module.command.base.CommandArgument; +import io.izzel.taboolib.module.command.base.CommandRegister; +import io.izzel.taboolib.util.ArrayUtil; import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.server.ServerCommandEvent; /** * @Author sky @@ -33,6 +31,7 @@ public class TabooLibExecuteCommand extends BaseMainCommand { @CommandRegister(priority = 1) BaseSubCommand chat = new BaseSubCommand() { + @Override public String getLabel() { return "chat"; @@ -58,7 +57,7 @@ public class TabooLibExecuteCommand extends BaseMainCommand { TLocale.sendTo(sender, "INVALID-PLAYER-OFFLINE", args[0]); return; } - player.chat(ArrayUtils.arrayJoin(args, 1)); + player.chat(ArrayUtil.arrayJoin(args, 1)); } }; @@ -69,6 +68,11 @@ public class TabooLibExecuteCommand extends BaseMainCommand { return "command"; } + @Override + public String[] getAliases() { + return new String[] {"cmd"}; + } + @Override public String getDescription() { return TLocale.asString("COMMANDS.TEXECUTE.COMMAND.DESCRIPTION"); @@ -85,7 +89,7 @@ public class TabooLibExecuteCommand extends BaseMainCommand { @Override public void onCommand(CommandSender sender, Command command, String label, String[] args) { if (args[0].equalsIgnoreCase("console")) { - dispatchCommand(Bukkit.getConsoleSender(), ArrayUtils.arrayJoin(args, 1)); + TabooLibAPI.dispatchCommand(Bukkit.getConsoleSender(), ArrayUtil.arrayJoin(args, 1)); return; } Player player = Bukkit.getPlayerExact(args[0]); @@ -93,17 +97,23 @@ public class TabooLibExecuteCommand extends BaseMainCommand { TLocale.sendTo(sender, "INVALID-TARGET-NOT-FOUND", args[0]); return; } - dispatchCommand(player, ArrayUtils.arrayJoin(args, 1)); + TabooLibAPI.dispatchCommand(player, ArrayUtil.arrayJoin(args, 1)); } }; @CommandRegister(priority = 2) BaseSubCommand commandAsOp = new BaseSubCommand() { + @Override public String getLabel() { return "commandAsOp"; } + @Override + public String[] getAliases() { + return new String[] {"op"}; + } + @Override public String getDescription() { return TLocale.asString("COMMANDS.TEXECUTE.COMMAND-AS-OP.DESCRIPTION"); @@ -120,7 +130,7 @@ public class TabooLibExecuteCommand extends BaseMainCommand { @Override public void onCommand(CommandSender sender, Command command, String label, String[] args) { if (args[0].equalsIgnoreCase("console")) { - dispatchCommand(Bukkit.getConsoleSender(), ArrayUtils.arrayJoin(args, 1)); + TabooLibAPI.dispatchCommand(Bukkit.getConsoleSender(), ArrayUtil.arrayJoin(args, 1)); return; } Player player = Bukkit.getPlayerExact(args[0]); @@ -131,33 +141,10 @@ public class TabooLibExecuteCommand extends BaseMainCommand { boolean isOp = player.isOp(); player.setOp(true); try { - dispatchCommand(player, ArrayUtils.arrayJoin(args, 1)); + TabooLibAPI.dispatchCommand(player, ArrayUtil.arrayJoin(args, 1)); } catch (Exception ignored) { } player.setOp(isOp); } }; - - public static boolean dispatchCommand(CommandSender sender, String command) { - try { - if ((sender instanceof Player)) { - PlayerCommandPreprocessEvent e = new PlayerCommandPreprocessEvent((Player) sender, "/" + command); - Bukkit.getPluginManager().callEvent(e); - if (e.isCancelled() || Strings.isBlank(e.getMessage()) || !e.getMessage().startsWith("/")) { - return false; - } - return Bukkit.dispatchCommand(e.getPlayer(), e.getMessage().substring(1)); - } else { - ServerCommandEvent e = new ServerCommandEvent(sender, command); - Bukkit.getPluginManager().callEvent(e); - if (e.isCancelled() || Strings.isBlank(e.getCommand())) { - return false; - } - return Bukkit.dispatchCommand(e.getSender(), e.getCommand()); - } - } catch (Exception e) { - e.printStackTrace(); - } - return false; - } -} +} \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/commands/locale/TabooLibLocaleCommand.java b/src/main/scala/io/izzel/taboolib/command/TabooLibLocaleCommand.java similarity index 89% rename from src/main/scala/me/skymc/taboolib/commands/locale/TabooLibLocaleCommand.java rename to src/main/scala/io/izzel/taboolib/command/TabooLibLocaleCommand.java index 855743e..487daad 100644 --- a/src/main/scala/me/skymc/taboolib/commands/locale/TabooLibLocaleCommand.java +++ b/src/main/scala/io/izzel/taboolib/command/TabooLibLocaleCommand.java @@ -1,12 +1,12 @@ -package me.skymc.taboolib.commands.locale; +package io.izzel.taboolib.command; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.resources.TLocaleLoader; -import me.skymc.taboolib.commands.internal.BaseMainCommand; -import me.skymc.taboolib.commands.internal.BaseSubCommand; -import me.skymc.taboolib.commands.internal.TCommand; -import me.skymc.taboolib.commands.internal.type.CommandArgument; -import me.skymc.taboolib.commands.internal.type.CommandRegister; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.locale.TLocaleLoader; +import io.izzel.taboolib.module.command.base.BaseMainCommand; +import io.izzel.taboolib.module.command.base.BaseSubCommand; +import io.izzel.taboolib.module.command.TCommand; +import io.izzel.taboolib.module.command.base.CommandArgument; +import io.izzel.taboolib.module.command.base.CommandRegister; import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; diff --git a/src/main/scala/me/skymc/taboolib/commands/plugin/TabooLibPluginCommand.java b/src/main/scala/io/izzel/taboolib/command/TabooLibPluginCommand.java similarity index 81% rename from src/main/scala/me/skymc/taboolib/commands/plugin/TabooLibPluginCommand.java rename to src/main/scala/io/izzel/taboolib/command/TabooLibPluginCommand.java index 79c7a67..8b3cf9f 100644 --- a/src/main/scala/me/skymc/taboolib/commands/plugin/TabooLibPluginCommand.java +++ b/src/main/scala/io/izzel/taboolib/command/TabooLibPluginCommand.java @@ -1,17 +1,18 @@ -package me.skymc.taboolib.commands.plugin; +package io.izzel.taboolib.command; import com.google.common.base.Joiner; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.commands.internal.BaseMainCommand; -import me.skymc.taboolib.commands.internal.BaseSubCommand; -import me.skymc.taboolib.commands.internal.TCommand; -import me.skymc.taboolib.commands.internal.type.CommandArgument; -import me.skymc.taboolib.commands.internal.type.CommandRegister; -import me.skymc.taboolib.plugin.PluginLoadState; -import me.skymc.taboolib.plugin.PluginLoadStateType; -import me.skymc.taboolib.plugin.PluginUnloadState; -import me.skymc.taboolib.plugin.PluginUtils; -import me.skymc.taboolib.string.ArrayUtils; +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.module.command.TCommand; +import io.izzel.taboolib.module.command.base.BaseMainCommand; +import io.izzel.taboolib.module.command.base.BaseSubCommand; +import io.izzel.taboolib.module.command.base.CommandArgument; +import io.izzel.taboolib.module.command.base.CommandRegister; +import io.izzel.taboolib.origin.plugin.PluginLoadState; +import io.izzel.taboolib.origin.plugin.PluginLoadStateType; +import io.izzel.taboolib.origin.plugin.PluginUnloadState; +import io.izzel.taboolib.origin.plugin.PluginUtils; +import io.izzel.taboolib.util.ArrayUtil; import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -37,17 +38,6 @@ public class TabooLibPluginCommand extends BaseMainCommand { return TLocale.asString("COMMANDS.TPLUGIN.COMMAND-TITLE"); } -// @Override -// public List onTabComplete(CommandSender commandSender, Command command, String s, String[] args) { -// if (args.length == 1) { -// return getSubCommands().stream().filter(internalCommandExecutor -> internalCommandExecutor != null && (args[0].isEmpty() || internalCommandExecutor.getLabel().toLowerCase().startsWith(args[0].toLowerCase()))).map(BaseSubCommand::getLabel).collect(Collectors.toList()); -// } else if (args.length > 1 && isPluginCommand(args[0])) { -// return Arrays.stream(Bukkit.getPluginManager().getPlugins()).filter(x -> !PluginUtils.isIgnored(x)).collect(Collectors.toList()).stream().filter(plugin -> args[1].isEmpty() || plugin.getName().toLowerCase().startsWith(args[1].toLowerCase())).map(Plugin::getName).collect(Collectors.toList()); -// } else { -// return null; -// } -// } - @CommandRegister(priority = 1) BaseSubCommand load = new BaseSubCommand() { @@ -68,7 +58,7 @@ public class TabooLibPluginCommand extends BaseMainCommand { @Override public void onCommand(CommandSender sender, Command command, String label, String[] args) { - String name = ArrayUtils.arrayJoin(args, 0); + String name = ArrayUtil.arrayJoin(args, 0); if (PluginUtils.getPluginByName(name) != null) { TLocale.sendTo(sender, "COMMANDS.TPLUGIN.LOAD.INVALID-PLUGIN", name, name + " already loaded!"); } else { @@ -114,13 +104,13 @@ public class TabooLibPluginCommand extends BaseMainCommand { @Override public CommandArgument[] getArguments() { return new CommandArgument[] {new CommandArgument(TLocale.asString("COMMANDS.TPLUGIN.UNLOAD.ARGUMENTS.0"), true, () -> { - return Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(Plugin::getName).collect(Collectors.toList()); + return java.util.Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(Plugin::getName).collect(Collectors.toList()); })}; } @Override public void onCommand(CommandSender sender, Command command, String label, String[] args) { - String name = ArrayUtils.arrayJoin(args, 0); + String name = ArrayUtil.arrayJoin(args, 0); Plugin plugin = PluginUtils.getPluginByName(name); if (plugin == null) { TLocale.sendTo(sender, "COMMANDS.TPLUGIN.UNLOAD.INVALID-PLUGIN", name); @@ -164,15 +154,15 @@ public class TabooLibPluginCommand extends BaseMainCommand { @Override public void onCommand(CommandSender sender, Command command, String label, String[] args) { - String name = ArrayUtils.arrayJoin(args, 0); + String name = ArrayUtil.arrayJoin(args, 0); Plugin plugin = PluginUtils.getPluginByName(name); if (plugin == null) { TLocale.sendTo(sender, "COMMANDS.TPLUGIN.RELOAD.INVALID-PLUGIN", name); } else if (PluginUtils.isIgnored(plugin)) { TLocale.sendTo(sender, "COMMANDS.TPLUGIN.RELOAD.INVALID-PLUGIN-IGNORED", name); } else { - TLocale.sendTo(sender, "COMMANDS.TPLUGIN.RELOAD.TRY-RELOAD"); - PluginUtils.reload(plugin); + TabooLibAPI.dispatchCommand(sender, "taboolibplugin unload " + plugin.getName()); + TabooLibAPI.dispatchCommand(sender, "taboolibplugin load " + plugin.getName()); } } }; @@ -192,12 +182,14 @@ public class TabooLibPluginCommand extends BaseMainCommand { @Override public CommandArgument[] getArguments() { - return new CommandArgument[] {new CommandArgument(TLocale.asString("COMMANDS.TPLUGIN.INFO.ARGUMENTS.0"), true)}; + return new CommandArgument[] {new CommandArgument(TLocale.asString("COMMANDS.TPLUGIN.INFO.ARGUMENTS.0"), true, () -> { + return Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(Plugin::getName).collect(Collectors.toList()); + })}; } @Override public void onCommand(CommandSender sender, Command command, String label, String[] args) { - String name = ArrayUtils.arrayJoin(args, 0); + String name = ArrayUtil.arrayJoin(args, 0); Plugin plugin = PluginUtils.getPluginByName(name); if (plugin == null) { TLocale.sendTo(sender, "COMMANDS.TPLUGIN.INFO.INVALID-PLUGIN", name); diff --git a/src/main/scala/me/skymc/taboolib/listener/ListenerNetWork.java b/src/main/scala/io/izzel/taboolib/listener/ListenerNetWork.java similarity index 59% rename from src/main/scala/me/skymc/taboolib/listener/ListenerNetWork.java rename to src/main/scala/io/izzel/taboolib/listener/ListenerNetWork.java index f3a1a28..c4f21fb 100644 --- a/src/main/scala/me/skymc/taboolib/listener/ListenerNetWork.java +++ b/src/main/scala/io/izzel/taboolib/listener/ListenerNetWork.java @@ -1,7 +1,6 @@ -package me.skymc.taboolib.listener; +package io.izzel.taboolib.listener; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.message.MsgUtils; +import io.izzel.taboolib.module.inject.TListener; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -14,11 +13,9 @@ import pw.yumc.Yum.events.PluginNetworkEvent; @TListener(depend = "YUM") public class ListenerNetWork implements Listener { - public static final String GG = "本监听只是为了防止本插件的更新检测被 YUM 插件阻止,别无它用。"; - @EventHandler(priority = EventPriority.HIGHEST) public void onNetWork(PluginNetworkEvent e) { - if (e.getPlugin() != null && e.getPlugin().equals(Main.getInst())) { + if (e.getPlugin() != null && e.getPlugin().getName().equals("TabooLib")) { e.setCancelled(false); } } diff --git a/src/main/scala/io/izzel/taboolib/listener/ListenerPlayerCommand.java b/src/main/scala/io/izzel/taboolib/listener/ListenerPlayerCommand.java new file mode 100644 index 0000000..c965d01 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/listener/ListenerPlayerCommand.java @@ -0,0 +1,59 @@ +package io.izzel.taboolib.listener; + +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.Version; +import io.izzel.taboolib.module.inject.TListener; +import io.izzel.taboolib.module.item.Items; +import io.izzel.taboolib.module.logger.TLogger; +import io.izzel.taboolib.module.tellraw.TellrawJson; +import io.izzel.taboolib.origin.database.PlayerDataManager; +import io.izzel.taboolib.origin.database.PluginDataManager; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.server.ServerCommandEvent; + +/** + * @author sky + */ +@TListener +public class ListenerPlayerCommand implements Listener { + + @EventHandler + public void cmd(ServerCommandEvent e) { + if (e.getCommand().equalsIgnoreCase("saveFiles")) { + if (Version.isAfter(Version.v1_8)) { + e.setCancelled(true); + } + PluginDataManager.saveAllCaches(); + PlayerDataManager.saveAllCaches(true, false); + TLogger.getGlobalLogger().info("Successfully."); + } else if (e.getCommand().equalsIgnoreCase("tDebug")) { + if (Version.isAfter(Version.v1_8)) { + e.setCancelled(true); + } + if (TabooLibAPI.isDebug()) { + TabooLibAPI.setDebug(false); + TLogger.getGlobalLogger().info("&cDisabled."); + } else { + TabooLibAPI.setDebug(true); + TLogger.getGlobalLogger().info("&aEnabled."); + } + } else if (e.getCommand().equalsIgnoreCase("tExceptionEvent")) { + e.setCancelled(true); + throw new IllegalStateException("TabooLib Example Exception"); + } + } + + @EventHandler + public void cmd(PlayerCommandPreprocessEvent e) { + if (e.getMessage().equals("/tellrawTest") && e.getPlayer().hasPermission("taboolib.tellraw")) { + e.setCancelled(true); + TellrawJson.create() + .append("§8[§3§lTabooLib§8] §7TellrawJson Test: §f[") + .append(Items.getName(e.getPlayer().getItemInHand())).hoverItem(e.getPlayer().getItemInHand()) + .append("§f]") + .send(e.getPlayer()); + } + } +} diff --git a/src/main/scala/me/skymc/taboolib/listener/ListenerPlayerJump.java b/src/main/scala/io/izzel/taboolib/listener/ListenerPlayerJump.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/listener/ListenerPlayerJump.java rename to src/main/scala/io/izzel/taboolib/listener/ListenerPlayerJump.java index ad2217c..feecb74 100644 --- a/src/main/scala/me/skymc/taboolib/listener/ListenerPlayerJump.java +++ b/src/main/scala/io/izzel/taboolib/listener/ListenerPlayerJump.java @@ -1,6 +1,7 @@ -package me.skymc.taboolib.listener; +package io.izzel.taboolib.listener; -import me.skymc.taboolib.events.PlayerJumpEvent; +import io.izzel.taboolib.module.inject.TListener; +import io.izzel.taboolib.origin.event.PlayerJumpEvent; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; @@ -30,7 +31,7 @@ public class ListenerPlayerJump implements Listener { PlayerJumpEvent evt = new PlayerJumpEvent(event.isCancelled(), event.getPlayer()); Bukkit.getPluginManager().callEvent(evt); if (evt.isCancelled()) { - event.setCancelled(true); + event.setTo(event.getFrom()); } } else if (this.cooldown.get(event.getPlayer()) <= System.currentTimeMillis()) { this.cooldown.put(event.getPlayer(), System.currentTimeMillis() + 350L); @@ -38,7 +39,7 @@ public class ListenerPlayerJump implements Listener { Bukkit.getPluginManager().callEvent(evt); if (evt.isCancelled()) { - event.setCancelled(true); + event.setTo(event.getFrom()); } } } diff --git a/src/main/scala/com/ilummc/tlib/resources/TLocale.java b/src/main/scala/io/izzel/taboolib/locale/TLocale.java similarity index 86% rename from src/main/scala/com/ilummc/tlib/resources/TLocale.java rename to src/main/scala/io/izzel/taboolib/locale/TLocale.java index 1b41f23..4a6f908 100644 --- a/src/main/scala/com/ilummc/tlib/resources/TLocale.java +++ b/src/main/scala/io/izzel/taboolib/locale/TLocale.java @@ -1,16 +1,15 @@ -package com.ilummc.tlib.resources; +package io.izzel.taboolib.locale; -import com.ilummc.tlib.TLib; -import com.ilummc.tlib.bungee.api.ChatColor; -import com.ilummc.tlib.bungee.api.chat.TextComponent; -import com.ilummc.tlib.bungee.chat.ComponentSerializer; -import com.ilummc.tlib.inject.TLoggerManager; -import com.ilummc.tlib.util.Ref; -import com.ilummc.tlib.util.Strings; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.module.logger.TLoggerManager; +import io.izzel.taboolib.module.nms.NMSHandler; +import io.izzel.taboolib.module.tellraw.TellrawCreator; +import io.izzel.taboolib.util.Ref; +import io.izzel.taboolib.util.Strings; +import io.izzel.taboolib.util.chat.ChatColor; +import io.izzel.taboolib.util.chat.ComponentSerializer; +import io.izzel.taboolib.util.chat.TextComponent; import me.clip.placeholderapi.PlaceholderAPI; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.common.nms.NMSHandler; -import me.skymc.taboolib.json.tellraw.TellrawCreator; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -58,19 +57,19 @@ public class TLocale { public static String asString(String path, String... args) { try { - return asString(path, Ref.getCallerClass(3).orElse(Main.class), args); + return asString(path, Ref.getCallerClass(3).orElse(TabooLib.class), args); } catch (Exception e) { - TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("FETCH-LOCALE-ERROR"), path)); - TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("LOCALE-ERROR-REASON"), e.getMessage())); + TabooLib.getLogger().error(Strings.replaceWithOrder(TabooLib.getInst().getInternal().getString("FETCH-LOCALE-ERROR"), path)); + TabooLib.getLogger().error(Strings.replaceWithOrder(TabooLib.getInst().getInternal().getString("LOCALE-ERROR-REASON"), e.getMessage())); return "§4<" + path + "§4>"; } } public static List asStringList(String path, String... args) { try { - return asStringList(path, Ref.getCallerClass(3).orElse(Main.class), args); + return asStringList(path, Ref.getCallerClass(3).orElse(TabooLib.class), args); } catch (Exception e) { - TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("LOCALE-ERROR-REASON"), e.getMessage())); + TabooLib.getLogger().error(Strings.replaceWithOrder(TabooLib.getInst().getInternal().getString("LOCALE-ERROR-REASON"), e.getMessage())); return Collections.singletonList("§4<" + path + "§4>"); } } @@ -108,7 +107,7 @@ public class TLocale { public static final class Translate extends TLocale { public static boolean isPlaceholderUseDefault() { - return Main.getInst().getConfig().getBoolean("LOCALE.USE_PAPI", false); + return TabooLib.getConfig().getBoolean("LOCALE.USE_PAPI", false); } public static boolean isPlaceholderPluginEnabled() { diff --git a/src/main/scala/com/ilummc/tlib/resources/TLocaleInstance.java b/src/main/scala/io/izzel/taboolib/locale/TLocaleInstance.java similarity index 87% rename from src/main/scala/com/ilummc/tlib/resources/TLocaleInstance.java rename to src/main/scala/io/izzel/taboolib/locale/TLocaleInstance.java index 5994aa2..f42b653 100644 --- a/src/main/scala/com/ilummc/tlib/resources/TLocaleInstance.java +++ b/src/main/scala/io/izzel/taboolib/locale/TLocaleInstance.java @@ -1,10 +1,9 @@ -package com.ilummc.tlib.resources; +package io.izzel.taboolib.locale; import com.google.common.collect.ImmutableList; -import com.ilummc.tlib.TLib; -import com.ilummc.tlib.resources.type.TLocaleText; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.TabooLib; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.locale.type.TLocaleText; +import io.izzel.taboolib.util.Strings; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.configuration.ConfigurationSection; @@ -12,7 +11,10 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.Plugin; import javax.annotation.concurrent.ThreadSafe; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -59,8 +61,8 @@ class TLocaleInstance { } }); } catch (Exception | Error e) { - TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("SEND-LOCALE-ERROR"), path)); - TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("LOCALE-ERROR-REASON"), e.toString())); + TabooLib.getLogger().error(Strings.replaceWithOrder(TabooLib.getInst().getInternal().getString("SEND-LOCALE-ERROR"), path)); + TabooLib.getLogger().error(Strings.replaceWithOrder(TabooLib.getInst().getInternal().getString("LOCALE-ERROR-REASON"), e.toString())); } } diff --git a/src/main/scala/io/izzel/taboolib/locale/TLocaleSender.java b/src/main/scala/io/izzel/taboolib/locale/TLocaleSender.java new file mode 100644 index 0000000..4a56088 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/locale/TLocaleSender.java @@ -0,0 +1,19 @@ +package io.izzel.taboolib.locale; + +import org.bukkit.command.CommandSender; + +import java.util.List; + +/** + * @Author sky + * @Since 2018-05-12 13:58 + */ +public interface TLocaleSender { + + void sendTo(CommandSender sender, String... args); + + String asString(String... args); + + List asStringList(String... args); + +} diff --git a/src/main/scala/com/ilummc/tlib/resources/TLocaleSerialize.java b/src/main/scala/io/izzel/taboolib/locale/TLocaleSerialize.java similarity index 98% rename from src/main/scala/com/ilummc/tlib/resources/TLocaleSerialize.java rename to src/main/scala/io/izzel/taboolib/locale/TLocaleSerialize.java index 3155d74..db71467 100644 --- a/src/main/scala/com/ilummc/tlib/resources/TLocaleSerialize.java +++ b/src/main/scala/io/izzel/taboolib/locale/TLocaleSerialize.java @@ -1,4 +1,4 @@ -package com.ilummc.tlib.resources; +package io.izzel.taboolib.locale; import org.bukkit.command.CommandSender; import org.bukkit.configuration.serialization.ConfigurationSerializable; diff --git a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleActionBar.java b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleActionBar.java similarity index 85% rename from src/main/scala/com/ilummc/tlib/resources/type/TLocaleActionBar.java rename to src/main/scala/io/izzel/taboolib/locale/type/TLocaleActionBar.java index ec7296c..c990156 100644 --- a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleActionBar.java +++ b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleActionBar.java @@ -1,11 +1,10 @@ -package com.ilummc.tlib.resources.type; +package io.izzel.taboolib.locale.type; import com.google.common.collect.Maps; -import com.ilummc.tlib.compat.PlaceholderHook; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.resources.TLocaleSerialize; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.display.ActionUtils; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.locale.TLocaleSerialize; +import io.izzel.taboolib.module.compat.PlaceholderHook; +import io.izzel.taboolib.util.Strings; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.configuration.serialization.SerializableAs; diff --git a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleBook.java b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleBook.java similarity index 84% rename from src/main/scala/com/ilummc/tlib/resources/type/TLocaleBook.java rename to src/main/scala/io/izzel/taboolib/locale/type/TLocaleBook.java index 24c8008..6b0068b 100644 --- a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleBook.java +++ b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleBook.java @@ -1,14 +1,14 @@ -package com.ilummc.tlib.resources.type; +package io.izzel.taboolib.locale.type; import com.google.common.collect.Maps; -import com.ilummc.tlib.bungee.chat.ComponentSerializer; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.resources.TLocaleSerialize; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.bookformatter.BookFormatter; -import me.skymc.taboolib.bookformatter.builder.BookBuilder; -import me.skymc.taboolib.json.tellraw.TellrawJson; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.locale.TLocaleSerialize; +import io.izzel.taboolib.module.tellraw.TellrawJson; +import io.izzel.taboolib.origin.book.BookFormatter; +import io.izzel.taboolib.origin.book.builder.BookBuilder; +import io.izzel.taboolib.util.Strings; +import io.izzel.taboolib.util.chat.ComponentSerializer; import org.bukkit.command.CommandSender; import org.bukkit.configuration.serialization.SerializableAs; import org.bukkit.entity.Player; @@ -77,9 +77,9 @@ public class TLocaleBook extends TLocaleSerialize { public void run() { BookFormatter.forceOpen((Player) sender, bookBuilder.build()); } - }.runTask(Main.getInst()); + }.runTask(TabooLib.getPlugin()); } - }.runTaskAsynchronously(Main.getInst()); + }.runTaskAsynchronously(TabooLib.getPlugin()); } private String format(TellrawJson jsonPage, CommandSender sender, String[] args) { diff --git a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleBossBar.java b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleBossBar.java similarity index 79% rename from src/main/scala/com/ilummc/tlib/resources/type/TLocaleBossBar.java rename to src/main/scala/io/izzel/taboolib/locale/type/TLocaleBossBar.java index 62261ca..4692f7c 100644 --- a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleBossBar.java +++ b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleBossBar.java @@ -1,14 +1,14 @@ -package com.ilummc.tlib.resources.type; +package io.izzel.taboolib.locale.type; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.resources.TLocaleSerialize; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.other.NumberUtils; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.locale.TLocaleSerialize; +import io.izzel.taboolib.util.Strings; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.configuration.serialization.SerializableAs; import org.bukkit.entity.Player; +import org.bukkit.util.NumberConversions; import org.inventivetalent.bossbar.BossBar; import org.inventivetalent.bossbar.BossBarAPI; @@ -72,7 +72,14 @@ public class TLocaleBossBar extends TLocaleSerialize { } public static TLocaleBossBar valueOf(Map map) { - return new TLocaleBossBar(map.getOrDefault("text", "§4* Invalid Text*").toString(), getColor(String.valueOf(map.get("color"))), getStyle(String.valueOf(map.get("style"))), (float) NumberUtils.getDouble(String.valueOf(map.getOrDefault("progress", 1))), NumberUtils.getInteger(String.valueOf(map.getOrDefault("timeout", 20))), NumberUtils.getInteger(String.valueOf(map.getOrDefault("timeout-interval", 2))), isPlaceholderEnabled(map)); + return new TLocaleBossBar( + map.getOrDefault("text", "§4* Invalid Text*").toString(), + getColor(String.valueOf(map.get("color"))), + getStyle(String.valueOf(map.get("style"))), + NumberConversions.toFloat(map.getOrDefault("progress", 1)), + NumberConversions.toInt(map.getOrDefault("timeout", 20)), + NumberConversions.toInt(map.getOrDefault("timeout-interval", 2)), + isPlaceholderEnabled(map)); } private static BossBarAPI.Color getColor(String color) { diff --git a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleJson.java b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleJson.java similarity index 90% rename from src/main/scala/com/ilummc/tlib/resources/type/TLocaleJson.java rename to src/main/scala/io/izzel/taboolib/locale/type/TLocaleJson.java index 456f862..7049717 100644 --- a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleJson.java +++ b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleJson.java @@ -1,21 +1,19 @@ -package com.ilummc.tlib.resources.type; +package io.izzel.taboolib.locale.type; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.ilummc.tlib.TLib; -import com.ilummc.tlib.bungee.api.chat.*; -import com.ilummc.tlib.bungee.chat.ComponentSerializer; -import com.ilummc.tlib.compat.PlaceholderHook; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.resources.TLocaleSerialize; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.inventory.ItemUtils; -import me.skymc.taboolib.json.tellraw.TellrawJson; -import me.skymc.taboolib.other.NumberUtils; -import me.skymc.taboolib.string.VariableFormatter; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.locale.TLocaleSerialize; +import io.izzel.taboolib.module.compat.PlaceholderHook; +import io.izzel.taboolib.module.tellraw.TellrawJson; +import io.izzel.taboolib.util.Strings; +import io.izzel.taboolib.util.Variables; +import io.izzel.taboolib.util.chat.*; import org.bukkit.command.CommandSender; import org.bukkit.configuration.serialization.SerializableAs; +import org.bukkit.util.NumberConversions; import javax.annotation.concurrent.ThreadSafe; import java.util.*; @@ -88,7 +86,7 @@ public class TLocaleJson extends TLocaleSerialize { } else { // 这个参数节点并没有找到,于是随便放点字符串进去 builder.addAll(Arrays.asList(TextComponent.fromLegacyText(text))); - TLib.getTLib().getLogger().warn(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("MISSING-ARGUMENT"), node)); + TabooLib.getLogger().warn(Strings.replaceWithOrder(TabooLib.getInst().getInternal().getString("MISSING-ARGUMENT"), node)); } // 有可能一开头就是 <@xxx>,然后 split 出来就少了一些,于是直接加上 if (index < template.length) { @@ -171,7 +169,7 @@ public class TLocaleJson extends TLocaleSerialize { // 遍历本页文本 for (int i = 0; i < textList.size(); i++) { // 捕捉变量 - for (VariableFormatter.Variable variable : new VariableFormatter(TLocale.Translate.setColored(textList.get(i)), pattern).find().getVariableList()) { + for (Variables.Variable variable : new Variables(TLocale.Translate.setColored(textList.get(i)), pattern).find().getVariableList()) { // 如果是变量 if (variable.isVariable()) { String[] split = variable.getText().split("@"); @@ -199,9 +197,6 @@ public class TLocaleJson extends TLocaleSerialize { // 文本 pageJson.append(args.getOrDefault("text", text).toString()); // 功能 - if (args.containsKey("item")) { - pageJson.hoverItem(ItemUtils.getCacheItem(args.get("item").toString())); - } if (args.containsKey("hover")) { pageJson.hoverText(args.get("hover").toString()); } @@ -212,7 +207,7 @@ public class TLocaleJson extends TLocaleSerialize { pageJson.clickCommand(args.get("command").toString()); } if (args.containsKey("page")) { - pageJson.clickChangePage(NumberUtils.getInteger(args.get("page").toString())); + pageJson.clickChangePage(NumberConversions.toInt(args.get("page").toString())); } if (args.containsKey("url")) { pageJson.clickOpenURL(args.get("url").toString()); diff --git a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleSound.java b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleSound.java similarity index 75% rename from src/main/scala/com/ilummc/tlib/resources/type/TLocaleSound.java rename to src/main/scala/io/izzel/taboolib/locale/type/TLocaleSound.java index 5aec6e1..a586b3e 100644 --- a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleSound.java +++ b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleSound.java @@ -1,8 +1,8 @@ -package com.ilummc.tlib.resources.type; +package io.izzel.taboolib.locale.type; import com.google.common.collect.Maps; -import com.ilummc.tlib.resources.TLocaleSerialize; -import me.skymc.taboolib.sound.SoundPack; +import io.izzel.taboolib.locale.TLocaleSerialize; +import io.izzel.taboolib.origin.lite.Sounds; import org.bukkit.command.CommandSender; import org.bukkit.configuration.serialization.SerializableAs; import org.bukkit.entity.Player; @@ -21,19 +21,19 @@ import java.util.stream.Collectors; @SerializableAs("ACTION") public class TLocaleSound extends TLocaleSerialize { - private final List soundPacks; + private final List soundPacks; - public TLocaleSound(List soundPacks) { + public TLocaleSound(List soundPacks) { this.soundPacks = soundPacks; } public static TLocaleSound valueOf(Map map) { - List soundPacks = new ArrayList<>(); + List soundPacks = new ArrayList<>(); Object sounds = map.containsKey("sounds") ? map.get("sounds") : map.getOrDefault("sound", ""); if (sounds instanceof List) { - soundPacks = ((List) sounds).stream().map(SoundPack::new).collect(Collectors.toList()); + soundPacks = ((List) sounds).stream().map(Sounds::new).collect(Collectors.toList()); } else { - soundPacks.add(new SoundPack(sounds.toString())); + soundPacks.add(new Sounds(sounds.toString())); } return new TLocaleSound(soundPacks); } @@ -61,7 +61,7 @@ public class TLocaleSound extends TLocaleSerialize { if (soundPacks.size() == 1) { map.put("sounds", soundPacks.get(0).toString()); } else if (soundPacks.size() > 1) { - map.put("sounds", soundPacks.stream().map(SoundPack::toString).collect(Collectors.toList())); + map.put("sounds", soundPacks.stream().map(Sounds::toString).collect(Collectors.toList())); } return map; } diff --git a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleText.java b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleText.java similarity index 93% rename from src/main/scala/com/ilummc/tlib/resources/type/TLocaleText.java rename to src/main/scala/io/izzel/taboolib/locale/type/TLocaleText.java index fc5e587..b1a1f9a 100644 --- a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleText.java +++ b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleText.java @@ -1,13 +1,11 @@ -package com.ilummc.tlib.resources.type; +package io.izzel.taboolib.locale.type; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; -import com.ilummc.tlib.compat.PlaceholderHook; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.resources.TLocaleSerialize; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.Main; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.locale.TLocaleSerialize; +import io.izzel.taboolib.util.Strings; import org.bukkit.command.CommandSender; import org.bukkit.configuration.serialization.SerializableAs; diff --git a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleTitle.java b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleTitle.java similarity index 92% rename from src/main/scala/com/ilummc/tlib/resources/type/TLocaleTitle.java rename to src/main/scala/io/izzel/taboolib/locale/type/TLocaleTitle.java index 1b1a710..32128bd 100644 --- a/src/main/scala/com/ilummc/tlib/resources/type/TLocaleTitle.java +++ b/src/main/scala/io/izzel/taboolib/locale/type/TLocaleTitle.java @@ -1,10 +1,9 @@ -package com.ilummc.tlib.resources.type; +package io.izzel.taboolib.locale.type; import com.google.common.collect.Maps; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.resources.TLocaleSerialize; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.display.TitleUtils; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.locale.TLocaleSerialize; +import io.izzel.taboolib.util.Strings; import org.bukkit.command.CommandSender; import org.bukkit.configuration.serialization.SerializableAs; import org.bukkit.entity.Player; diff --git a/src/main/scala/me/skymc/taboolib/common/pathfinder/PathfinderCreator.java b/src/main/scala/io/izzel/taboolib/module/ai/PathfinderCreator.java similarity index 75% rename from src/main/scala/me/skymc/taboolib/common/pathfinder/PathfinderCreator.java rename to src/main/scala/io/izzel/taboolib/module/ai/PathfinderCreator.java index e84fddb..60cb498 100644 --- a/src/main/scala/me/skymc/taboolib/common/pathfinder/PathfinderCreator.java +++ b/src/main/scala/io/izzel/taboolib/module/ai/PathfinderCreator.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.pathfinder; +package io.izzel.taboolib.module.ai; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/common/pathfinder/PathfinderExecutor.java b/src/main/scala/io/izzel/taboolib/module/ai/PathfinderExecutor.java similarity index 97% rename from src/main/scala/me/skymc/taboolib/common/pathfinder/PathfinderExecutor.java rename to src/main/scala/io/izzel/taboolib/module/ai/PathfinderExecutor.java index 9fb04f2..a7013fc 100644 --- a/src/main/scala/me/skymc/taboolib/common/pathfinder/PathfinderExecutor.java +++ b/src/main/scala/io/izzel/taboolib/module/ai/PathfinderExecutor.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.pathfinder; +package io.izzel.taboolib.module.ai; import org.bukkit.Location; import org.bukkit.entity.Entity; diff --git a/src/main/scala/me/skymc/taboolib/common/pathfinder/SimpleAi.java b/src/main/scala/io/izzel/taboolib/module/ai/SimpleAi.java similarity index 87% rename from src/main/scala/me/skymc/taboolib/common/pathfinder/SimpleAi.java rename to src/main/scala/io/izzel/taboolib/module/ai/SimpleAi.java index e1ac15b..3515f20 100644 --- a/src/main/scala/me/skymc/taboolib/common/pathfinder/SimpleAi.java +++ b/src/main/scala/io/izzel/taboolib/module/ai/SimpleAi.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.pathfinder; +package io.izzel.taboolib.module.ai; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/common/pathfinder/SimpleAiSelector.java b/src/main/scala/io/izzel/taboolib/module/ai/SimpleAiSelector.java similarity index 61% rename from src/main/scala/me/skymc/taboolib/common/pathfinder/SimpleAiSelector.java rename to src/main/scala/io/izzel/taboolib/module/ai/SimpleAiSelector.java index 6a45ce2..832ae83 100644 --- a/src/main/scala/me/skymc/taboolib/common/pathfinder/SimpleAiSelector.java +++ b/src/main/scala/io/izzel/taboolib/module/ai/SimpleAiSelector.java @@ -1,22 +1,22 @@ -package me.skymc.taboolib.common.pathfinder; +package io.izzel.taboolib.module.ai; -import me.skymc.taboolib.common.loader.Instantiable; -import me.skymc.taboolib.common.versioncontrol.SimpleVersionControl; +import io.izzel.taboolib.module.inject.TFunction; +import io.izzel.taboolib.module.lite.SimpleVersionControl; /** * @Author sky * @Since 2018-09-19 20:31 */ -@Instantiable("SimpleAiSelector") +@TFunction(enable = "init") public class SimpleAiSelector { private static PathfinderCreator internalPathfinderCreator; private static PathfinderExecutor internalPathfinderExecutor; - public SimpleAiSelector() { + static void init() { try { - internalPathfinderCreator = (PathfinderCreator) SimpleVersionControl.createNMS("me.skymc.taboolib.common.pathfinder.internal.InternalPathfinderCreator").translate().newInstance(); - internalPathfinderExecutor = (PathfinderExecutor) SimpleVersionControl.createNMS("me.skymc.taboolib.common.pathfinder.internal.InternalPathfinderExecutor").translate().newInstance(); + internalPathfinderCreator = (PathfinderCreator) SimpleVersionControl.createNMS("io.izzel.taboolib.module.ai.internal.InternalPathfinderCreator").translate().newInstance(); + internalPathfinderExecutor = (PathfinderExecutor) SimpleVersionControl.createNMS("io.izzel.taboolib.module.ai.internal.InternalPathfinderExecutor").translate().newInstance(); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/scala/me/skymc/taboolib/common/pathfinder/internal/InternalPathfinderCreator.java b/src/main/scala/io/izzel/taboolib/module/ai/internal/InternalPathfinderCreator.java similarity index 84% rename from src/main/scala/me/skymc/taboolib/common/pathfinder/internal/InternalPathfinderCreator.java rename to src/main/scala/io/izzel/taboolib/module/ai/internal/InternalPathfinderCreator.java index 027ec95..abc1d0c 100644 --- a/src/main/scala/me/skymc/taboolib/common/pathfinder/internal/InternalPathfinderCreator.java +++ b/src/main/scala/io/izzel/taboolib/module/ai/internal/InternalPathfinderCreator.java @@ -1,7 +1,7 @@ -package me.skymc.taboolib.common.pathfinder.internal; +package io.izzel.taboolib.module.ai.internal; -import me.skymc.taboolib.common.pathfinder.PathfinderCreator; -import me.skymc.taboolib.common.pathfinder.SimpleAi; +import io.izzel.taboolib.module.ai.PathfinderCreator; +import io.izzel.taboolib.module.ai.SimpleAi; /** * 该类仅用作生成 ASM 代码,无任何意义 diff --git a/src/main/scala/me/skymc/taboolib/common/pathfinder/internal/InternalPathfinderExecutor.java b/src/main/scala/io/izzel/taboolib/module/ai/internal/InternalPathfinderExecutor.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/common/pathfinder/internal/InternalPathfinderExecutor.java rename to src/main/scala/io/izzel/taboolib/module/ai/internal/InternalPathfinderExecutor.java index ebfbb90..d72c69b 100644 --- a/src/main/scala/me/skymc/taboolib/common/pathfinder/internal/InternalPathfinderExecutor.java +++ b/src/main/scala/io/izzel/taboolib/module/ai/internal/InternalPathfinderExecutor.java @@ -1,9 +1,9 @@ -package me.skymc.taboolib.common.pathfinder.internal; +package io.izzel.taboolib.module.ai.internal; -import me.skymc.taboolib.common.pathfinder.PathfinderExecutor; -import me.skymc.taboolib.common.pathfinder.SimpleAi; -import me.skymc.taboolib.common.pathfinder.SimpleAiSelector; -import me.skymc.taboolib.nms.NMSUtils; +import io.izzel.taboolib.module.ai.PathfinderExecutor; +import io.izzel.taboolib.module.ai.SimpleAi; +import io.izzel.taboolib.module.ai.SimpleAiSelector; +import io.izzel.taboolib.module.lite.SimpleReflection; import net.minecraft.server.v1_8_R3.*; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; @@ -27,18 +27,17 @@ public class InternalPathfinderExecutor extends PathfinderExecutor { public InternalPathfinderExecutor() { try { - pathfinderGoalSelectorSet = NMSUtils.getNMSClass("PathfinderGoalSelector").getDeclaredField("b"); - pathfinderGoalSelectorSet.setAccessible(true); - controllerJumpCurrent = NMSUtils.getNMSClass("ControllerJump").getDeclaredField("a"); - controllerJumpCurrent.setAccessible(true); + SimpleReflection.saveField(PathfinderGoalSelector.class); + SimpleReflection.saveField(ControllerJump.class); + pathfinderGoalSelectorSet =SimpleReflection.getField(PathfinderGoalSelector.class, "b"); + controllerJumpCurrent = SimpleReflection.getField(ControllerJump.class, "a"); } catch (Exception e) { e.printStackTrace(); } try { - Class pathEntityClass = NMSUtils.getNMSClass("PathEntity"); - for (Field field : NMSUtils.getNMSClass("NavigationAbstract").getDeclaredFields()) { - if (field.getType().equals(pathEntityClass)) { - field.setAccessible(true); + SimpleReflection.saveField(NavigationAbstract.class); + for (Field field : SimpleReflection.getFields(NavigationAbstract.class).values()) { + if (field.getType().equals(PathEntity.class)) { pathEntity = field; return; } diff --git a/src/main/scala/me/skymc/taboolib/commands/internal/TCommand.java b/src/main/scala/io/izzel/taboolib/module/command/TCommand.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/commands/internal/TCommand.java rename to src/main/scala/io/izzel/taboolib/module/command/TCommand.java index b3a69c7..df9bd6d 100644 --- a/src/main/scala/me/skymc/taboolib/commands/internal/TCommand.java +++ b/src/main/scala/io/izzel/taboolib/module/command/TCommand.java @@ -1,10 +1,9 @@ -package me.skymc.taboolib.commands.internal; +package io.izzel.taboolib.module.command; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.util.List; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/commands/internal/TCommandHandler.java b/src/main/scala/io/izzel/taboolib/module/command/TCommandHandler.java similarity index 58% rename from src/main/scala/me/skymc/taboolib/commands/internal/TCommandHandler.java rename to src/main/scala/io/izzel/taboolib/module/command/TCommandHandler.java index b9699ae..3a56449 100644 --- a/src/main/scala/me/skymc/taboolib/commands/internal/TCommandHandler.java +++ b/src/main/scala/io/izzel/taboolib/module/command/TCommandHandler.java @@ -1,18 +1,15 @@ -package me.skymc.taboolib.commands.internal; +package io.izzel.taboolib.module.command; -import com.ilummc.tlib.inject.TPluginManager; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.common.util.SimpleReflection; -import me.skymc.taboolib.fileutils.FileUtils; -import me.skymc.taboolib.listener.TListener; -import me.skymc.taboolib.methods.ReflectionUtils; -import me.skymc.taboolib.string.ArrayUtils; +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.module.command.base.BaseMainCommand; +import io.izzel.taboolib.module.inject.TFunction; +import io.izzel.taboolib.module.lite.SimpleReflection; +import io.izzel.taboolib.util.ArrayUtil; +import io.izzel.taboolib.util.Files; +import io.izzel.taboolib.util.Reflection; import org.bukkit.Bukkit; import org.bukkit.command.*; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.SimplePluginManager; @@ -26,30 +23,17 @@ import java.util.stream.Collectors; * @Author sky * @Since 2018-05-23 2:43 */ -@TListener -public class TCommandHandler implements Listener { +@TFunction(enable = "init") +public class TCommandHandler { private static SimpleCommandMap commandMap; private static Map knownCommands; - public TCommandHandler() { - SimpleReflection.saveField(Bukkit.getPluginManager() instanceof TPluginManager ? TPluginManager.class : SimplePluginManager.class, "commandMap"); + static void init() { + SimpleReflection.saveField(SimplePluginManager.class, "commandMap"); SimpleReflection.saveField(SimpleCommandMap.class, "knownCommands"); - commandMap = (SimpleCommandMap) SimpleReflection.getFieldValue(Bukkit.getPluginManager() instanceof TPluginManager ? TPluginManager.class : SimplePluginManager.class, Bukkit.getPluginManager(), "commandMap"); + commandMap = (SimpleCommandMap) SimpleReflection.getFieldValue(SimplePluginManager.class, Bukkit.getPluginManager(), "commandMap"); knownCommands = (Map) SimpleReflection.getFieldValue(SimpleCommandMap.class, commandMap, "knownCommands"); - try { - registerCommands(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @EventHandler - public void onEnable(PluginEnableEvent e) { - try { - registerCommand(e.getPlugin()); - } catch (Exception ignored) { - } } public static boolean registerPluginCommand(Plugin plugin, String command, CommandExecutor commandExecutor) { @@ -72,8 +56,11 @@ public class TCommandHandler implements Listener { return registerPluginCommand(plugin, command, description, usage, aliases, null, null, commandExecutor, tabCompleter); } - public static boolean registerPluginCommand(Plugin plugin, String command, String description, String usage, List aliases, String permission, String permissionMessage, CommandExecutor commandExecutor, TabCompleter tabCompleter) { - return registerPluginCommand(plugin, command, description, usage, aliases, permission, permissionMessage, commandExecutor, tabCompleter, false); + /** + * 获取插件注册的命令 + */ + public static Command getPluginCommand(String command) { + return commandMap.getCommand(command); } /** @@ -88,27 +75,23 @@ public class TCommandHandler implements Listener { * @param permissionMessage 权限提示 * @param commandExecutor 命令执行器 * @param tabCompleter 补全执行器 - * @param silence 是否屏蔽提示 * @return 注册结果(boolean) */ - public static boolean registerPluginCommand(Plugin plugin, String command, String description, String usage, List aliases, String permission, String permissionMessage, CommandExecutor commandExecutor, TabCompleter tabCompleter, boolean silence) { + public static boolean registerPluginCommand(Plugin plugin, String command, String description, String usage, List aliases, String permission, String permissionMessage, CommandExecutor commandExecutor, TabCompleter tabCompleter) { try { Constructor constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); constructor.setAccessible(true); PluginCommand pluginCommand = constructor.newInstance(command, plugin); pluginCommand.setExecutor(commandExecutor); pluginCommand.setTabCompleter(tabCompleter); - ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "description", description); - ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "usageMessage", usage); - ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "aliases", aliases.stream().map(String::toLowerCase).collect(Collectors.toList())); - ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "activeAliases", aliases.stream().map(String::toLowerCase).collect(Collectors.toList())); - ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "permission", permission); - ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "permissionMessage", permissionMessage); + Reflection.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "description", description); + Reflection.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "usageMessage", usage); + Reflection.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "aliases", aliases.stream().map(String::toLowerCase).collect(Collectors.toList())); + Reflection.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "activeAliases", aliases.stream().map(String::toLowerCase).collect(Collectors.toList())); + Reflection.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "permission", permission); + Reflection.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "permissionMessage", permissionMessage); commandMap.register(plugin.getName(), pluginCommand); - TabooLib.debug("Command " + command + " created. (" + plugin.getName() + ")"); -// if (!TabooLib.isTabooLib(plugin) && !silence) { -// TLocale.Logger.info("COMMANDS.INTERNAL.COMMAND-CREATE", plugin.getName(), command); -// } + TabooLibAPI.debug("Command " + command + " created. (" + plugin.getName() + ")"); return true; } catch (Exception e) { TLocale.Logger.error("COMMANDS.INTERNAL.COMMAND-CREATE-FAILED", plugin.getName(), command, e.toString()); @@ -129,40 +112,23 @@ public class TCommandHandler implements Listener { registerPluginCommand( plugin, command, - ArrayUtils.skipEmpty(tCommand.description(), "Registered by TabooLib."), - ArrayUtils.skipEmpty(tCommand.usage(), "/" + command), - ArrayUtils.skipEmpty(ArrayUtils.asList(tCommand.aliases()), new ArrayList<>()), - ArrayUtils.skipEmpty(tCommand.permission()), - ArrayUtils.skipEmpty(tCommand.permissionMessage()), + ArrayUtil.skipEmpty(tCommand.description(), "Registered by TabooLib."), + ArrayUtil.skipEmpty(tCommand.usage(), "/" + command), + ArrayUtil.skipEmpty(ArrayUtil.asList(tCommand.aliases()), new ArrayList<>()), + ArrayUtil.skipEmpty(tCommand.permission()), + ArrayUtil.skipEmpty(tCommand.permissionMessage()), baseMainCommand, baseMainCommand); } return BaseMainCommand.createCommandExecutor(command, baseMainCommand); } - /** - * 注册所有插件的所有 TCommand 命令 - */ - public static void registerCommands() { - for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) { - try { - registerCommand(plugin); - } catch (Exception e) { - e.printStackTrace(); - } - } - } /** * 注册插件的所有 TCommand 命令 - * - * @param plugin 插件 */ public static void registerCommand(Plugin plugin) { - if (!(plugin.equals(TabooLib.instance()) || TabooLib.isDependTabooLib(plugin))) { - return; - } - for (Class pluginClass : FileUtils.getClasses(plugin)) { + for (Class pluginClass : Files.getClasses(plugin)) { if (BaseMainCommand.class.isAssignableFrom(pluginClass) && pluginClass.isAnnotationPresent(TCommand.class)) { TCommand tCommand = (TCommand) pluginClass.getAnnotation(TCommand.class); try { @@ -174,16 +140,6 @@ public class TCommandHandler implements Listener { } } - /** - * 获取插件注册的命令 - * - * @param command 命令名称 - * @return {@link Command} - */ - public static Command getPluginCommand(String command) { - return commandMap.getCommand(command); - } - // ********************************* // // Getter and Setter diff --git a/src/main/scala/me/skymc/taboolib/commands/internal/BaseMainCommand.java b/src/main/scala/io/izzel/taboolib/module/command/base/BaseMainCommand.java similarity index 74% rename from src/main/scala/me/skymc/taboolib/commands/internal/BaseMainCommand.java rename to src/main/scala/io/izzel/taboolib/module/command/base/BaseMainCommand.java index 6f10d22..48012ef 100644 --- a/src/main/scala/me/skymc/taboolib/commands/internal/BaseMainCommand.java +++ b/src/main/scala/io/izzel/taboolib/module/command/base/BaseMainCommand.java @@ -1,22 +1,25 @@ -package me.skymc.taboolib.commands.internal; +package io.izzel.taboolib.module.command.base; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.commands.internal.type.*; -import me.skymc.taboolib.string.ArrayUtils; -import me.skymc.taboolib.string.StringUtils; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.Version; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.util.ArrayUtil; +import io.izzel.taboolib.util.Strings; import org.bukkit.Bukkit; import org.bukkit.command.*; import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitRunnable; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.util.*; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Collectors; @@ -28,7 +31,7 @@ public abstract class BaseMainCommand implements CommandExecutor, TabExecutor { private PluginCommand registerCommand; private List> linkClasses = new CopyOnWriteArrayList<>(); - private List subCommands = new CopyOnWriteArrayList<>(); + private List subCommands = new CopyOnWriteArrayList<>(); public static BaseMainCommand createCommandExecutor(String command, BaseMainCommand baseMainCommand) { Preconditions.checkArgument(Bukkit.getPluginCommand(command) != null, "PluginCommand \"" + command + "\" not found"); @@ -46,7 +49,7 @@ public abstract class BaseMainCommand implements CommandExecutor, TabExecutor { public static void loadCommandRegister(BaseMainCommand baseMainCommand) { List methods = new ArrayList<>(); List fields = new ArrayList<>(); - baseMainCommand.getLinkClasses().forEach(clazz -> Arrays.stream(clazz.getDeclaredMethods()).filter(method -> method.getAnnotation(CommandRegister.class) != null).forEach(methods::add)); + baseMainCommand.getLinkClasses().forEach(clazz -> java.util.Arrays.stream(clazz.getDeclaredMethods()).filter(method -> method.getAnnotation(CommandRegister.class) != null).forEach(methods::add)); if (methods.size() > 0) { methods.sort(Comparator.comparingDouble(a -> a.getAnnotation(CommandRegister.class).priority())); methods.forEach(x -> { @@ -57,13 +60,13 @@ public abstract class BaseMainCommand implements CommandExecutor, TabExecutor { } }); } - baseMainCommand.getLinkClasses().forEach(clazz -> Arrays.stream(clazz.getDeclaredFields()).filter(field -> field.getAnnotation(CommandRegister.class) != null && field.getType().equals(BaseSubCommand.class)).forEach(field -> fields.add(new CommandField(field, clazz)))); + baseMainCommand.getLinkClasses().forEach(clazz -> java.util.Arrays.stream(clazz.getDeclaredFields()).filter(field -> field.getAnnotation(CommandRegister.class) != null && field.getType().equals(io.izzel.taboolib.module.command.base.BaseSubCommand.class)).forEach(field -> fields.add(new CommandField(field, clazz)))); if (fields.size() > 0) { fields.sort(Comparator.comparingDouble(commandField -> commandField.getField().getAnnotation(CommandRegister.class).priority())); fields.forEach(commandField -> { try { commandField.getField().setAccessible(true); - BaseSubCommand subCommand = (BaseSubCommand) commandField.getField().get(commandField.getParent().newInstance()); + io.izzel.taboolib.module.command.base.BaseSubCommand subCommand = (io.izzel.taboolib.module.command.base.BaseSubCommand) commandField.getField().get(commandField.getParent().newInstance()); subCommand.setLabel(commandField.getField().getName()); baseMainCommand.registerSubCommand(subCommand); } catch (Exception ignored) { @@ -71,8 +74,7 @@ public abstract class BaseMainCommand implements CommandExecutor, TabExecutor { }); } if (methods.size() + fields.size() > 0) { - TabooLib.debug("Registered " + (methods.size() + fields.size()) + " sub-command with " + baseMainCommand.getRegisterCommand().getName() + " (" + baseMainCommand.getRegisterCommand().getPlugin().getName() + ")"); -// TLocale.Logger.info("COMMANDS.INTERNAL.COMMAND-REGISTER", baseMainCommand.getRegisterCommand().getPlugin().getName(), baseMainCommand.getRegisterCommand().getName(), String.valueOf(methods.size() + fields.size())); + TabooLibAPI.debug("Registered " + (methods.size() + fields.size()) + " sub-command with " + baseMainCommand.getRegisterCommand().getName() + " (" + baseMainCommand.getRegisterCommand().getPlugin().getName() + ")"); } } @@ -88,11 +90,11 @@ public abstract class BaseMainCommand implements CommandExecutor, TabExecutor { return linkClasses; } - public List getSubCommands() { + public List getSubCommands() { return subCommands; } - public void registerSubCommand(BaseSubCommand subCommand) { + public void registerSubCommand(io.izzel.taboolib.module.command.base.BaseSubCommand subCommand) { if (subCommand != null) { Preconditions.checkArgument(subCommand.getLabel() != null, "Command label can not be null"); Preconditions.checkArgument(subCommand.getArguments() != null, "Command arguments can not be null"); @@ -120,7 +122,7 @@ public abstract class BaseMainCommand implements CommandExecutor, TabExecutor { }); return label.stream().filter(l -> args[0].isEmpty() || l.toLowerCase().startsWith(args[0].toLowerCase())).collect(Collectors.toList()); } - for (BaseSubCommand subCommand : subCommands) { + for (io.izzel.taboolib.module.command.base.BaseSubCommand subCommand : subCommands) { CommandArgument[] arguments = subCommand.getArguments(); if (args[0].equalsIgnoreCase(subCommand.getLabel()) && args.length - 1 <= arguments.length) { CommandTab commandTab = arguments[args.length - 2].getTab(); @@ -137,15 +139,15 @@ public abstract class BaseMainCommand implements CommandExecutor, TabExecutor { if (args.length == 0) { onCommandHelp(sender, command, label, args); } else { - for (BaseSubCommand subCommand : subCommands) { - if (subCommand == null || !(args[0].equalsIgnoreCase(subCommand.getLabel()) || Arrays.stream(subCommand.getAliases()).anyMatch(args[0]::equalsIgnoreCase)) || !hasPermission(sender, subCommand)) { + for (io.izzel.taboolib.module.command.base.BaseSubCommand subCommand : subCommands) { + if (subCommand == null || !(args[0].equalsIgnoreCase(subCommand.getLabel()) || java.util.Arrays.stream(subCommand.getAliases()).anyMatch(args[0]::equalsIgnoreCase)) || !hasPermission(sender, subCommand)) { continue; } if (!isConfirmType(sender, subCommand.getType())) { TLocale.sendTo(sender, "COMMANDS.INTERNAL.TYPE-ERROR", args[0], TLocale.asString("COMMANDS.INTERNAL.TYPE-" + subCommand.getType())); return true; } - String[] subCommandArgs = ArrayUtils.removeFirst(args); + String[] subCommandArgs = ArrayUtil.removeFirst(args); if (subCommand.isParameterConform(subCommandArgs)) { subCommand.onCommand(sender, command, label, subCommand.ignoredLabel() ? subCommandArgs : args); } else { @@ -157,12 +159,12 @@ public abstract class BaseMainCommand implements CommandExecutor, TabExecutor { @Override public void run() { - List commandCompute = subCommands.stream().filter(x -> x != null && hasPermission(sender, x)).sorted((b, a) -> Double.compare(StringUtils.similarDegree(args[0], a.getLabel()), StringUtils.similarDegree(args[0], b.getLabel()))).collect(Collectors.toList()); + List commandCompute = subCommands.stream().filter(x -> x != null && hasPermission(sender, x)).sorted((b, a) -> Double.compare(Strings.similarDegree(args[0], a.getLabel()), Strings.similarDegree(args[0], b.getLabel()))).collect(Collectors.toList()); if (commandCompute.size() > 0) { TLocale.sendTo(sender, "COMMANDS.INTERNAL.ERROR-COMMAND", args[0], commandCompute.get(0).getCommandString(label).trim()); } } - }.runTaskAsynchronously(Main.getInst()); + }.runTaskAsynchronously(TabooLib.getPlugin()); } return true; } @@ -196,7 +198,7 @@ public abstract class BaseMainCommand implements CommandExecutor, TabExecutor { // ********************************* private String getEmptyLine() { - return TabooLib.getVerint() < 10800 ? "~" : ""; + return Version.isAfter(Version.v1_8) ? "" : "~"; } private boolean isConfirmType(CommandSender sender, CommandType commandType) { @@ -206,10 +208,10 @@ public abstract class BaseMainCommand implements CommandExecutor, TabExecutor { } private void disguisedPlugin() { - linkClasses.forEach(clazz -> disguisedPlugin(clazz, (JavaPlugin) registerCommand.getPlugin())); + linkClasses.forEach(clazz -> disguisedPlugin(clazz, registerCommand.getPlugin())); } - private void disguisedPlugin(Class targetClass, JavaPlugin plugin) { + private void disguisedPlugin(Class targetClass, Plugin plugin) { try { Field pluginField = targetClass.getClassLoader().getClass().getDeclaredField("plugin"); pluginField.setAccessible(true); @@ -218,7 +220,7 @@ public abstract class BaseMainCommand implements CommandExecutor, TabExecutor { } } - private boolean hideInHelp(BaseSubCommand baseSubCommand) { + private boolean hideInHelp(io.izzel.taboolib.module.command.base.BaseSubCommand baseSubCommand) { return baseSubCommand != null && baseSubCommand.hideInHelp(); } diff --git a/src/main/scala/me/skymc/taboolib/commands/internal/BaseSubCommand.java b/src/main/scala/io/izzel/taboolib/module/command/base/BaseSubCommand.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/commands/internal/BaseSubCommand.java rename to src/main/scala/io/izzel/taboolib/module/command/base/BaseSubCommand.java index a244d06..0ef8c9f 100644 --- a/src/main/scala/me/skymc/taboolib/commands/internal/BaseSubCommand.java +++ b/src/main/scala/io/izzel/taboolib/module/command/base/BaseSubCommand.java @@ -1,8 +1,6 @@ -package me.skymc.taboolib.commands.internal; +package io.izzel.taboolib.module.command.base; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.commands.internal.type.CommandArgument; -import me.skymc.taboolib.commands.internal.type.CommandType; +import io.izzel.taboolib.locale.TLocale; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; diff --git a/src/main/scala/me/skymc/taboolib/commands/internal/type/CommandArgument.java b/src/main/scala/io/izzel/taboolib/module/command/base/CommandArgument.java similarity index 94% rename from src/main/scala/me/skymc/taboolib/commands/internal/type/CommandArgument.java rename to src/main/scala/io/izzel/taboolib/module/command/base/CommandArgument.java index 20b66a3..432c07b 100644 --- a/src/main/scala/me/skymc/taboolib/commands/internal/type/CommandArgument.java +++ b/src/main/scala/io/izzel/taboolib/module/command/base/CommandArgument.java @@ -1,6 +1,6 @@ -package me.skymc.taboolib.commands.internal.type; +package io.izzel.taboolib.module.command.base; -import com.ilummc.tlib.resources.TLocale; +import io.izzel.taboolib.locale.TLocale; import java.util.Objects; diff --git a/src/main/scala/me/skymc/taboolib/commands/internal/type/CommandField.java b/src/main/scala/io/izzel/taboolib/module/command/base/CommandField.java similarity index 89% rename from src/main/scala/me/skymc/taboolib/commands/internal/type/CommandField.java rename to src/main/scala/io/izzel/taboolib/module/command/base/CommandField.java index 77dd269..3e3d2f3 100644 --- a/src/main/scala/me/skymc/taboolib/commands/internal/type/CommandField.java +++ b/src/main/scala/io/izzel/taboolib/module/command/base/CommandField.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.commands.internal.type; +package io.izzel.taboolib.module.command.base; import java.lang.reflect.Field; diff --git a/src/main/scala/me/skymc/taboolib/commands/internal/type/CommandRegister.java b/src/main/scala/io/izzel/taboolib/module/command/base/CommandRegister.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/commands/internal/type/CommandRegister.java rename to src/main/scala/io/izzel/taboolib/module/command/base/CommandRegister.java index 8f10049..5f2dbac 100644 --- a/src/main/scala/me/skymc/taboolib/commands/internal/type/CommandRegister.java +++ b/src/main/scala/io/izzel/taboolib/module/command/base/CommandRegister.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.commands.internal.type; +package io.izzel.taboolib.module.command.base; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/scala/me/skymc/taboolib/commands/internal/type/CommandTab.java b/src/main/scala/io/izzel/taboolib/module/command/base/CommandTab.java similarity index 77% rename from src/main/scala/me/skymc/taboolib/commands/internal/type/CommandTab.java rename to src/main/scala/io/izzel/taboolib/module/command/base/CommandTab.java index bfa552d..0d13172 100644 --- a/src/main/scala/me/skymc/taboolib/commands/internal/type/CommandTab.java +++ b/src/main/scala/io/izzel/taboolib/module/command/base/CommandTab.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.commands.internal.type; +package io.izzel.taboolib.module.command.base; import java.util.List; diff --git a/src/main/scala/me/skymc/taboolib/commands/internal/type/CommandType.java b/src/main/scala/io/izzel/taboolib/module/command/base/CommandType.java similarity index 66% rename from src/main/scala/me/skymc/taboolib/commands/internal/type/CommandType.java rename to src/main/scala/io/izzel/taboolib/module/command/base/CommandType.java index 957c300..713c158 100644 --- a/src/main/scala/me/skymc/taboolib/commands/internal/type/CommandType.java +++ b/src/main/scala/io/izzel/taboolib/module/command/base/CommandType.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.commands.internal.type; +package io.izzel.taboolib.module.command.base; /** * @author Bkm016 diff --git a/src/main/scala/me/skymc/taboolib/commands/builder/type/CompleterCommand.java b/src/main/scala/io/izzel/taboolib/module/command/lite/CompleterCommand.java similarity index 63% rename from src/main/scala/me/skymc/taboolib/commands/builder/type/CompleterCommand.java rename to src/main/scala/io/izzel/taboolib/module/command/lite/CompleterCommand.java index c152b75..f901ae9 100644 --- a/src/main/scala/me/skymc/taboolib/commands/builder/type/CompleterCommand.java +++ b/src/main/scala/io/izzel/taboolib/module/command/lite/CompleterCommand.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.commands.builder.type; +package io.izzel.taboolib.module.command.lite; import org.bukkit.command.CommandSender; @@ -9,6 +9,6 @@ import org.bukkit.command.CommandSender; */ public interface CompleterCommand { - boolean execute(CommandSender sender, String[] args); + void execute(CommandSender sender, String[] args); } \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/commands/builder/type/CompleterTab.java b/src/main/scala/io/izzel/taboolib/module/command/lite/CompleterTab.java similarity index 84% rename from src/main/scala/me/skymc/taboolib/commands/builder/type/CompleterTab.java rename to src/main/scala/io/izzel/taboolib/module/command/lite/CompleterTab.java index edd6f08..72b928c 100644 --- a/src/main/scala/me/skymc/taboolib/commands/builder/type/CompleterTab.java +++ b/src/main/scala/io/izzel/taboolib/module/command/lite/CompleterTab.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.commands.builder.type; +package io.izzel.taboolib.module.command.lite; import org.bukkit.command.CommandSender; diff --git a/src/main/scala/me/skymc/taboolib/commands/builder/SimpleCommandBuilder.java b/src/main/scala/io/izzel/taboolib/module/command/lite/SimpleCommandBuilder.java similarity index 82% rename from src/main/scala/me/skymc/taboolib/commands/builder/SimpleCommandBuilder.java rename to src/main/scala/io/izzel/taboolib/module/command/lite/SimpleCommandBuilder.java index de03b95..8bc7bc4 100644 --- a/src/main/scala/me/skymc/taboolib/commands/builder/SimpleCommandBuilder.java +++ b/src/main/scala/io/izzel/taboolib/module/command/lite/SimpleCommandBuilder.java @@ -1,11 +1,8 @@ -package me.skymc.taboolib.commands.builder; +package io.izzel.taboolib.module.command.lite; import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; -import me.skymc.taboolib.commands.builder.type.CompleterCommand; -import me.skymc.taboolib.commands.builder.type.CompleterTab; -import me.skymc.taboolib.commands.internal.TCommandHandler; -import me.skymc.taboolib.string.ArrayUtils; +import io.izzel.taboolib.module.command.TCommandHandler; +import io.izzel.taboolib.util.ArrayUtil; import org.bukkit.plugin.Plugin; import java.util.ArrayList; @@ -19,7 +16,7 @@ import java.util.List; public class SimpleCommandBuilder { public static final CompleterTab EMPTY_COMPLETER_TAB = ((sender, args) -> new ArrayList<>()); - public static final CompleterCommand EMPTY_COMPLETER_COMMAND = ((sender, args) -> false); + public static final CompleterCommand EMPTY_COMPLETER_COMMAND = ((sender, args) -> {}); private String command; private Plugin plugin; @@ -30,7 +27,6 @@ public class SimpleCommandBuilder { private String permissionMessage; private CompleterTab completerTab = EMPTY_COMPLETER_TAB; private CompleterCommand completerCommand = EMPTY_COMPLETER_COMMAND; - private boolean silence; private boolean forceRegister; private boolean build; @@ -40,7 +36,6 @@ public class SimpleCommandBuilder { this.description = ""; this.usage = "/" + command; this.aliases = new ArrayList<>(); - this.silence = false; this.build = false; } @@ -69,7 +64,7 @@ public class SimpleCommandBuilder { } public SimpleCommandBuilder aliases(String... aliases) { - this.aliases = ArrayUtils.asList(aliases); + this.aliases = ArrayUtil.asList(aliases); return this; } @@ -93,12 +88,6 @@ public class SimpleCommandBuilder { return this; } - @Deprecated - public SimpleCommandBuilder silence() { - this.silence = true; - return this; - } - public SimpleCommandBuilder forceRegister() { this.forceRegister = true; return this; @@ -121,12 +110,8 @@ public class SimpleCommandBuilder { permission, permissionMessage, (sender, command, s, args) -> { - try { - return completerCommand.execute(sender, args); - } catch (Throwable t) { - t.printStackTrace(); - } - return false; + completerCommand.execute(sender, args); + return true; }, (sender, command, s, args) -> { try { @@ -134,9 +119,8 @@ public class SimpleCommandBuilder { } catch (Throwable t) { t.printStackTrace(); } - return Lists.newArrayList(); - }, - silence); + return null; + }); build = true; return this; } @@ -183,10 +167,6 @@ public class SimpleCommandBuilder { return completerCommand; } - public boolean isSilence() { - return silence; - } - public boolean isForceRegister() { return forceRegister; } diff --git a/src/main/scala/io/izzel/taboolib/module/compat/EconomyHook.java b/src/main/scala/io/izzel/taboolib/module/compat/EconomyHook.java new file mode 100644 index 0000000..20cc306 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/module/compat/EconomyHook.java @@ -0,0 +1,55 @@ +package io.izzel.taboolib.module.compat; + +import io.izzel.taboolib.module.inject.TFunction; +import net.milkbowl.vault.economy.Economy; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.plugin.RegisteredServiceProvider; + +/** + * @Author 坏黑 + * @Since 2019-07-05 18:50 + */ +@TFunction(enable = "init") +public class EconomyHook { + + private static Economy economy; + + static void init() { + if (Bukkit.getPluginManager().getPlugin("Vault") == null) { + return; + } + RegisteredServiceProvider l = Bukkit.getServer().getServicesManager().getRegistration(Economy.class); + if (l != null) { + economy = l.getProvider(); + } + } + + public static void remove(OfflinePlayer p, double d) { + economy.withdrawPlayer(p, d); + } + + public static void add(OfflinePlayer p, double d) { + economy.depositPlayer(p, d); + } + + public static void set(OfflinePlayer p, double d) { + add(p, d - get(p)); + } + + public static double get(OfflinePlayer p) { + return economy.getBalance(p); + } + + public static void create(OfflinePlayer p) { + economy.createPlayerAccount(p); + } + + public static boolean exists() { + return economy != null; + } + + public static net.milkbowl.vault.economy.Economy getEconomy() { + return economy; + } +} diff --git a/src/main/scala/io/izzel/taboolib/module/compat/PermissionHook.java b/src/main/scala/io/izzel/taboolib/module/compat/PermissionHook.java new file mode 100644 index 0000000..b2bc5d5 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/module/compat/PermissionHook.java @@ -0,0 +1,39 @@ +package io.izzel.taboolib.module.compat; + +import io.izzel.taboolib.module.inject.TFunction; +import net.milkbowl.vault.permission.Permission; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.RegisteredServiceProvider; + +import java.util.Arrays; + +@TFunction(enable = "init") +public class PermissionHook { + + private static Permission perms; + + static void init() { + if (Bukkit.getPluginManager().getPlugin("Vault") == null) { + return; + } + RegisteredServiceProvider rsp = Bukkit.getServer().getServicesManager().getRegistration(Permission.class); + perms = rsp.getProvider(); + } + + public static Permission getPermission() { + return perms; + } + + public static void addPermission(Player player, String perm) { + perms.playerAdd(player, perm); + } + + public static void removePermission(Player player, String perm) { + perms.playerRemove(player, perm); + } + + public static boolean hasPermission(Player player, String perm) { + return perms.playerHas(player, perm) || Arrays.stream(perms.getPlayerGroups(player)).anyMatch(group -> perms.groupHas(player.getWorld(), group, perm)); + } +} diff --git a/src/main/scala/com/ilummc/tlib/compat/PlaceholderHook.java b/src/main/scala/io/izzel/taboolib/module/compat/PlaceholderHook.java similarity index 87% rename from src/main/scala/com/ilummc/tlib/compat/PlaceholderHook.java rename to src/main/scala/io/izzel/taboolib/module/compat/PlaceholderHook.java index c0b26c8..17efce8 100644 --- a/src/main/scala/com/ilummc/tlib/compat/PlaceholderHook.java +++ b/src/main/scala/io/izzel/taboolib/module/compat/PlaceholderHook.java @@ -1,15 +1,17 @@ -package com.ilummc.tlib.compat; +package io.izzel.taboolib.module.compat; import me.clip.placeholderapi.PlaceholderAPI; +import io.izzel.taboolib.module.inject.TFunction; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +@TFunction(enable = "init") public abstract class PlaceholderHook { private static PlaceholderHook impl; - public static void init() { + static void init() { if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { impl = new PlaceholderImpl(); } else { diff --git a/src/main/scala/me/skymc/taboolib/support/SupportWorldGuard.java b/src/main/scala/io/izzel/taboolib/module/compat/WorldGuardHook.java similarity index 94% rename from src/main/scala/me/skymc/taboolib/support/SupportWorldGuard.java rename to src/main/scala/io/izzel/taboolib/module/compat/WorldGuardHook.java index 836967c..1b43426 100644 --- a/src/main/scala/me/skymc/taboolib/support/SupportWorldGuard.java +++ b/src/main/scala/io/izzel/taboolib/module/compat/WorldGuardHook.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.support; +package io.izzel.taboolib.module.compat; import com.google.common.base.Preconditions; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -19,13 +19,13 @@ import java.util.stream.Collectors; /** * @Author AgarthaLib */ -public class SupportWorldGuard { +public class WorldGuardHook { - public static final SupportWorldGuard INSTANCE = new SupportWorldGuard(); + public static final WorldGuardHook INSTANCE = new WorldGuardHook(); private WorldGuardPlugin worldGuard; private Method getRegionManager; - public SupportWorldGuard() { + public WorldGuardHook() { Preconditions.checkNotNull(Bukkit.getServer().getPluginManager().getPlugin("WorldGuard"), "WorldGuard was not found."); worldGuard = WorldGuardPlugin.inst(); if (!worldGuard.getDescription().getVersion().startsWith("7")) { diff --git a/src/main/scala/me/skymc/taboolib/common/configuration/TConfiguration.java b/src/main/scala/io/izzel/taboolib/module/config/TConfig.java similarity index 57% rename from src/main/scala/me/skymc/taboolib/common/configuration/TConfiguration.java rename to src/main/scala/io/izzel/taboolib/module/config/TConfig.java index 8c948ce..6ad1bbc 100644 --- a/src/main/scala/me/skymc/taboolib/common/configuration/TConfiguration.java +++ b/src/main/scala/io/izzel/taboolib/module/config/TConfig.java @@ -1,12 +1,12 @@ -package me.skymc.taboolib.common.configuration; +package io.izzel.taboolib.module.config; import com.google.common.collect.Maps; -import com.ilummc.tlib.TLib; -import com.ilummc.tlib.logger.TLogger; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.util.Ref; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.module.logger.TLogger; +import io.izzel.taboolib.util.Files; +import io.izzel.taboolib.util.Ref; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.Plugin; @@ -22,56 +22,36 @@ import java.util.Optional; * @Author sky * @Since 2018-09-08 15:00 */ -public class TConfiguration extends YamlConfiguration { +public class TConfig extends YamlConfiguration { private static Map> files = Maps.newHashMap(); private File file; private Runnable runnable; - private TConfiguration(File file, Plugin plugin) { + private TConfig(File file, Plugin plugin) { files.computeIfAbsent(plugin.getName(), name -> new ArrayList<>()).add(file); this.file = file; reload(); - TLib.getTLib().getConfigWatcher().addSimpleListener(this.file, this::reload); - TabooLib.debug("Loaded TConfiguration \"" + file.getName() + "\" from Plugin \"" + plugin.getName() + "\""); + TConfigWatcher.getInst().addSimpleListener(this.file, this::reload); + TabooLibAPI.debug("Loaded TConfiguration \"" + file.getName() + "\" from Plugin \"" + plugin.getName() + "\""); } public static Map> getFiles() { return files; } - /** - * 创建配置文件 - * - * @param file 文件 - * @return {@link TConfiguration} - */ - public static TConfiguration create(File file) { - return new TConfiguration(file, Ref.getCallerPlugin(Ref.getCallerClass(3).orElse(Main.class))); + public static TConfig create(File file) { + return new TConfig(file, Ref.getCallerPlugin(Ref.getCallerClass(3).orElse(TabooLib.class))); } - /** - * 创建配置文件 - * - * @param file 文件 - * @param plugin 插件 - * @return {@link TConfiguration} - */ - public static TConfiguration create(File file, Plugin plugin) { - return new TConfiguration(file, plugin); + public static TConfig create(File file, Plugin plugin) { + return new TConfig(file, plugin); } - /** - * 从插件里释放文件并创建 - * - * @param plugin 插件 - * @param path 目录 - * @return {@link TConfiguration} - */ - public static TConfiguration createInResource(Plugin plugin, String path) { + public static TConfig create(Plugin plugin, String path) { File file = new File(plugin.getDataFolder(), path); if (!file.exists()) { - plugin.saveResource(path, true); + Files.releaseResource(plugin, path, false); } return create(file, plugin); } @@ -89,7 +69,7 @@ public class TConfiguration extends YamlConfiguration { } public void release() { - TLib.getTLib().getConfigWatcher().removeListener(file); + TConfigWatcher.getInst().removeListener(file); } public void reload() { @@ -111,7 +91,7 @@ public class TConfiguration extends YamlConfiguration { return file; } - public TConfiguration listener(Runnable runnable) { + public TConfig listener(Runnable runnable) { this.runnable = runnable; return this; } diff --git a/src/main/scala/com/ilummc/tlib/inject/TConfigWatcher.java b/src/main/scala/io/izzel/taboolib/module/config/TConfigWatcher.java similarity index 93% rename from src/main/scala/com/ilummc/tlib/inject/TConfigWatcher.java rename to src/main/scala/io/izzel/taboolib/module/config/TConfigWatcher.java index 95ef971..9c3b6b1 100644 --- a/src/main/scala/com/ilummc/tlib/inject/TConfigWatcher.java +++ b/src/main/scala/io/izzel/taboolib/module/config/TConfigWatcher.java @@ -1,4 +1,4 @@ -package com.ilummc.tlib.inject; +package io.izzel.taboolib.module.config; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.apache.commons.lang3.tuple.Triple; @@ -19,6 +19,7 @@ import java.util.function.Consumer; */ public class TConfigWatcher { + private static TConfigWatcher configWatcher = new TConfigWatcher(); private final ScheduledExecutorService service = Executors.newScheduledThreadPool(1, new BasicThreadFactory.Builder().namingPattern("TConfigWatcherService-%d").build()); private final Map>> map = new HashMap<>(); @@ -40,6 +41,10 @@ public class TConfigWatcher { }, 1000, 100, TimeUnit.MILLISECONDS); } + public static TConfigWatcher getInst() { + return configWatcher; + } + public void addSimpleListener(File file, Runnable runnable) { addListener(file, null, obj -> runnable.run()); } diff --git a/src/main/scala/com/ilummc/tlib/annotations/Dependencies.java b/src/main/scala/io/izzel/taboolib/module/dependency/Dependencies.java similarity index 86% rename from src/main/scala/com/ilummc/tlib/annotations/Dependencies.java rename to src/main/scala/io/izzel/taboolib/module/dependency/Dependencies.java index a87a8d7..50a1164 100644 --- a/src/main/scala/com/ilummc/tlib/annotations/Dependencies.java +++ b/src/main/scala/io/izzel/taboolib/module/dependency/Dependencies.java @@ -1,4 +1,4 @@ -package com.ilummc.tlib.annotations; +package io.izzel.taboolib.module.dependency; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/scala/com/ilummc/tlib/annotations/Dependency.java b/src/main/scala/io/izzel/taboolib/module/dependency/Dependency.java similarity index 81% rename from src/main/scala/com/ilummc/tlib/annotations/Dependency.java rename to src/main/scala/io/izzel/taboolib/module/dependency/Dependency.java index 9c706c9..26f459f 100644 --- a/src/main/scala/com/ilummc/tlib/annotations/Dependency.java +++ b/src/main/scala/io/izzel/taboolib/module/dependency/Dependency.java @@ -1,6 +1,4 @@ -package com.ilummc.tlib.annotations; - -import com.ilummc.tlib.dependency.TDependency; +package io.izzel.taboolib.module.dependency; import java.lang.annotation.*; diff --git a/src/main/scala/io/izzel/taboolib/module/dependency/TDependency.java b/src/main/scala/io/izzel/taboolib/module/dependency/TDependency.java new file mode 100644 index 0000000..31f5fc4 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/module/dependency/TDependency.java @@ -0,0 +1,62 @@ +package io.izzel.taboolib.module.dependency; + +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.util.Files; + +import java.io.File; +import java.util.Arrays; + +public class TDependency { + + // 阿里 http://maven.aliyun.com/nexus/content/groups/public + public static final String MAVEN_REPO = "http://repo1.maven.org/maven2"; + + /** + * 请求一个插件作为依赖,这个插件将会在所有已经添加的 Jenkins 仓库、Maven 仓库寻找 + *

+ * 阻塞线程进行下载/加载 + * + * @param args 插件名称,下载地址(可选) + * @return 是否成功加载了依赖 + */ + public static boolean requestPlugin(String... args) { + return false; + } + + /** + * 请求一个库作为依赖,这个库将会在 Maven Central、oss.sonatype 以及自定义的 Maven 仓库寻找 + *

+ * 阻塞线程进行下载/加载 + * + * @param type 依赖名,格式为 groupId:artifactId:version + * @return 是否成功加载库,如果加载成功,插件将可以任意调用使用的类 + */ + public static boolean requestLib(String type, String repo, String url) { + // 清理大小为 0 的依赖文件 + File libFolder = new File(TabooLib.getPlugin().getDataFolder(), "/libs"); + if (libFolder.exists()) { + Arrays.stream(libFolder.listFiles()).filter(listFile -> listFile.length() == 0).forEach(File::delete); + } + if (type.matches(".*:.*:.*")) { + String[] arr = type.split(":"); + File file = new File(TabooLib.getPlugin().getDataFolder(), "/libs/" + String.join("-", arr) + ".jar"); + if (file.exists()) { + TDependencyLoader.addToPath(TabooLib.getPlugin(), file); + return true; + } else { + if (downloadMaven(repo, arr[0], arr[1], arr[2], file, url)) { + TDependencyLoader.addToPath(TabooLib.getPlugin(), file); + return true; + } else { + return false; + } + } + } + return false; + } + + private static boolean downloadMaven(String url, String groupId, String artifactId, String version, File target, String dl) { + Files.toFile(Files.readFromURL(dl.length() == 0 ? url + "/" + groupId.replace('.', '/') + "/" + artifactId + "/" + version + "/" + artifactId + "-" + version + ".jar" : dl, ""), Files.file(target)); + return target.length() > 0; + } +} diff --git a/src/main/scala/io/izzel/taboolib/module/dependency/TDependencyInjector.java b/src/main/scala/io/izzel/taboolib/module/dependency/TDependencyInjector.java new file mode 100644 index 0000000..4f386cf --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/module/dependency/TDependencyInjector.java @@ -0,0 +1,40 @@ +package io.izzel.taboolib.module.dependency; + +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.locale.TLocale; +import org.bukkit.plugin.Plugin; + +/** + * @author Izzel_Aliz + */ +public class TDependencyInjector { + + public static Dependency[] getDependencies(Class clazz) { + Dependency[] dependencies = new Dependency[0]; + Dependencies d = clazz.getAnnotation(Dependencies.class); + if (d != null) { + dependencies = d.value(); + } + Dependency d2 = clazz.getAnnotation(Dependency.class); + if (d2 != null) { + dependencies = new Dependency[] {d2}; + } + return dependencies; + } + + public static void inject(Plugin plugin, Class clazz) { + inject(plugin.getName(), clazz); + } + + public static void inject(String name, Class clazz) { + for (Dependency dependency : getDependencies(clazz)) { + if (dependency.type() == Dependency.Type.LIBRARY) { + if (TDependency.requestLib(dependency.maven(), dependency.mavenRepo(), dependency.url())) { + TabooLibAPI.debug(" Loaded " + String.join(":", dependency.maven()) + " (" + name + ")"); + } else { + TLocale.Logger.warn("DEPENDENCY.LIBRARY-LOAD-FAIL", name, String.join(":", dependency.maven())); + } + } + } + } +} diff --git a/src/main/scala/me/skymc/taboolib/common/playercontainer/Container.java b/src/main/scala/io/izzel/taboolib/module/inject/Container.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/common/playercontainer/Container.java rename to src/main/scala/io/izzel/taboolib/module/inject/Container.java index 2d9dcbf..c5319fe 100644 --- a/src/main/scala/me/skymc/taboolib/common/playercontainer/Container.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/Container.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.playercontainer; +package io.izzel.taboolib.module.inject; /** * @author sky diff --git a/src/main/scala/me/skymc/taboolib/common/playercontainer/PlayerContainer.java b/src/main/scala/io/izzel/taboolib/module/inject/PlayerContainer.java similarity index 87% rename from src/main/scala/me/skymc/taboolib/common/playercontainer/PlayerContainer.java rename to src/main/scala/io/izzel/taboolib/module/inject/PlayerContainer.java index 3f35b81..a586d9d 100644 --- a/src/main/scala/me/skymc/taboolib/common/playercontainer/PlayerContainer.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/PlayerContainer.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.playercontainer; +package io.izzel.taboolib.module.inject; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/scala/me/skymc/taboolib/common/playercontainer/PlayerContainerLoader.java b/src/main/scala/io/izzel/taboolib/module/inject/PlayerContainerLoader.java similarity index 84% rename from src/main/scala/me/skymc/taboolib/common/playercontainer/PlayerContainerLoader.java rename to src/main/scala/io/izzel/taboolib/module/inject/PlayerContainerLoader.java index 5cbc001..b0547d2 100644 --- a/src/main/scala/me/skymc/taboolib/common/playercontainer/PlayerContainerLoader.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/PlayerContainerLoader.java @@ -1,9 +1,7 @@ -package me.skymc.taboolib.common.playercontainer; +package io.izzel.taboolib.module.inject; -import com.ilummc.tlib.logger.TLogger; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.TabooLibLoader; -import org.bukkit.Bukkit; +import io.izzel.taboolib.TabooLibLoader; +import io.izzel.taboolib.module.logger.TLogger; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -21,13 +19,10 @@ import java.util.concurrent.ConcurrentHashMap; * @Author sky * @Since 2018-09-14 23:45 */ +@TListener public class PlayerContainerLoader implements Listener, TabooLibLoader.Loader { - Map> pluginContainer = new ConcurrentHashMap<>(); - - PlayerContainerLoader() { - Bukkit.getPluginManager().registerEvents(this, TabooLib.instance()); - } + static Map> pluginContainer = new ConcurrentHashMap<>(); @Override public void postLoad(Plugin plugin, Class pluginClass) { diff --git a/src/main/scala/me/skymc/taboolib/common/function/TFunction.java b/src/main/scala/io/izzel/taboolib/module/inject/TFunction.java similarity index 90% rename from src/main/scala/me/skymc/taboolib/common/function/TFunction.java rename to src/main/scala/io/izzel/taboolib/module/inject/TFunction.java index 4bc3925..15905d2 100644 --- a/src/main/scala/me/skymc/taboolib/common/function/TFunction.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TFunction.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.function; +package io.izzel.taboolib.module.inject; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/scala/me/skymc/taboolib/common/function/TFunctionLoader.java b/src/main/scala/io/izzel/taboolib/module/inject/TFunctionLoader.java similarity index 82% rename from src/main/scala/me/skymc/taboolib/common/function/TFunctionLoader.java rename to src/main/scala/io/izzel/taboolib/module/inject/TFunctionLoader.java index 1ab3d4e..af4b066 100644 --- a/src/main/scala/me/skymc/taboolib/common/function/TFunctionLoader.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TFunctionLoader.java @@ -1,8 +1,8 @@ -package me.skymc.taboolib.common.function; +package io.izzel.taboolib.module.inject; -import com.ilummc.tlib.logger.TLogger; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.TabooLibLoader; +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.TabooLibLoader; +import io.izzel.taboolib.module.logger.TLogger; import org.bukkit.plugin.Plugin; import java.lang.reflect.Method; @@ -26,7 +26,7 @@ public class TFunctionLoader implements TabooLibLoader.Loader { } method.setAccessible(true); method.invoke(null); - TabooLib.debug("Function " + pluginClass.getSimpleName() + " loaded. (" + plugin.getName() + ")"); + TabooLibAPI.debug("Function " + pluginClass.getSimpleName() + " loaded. (" + plugin.getName() + ")"); } catch (NoSuchMethodException ignore) { } catch (Exception e) { TLogger.getGlobalLogger().warn("TFunction load Failed: " + pluginClass.getName()); @@ -47,7 +47,7 @@ public class TFunctionLoader implements TabooLibLoader.Loader { } method.setAccessible(true); method.invoke(null); - TabooLib.debug("Function " + pluginClass.getSimpleName() + " unloaded. (" + plugin.getName() + ")"); + TabooLibAPI.debug("Function " + pluginClass.getSimpleName() + " unloaded. (" + plugin.getName() + ")"); } catch (NoSuchMethodException ignore) { } catch (Exception e) { TLogger.getGlobalLogger().warn("TFunction unload Failed: " + pluginClass.getName()); diff --git a/src/main/scala/me/skymc/taboolib/common/inject/TInject.java b/src/main/scala/io/izzel/taboolib/module/inject/TInject.java similarity index 89% rename from src/main/scala/me/skymc/taboolib/common/inject/TInject.java rename to src/main/scala/io/izzel/taboolib/module/inject/TInject.java index c1d9e5d..08b617e 100644 --- a/src/main/scala/me/skymc/taboolib/common/inject/TInject.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TInject.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.inject; +package io.izzel.taboolib.module.inject; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/scala/me/skymc/taboolib/common/inject/TInjectLoader.java b/src/main/scala/io/izzel/taboolib/module/inject/TInjectLoader.java similarity index 84% rename from src/main/scala/me/skymc/taboolib/common/inject/TInjectLoader.java rename to src/main/scala/io/izzel/taboolib/module/inject/TInjectLoader.java index d0423bb..fc244e0 100644 --- a/src/main/scala/me/skymc/taboolib/common/inject/TInjectLoader.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TInjectLoader.java @@ -1,15 +1,15 @@ -package me.skymc.taboolib.common.inject; +package io.izzel.taboolib.module.inject; import com.google.common.collect.Maps; -import com.ilummc.tlib.logger.TLogger; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.TabooLibLoader; -import me.skymc.taboolib.commands.builder.SimpleCommandBuilder; -import me.skymc.taboolib.common.configuration.TConfiguration; -import me.skymc.taboolib.common.packet.TPacketHandler; -import me.skymc.taboolib.common.packet.TPacketListener; -import me.skymc.taboolib.cooldown.seconds.CooldownPack2; -import me.skymc.taboolib.cooldown.seconds.CooldownUtils2; +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.TabooLibLoader; +import io.izzel.taboolib.module.command.lite.SimpleCommandBuilder; +import io.izzel.taboolib.module.config.TConfig; +import io.izzel.taboolib.module.logger.TLogger; +import io.izzel.taboolib.module.packet.TPacketHandler; +import io.izzel.taboolib.module.packet.TPacketListener; +import io.izzel.taboolib.origin.lite.cooldown.Cooldown; +import io.izzel.taboolib.origin.lite.cooldown.Cooldowns; import org.bukkit.plugin.Plugin; import java.lang.reflect.Field; @@ -50,9 +50,9 @@ public class TInjectLoader implements TabooLibLoader.Loader { } }); // TConfiguration Inject - injectTypes.put(TConfiguration.class, (plugin, field, args, instance) -> { + injectTypes.put(TConfig.class, (plugin, field, args, instance) -> { try { - field.set(instance, TConfiguration.createInResource(plugin, args.length == 0 ? "config.yml" : args[0])); + field.set(instance, TConfig.create(plugin, args.length == 0 ? "config.yml" : args[0])); } catch (Exception e) { e.printStackTrace(); } @@ -74,9 +74,9 @@ public class TInjectLoader implements TabooLibLoader.Loader { } }); // CooldownPack Inject - injectTypes.put(CooldownPack2.class, (plugin, field, args, instance) -> { + injectTypes.put(Cooldown.class, (plugin, field, args, instance) -> { try { - CooldownUtils2.register((CooldownPack2) field.get(instance), plugin); + Cooldowns.register((Cooldown) field.get(instance), plugin); } catch (Throwable t) { t.printStackTrace(); } @@ -142,7 +142,7 @@ public class TInjectLoader implements TabooLibLoader.Loader { try { field.setAccessible(true); injectTask.run(plugin, field, annotation.value(), instance); - TabooLib.debug(field.getName() + " injected. (" + field.getType().getName() + ")"); + TabooLibAPI.debug(field.getName() + " injected. (" + field.getType().getName() + ")"); } catch (Throwable e) { TLogger.getGlobalLogger().error(field.getName() + " inject failed: " + e.getMessage() + " (" + field.getType().getName() + ")"); if (e.getMessage() == null) { diff --git a/src/main/scala/me/skymc/taboolib/common/inject/TInjectTask.java b/src/main/scala/io/izzel/taboolib/module/inject/TInjectTask.java similarity index 84% rename from src/main/scala/me/skymc/taboolib/common/inject/TInjectTask.java rename to src/main/scala/io/izzel/taboolib/module/inject/TInjectTask.java index 8dc7b76..e0f342a 100644 --- a/src/main/scala/me/skymc/taboolib/common/inject/TInjectTask.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TInjectTask.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.inject; +package io.izzel.taboolib.module.inject; import org.bukkit.plugin.Plugin; diff --git a/src/main/scala/me/skymc/taboolib/listener/TListener.java b/src/main/scala/io/izzel/taboolib/module/inject/TListener.java similarity index 94% rename from src/main/scala/me/skymc/taboolib/listener/TListener.java rename to src/main/scala/io/izzel/taboolib/module/inject/TListener.java index 2ce6682..4f2d4ae 100644 --- a/src/main/scala/me/skymc/taboolib/listener/TListener.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TListener.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.listener; +package io.izzel.taboolib.module.inject; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/scala/me/skymc/taboolib/listener/TListenerHandler.java b/src/main/scala/io/izzel/taboolib/module/inject/TListenerHandler.java similarity index 77% rename from src/main/scala/me/skymc/taboolib/listener/TListenerHandler.java rename to src/main/scala/io/izzel/taboolib/module/inject/TListenerHandler.java index 92243bd..68f4240 100644 --- a/src/main/scala/me/skymc/taboolib/listener/TListenerHandler.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TListenerHandler.java @@ -1,18 +1,15 @@ -package me.skymc.taboolib.listener; +package io.izzel.taboolib.module.inject; -import com.ilummc.tlib.logger.TLogger; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.TabooLibLoader; -import me.skymc.taboolib.cronus.util.StringExpression; -import me.skymc.taboolib.events.TPluginEnableEvent; -import me.skymc.taboolib.methods.ReflectionUtils; +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.TabooLibLoader; +import io.izzel.taboolib.Version; +import io.izzel.taboolib.module.logger.TLogger; +import io.izzel.taboolib.origin.cronus.util.StringExpression; +import io.izzel.taboolib.util.Strings; +import io.izzel.taboolib.util.Reflection; import org.bukkit.Bukkit; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; -import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.plugin.Plugin; import java.lang.reflect.Method; @@ -22,8 +19,7 @@ import java.util.*; * @Author sky * @Since 2018-08-22 13:48 */ -@TListener -public class TListenerHandler implements Listener { +public class TListenerHandler { private static HashMap> listeners = new HashMap<>(); @@ -52,7 +48,7 @@ public class TListenerHandler implements Listener { try { TListener tListener = pluginClass.getAnnotation(TListener.class); // 检查版本 - if (!new StringExpression(tListener.version()).isSelect(TabooLib.getVersionNumber())) { + if (!new StringExpression(tListener.version()).isSelect(Version.getCurrentVersion().getVersionInt())) { continue; } // 检查注册条件 @@ -62,16 +58,16 @@ public class TListenerHandler implements Listener { } } // 实例化监听器 - Listener listener = plugin.getClass().equals(pluginClass) ? (Listener) plugin : (Listener) ReflectionUtils.instantiateObject(pluginClass); + Listener listener = plugin.getClass().equals(pluginClass) ? (Listener) plugin : (Listener) Reflection.instantiateObject(pluginClass); try { listeners.computeIfAbsent(plugin.getName(), name -> new ArrayList<>()).add(listener); - TabooLib.debug("Listener " + listener.getClass().getSimpleName() + " setup successfully. (" + plugin.getName() + ")"); + TabooLibAPI.debug("Listener " + listener.getClass().getSimpleName() + " setup successfully. (" + plugin.getName() + ")"); } catch (Exception e) { TLogger.getGlobalLogger().warn("TListener setup Failed: " + pluginClass.getName()); e.printStackTrace(); } } catch (Exception e) { - TabooLib.debug("Listener " + pluginClass.getSimpleName() + "(" + plugin.getName() + ")" + " setup failed: " + e.toString()); + TabooLibAPI.debug("Listener " + pluginClass.getSimpleName() + "(" + plugin.getName() + ")" + " setup failed: " + e.toString()); } } } @@ -124,7 +120,7 @@ public class TListenerHandler implements Listener { } // 注册监听 Bukkit.getPluginManager().registerEvents(listener, plugin); - TabooLib.debug("Listener " + listener.getClass().getSimpleName() + " registered. (" + plugin.getName() + ")"); + TabooLibAPI.debug("Listener " + listener.getClass().getSimpleName() + " registered. (" + plugin.getName() + ")"); } }); } @@ -169,21 +165,4 @@ public class TListenerHandler implements Listener { public static HashMap> getListeners() { return listeners; } - - @EventHandler(priority = EventPriority.LOW) - public void onPluginEnable(TPluginEnableEvent e) { - try { - setupListener(e.getPlugin()); - Bukkit.getScheduler().runTask(TabooLib.instance(), () -> registerListener(e.getPlugin())); - } catch (Exception ignored) { - } - } - - @EventHandler - public void onPluginDisable(PluginDisableEvent e) { - try { - cancelListener(e.getPlugin()); - } catch (Exception ignored) { - } - } } diff --git a/src/main/scala/me/skymc/taboolib/common/schedule/TSchedule.java b/src/main/scala/io/izzel/taboolib/module/inject/TSchedule.java similarity index 90% rename from src/main/scala/me/skymc/taboolib/common/schedule/TSchedule.java rename to src/main/scala/io/izzel/taboolib/module/inject/TSchedule.java index c83281d..90b1b7b 100644 --- a/src/main/scala/me/skymc/taboolib/common/schedule/TSchedule.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TSchedule.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.schedule; +package io.izzel.taboolib.module.inject; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/scala/me/skymc/taboolib/common/schedule/TScheduleData.java b/src/main/scala/io/izzel/taboolib/module/inject/TScheduleData.java similarity index 92% rename from src/main/scala/me/skymc/taboolib/common/schedule/TScheduleData.java rename to src/main/scala/io/izzel/taboolib/module/inject/TScheduleData.java index 15ab627..befedce 100644 --- a/src/main/scala/me/skymc/taboolib/common/schedule/TScheduleData.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TScheduleData.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.schedule; +package io.izzel.taboolib.module.inject; import org.bukkit.scheduler.BukkitRunnable; diff --git a/src/main/scala/me/skymc/taboolib/common/schedule/TScheduleLoader.java b/src/main/scala/io/izzel/taboolib/module/inject/TScheduleLoader.java similarity index 69% rename from src/main/scala/me/skymc/taboolib/common/schedule/TScheduleLoader.java rename to src/main/scala/io/izzel/taboolib/module/inject/TScheduleLoader.java index a093291..1209113 100644 --- a/src/main/scala/me/skymc/taboolib/common/schedule/TScheduleLoader.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TScheduleLoader.java @@ -1,14 +1,10 @@ -package me.skymc.taboolib.common.schedule; +package io.izzel.taboolib.module.inject; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.ilummc.tlib.logger.TLogger; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.TabooLibLoader; -import org.bukkit.Bukkit; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.server.PluginEnableEvent; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.TabooLibLoader; +import io.izzel.taboolib.module.logger.TLogger; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitRunnable; @@ -16,19 +12,14 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.List; import java.util.Map; -import java.util.Optional; /** * @Author 坏黑 * @Since 2018-12-15 15:09 */ -public class TScheduleLoader implements Listener, TabooLibLoader.Loader { +public class TScheduleLoader implements TabooLibLoader.Loader { - private Map> schedules = Maps.newHashMap(); - - TScheduleLoader() { - Bukkit.getPluginManager().registerEvents(this, TabooLib.instance()); - } + static Map> schedules = Maps.newHashMap(); public static void run(Plugin plugin, BukkitRunnable runnable, int delay, int period, boolean async) { if (async) { @@ -38,13 +29,6 @@ public class TScheduleLoader implements Listener, TabooLibLoader.Loader { } } - @EventHandler - public void onEnable(PluginEnableEvent e) { - Optional.ofNullable(schedules.remove(e.getPlugin().getName())).ifPresent(list -> list.forEach(scheduleData -> { - run(e.getPlugin(), scheduleData.getRunnable(), scheduleData.getAnnotation().delay(), scheduleData.getAnnotation().period(), scheduleData.getAnnotation().async()); - })); - } - @Override public void postLoad(Plugin plugin, Class loadClass) { for (Method method : loadClass.getDeclaredMethods()) { @@ -61,7 +45,7 @@ public class TScheduleLoader implements Listener, TabooLibLoader.Loader { } method.setAccessible(true); // 如果是本插件 - if (plugin.equals(TabooLib.instance())) { + if (plugin.equals(TabooLib.getPlugin())) { run(plugin, new BukkitRunnable() { @Override diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/ItemBuilder.java b/src/main/scala/io/izzel/taboolib/module/item/ItemBuilder.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/inventory/builder/ItemBuilder.java rename to src/main/scala/io/izzel/taboolib/module/item/ItemBuilder.java index b418223..8ea6d4a 100644 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/ItemBuilder.java +++ b/src/main/scala/io/izzel/taboolib/module/item/ItemBuilder.java @@ -1,9 +1,8 @@ -package me.skymc.taboolib.inventory.builder; +package io.izzel.taboolib.module.item; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.string.ArrayUtils; -import org.bukkit.Bukkit; +import io.izzel.taboolib.Version; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.util.ArrayUtil; import org.bukkit.Color; import org.bukkit.Material; import org.bukkit.OfflinePlayer; @@ -16,7 +15,6 @@ import org.bukkit.inventory.meta.*; import org.bukkit.potion.PotionData; import org.bukkit.potion.PotionEffect; -import java.util.Arrays; import java.util.List; /** @@ -88,7 +86,7 @@ public class ItemBuilder { } public ItemBuilder lore(String... lore) { - itemMeta.setLore(ArrayUtils.asList(lore)); + itemMeta.setLore(ArrayUtil.asList(lore)); return this; } @@ -119,7 +117,7 @@ public class ItemBuilder { public ItemBuilder banner(Pattern... patterns) { if (itemMeta instanceof BannerMeta) { - Arrays.stream(patterns).forEach(pattern -> ((BannerMeta) itemMeta).addPattern(pattern)); + java.util.Arrays.stream(patterns).forEach(pattern -> ((BannerMeta) itemMeta).addPattern(pattern)); } return this; } @@ -167,7 +165,7 @@ public class ItemBuilder { } public ItemBuilder unbreakable(boolean value) { - if (TabooLib.getVersionNumber() >= 12000) { + if (Version.isAfter(Version.v1_12)) { itemMeta.setUnbreakable(value); } else { itemMeta.spigot().setUnbreakable(value); @@ -192,14 +190,4 @@ public class ItemBuilder { } return buildItem; } - - /** - * 从文本中获取物品(name:名字;lore:描述||描述;material:材质) - * - * @param str - * @return - */ - public static ItemStack fromString(String str) { - return null; - } } diff --git a/src/main/scala/io/izzel/taboolib/module/item/Items.java b/src/main/scala/io/izzel/taboolib/module/item/Items.java new file mode 100644 index 0000000..c423167 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/module/item/Items.java @@ -0,0 +1,286 @@ +package io.izzel.taboolib.module.item; + +import io.izzel.taboolib.Version; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.module.lite.SimpleI18n; +import io.izzel.taboolib.module.nms.NMSHandler; +import io.izzel.taboolib.module.nms.nbt.NBTBase; +import io.izzel.taboolib.module.nms.nbt.NBTCompound; +import io.izzel.taboolib.module.nms.nbt.NBTList; +import io.izzel.taboolib.origin.lite.Numbers; +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.util.NumberConversions; + +import java.util.List; + +/** + * @Author 坏黑 + * @Since 2019-07-05 16:44 + */ +public class Items { + + public final static Integer[] INVENTORY_CENTER = { + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34, + 37, 38, 39, 40, 41, 42, 43 + }; + + public static String getName(ItemStack item) { + return SimpleI18n.getCustomName(item); + } + + public static boolean isNull(ItemStack item) { + return item == null || item.getType().equals(Material.AIR); + } + + public static boolean hasLore(ItemStack i, String a) { + return hasLore(i) && i.getItemMeta().getLore().toString().contains(a); + } + + public static boolean hasLore(ItemStack i) { + return !isNull(i) && i.getItemMeta().hasLore(); + } + + public static boolean hasName(ItemStack i) { + return !isNull(i) && i.getItemMeta().hasDisplayName(); + } + + public static Material asMaterial(String args) { + try { + Material material = Material.getMaterial(args.toUpperCase()); + return material != null ? material : Material.getMaterial(Integer.valueOf(args)); + } catch (Exception e) { + return Material.STONE; + } + } + + public static Enchantment asEnchantment(String enchant) { + try { + Enchantment enchantment = Enchantment.getByName(enchant); + return enchantment != null ? enchantment : Enchantment.getById(Integer.valueOf(enchant)); + } catch (Exception e) { + return null; + } + } + + public static PotionEffectType asPotionEffectType(String potion) { + try { + PotionEffectType type = PotionEffectType.getByName(potion); + return type != null ? type : PotionEffectType.getById(Integer.valueOf(potion)); + } catch (Exception e) { + return null; + } + } + + public static ItemFlag asItemFlag(String flag) { + try { + return ItemFlag.valueOf(flag); + } catch (Exception e) { + return null; + } + } + + public static Color asColor(String color) { + try { + return Color.fromBGR(Integer.valueOf(color.split("-")[0]), Integer.valueOf(color.split("-")[1]), Integer.valueOf(color.split("-")[2])); + } catch (Exception e) { + return Color.fromBGR(0, 0, 0); + } + } + + public static String asAttribute(String name) { + switch (name.toLowerCase()) { + case "damage": + return "generic.attackDamage"; + case "attackspeed": + return "generic.attackSpeed"; + case "health": + return "generic.maxHealth"; + case "speed": + return "generic.movementSpeed"; + case "knockback": + return "generic.knockbackResistance"; + case "armor": + return "generic.armor"; + case "luck": + return "generic.luck"; + default: + return null; + } + } + + public static ItemStack replaceLore(ItemStack item, String loreOld, String loreNew) { + if (hasLore(item)) { + ItemMeta meta = item.getItemMeta(); + List lore = meta.getLore(); + for (int i = 0; i < lore.size(); i++) { + lore.set(i, lore.get(i).replace(loreOld, loreNew)); + } + meta.setLore(lore); + item.setItemMeta(meta); + } + return item; + } + + public static boolean checkItem(Player player, ItemStack item, int amount, boolean remove) { + return checkItem(player.getInventory(), item, amount, remove); + } + + public static boolean checkItem(Inventory inventory, ItemStack item, int amount, boolean remove) { + int hasAmount = 0; + for (ItemStack _item : inventory) { + if (item.isSimilar(_item)) { + hasAmount += _item.getAmount(); + } + } + if (hasAmount < amount) { + return false; + } + int requireAmount = amount; + for (int i = 0; i < inventory.getSize() && remove; i++) { + ItemStack _item = inventory.getItem(i); + if (_item != null && _item.isSimilar(item)) { + if (_item.getAmount() < requireAmount) { + inventory.setItem(i, null); + requireAmount -= _item.getAmount(); + } else if (_item.getAmount() == requireAmount) { + inventory.setItem(i, null); + return true; + } else { + _item.setAmount(_item.getAmount() - requireAmount); + return true; + } + } + } + return true; + } + + public static ItemStack loadItem(ConfigurationSection section) { + if (section.get("bukkit") instanceof ItemStack) { + return section.getItemStack("bukkit"); + } + // 材质 + ItemStack item = new ItemStack(asMaterial(section.getString("material"))); + // 数量 + item.setAmount(section.contains("amount") ? section.getInt("amount") : 1); + // 耐久 + item.setDurability((short) section.getInt("data")); + // 元数据 + ItemMeta meta = item.getItemMeta(); + // 展示名 + if (section.contains("name")) { + meta.setDisplayName(section.getString("name")); + } + // 描述 + if (section.contains("lore")) { + meta.setLore(section.getStringList("lore")); + } + // 附魔 + if (section.contains("enchant")) { + for (String preEnchant : section.getConfigurationSection("enchant").getKeys(false)) { + Enchantment enchant = asEnchantment(preEnchant); + if (enchant != null) { + meta.addEnchant(enchant, section.getInt("enchant." + preEnchant), true); + } else { + TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-ENCHANTS", preEnchant); + } + } + } + // 标签 + if (section.contains("flags") && Version.isAfter(Version.v1_8)) { + for (String preFlag : section.getStringList("flags")) { + ItemFlag flag = asItemFlag(preFlag); + if (flag != null) { + meta.addItemFlags(flag); + } else { + TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-FLAG", preFlag); + } + } + } + // 皮革 + if (meta instanceof LeatherArmorMeta && section.contains("color")) { + ((LeatherArmorMeta) meta).setColor(asColor(section.getString("color"))); + } + // 药水 + if (meta instanceof PotionMeta && section.contains("potions")) { + PotionMeta potionMeta = (PotionMeta) meta; + for (String prePotionName : section.getConfigurationSection("potions").getKeys(false)) { + PotionEffectType potionEffectType = asPotionEffectType(prePotionName); + if (potionEffectType != null) { + potionMeta.addCustomEffect(new PotionEffect( + potionEffectType, + NumberConversions.toInt(section.getString("potions." + prePotionName).split("-")[0]), + NumberConversions.toInt(section.getString("potions." + prePotionName).split("-")[1]) - 1), true); + } else { + TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-POTION", prePotionName); + } + } + } + // 元数据 + item.setItemMeta(meta); + // 数据 + NBTCompound nbt = NMSHandler.getHandler().loadNBT(item); + // 物品标签 + if (section.contains("nbt")) { + for (String name : section.getConfigurationSection("nbt").getKeys(false)) { + Object obj = section.get("nbt." + name); + if (obj instanceof String) { + nbt.put(name, new NBTBase(obj.toString())); + } else if (obj instanceof Double) { + nbt.put(name, new NBTBase(NumberConversions.toDouble(obj))); + } else if (obj instanceof Integer) { + nbt.put(name, new NBTBase(NumberConversions.toInt(obj))); + } else if (obj instanceof Long) { + nbt.put(name, new NBTBase(NumberConversions.toLong(obj))); + } + } + } + // 物品属性 + if (section.contains("attributes")) { + NBTList attr = new NBTList(); + for (String hand : section.getConfigurationSection("attributes").getKeys(false)) { + for (String name : section.getConfigurationSection("attributes." + hand).getKeys(false)) { + if (asAttribute(name) != null) { + try { + NBTCompound a = new NBTCompound(); + String num = section.getString("attributes." + hand + "." + name); + if (num.endsWith("%")) { + a.put("Amount", new NBTBase(NumberConversions.toDouble(num.substring(0, num.length() - 1)) / 100D)); + a.put("Operation", new NBTBase(1)); + } else { + a.put("Amount", new NBTBase(NumberConversions.toDouble(num))); + a.put("Operation", new NBTBase(0)); + } + a.put("AttributeName", new NBTBase(asAttribute(name))); + a.put("UUIDMost", new NBTBase(Numbers.getRandom().nextInt(Integer.MAX_VALUE))); + a.put("UUIDLeast", new NBTBase(Numbers.getRandom().nextInt(Integer.MAX_VALUE))); + a.put("Name", new NBTBase(asAttribute(name))); + if (!hand.equals("all")) { + a.put("Slot", new NBTBase(hand)); + } + attr.add(a); + } catch (Exception ignored) { + } + } else { + TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-POTION", name); + } + } + } + nbt.put("AttributeModifiers", attr); + } + return NMSHandler.getHandler().saveNBT(item, nbt); + } +} diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickEvent.java b/src/main/scala/io/izzel/taboolib/module/item/inventory/ClickEvent.java similarity index 95% rename from src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickEvent.java rename to src/main/scala/io/izzel/taboolib/module/item/inventory/ClickEvent.java index 913797f..9903a57 100644 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickEvent.java +++ b/src/main/scala/io/izzel/taboolib/module/item/inventory/ClickEvent.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.inventory.builder.v2; +package io.izzel.taboolib.module.item.inventory; import org.bukkit.entity.Player; import org.bukkit.event.Event; diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickListener.java b/src/main/scala/io/izzel/taboolib/module/item/inventory/ClickListener.java similarity index 96% rename from src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickListener.java rename to src/main/scala/io/izzel/taboolib/module/item/inventory/ClickListener.java index 5cbb4b7..916ddb3 100644 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickListener.java +++ b/src/main/scala/io/izzel/taboolib/module/item/inventory/ClickListener.java @@ -1,6 +1,6 @@ -package me.skymc.taboolib.inventory.builder.v2; +package io.izzel.taboolib.module.item.inventory; -import me.skymc.taboolib.listener.TListener; +import io.izzel.taboolib.module.inject.TListener; import org.bukkit.Bukkit; import org.bukkit.entity.HumanEntity; import org.bukkit.event.EventHandler; diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickListener1_9.java b/src/main/scala/io/izzel/taboolib/module/item/inventory/ClickListenerOffhand.java similarity index 78% rename from src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickListener1_9.java rename to src/main/scala/io/izzel/taboolib/module/item/inventory/ClickListenerOffhand.java index 206f02e..181a3d1 100644 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickListener1_9.java +++ b/src/main/scala/io/izzel/taboolib/module/item/inventory/ClickListenerOffhand.java @@ -1,6 +1,6 @@ -package me.skymc.taboolib.inventory.builder.v2; +package io.izzel.taboolib.module.item.inventory; -import me.skymc.taboolib.listener.TListener; +import io.izzel.taboolib.module.inject.TListener; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerSwapHandItemsEvent; @@ -10,7 +10,7 @@ import org.bukkit.event.player.PlayerSwapHandItemsEvent; * @Since 2019-05-21 22:04 */ @TListener(version = ">=10900") -class ClickListener1_9 implements Listener { +class ClickListenerOffhand implements Listener { @EventHandler public void onSwap(PlayerSwapHandItemsEvent e) { diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickTask.java b/src/main/scala/io/izzel/taboolib/module/item/inventory/ClickTask.java similarity index 70% rename from src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickTask.java rename to src/main/scala/io/izzel/taboolib/module/item/inventory/ClickTask.java index fec7922..41b673c 100644 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickTask.java +++ b/src/main/scala/io/izzel/taboolib/module/item/inventory/ClickTask.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.inventory.builder.v2; +package io.izzel.taboolib.module.item.inventory; /** * @Author 坏黑 diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickType.java b/src/main/scala/io/izzel/taboolib/module/item/inventory/ClickType.java similarity index 66% rename from src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickType.java rename to src/main/scala/io/izzel/taboolib/module/item/inventory/ClickType.java index 5af5852..d68aba8 100644 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickType.java +++ b/src/main/scala/io/izzel/taboolib/module/item/inventory/ClickType.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.inventory.builder.v2; +package io.izzel.taboolib.module.item.inventory; /** * @Author 坏黑 diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/CloseTask.java b/src/main/scala/io/izzel/taboolib/module/item/inventory/CloseTask.java similarity index 78% rename from src/main/scala/me/skymc/taboolib/inventory/builder/v2/CloseTask.java rename to src/main/scala/io/izzel/taboolib/module/item/inventory/CloseTask.java index 3e672a8..298e5f2 100644 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/CloseTask.java +++ b/src/main/scala/io/izzel/taboolib/module/item/inventory/CloseTask.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.inventory.builder.v2; +package io.izzel.taboolib.module.item.inventory; import org.bukkit.event.inventory.InventoryCloseEvent; diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/MenuBuilder.java b/src/main/scala/io/izzel/taboolib/module/item/inventory/MenuBuilder.java similarity index 95% rename from src/main/scala/me/skymc/taboolib/inventory/builder/v2/MenuBuilder.java rename to src/main/scala/io/izzel/taboolib/module/item/inventory/MenuBuilder.java index 835fa52..f8bf3e1 100644 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/MenuBuilder.java +++ b/src/main/scala/io/izzel/taboolib/module/item/inventory/MenuBuilder.java @@ -1,8 +1,8 @@ -package me.skymc.taboolib.inventory.builder.v2; +package io.izzel.taboolib.module.item.inventory; import com.google.common.collect.Maps; -import com.ilummc.tlib.util.Ref; -import me.skymc.taboolib.Main; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.util.Ref; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.inventory.Inventory; @@ -35,7 +35,7 @@ public class MenuBuilder { } public static MenuBuilder builder() { - return new MenuBuilder(Ref.getCallerPlugin(Ref.getCallerClass(3).orElse(Main.class))); + return new MenuBuilder(Ref.getCallerPlugin(Ref.getCallerClass(3).orElse(TabooLib.class))); } public MenuBuilder lockHand() { diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/MenuHolder.java b/src/main/scala/io/izzel/taboolib/module/item/inventory/MenuHolder.java similarity index 90% rename from src/main/scala/me/skymc/taboolib/inventory/builder/v2/MenuHolder.java rename to src/main/scala/io/izzel/taboolib/module/item/inventory/MenuHolder.java index 09912d3..bfb466d 100644 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/MenuHolder.java +++ b/src/main/scala/io/izzel/taboolib/module/item/inventory/MenuHolder.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.inventory.builder.v2; +package io.izzel.taboolib.module.item.inventory; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; diff --git a/src/main/scala/me/skymc/taboolib/common/versioncontrol/SimpleClassVisitor.java b/src/main/scala/io/izzel/taboolib/module/lite/SimpleClassVisitor.java similarity index 97% rename from src/main/scala/me/skymc/taboolib/common/versioncontrol/SimpleClassVisitor.java rename to src/main/scala/io/izzel/taboolib/module/lite/SimpleClassVisitor.java index b17c54c..1cd94fe 100644 --- a/src/main/scala/me/skymc/taboolib/common/versioncontrol/SimpleClassVisitor.java +++ b/src/main/scala/io/izzel/taboolib/module/lite/SimpleClassVisitor.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.versioncontrol; +package io.izzel.taboolib.module.lite; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; diff --git a/src/main/scala/me/skymc/taboolib/common/util/SimpleCounter.java b/src/main/scala/io/izzel/taboolib/module/lite/SimpleCounter.java similarity index 95% rename from src/main/scala/me/skymc/taboolib/common/util/SimpleCounter.java rename to src/main/scala/io/izzel/taboolib/module/lite/SimpleCounter.java index 430857f..1630a61 100644 --- a/src/main/scala/me/skymc/taboolib/common/util/SimpleCounter.java +++ b/src/main/scala/io/izzel/taboolib/module/lite/SimpleCounter.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.util; +package io.izzel.taboolib.module.lite; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/inventory/TEquipment.java b/src/main/scala/io/izzel/taboolib/module/lite/SimpleEquip.java similarity index 80% rename from src/main/scala/me/skymc/taboolib/inventory/TEquipment.java rename to src/main/scala/io/izzel/taboolib/module/lite/SimpleEquip.java index 4e131ec..e6d16d0 100644 --- a/src/main/scala/me/skymc/taboolib/inventory/TEquipment.java +++ b/src/main/scala/io/izzel/taboolib/module/lite/SimpleEquip.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.inventory; +package io.izzel.taboolib.module.lite; import com.google.common.collect.Maps; import org.bukkit.entity.Player; @@ -12,7 +12,7 @@ import java.util.Map; * @Author 坏黑 * @Since 2019-04-25 22:01 */ -public enum TEquipment { +public enum SimpleEquip { HAND(EquipmentSlot.HAND, -1), @@ -29,7 +29,7 @@ public enum TEquipment { private EquipmentSlot bukkit; private int slot; - TEquipment(EquipmentSlot bukkit, int slot) { + SimpleEquip(EquipmentSlot bukkit, int slot) { this.bukkit = bukkit; this.slot = slot; } @@ -50,13 +50,13 @@ public enum TEquipment { } } - public static TEquipment fromBukkit(EquipmentSlot bukkit) { + public static SimpleEquip fromBukkit(EquipmentSlot bukkit) { return Arrays.stream(values()).filter(tEquipment -> tEquipment.bukkit == bukkit).findFirst().orElse(null); } - public static Map getItems(Player player) { - Map map = Maps.newHashMap(); - for (TEquipment equipment : values()) { + public static Map getItems(Player player) { + Map map = Maps.newHashMap(); + for (SimpleEquip equipment : values()) { map.put(equipment, equipment.getItem(player)); } return map; diff --git a/src/main/scala/me/skymc/taboolib/common/util/SimpleI18n.java b/src/main/scala/io/izzel/taboolib/module/lite/SimpleI18n.java similarity index 72% rename from src/main/scala/me/skymc/taboolib/common/util/SimpleI18n.java rename to src/main/scala/io/izzel/taboolib/module/lite/SimpleI18n.java index 017cfcf..d17ed27 100644 --- a/src/main/scala/me/skymc/taboolib/common/util/SimpleI18n.java +++ b/src/main/scala/io/izzel/taboolib/module/lite/SimpleI18n.java @@ -1,13 +1,12 @@ -package me.skymc.taboolib.common.util; +package io.izzel.taboolib.module.lite; -import com.ilummc.tlib.resources.TLocaleLoader; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.common.function.TFunction; -import me.skymc.taboolib.common.nms.NMSHandler; -import me.skymc.taboolib.common.nms.nbt.NBTCompound; -import me.skymc.taboolib.fileutils.ConfigUtils; -import me.skymc.taboolib.fileutils.FileUtils; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.Version; +import io.izzel.taboolib.locale.TLocaleLoader; +import io.izzel.taboolib.module.inject.TFunction; +import io.izzel.taboolib.module.nms.NMSHandler; +import io.izzel.taboolib.module.nms.nbt.NBTCompound; +import io.izzel.taboolib.util.Files; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; @@ -31,15 +30,15 @@ public class SimpleI18n { private static boolean released; static void init() { - File localeFile = getLocaleFile(TabooLib.instance()); + File localeFile = getLocaleFile(TabooLib.getPlugin()); if (localeFile == null) { lang = new YamlConfiguration(); } else { - lang = ConfigUtils.load(TabooLib.instance(), localeFile); + lang = Files.load(TabooLib.getPlugin(), localeFile); } if (lang.getInt("version") < 3 && !released) { released = true; - FileUtils.deleteAllFile(new File(Main.getInst().getDataFolder(), "simpleI18n")); + Files.deepDelete(new File(TabooLib.getPlugin().getDataFolder(), "simpleI18n")); init(); } } @@ -68,7 +67,7 @@ public class SimpleI18n { if (itemMeta instanceof BookMeta && ((BookMeta) itemMeta).getTitle() != null) { return ((BookMeta) itemMeta).getTitle(); } - if (TabooLib.getVersionNumber() < 11100) { + if (!Version.isAfter(Version.v1_11)) { if (item.getType().name().equals("MONSTER_EGG")) { NBTCompound nbtCompound = NMSHandler.getHandler().loadNBT(item); if (nbtCompound.containsKey("EntityTag")) { @@ -76,7 +75,7 @@ public class SimpleI18n { } return lang.getString("item_monsterPlacer_name"); } - } else if (TabooLib.getVersionNumber() < 11300) { + } else if (!Version.isAfter(Version.v1_13)) { if (itemMeta instanceof SpawnEggMeta) { String spawnEggType = lang.getString("entity_" + ((SpawnEggMeta) itemMeta).getSpawnedType().getEntityClass().getSimpleName().replace(".", "_") + "_name"); if (spawnEggType != null) { @@ -88,15 +87,15 @@ public class SimpleI18n { } private static void releaseLocales(Plugin plugin) { - TLocaleLoader.getLocalePriority().stream().filter(localeName -> !new File(plugin.getDataFolder(), "simpleI18n/" + getVersion() + "/" + localeName + ".yml").exists() && plugin.getResource("simpleI18n/" + getVersion() + "/" + localeName + ".yml") != null).forEach(localeName -> plugin.saveResource("simpleI18n/" + getVersion() + "/" + localeName + ".yml", true)); + TLocaleLoader.getLocalePriority().stream().filter(localeName -> !new File("plugins/TabooLib/simpleI18n/" + getVersion() + "/" + localeName + ".yml").exists() && plugin.getResource("simpleI18n/" + getVersion() + "/" + localeName + ".yml") != null).forEach(localeName -> plugin.saveResource("simpleI18n/" + getVersion() + "/" + localeName + ".yml", true)); } private static File getLocaleFile(Plugin plugin) { releaseLocales(plugin); - return TLocaleLoader.getLocalePriority().stream().map(localeName -> new File(plugin.getDataFolder(), "simpleI18n/" + getVersion() + "/" + localeName + ".yml")).filter(File::exists).findFirst().orElse(null); + return TLocaleLoader.getLocalePriority().stream().map(localeName -> new File("plugins/TabooLib/simpleI18n/" + getVersion() + "/" + localeName + ".yml")).filter(File::exists).findFirst().orElse(null); } private static String getVersion() { - return TabooLib.getVersionNumber() < 11300 ? "low" : "high"; + return Version.isAfter(Version.v1_13) ? "high" : "low"; } } diff --git a/src/main/scala/me/skymc/taboolib/common/util/SimpleIterator.java b/src/main/scala/io/izzel/taboolib/module/lite/SimpleIterator.java similarity index 96% rename from src/main/scala/me/skymc/taboolib/common/util/SimpleIterator.java rename to src/main/scala/io/izzel/taboolib/module/lite/SimpleIterator.java index 88ce0be..f64f2c4 100644 --- a/src/main/scala/me/skymc/taboolib/common/util/SimpleIterator.java +++ b/src/main/scala/io/izzel/taboolib/module/lite/SimpleIterator.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.util; +package io.izzel.taboolib.module.lite; import com.google.common.collect.Lists; diff --git a/src/main/scala/me/skymc/taboolib/common/versioncontrol/SimpleMethodVisitor.java b/src/main/scala/io/izzel/taboolib/module/lite/SimpleMethodVisitor.java similarity index 98% rename from src/main/scala/me/skymc/taboolib/common/versioncontrol/SimpleMethodVisitor.java rename to src/main/scala/io/izzel/taboolib/module/lite/SimpleMethodVisitor.java index 292d81a..8c61071 100644 --- a/src/main/scala/me/skymc/taboolib/common/versioncontrol/SimpleMethodVisitor.java +++ b/src/main/scala/io/izzel/taboolib/module/lite/SimpleMethodVisitor.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.versioncontrol; +package io.izzel.taboolib.module.lite; import org.objectweb.asm.*; diff --git a/src/main/scala/me/skymc/taboolib/common/util/SimpleReflection.java b/src/main/scala/io/izzel/taboolib/module/lite/SimpleReflection.java similarity index 99% rename from src/main/scala/me/skymc/taboolib/common/util/SimpleReflection.java rename to src/main/scala/io/izzel/taboolib/module/lite/SimpleReflection.java index c499ada..5b0c8bf 100644 --- a/src/main/scala/me/skymc/taboolib/common/util/SimpleReflection.java +++ b/src/main/scala/io/izzel/taboolib/module/lite/SimpleReflection.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.util; +package io.izzel.taboolib.module.lite; import com.google.common.collect.Maps; diff --git a/src/main/scala/me/skymc/taboolib/common/versioncontrol/SimpleVersionControl.java b/src/main/scala/io/izzel/taboolib/module/lite/SimpleVersionControl.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/common/versioncontrol/SimpleVersionControl.java rename to src/main/scala/io/izzel/taboolib/module/lite/SimpleVersionControl.java index 1a1fc41..2e52361 100644 --- a/src/main/scala/me/skymc/taboolib/common/versioncontrol/SimpleVersionControl.java +++ b/src/main/scala/io/izzel/taboolib/module/lite/SimpleVersionControl.java @@ -1,10 +1,10 @@ -package me.skymc.taboolib.common.versioncontrol; +package io.izzel.taboolib.module.lite; import com.google.common.collect.Lists; -import com.ilummc.tlib.util.asm.AsmClassLoader; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.fileutils.FileUtils; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.Version; +import io.izzel.taboolib.util.Files; +import io.izzel.taboolib.util.asm.AsmClassLoader; import org.bukkit.plugin.Plugin; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; @@ -35,11 +35,11 @@ public class SimpleVersionControl { } public static SimpleVersionControl create() { - return new SimpleVersionControl().to(TabooLib.getVersion()).plugin(Main.getInst()); + return new SimpleVersionControl().to(Version.getBukkitVersion()).plugin(TabooLib.getPlugin()); } public static SimpleVersionControl create(String toVersion) { - return new SimpleVersionControl().to(toVersion).plugin(Main.getInst()); + return new SimpleVersionControl().to(toVersion).plugin(TabooLib.getPlugin()); } public static SimpleVersionControl createSimple(String target, String... from) { @@ -113,7 +113,7 @@ public class SimpleVersionControl { if (useCache && cacheClasses.containsKey(target)) { return cacheClasses.get(target); } - ClassReader classReader = new ClassReader(FileUtils.getResource(plugin, target.replace(".", "/") + ".class")); + ClassReader classReader = new ClassReader(Files.getResource(plugin, target.replace(".", "/") + ".class")); ClassWriter classWriter = new ClassWriter(0); ClassVisitor classVisitor = new SimpleClassVisitor(this, classWriter); classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES); diff --git a/src/main/scala/com/ilummc/tlib/logger/TLogger.java b/src/main/scala/io/izzel/taboolib/module/logger/TLogger.java similarity index 67% rename from src/main/scala/com/ilummc/tlib/logger/TLogger.java rename to src/main/scala/io/izzel/taboolib/module/logger/TLogger.java index 2b3b664..95d7a20 100644 --- a/src/main/scala/com/ilummc/tlib/logger/TLogger.java +++ b/src/main/scala/io/izzel/taboolib/module/logger/TLogger.java @@ -1,9 +1,8 @@ -package com.ilummc.tlib.logger; +package io.izzel.taboolib.module.logger; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.util.Strings; import net.md_5.bungee.BungeeCord; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Bukkit; @@ -13,13 +12,32 @@ public class TLogger { public static final int VERBOSE = 0, FINEST = 1, FINE = 2, INFO = 3, WARN = 4, ERROR = 5, FATAL = 6; - private static TLogger globalLogger = new TLogger("§8[§3§lTabooLib§8][§r{1}§8] §f{2}", Main.getInst(), TLogger.FINE); private final String pattern; - private String name; + private final String name; private int level; + public TLogger(String pattern, Plugin plugin, int level) { + this.pattern = pattern; + this.name = plugin.getName(); + this.level = level; + } + + public TLogger(String pattern, String name, int level) { + this.pattern = pattern; + this.name = name; + this.level = level; + } + public static TLogger getGlobalLogger() { - return globalLogger; + return io.izzel.taboolib.TabooLib.getLogger(); + } + + public static TLogger getUnformatted(Plugin plugin) { + return new TLogger("§8[§3§l{0}§8][§r{1}§8] §f{2}", plugin, TLogger.FINE); + } + + public static TLogger getUnformatted(String name) { + return new TLogger("§8[§3§l{0}§8][§r{1}§8] §f{2}", name, TLogger.FINE); } public String getPattern() { @@ -38,93 +56,73 @@ public class TLogger { this.level = level; } - public TLogger(String pattern, Plugin plugin, int level) { - this.pattern = pattern; - this.name = plugin.getName(); - this.level = level; - } - - public TLogger(String pattern, String name, int level) { - this.pattern = pattern; - this.name = name; - this.level = level; - } - public void verbose(String msg) { if (level <= VERBOSE) { - if (TabooLib.isSpigot()) { - Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§f全部", TLocale.Translate.setColored(msg))); + if (TabooLibAPI.isBukkit()) { + Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§fVERBOSE", TLocale.Translate.setColored(msg))); } else { - BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§f全部", TLocale.Translate.setColored(msg)))); + BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§fVERBOSE", TLocale.Translate.setColored(msg)))); } } } public void finest(String msg) { if (level <= FINEST) { - if (TabooLib.isSpigot()) { - Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§e良好", TLocale.Translate.setColored(msg))); + if (TabooLibAPI.isBukkit()) { + Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§eFINEST", TLocale.Translate.setColored(msg))); } else { - BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§e良好", TLocale.Translate.setColored(msg)))); + BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§eFINEST", TLocale.Translate.setColored(msg)))); } } } public void fine(String msg) { if (level <= FINE) { - if (TabooLib.isSpigot()) { - Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§a正常", TLocale.Translate.setColored(msg))); + if (TabooLibAPI.isBukkit()) { + Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§aFINE", TLocale.Translate.setColored(msg))); } else { - BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§a正常", TLocale.Translate.setColored(msg)))); + BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§aFINE", TLocale.Translate.setColored(msg)))); } } } public void info(String msg) { if (level <= INFO) { - if (TabooLib.isSpigot()) { - Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§b信息", TLocale.Translate.setColored(msg))); + if (TabooLibAPI.isBukkit()) { + Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§bINFO", TLocale.Translate.setColored(msg))); } else { - BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§b信息", TLocale.Translate.setColored(msg)))); + BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§bINFO", TLocale.Translate.setColored(msg)))); } } } public void warn(String msg) { if (level <= WARN) { - if (TabooLib.isSpigot()) { - Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§6警告", "§6" + TLocale.Translate.setColored(msg))); + if (TabooLibAPI.isBukkit()) { + Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§6WARN", "§6" + TLocale.Translate.setColored(msg))); } else { - BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§6警告", "§6" + TLocale.Translate.setColored(msg)))); + BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§6WARN", "§6" + TLocale.Translate.setColored(msg)))); } } } public void error(String msg) { if (level <= ERROR) { - if (TabooLib.isSpigot()) { - Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§c错误", "§c" + TLocale.Translate.setColored(msg))); + if (TabooLibAPI.isBukkit()) { + Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§cERROR", "§c" + TLocale.Translate.setColored(msg))); } else { - BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§c错误", "§c" + TLocale.Translate.setColored(msg)))); + BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§cERROR", "§c" + TLocale.Translate.setColored(msg)))); } } } public void fatal(String msg) { if (level <= FATAL) { - if (TabooLib.isSpigot()) { - Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§4致命错误", "§4" + TLocale.Translate.setColored(msg))); + if (TabooLibAPI.isBukkit()) { + Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§4FATAL", "§4" + TLocale.Translate.setColored(msg))); } else { - BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§4致命错误", "§4" + TLocale.Translate.setColored(msg)))); + BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§4FATAL", "§4" + TLocale.Translate.setColored(msg)))); } } } - - public static TLogger getUnformatted(Plugin plugin) { - return new TLogger("§8[§3§l{0}§8][§r{1}§8] §f{2}", plugin, TLogger.FINE); - } - - public static TLogger getUnformatted(String name) { - return new TLogger("§8[§3§l{0}§8][§r{1}§8] §f{2}", name, TLogger.FINE); - } } diff --git a/src/main/scala/com/ilummc/tlib/inject/TLoggerManager.java b/src/main/scala/io/izzel/taboolib/module/logger/TLoggerManager.java similarity index 88% rename from src/main/scala/com/ilummc/tlib/inject/TLoggerManager.java rename to src/main/scala/io/izzel/taboolib/module/logger/TLoggerManager.java index 98f30f4..bf2503f 100644 --- a/src/main/scala/com/ilummc/tlib/inject/TLoggerManager.java +++ b/src/main/scala/io/izzel/taboolib/module/logger/TLoggerManager.java @@ -1,6 +1,5 @@ -package com.ilummc.tlib.inject; +package io.izzel.taboolib.module.logger; -import com.ilummc.tlib.logger.TLogger; import org.bukkit.plugin.Plugin; import java.util.HashMap; diff --git a/src/main/scala/me/skymc/taboolib/mysql/IColumn.java b/src/main/scala/io/izzel/taboolib/module/mysql/IColumn.java similarity index 77% rename from src/main/scala/me/skymc/taboolib/mysql/IColumn.java rename to src/main/scala/io/izzel/taboolib/module/mysql/IColumn.java index 6a5f90d..c0b2746 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/IColumn.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/IColumn.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.mysql; +package io.izzel.taboolib.module.mysql; /** * @Author 坏黑 diff --git a/src/main/scala/me/skymc/taboolib/mysql/IHost.java b/src/main/scala/io/izzel/taboolib/module/mysql/IHost.java similarity index 95% rename from src/main/scala/me/skymc/taboolib/mysql/IHost.java rename to src/main/scala/io/izzel/taboolib/module/mysql/IHost.java index 5adf5fa..def7b61 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/IHost.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/IHost.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.mysql; +package io.izzel.taboolib.module.mysql; import org.bukkit.plugin.Plugin; diff --git a/src/main/scala/me/skymc/taboolib/mysql/builder/SQLColumn.java b/src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLColumn.java similarity index 96% rename from src/main/scala/me/skymc/taboolib/mysql/builder/SQLColumn.java rename to src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLColumn.java index d154939..109c5c5 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/builder/SQLColumn.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLColumn.java @@ -1,7 +1,7 @@ -package me.skymc.taboolib.mysql.builder; +package io.izzel.taboolib.module.mysql.builder; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.mysql.IColumn; +import io.izzel.taboolib.util.Strings; +import io.izzel.taboolib.module.mysql.IColumn; import java.util.Arrays; diff --git a/src/main/scala/me/skymc/taboolib/mysql/builder/SQLColumnOption.java b/src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLColumnOption.java similarity index 90% rename from src/main/scala/me/skymc/taboolib/mysql/builder/SQLColumnOption.java rename to src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLColumnOption.java index bedc9de..b451e23 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/builder/SQLColumnOption.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLColumnOption.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.mysql.builder; +package io.izzel.taboolib.module.mysql.builder; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/mysql/builder/SQLColumnType.java b/src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLColumnType.java similarity index 98% rename from src/main/scala/me/skymc/taboolib/mysql/builder/SQLColumnType.java rename to src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLColumnType.java index a882ac8..ab41432 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/builder/SQLColumnType.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLColumnType.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.mysql.builder; +package io.izzel.taboolib.module.mysql.builder; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/mysql/builder/SQLExecutor.java b/src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLExecutor.java similarity index 94% rename from src/main/scala/me/skymc/taboolib/mysql/builder/SQLExecutor.java rename to src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLExecutor.java index a6846ab..61618a1 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/builder/SQLExecutor.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLExecutor.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.mysql.builder; +package io.izzel.taboolib.module.mysql.builder; import java.sql.Connection; import java.sql.PreparedStatement; diff --git a/src/main/scala/me/skymc/taboolib/mysql/builder/SQLHost.java b/src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLHost.java similarity index 93% rename from src/main/scala/me/skymc/taboolib/mysql/builder/SQLHost.java rename to src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLHost.java index 96fa4ea..0f000ac 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/builder/SQLHost.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLHost.java @@ -1,11 +1,11 @@ -package me.skymc.taboolib.mysql.builder; +package io.izzel.taboolib.module.mysql.builder; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.mysql.IHost; -import me.skymc.taboolib.string.ArrayUtils; +import io.izzel.taboolib.module.mysql.IHost; +import io.izzel.taboolib.util.Strings; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.plugin.Plugin; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -21,7 +21,7 @@ public class SQLHost extends IHost { private String port; private String password; private String database; - private List flags = ArrayUtils.asList("characterEncoding=utf-8", "useSSL=false"); + private List flags = Arrays.asList("characterEncoding=utf-8", "useSSL=false"); public SQLHost(ConfigurationSection section, Plugin plugin) { this(section, plugin, false); diff --git a/src/main/scala/me/skymc/taboolib/mysql/builder/SQLTable.java b/src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLTable.java similarity index 82% rename from src/main/scala/me/skymc/taboolib/mysql/builder/SQLTable.java rename to src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLTable.java index 159e046..12250fc 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/builder/SQLTable.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/builder/SQLTable.java @@ -1,12 +1,10 @@ -package me.skymc.taboolib.mysql.builder; +package io.izzel.taboolib.module.mysql.builder; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.mysql.IColumn; -import me.skymc.taboolib.mysql.builder.query.RunnableQuery; -import me.skymc.taboolib.mysql.builder.query.RunnableUpdate; -import me.skymc.taboolib.string.ArrayUtils; - -import java.util.Arrays; +import io.izzel.taboolib.module.mysql.IColumn; +import io.izzel.taboolib.module.mysql.builder.query.RunnableQuery; +import io.izzel.taboolib.module.mysql.builder.query.RunnableUpdate; +import io.izzel.taboolib.util.ArrayUtil; +import io.izzel.taboolib.util.Strings; /** * @Author sky @@ -32,19 +30,19 @@ public class SQLTable { } public SQLTable column(IColumn column) { - columns = columns == null ? new IColumn[] {column} : ArrayUtils.arrayAppend(columns, column); + columns = columns == null ? new IColumn[] {column} : ArrayUtil.arrayAppend(columns, column); return this; } @Deprecated public SQLTable addColumn(SQLColumn sqlColumn) { - columns = columns == null ? new SQLColumn[] {sqlColumn} : ArrayUtils.arrayAppend(columns, sqlColumn); + columns = columns == null ? new SQLColumn[] {sqlColumn} : ArrayUtil.arrayAppend(columns, sqlColumn); return this; } public String createQuery() { StringBuilder builder = new StringBuilder(); - Arrays.stream(columns).forEach(sqlColumn -> builder.append(sqlColumn.convertToCommand()).append(", ")); + java.util.Arrays.stream(columns).forEach(sqlColumn -> builder.append(sqlColumn.convertToCommand()).append(", ")); return Strings.replaceWithOrder("create table if not exists `{0}` ({1})", tableName, builder.substring(0, builder.length() - 2)); } diff --git a/src/main/scala/me/skymc/taboolib/mysql/builder/query/RunnableQuery.java b/src/main/scala/io/izzel/taboolib/module/mysql/builder/query/RunnableQuery.java similarity index 96% rename from src/main/scala/me/skymc/taboolib/mysql/builder/query/RunnableQuery.java rename to src/main/scala/io/izzel/taboolib/module/mysql/builder/query/RunnableQuery.java index c3f016d..4928e52 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/builder/query/RunnableQuery.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/builder/query/RunnableQuery.java @@ -1,7 +1,7 @@ -package me.skymc.taboolib.mysql.builder.query; +package io.izzel.taboolib.module.mysql.builder.query; -import com.ilummc.tlib.logger.TLogger; -import me.skymc.taboolib.mysql.builder.SQLExecutor; +import io.izzel.taboolib.module.logger.TLogger; +import io.izzel.taboolib.module.mysql.builder.SQLExecutor; import javax.sql.DataSource; import java.sql.Connection; diff --git a/src/main/scala/me/skymc/taboolib/mysql/builder/query/RunnableUpdate.java b/src/main/scala/io/izzel/taboolib/module/mysql/builder/query/RunnableUpdate.java similarity index 93% rename from src/main/scala/me/skymc/taboolib/mysql/builder/query/RunnableUpdate.java rename to src/main/scala/io/izzel/taboolib/module/mysql/builder/query/RunnableUpdate.java index 91cdb50..51a2867 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/builder/query/RunnableUpdate.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/builder/query/RunnableUpdate.java @@ -1,7 +1,7 @@ -package me.skymc.taboolib.mysql.builder.query; +package io.izzel.taboolib.module.mysql.builder.query; -import com.ilummc.tlib.logger.TLogger; -import me.skymc.taboolib.mysql.builder.SQLExecutor; +import io.izzel.taboolib.module.logger.TLogger; +import io.izzel.taboolib.module.mysql.builder.SQLExecutor; import javax.sql.DataSource; import java.sql.Connection; diff --git a/src/main/scala/me/skymc/taboolib/mysql/builder/query/TaskResult.java b/src/main/scala/io/izzel/taboolib/module/mysql/builder/query/TaskResult.java similarity index 79% rename from src/main/scala/me/skymc/taboolib/mysql/builder/query/TaskResult.java rename to src/main/scala/io/izzel/taboolib/module/mysql/builder/query/TaskResult.java index 21acd8d..1923e94 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/builder/query/TaskResult.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/builder/query/TaskResult.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.mysql.builder.query; +package io.izzel.taboolib.module.mysql.builder.query; import java.sql.ResultSet; import java.sql.SQLException; diff --git a/src/main/scala/me/skymc/taboolib/mysql/builder/query/TaskStatement.java b/src/main/scala/io/izzel/taboolib/module/mysql/builder/query/TaskStatement.java similarity index 80% rename from src/main/scala/me/skymc/taboolib/mysql/builder/query/TaskStatement.java rename to src/main/scala/io/izzel/taboolib/module/mysql/builder/query/TaskStatement.java index 58d1707..09d41bd 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/builder/query/TaskStatement.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/builder/query/TaskStatement.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.mysql.builder.query; +package io.izzel.taboolib.module.mysql.builder.query; import java.sql.PreparedStatement; import java.sql.SQLException; diff --git a/src/main/scala/me/skymc/taboolib/mysql/hikari/HikariHandler.java b/src/main/scala/io/izzel/taboolib/module/mysql/hikari/HikariHandler.java similarity index 78% rename from src/main/scala/me/skymc/taboolib/mysql/hikari/HikariHandler.java rename to src/main/scala/io/izzel/taboolib/module/mysql/hikari/HikariHandler.java index aa3fc79..bfa9761 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/hikari/HikariHandler.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/hikari/HikariHandler.java @@ -1,14 +1,13 @@ -package me.skymc.taboolib.mysql.hikari; +package io.izzel.taboolib.module.mysql.hikari; -import com.google.common.base.Preconditions; -import com.ilummc.tlib.resources.TLocale; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.fileutils.ConfigUtils; -import me.skymc.taboolib.mysql.IHost; -import me.skymc.taboolib.mysql.builder.SQLHost; -import me.skymc.taboolib.mysql.sqlite.SQLiteHost; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.module.config.TConfig; +import io.izzel.taboolib.module.inject.TInject; +import io.izzel.taboolib.module.mysql.IHost; +import io.izzel.taboolib.module.mysql.builder.SQLHost; +import io.izzel.taboolib.module.mysql.lite.SQLiteHost; import org.bukkit.configuration.file.FileConfiguration; import javax.sql.DataSource; @@ -20,8 +19,9 @@ import java.util.concurrent.ConcurrentHashMap; */ public class HikariHandler { + @TInject("datasource.yml") + private static TConfig settings; private static ConcurrentHashMap dataSource = new ConcurrentHashMap<>(); - private static FileConfiguration settings = ConfigUtils.saveDefaultConfig(Main.getInst(), "hikarisettings.yml"); public static DataSource createDataSource(IHost host) { return createDataSource(host, null); @@ -39,7 +39,6 @@ public class HikariHandler { } public static void closeDataSourceForce() { - Preconditions.checkArgument(Main.isDisable(), "Cannot be invoked when the server is running."); dataSource.values().forEach(x -> x.getHikariDataSource().close()); } @@ -84,26 +83,6 @@ public class HikariHandler { return config; } - @Deprecated - public static DataSource createDataSource(SQLHost host) { - return createDataSource((IHost) host, null); - } - - @Deprecated - public static HikariConfig createConfig(SQLHost host) { - return createConfig((IHost) host); - } - - @Deprecated - public static HikariDataSource createDataSource(SQLHost host, HikariConfig hikariConfig) { - return createDataSource((IHost) host, hikariConfig); - } - - @Deprecated - public static void closeDataSource(SQLHost host) { - closeDataSource((IHost) host); - } - // ********************************* // // Getter and Setter diff --git a/src/main/scala/me/skymc/taboolib/mysql/hikari/MapDataSource.java b/src/main/scala/io/izzel/taboolib/module/mysql/hikari/MapDataSource.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/mysql/hikari/MapDataSource.java rename to src/main/scala/io/izzel/taboolib/module/mysql/hikari/MapDataSource.java index 17a95c9..51f4832 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/hikari/MapDataSource.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/hikari/MapDataSource.java @@ -1,7 +1,7 @@ -package me.skymc.taboolib.mysql.hikari; +package io.izzel.taboolib.module.mysql.hikari; import com.zaxxer.hikari.HikariDataSource; -import me.skymc.taboolib.mysql.IHost; +import io.izzel.taboolib.module.mysql.IHost; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/scala/me/skymc/taboolib/mysql/sqlite/SQLiteColumn.java b/src/main/scala/io/izzel/taboolib/module/mysql/lite/SQLiteColumn.java similarity index 96% rename from src/main/scala/me/skymc/taboolib/mysql/sqlite/SQLiteColumn.java rename to src/main/scala/io/izzel/taboolib/module/mysql/lite/SQLiteColumn.java index c28cf07..1598293 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/sqlite/SQLiteColumn.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/lite/SQLiteColumn.java @@ -1,7 +1,7 @@ -package me.skymc.taboolib.mysql.sqlite; +package io.izzel.taboolib.module.mysql.lite; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.mysql.IColumn; +import io.izzel.taboolib.util.Strings; +import io.izzel.taboolib.module.mysql.IColumn; import java.util.Arrays; diff --git a/src/main/scala/me/skymc/taboolib/mysql/sqlite/SQLiteColumnOption.java b/src/main/scala/io/izzel/taboolib/module/mysql/lite/SQLiteColumnOption.java similarity index 91% rename from src/main/scala/me/skymc/taboolib/mysql/sqlite/SQLiteColumnOption.java rename to src/main/scala/io/izzel/taboolib/module/mysql/lite/SQLiteColumnOption.java index 4967b0e..835729f 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/sqlite/SQLiteColumnOption.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/lite/SQLiteColumnOption.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.mysql.sqlite; +package io.izzel.taboolib.module.mysql.lite; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/mysql/sqlite/SQLiteColumnType.java b/src/main/scala/io/izzel/taboolib/module/mysql/lite/SQLiteColumnType.java similarity index 92% rename from src/main/scala/me/skymc/taboolib/mysql/sqlite/SQLiteColumnType.java rename to src/main/scala/io/izzel/taboolib/module/mysql/lite/SQLiteColumnType.java index 894aa9a..870dc41 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/sqlite/SQLiteColumnType.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/lite/SQLiteColumnType.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.mysql.sqlite; +package io.izzel.taboolib.module.mysql.lite; /** * @Author 坏黑 diff --git a/src/main/scala/me/skymc/taboolib/mysql/sqlite/SQLiteHost.java b/src/main/scala/io/izzel/taboolib/module/mysql/lite/SQLiteHost.java similarity index 93% rename from src/main/scala/me/skymc/taboolib/mysql/sqlite/SQLiteHost.java rename to src/main/scala/io/izzel/taboolib/module/mysql/lite/SQLiteHost.java index 7d0928d..7649558 100644 --- a/src/main/scala/me/skymc/taboolib/mysql/sqlite/SQLiteHost.java +++ b/src/main/scala/io/izzel/taboolib/module/mysql/lite/SQLiteHost.java @@ -1,6 +1,6 @@ -package me.skymc.taboolib.mysql.sqlite; +package io.izzel.taboolib.module.mysql.lite; -import me.skymc.taboolib.mysql.IHost; +import io.izzel.taboolib.module.mysql.IHost; import org.bukkit.plugin.Plugin; import java.io.File; diff --git a/src/main/scala/me/skymc/taboolib/common/nms/NMSHandler.java b/src/main/scala/io/izzel/taboolib/module/nms/NMSHandler.java similarity index 71% rename from src/main/scala/me/skymc/taboolib/common/nms/NMSHandler.java rename to src/main/scala/io/izzel/taboolib/module/nms/NMSHandler.java index 843fa49..ed00ceb 100644 --- a/src/main/scala/me/skymc/taboolib/common/nms/NMSHandler.java +++ b/src/main/scala/io/izzel/taboolib/module/nms/NMSHandler.java @@ -1,8 +1,9 @@ -package me.skymc.taboolib.common.nms; +package io.izzel.taboolib.module.nms; -import me.skymc.taboolib.common.function.TFunction; -import me.skymc.taboolib.common.nms.nbt.NBTCompound; -import me.skymc.taboolib.common.versioncontrol.SimpleVersionControl; +import io.izzel.taboolib.module.inject.TFunction; +import io.izzel.taboolib.module.lite.SimpleVersionControl; +import io.izzel.taboolib.module.nms.nbt.NBTCompound; +import org.bukkit.Particle; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -22,12 +23,16 @@ public abstract class NMSHandler { static void init() { try { - handler = (NMSHandler) SimpleVersionControl.createNMS("me.skymc.taboolib.common.nms.NMSHandlerImpl").translate().newInstance(); + handler = (NMSHandler) SimpleVersionControl.createNMS("io.izzel.taboolib.module.nms.NMSHandlerImpl").translate().newInstance(); } catch (Exception e) { e.printStackTrace(); } } + abstract public boolean isRunning(); + + abstract public Object toPacketPlayOutWorldParticles(Particle var1, boolean var2, float var3, float var4, float var5, float var6, float var7, float var8, float var9, int var10, Object var11); + abstract public double[] getTPS(); abstract public String getName(ItemStack itemStack); diff --git a/src/main/scala/me/skymc/taboolib/common/nms/NMSHandlerImpl.java b/src/main/scala/io/izzel/taboolib/module/nms/NMSHandlerImpl.java similarity index 82% rename from src/main/scala/me/skymc/taboolib/common/nms/NMSHandlerImpl.java rename to src/main/scala/io/izzel/taboolib/module/nms/NMSHandlerImpl.java index e856d65..bf307f0 100644 --- a/src/main/scala/me/skymc/taboolib/common/nms/NMSHandlerImpl.java +++ b/src/main/scala/io/izzel/taboolib/module/nms/NMSHandlerImpl.java @@ -1,17 +1,20 @@ -package me.skymc.taboolib.common.nms; +package io.izzel.taboolib.module.nms; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.common.nms.nbt.NBTCompound; -import me.skymc.taboolib.common.nms.nbt.NBTList; -import me.skymc.taboolib.common.packet.TPacketHandler; -import me.skymc.taboolib.common.util.SimpleReflection; -import me.skymc.taboolib.nms.NMSUtils; +import io.izzel.taboolib.Version; +import io.izzel.taboolib.module.lite.SimpleReflection; +import io.izzel.taboolib.module.nms.nbt.NBTCompound; +import io.izzel.taboolib.module.nms.nbt.NBTList; +import io.izzel.taboolib.module.packet.TPacketHandler; import net.minecraft.server.v1_12_R1.ChatMessageType; import net.minecraft.server.v1_12_R1.EntityVillager; import net.minecraft.server.v1_12_R1.MinecraftServer; import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_13_R2.IRegistry; import net.minecraft.server.v1_8_R3.*; +import org.bukkit.Bukkit; +import org.bukkit.Particle; +import org.bukkit.craftbukkit.v1_12_R1.CraftParticle; +import org.bukkit.craftbukkit.v1_13_R2.CraftServer; import org.bukkit.craftbukkit.v1_13_R2.entity.CraftVillager; import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; import org.bukkit.entity.Entity; @@ -30,7 +33,6 @@ import java.util.Map; */ public class NMSHandlerImpl extends NMSHandler { - private final int VERSION = TabooLib.getVersionNumber(); private Field entityTypesField; static { @@ -48,15 +50,26 @@ public class NMSHandlerImpl extends NMSHandler { } public NMSHandlerImpl() { - if (TabooLib.getVersionNumber() >= 11300) { - for (Field declaredField : NMSUtils.getNMSClass("Entity").getDeclaredFields()) { + if (Version.isAfter(Version.v1_13)) { + SimpleReflection.saveField(net.minecraft.server.v1_12_R1.Entity.class); + for (Field declaredField : SimpleReflection.getFields(net.minecraft.server.v1_12_R1.Entity.class).values()) { if (declaredField.getType().getSimpleName().equals("EntityTypes")) { - declaredField.setAccessible(true); entityTypesField = declaredField; break; } } } + SimpleReflection.saveField(MinecraftServer.class); + } + + @Override + public boolean isRunning() { + return !SimpleReflection.getFieldValue(MinecraftServer.class, ((CraftServer) Bukkit.getServer()).getServer(), "hasStopped", false); + } + + @Override + public Object toPacketPlayOutWorldParticles(Particle var1, boolean var2, float var3, float var4, float var5, float var6, float var7, float var8, float var9, int var10, Object var11) { + return new net.minecraft.server.v1_12_R1.PacketPlayOutWorldParticles(CraftParticle.toNMS(var1), var2, var3, var4, var5, var6, var7, var8, var9, var10, CraftParticle.toData(var1, var11)); } @Override @@ -67,13 +80,13 @@ public class NMSHandlerImpl extends NMSHandler { @Override public String getName(ItemStack itemStack) { Object nmsItem = CraftItemStack.asNMSCopy(itemStack); - if (TabooLib.getVersionNumber() >= 11300) { + if (Version.isAfter(Version.v1_13)) { String name = ((net.minecraft.server.v1_8_R3.ItemStack) nmsItem).getItem().getName(); if (itemStack.getItemMeta() instanceof PotionMeta) { name += ".effect." + ((net.minecraft.server.v1_8_R3.ItemStack) nmsItem).getTag().getString("Potion").replaceAll("minecraft:(strong_|long_)?", ""); } return name; - } else if (TabooLib.getVersionNumber() >= 11100) { + } else if (Version.isAfter(Version.v1_11)) { String name = ((net.minecraft.server.v1_12_R1.ItemStack) nmsItem).getItem().a((net.minecraft.server.v1_12_R1.ItemStack) nmsItem); if (itemStack.getItemMeta() instanceof PotionMeta) { return name.replace("item.", "") + ".effect." + ((net.minecraft.server.v1_8_R3.ItemStack) nmsItem).getTag().getString("Potion").replaceAll("(minecraft:)?(strong_|long_)?", ""); @@ -90,10 +103,10 @@ public class NMSHandlerImpl extends NMSHandler { @Override public String getName(Entity entity) { - if (TabooLib.getVersionNumber() >= 11400) { + if (Version.isAfter(Version.v1_14)) { net.minecraft.server.v1_14_R1.MinecraftKey minecraftKey = net.minecraft.server.v1_14_R1.EntityTypes.getName(((org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity) entity).getHandle().getEntityType()); return "entity.minecraft." + minecraftKey.getKey(); - } else if (TabooLib.getVersionNumber() == 11300) { + } else if (Version.isAfter(Version.v1_13)) { try { String name = "entity.minecraft." + IRegistry.ENTITY_TYPE.getKey((net.minecraft.server.v1_13_R2.EntityTypes) entityTypesField.get(((org.bukkit.craftbukkit.v1_13_R2.entity.CraftEntity) entity).getHandle())).getKey(); if (entity instanceof Villager && ((CraftVillager) entity).getCareer() != null) { @@ -177,7 +190,7 @@ public class NMSHandlerImpl extends NMSHandler { @Override public void sendActionBar(Player player, String text) { - if (TabooLib.getVersionNumber() > 11100) { + if (Version.isAfter(Version.v1_12)) { TPacketHandler.sendPacket(player, new net.minecraft.server.v1_12_R1.PacketPlayOutChat(new net.minecraft.server.v1_12_R1.ChatComponentText(String.valueOf(text)), ChatMessageType.GAME_INFO)); } else { TPacketHandler.sendPacket(player, new PacketPlayOutChat(new ChatComponentText(String.valueOf(text)), (byte) 2)); @@ -188,7 +201,7 @@ public class NMSHandlerImpl extends NMSHandler { public ItemStack _NBT(ItemStack itemStack, Object compound) { Object nmsItem = CraftItemStack.asNMSCopy(itemStack); try { - ((net.minecraft.server.v1_8_R3.ItemStack) nmsItem).setTag((net.minecraft.server.v1_8_R3.NBTTagCompound) toNBTBase((me.skymc.taboolib.common.nms.nbt.NBTBase) compound)); + ((net.minecraft.server.v1_8_R3.ItemStack) nmsItem).setTag((net.minecraft.server.v1_8_R3.NBTTagCompound) toNBTBase((io.izzel.taboolib.module.nms.nbt.NBTBase) compound)); } catch (Throwable t) { t.printStackTrace(); } @@ -206,7 +219,7 @@ public class NMSHandlerImpl extends NMSHandler { return new NBTCompound(); } - private Object toNBTBase(me.skymc.taboolib.common.nms.nbt.NBTBase base) { + private Object toNBTBase(io.izzel.taboolib.module.nms.nbt.NBTBase base) { switch (base.getType().getId()) { case 1: return new NBTTagByte(base.asByte()); @@ -228,13 +241,13 @@ public class NMSHandlerImpl extends NMSHandler { return new NBTTagString(base.asString()); case 9: Object nmsList = new NBTTagList(); - for (me.skymc.taboolib.common.nms.nbt.NBTBase value : base.asList()) { + for (io.izzel.taboolib.module.nms.nbt.NBTBase value : base.asList()) { // 1.14+ - if (TabooLib.getVersionNumber() >= 11400) { + if (Version.isAfter(Version.v1_14)) { ((net.minecraft.server.v1_14_R1.NBTTagList) nmsList).add(((net.minecraft.server.v1_14_R1.NBTTagList) nmsList).size(), (net.minecraft.server.v1_14_R1.NBTBase) toNBTBase(value)); } // 1.13 - else if (TabooLib.getVersionNumber() == 11300) { + else if (Version.isAfter(Version.v1_13)) { ((net.minecraft.server.v1_13_R2.NBTTagList) nmsList).add((net.minecraft.server.v1_13_R2.NBTBase) toNBTBase(value)); } // 1.12- @@ -245,7 +258,7 @@ public class NMSHandlerImpl extends NMSHandler { return nmsList; case 10: Object nmsTag = new net.minecraft.server.v1_8_R3.NBTTagCompound(); - for (Map.Entry entry : base.asCompound().entrySet()) { + for (Map.Entry entry : base.asCompound().entrySet()) { ((Map) SimpleReflection.getFieldValue(NBTTagCompound.class, nmsTag, "map")).put(entry.getKey(), toNBTBase(entry.getValue())); } return nmsTag; @@ -257,33 +270,33 @@ public class NMSHandlerImpl extends NMSHandler { if (base instanceof net.minecraft.server.v1_8_R3.NBTTagCompound) { NBTCompound nbtCompound = new NBTCompound(); for (Map.Entry entry : ((Map) SimpleReflection.getFieldValue(NBTTagCompound.class, base, "map")).entrySet()) { - nbtCompound.put(entry.getKey(), (me.skymc.taboolib.common.nms.nbt.NBTBase) fromNBTBase(entry.getValue())); + nbtCompound.put(entry.getKey(), (io.izzel.taboolib.module.nms.nbt.NBTBase) fromNBTBase(entry.getValue())); } return nbtCompound; } else if (base instanceof NBTTagList) { NBTList nbtList = new NBTList(); for (Object v : (List) SimpleReflection.getFieldValue(NBTTagList.class, base, "list")) { - nbtList.add((me.skymc.taboolib.common.nms.nbt.NBTBase) fromNBTBase(v)); + nbtList.add((io.izzel.taboolib.module.nms.nbt.NBTBase) fromNBTBase(v)); } return nbtList; } else if (base instanceof NBTTagString) { - return new me.skymc.taboolib.common.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagString.class, base, "data", "")); + return new io.izzel.taboolib.module.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagString.class, base, "data", "")); } else if (base instanceof NBTTagDouble) { - return new me.skymc.taboolib.common.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagDouble.class, base, "data", 0D)); + return new io.izzel.taboolib.module.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagDouble.class, base, "data", 0D)); } else if (base instanceof NBTTagInt) { - return new me.skymc.taboolib.common.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagInt.class, base, "data", 0)); + return new io.izzel.taboolib.module.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagInt.class, base, "data", 0)); } else if (base instanceof NBTTagFloat) { - return new me.skymc.taboolib.common.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagFloat.class, base, "data", (float) 0)); + return new io.izzel.taboolib.module.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagFloat.class, base, "data", (float) 0)); } else if (base instanceof NBTTagShort) { - return new me.skymc.taboolib.common.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagShort.class, base, "data", (short) 0)); + return new io.izzel.taboolib.module.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagShort.class, base, "data", (short) 0)); } else if (base instanceof NBTTagLong) { - return new me.skymc.taboolib.common.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagLong.class, base, "data", 0L)); + return new io.izzel.taboolib.module.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagLong.class, base, "data", 0L)); } else if (base instanceof NBTTagByte) { - return new me.skymc.taboolib.common.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagByte.class, base, "data", (byte) 0D)); + return new io.izzel.taboolib.module.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagByte.class, base, "data", (byte) 0D)); } else if (base instanceof NBTTagIntArray) { - return new me.skymc.taboolib.common.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagIntArray.class, base, "data", new int[0])); + return new io.izzel.taboolib.module.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagIntArray.class, base, "data", new int[0])); } else if (base instanceof NBTTagByteArray) { - return new me.skymc.taboolib.common.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagByteArray.class, base, "data", new byte[0])); + return new io.izzel.taboolib.module.nms.nbt.NBTBase(SimpleReflection.getFieldValue(NBTTagByteArray.class, base, "data", new byte[0])); } return null; } diff --git a/src/main/scala/me/skymc/taboolib/common/nms/nbt/NBTBase.java b/src/main/scala/io/izzel/taboolib/module/nms/nbt/NBTBase.java similarity index 98% rename from src/main/scala/me/skymc/taboolib/common/nms/nbt/NBTBase.java rename to src/main/scala/io/izzel/taboolib/module/nms/nbt/NBTBase.java index ad5ebce..d76f69b 100644 --- a/src/main/scala/me/skymc/taboolib/common/nms/nbt/NBTBase.java +++ b/src/main/scala/io/izzel/taboolib/module/nms/nbt/NBTBase.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.nms.nbt; +package io.izzel.taboolib.module.nms.nbt; import java.util.Arrays; import java.util.Objects; diff --git a/src/main/scala/me/skymc/taboolib/common/nms/nbt/NBTCompound.java b/src/main/scala/io/izzel/taboolib/module/nms/nbt/NBTCompound.java similarity index 98% rename from src/main/scala/me/skymc/taboolib/common/nms/nbt/NBTCompound.java rename to src/main/scala/io/izzel/taboolib/module/nms/nbt/NBTCompound.java index d7a34ef..f475678 100644 --- a/src/main/scala/me/skymc/taboolib/common/nms/nbt/NBTCompound.java +++ b/src/main/scala/io/izzel/taboolib/module/nms/nbt/NBTCompound.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.nms.nbt; +package io.izzel.taboolib.module.nms.nbt; import com.google.common.collect.Maps; diff --git a/src/main/scala/me/skymc/taboolib/common/nms/nbt/NBTList.java b/src/main/scala/io/izzel/taboolib/module/nms/nbt/NBTList.java similarity index 96% rename from src/main/scala/me/skymc/taboolib/common/nms/nbt/NBTList.java rename to src/main/scala/io/izzel/taboolib/module/nms/nbt/NBTList.java index 83a47c3..06ed845 100644 --- a/src/main/scala/me/skymc/taboolib/common/nms/nbt/NBTList.java +++ b/src/main/scala/io/izzel/taboolib/module/nms/nbt/NBTList.java @@ -1,8 +1,7 @@ -package me.skymc.taboolib.common.nms.nbt; - -import com.google.common.collect.Lists; +package io.izzel.taboolib.module.nms.nbt; import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.UnaryOperator; @@ -14,7 +13,7 @@ import java.util.stream.Stream; */ public class NBTList extends NBTBase implements List { - private List value = Lists.newCopyOnWriteArrayList(); + private List value = new CopyOnWriteArrayList<>(); public NBTList() { super(0); diff --git a/src/main/scala/me/skymc/taboolib/common/nms/nbt/NBTType.java b/src/main/scala/io/izzel/taboolib/module/nms/nbt/NBTType.java similarity index 90% rename from src/main/scala/me/skymc/taboolib/common/nms/nbt/NBTType.java rename to src/main/scala/io/izzel/taboolib/module/nms/nbt/NBTType.java index b1769cd..21f06d1 100644 --- a/src/main/scala/me/skymc/taboolib/common/nms/nbt/NBTType.java +++ b/src/main/scala/io/izzel/taboolib/module/nms/nbt/NBTType.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.nms.nbt; +package io.izzel.taboolib.module.nms.nbt; /** * @Author 坏黑 diff --git a/src/main/scala/me/skymc/taboolib/common/packet/TPacketHandler.java b/src/main/scala/io/izzel/taboolib/module/packet/TPacketHandler.java similarity index 87% rename from src/main/scala/me/skymc/taboolib/common/packet/TPacketHandler.java rename to src/main/scala/io/izzel/taboolib/module/packet/TPacketHandler.java index 5a00d14..4dee6a7 100644 --- a/src/main/scala/me/skymc/taboolib/common/packet/TPacketHandler.java +++ b/src/main/scala/io/izzel/taboolib/module/packet/TPacketHandler.java @@ -1,10 +1,10 @@ -package me.skymc.taboolib.common.packet; +package io.izzel.taboolib.module.packet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import me.skymc.taboolib.common.packet.channel.ChannelExecutor; -import me.skymc.taboolib.common.versioncontrol.SimpleVersionControl; -import me.skymc.taboolib.listener.TListener; +import io.izzel.taboolib.module.packet.channel.ChannelExecutor; +import io.izzel.taboolib.module.lite.SimpleVersionControl; +import io.izzel.taboolib.module.inject.TListener; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -30,7 +30,7 @@ public class TPacketHandler implements Listener { public TPacketHandler() { try { - channelExecutor = (ChannelExecutor) SimpleVersionControl.createNMS("me.skymc.taboolib.common.packet.channel.InternalChannelExecutor").translate().newInstance(); + channelExecutor = (ChannelExecutor) SimpleVersionControl.createNMS("io.izzel.taboolib.module.packet.channel.InternalChannelExecutor").translate().newInstance(); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/scala/me/skymc/taboolib/common/packet/TPacketListener.java b/src/main/scala/io/izzel/taboolib/module/packet/TPacketListener.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/common/packet/TPacketListener.java rename to src/main/scala/io/izzel/taboolib/module/packet/TPacketListener.java index 03bc82b..cc36ce4 100644 --- a/src/main/scala/me/skymc/taboolib/common/packet/TPacketListener.java +++ b/src/main/scala/io/izzel/taboolib/module/packet/TPacketListener.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.packet; +package io.izzel.taboolib.module.packet; import org.bukkit.entity.Player; diff --git a/src/main/scala/me/skymc/taboolib/common/packet/channel/ChannelExecutor.java b/src/main/scala/io/izzel/taboolib/module/packet/channel/ChannelExecutor.java similarity index 96% rename from src/main/scala/me/skymc/taboolib/common/packet/channel/ChannelExecutor.java rename to src/main/scala/io/izzel/taboolib/module/packet/channel/ChannelExecutor.java index 20143cb..e0c0045 100644 --- a/src/main/scala/me/skymc/taboolib/common/packet/channel/ChannelExecutor.java +++ b/src/main/scala/io/izzel/taboolib/module/packet/channel/ChannelExecutor.java @@ -1,10 +1,10 @@ -package me.skymc.taboolib.common.packet.channel; +package io.izzel.taboolib.module.packet.channel; import io.netty.channel.Channel; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; -import me.skymc.taboolib.common.packet.TPacketHandler; +import io.izzel.taboolib.module.packet.TPacketHandler; import org.bukkit.entity.Player; import java.util.Collection; diff --git a/src/main/scala/me/skymc/taboolib/common/packet/channel/InternalChannelExecutor.java b/src/main/scala/io/izzel/taboolib/module/packet/channel/InternalChannelExecutor.java similarity index 89% rename from src/main/scala/me/skymc/taboolib/common/packet/channel/InternalChannelExecutor.java rename to src/main/scala/io/izzel/taboolib/module/packet/channel/InternalChannelExecutor.java index bbaf842..e85dda1 100644 --- a/src/main/scala/me/skymc/taboolib/common/packet/channel/InternalChannelExecutor.java +++ b/src/main/scala/io/izzel/taboolib/module/packet/channel/InternalChannelExecutor.java @@ -1,6 +1,6 @@ -package me.skymc.taboolib.common.packet.channel; +package io.izzel.taboolib.module.packet.channel; -import com.ilummc.tlib.logger.TLogger; +import io.izzel.taboolib.module.logger.TLogger; import io.netty.channel.Channel; import net.minecraft.server.v1_8_R3.Packet; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/DoNotSerialize.java b/src/main/scala/io/izzel/taboolib/module/serialize/DoNotSerialize.java similarity index 89% rename from src/main/scala/me/skymc/taboolib/common/serialize/DoNotSerialize.java rename to src/main/scala/io/izzel/taboolib/module/serialize/DoNotSerialize.java index f6cee54..a922783 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/DoNotSerialize.java +++ b/src/main/scala/io/izzel/taboolib/module/serialize/DoNotSerialize.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.serialize; +package io.izzel.taboolib.module.serialize; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializable.java b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializable.java similarity index 94% rename from src/main/scala/me/skymc/taboolib/common/serialize/TSerializable.java rename to src/main/scala/io/izzel/taboolib/module/serialize/TSerializable.java index f57ae2a..4e27daf 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializable.java +++ b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializable.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.serialize; +package io.izzel.taboolib.module.serialize; import java.nio.charset.StandardCharsets; import java.util.Base64; diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCollection.java b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializeCollection.java similarity index 89% rename from src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCollection.java rename to src/main/scala/io/izzel/taboolib/module/serialize/TSerializeCollection.java index 0b418da..c03f65d 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCollection.java +++ b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializeCollection.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.serialize; +package io.izzel.taboolib.module.serialize; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCustom.java b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializeCustom.java similarity index 89% rename from src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCustom.java rename to src/main/scala/io/izzel/taboolib/module/serialize/TSerializeCustom.java index 9f85ef5..55e5523 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCustom.java +++ b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializeCustom.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.serialize; +package io.izzel.taboolib.module.serialize; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeMap.java b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializeMap.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/common/serialize/TSerializeMap.java rename to src/main/scala/io/izzel/taboolib/module/serialize/TSerializeMap.java index 27fcd43..caded52 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeMap.java +++ b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializeMap.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.serialize; +package io.izzel.taboolib.module.serialize; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializer.java b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializer.java similarity index 96% rename from src/main/scala/me/skymc/taboolib/common/serialize/TSerializer.java rename to src/main/scala/io/izzel/taboolib/module/serialize/TSerializer.java index 7c7bcf3..3cf05d9 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializer.java +++ b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializer.java @@ -1,9 +1,8 @@ -package me.skymc.taboolib.common.serialize; +package io.izzel.taboolib.module.serialize; -import ch.njol.skript.classes.ConfigurationSerializer; import com.google.common.collect.Maps; import com.google.gson.*; -import me.skymc.taboolib.common.util.SimpleReflection; +import io.izzel.taboolib.module.lite.SimpleReflection; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.serialization.ConfigurationSerializable; @@ -23,10 +22,6 @@ public class TSerializer { private static Map generated = Maps.newHashMap(); - public static T read(String value, Class type) { - return ConfigurationSerializer.deserializeCS(value, type); - } - public static TSerializable read(TSerializable serializable, String serializedString) { SimpleReflection.checkAndSave(serializable.getClass()); try { @@ -92,10 +87,6 @@ public class TSerializer { return serializable; } - public static String write(ConfigurationSerializable serializable) { - return ConfigurationSerializer.serializeCS(serializable); - } - public static String write(TSerializable serializable) { SimpleReflection.checkAndSave(serializable.getClass()); JsonObject jsonObject = new JsonObject(); diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElement.java b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializerElement.java similarity index 81% rename from src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElement.java rename to src/main/scala/io/izzel/taboolib/module/serialize/TSerializerElement.java index 9ad5932..67a60ce 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElement.java +++ b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializerElement.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.serialize; +package io.izzel.taboolib.module.serialize; /** * @Author 坏黑 diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElementGeneral.java b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializerElementGeneral.java similarity index 97% rename from src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElementGeneral.java rename to src/main/scala/io/izzel/taboolib/module/serialize/TSerializerElementGeneral.java index 1697dd1..a2168e9 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElementGeneral.java +++ b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializerElementGeneral.java @@ -1,6 +1,6 @@ -package me.skymc.taboolib.common.serialize; +package io.izzel.taboolib.module.serialize; -import me.skymc.taboolib.other.NumberUtils; +import io.izzel.taboolib.origin.lite.Numbers; import org.bukkit.Location; import org.bukkit.inventory.ItemStack; @@ -150,7 +150,7 @@ public enum TSerializerElementGeneral { @Override public Boolean read(String value) { try { - return NumberUtils.getBooleanAbbreviation(value); + return Numbers.getBoolean(value); } catch (Throwable t) { t.printStackTrace(); } diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerExample.java b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializerExample.java similarity index 93% rename from src/main/scala/me/skymc/taboolib/common/serialize/TSerializerExample.java rename to src/main/scala/io/izzel/taboolib/module/serialize/TSerializerExample.java index 504ad7d..a560814 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerExample.java +++ b/src/main/scala/io/izzel/taboolib/module/serialize/TSerializerExample.java @@ -1,9 +1,9 @@ -package me.skymc.taboolib.common.serialize; +package io.izzel.taboolib.module.serialize; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import me.skymc.taboolib.string.ArrayUtils; +import io.izzel.taboolib.util.ArrayUtil; import java.util.List; import java.util.Map; @@ -19,7 +19,7 @@ public class TSerializerExample { SimpleData data = new SimpleData(); // 修改参数 data.number = 9999; - data.list.addAll(ArrayUtils.asList(111D, 222D)); + data.list.addAll(ArrayUtil.asList(111D, 222D)); data.map.putAll(ImmutableMap.of("a", "b", "c", "d")); // 序列化 String value = data.write(); diff --git a/src/main/scala/me/skymc/taboolib/json/tellraw/TellrawCreator.java b/src/main/scala/io/izzel/taboolib/module/tellraw/TellrawCreator.java similarity index 71% rename from src/main/scala/me/skymc/taboolib/json/tellraw/TellrawCreator.java rename to src/main/scala/io/izzel/taboolib/module/tellraw/TellrawCreator.java index d65397c..a792500 100644 --- a/src/main/scala/me/skymc/taboolib/json/tellraw/TellrawCreator.java +++ b/src/main/scala/io/izzel/taboolib/module/tellraw/TellrawCreator.java @@ -1,26 +1,26 @@ -package me.skymc.taboolib.json.tellraw; +package io.izzel.taboolib.module.tellraw; -import me.skymc.taboolib.common.loader.Instantiable; -import me.skymc.taboolib.common.versioncontrol.SimpleVersionControl; -import me.skymc.taboolib.json.tellraw.internal.AbstractTellraw; +import io.izzel.taboolib.module.inject.TFunction; +import io.izzel.taboolib.module.lite.SimpleVersionControl; +import io.izzel.taboolib.module.tellraw.internal.AbstractTellraw; import org.bukkit.Bukkit; /** * @Author 坏黑 * @Since 2018-11-07 22:58 */ -@Instantiable("TabooLib|TellrawCreator") +@TFunction(enable = "init") public class TellrawCreator { private static AbstractTellraw abstractTellraw; private static boolean viaVersionLoaded; private static boolean protocolSupportLoaded; - public TellrawCreator() { + public static void init() { viaVersionLoaded = Bukkit.getPluginManager().getPlugin("ViaVersion") != null; protocolSupportLoaded = Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null; try { - abstractTellraw = (AbstractTellraw) SimpleVersionControl.createNMS("me.skymc.taboolib.json.tellraw.internal.InternalTellraw").translate().newInstance(); + abstractTellraw = (AbstractTellraw) SimpleVersionControl.createNMS("io.izzel.taboolib.module.tellraw.internal.InternalTellraw").translate().newInstance(); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/scala/me/skymc/taboolib/json/tellraw/TellrawJson.java b/src/main/scala/io/izzel/taboolib/module/tellraw/TellrawJson.java similarity index 89% rename from src/main/scala/me/skymc/taboolib/json/tellraw/TellrawJson.java rename to src/main/scala/io/izzel/taboolib/module/tellraw/TellrawJson.java index 12e0fb0..e48189d 100644 --- a/src/main/scala/me/skymc/taboolib/json/tellraw/TellrawJson.java +++ b/src/main/scala/io/izzel/taboolib/module/tellraw/TellrawJson.java @@ -1,11 +1,9 @@ -package me.skymc.taboolib.json.tellraw; +package io.izzel.taboolib.module.tellraw; -import com.ilummc.tlib.bungee.api.chat.*; -import com.ilummc.tlib.bungee.chat.ComponentSerializer; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.string.ArrayUtils; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.util.ArrayUtil; +import io.izzel.taboolib.util.Strings; +import io.izzel.taboolib.util.chat.*; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -13,10 +11,7 @@ import org.bukkit.inventory.ItemStack; import protocolsupport.api.ProtocolSupportAPI; import us.myles.ViaVersion.api.Via; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; /** @@ -26,11 +21,10 @@ import java.util.stream.Collectors; */ public class TellrawJson { - private int bukkitVersion = TabooLib.getVersionNumber(); private List components = new ArrayList<>(); private List componentsLatest = new ArrayList<>(); private Map itemTag = new HashMap<>(); - private List nbtWhitelist = ArrayUtils.asList( + private List nbtWhitelist = ArrayUtil.asList( // 附魔 "ench", // 附魔书 @@ -113,13 +107,13 @@ public class TellrawJson { public TellrawJson append(String text) { appendComponents(); - componentsLatest.addAll(ArrayUtils.asList(TextComponent.fromLegacyText(text))); + componentsLatest.addAll(Arrays.asList(TextComponent.fromLegacyText(text))); return this; } public TellrawJson append(TellrawJson json) { appendComponents(); - componentsLatest.addAll(ArrayUtils.asList(json.getComponentsAll())); + componentsLatest.addAll(Arrays.asList(json.getComponentsAll())); itemTag.putAll(json.itemTag); return this; } @@ -188,7 +182,7 @@ public class TellrawJson { } private void setLatestComponent(BaseComponent... component) { - componentsLatest.addAll(ArrayUtils.asList(component)); + componentsLatest.addAll(Arrays.asList(component)); } private void appendComponents() { @@ -203,17 +197,13 @@ public class TellrawJson { // ********************************* public void setComponents(BaseComponent[] components) { - this.components = ArrayUtils.asList(components); + this.components = Arrays.asList(components); } public BaseComponent[] getComponents() { return components.toArray(new BaseComponent[0]); } - public int getBukkitVersion() { - return bukkitVersion; - } - public List getComponentsLatest() { return componentsLatest; } diff --git a/src/main/scala/me/skymc/taboolib/json/tellraw/TellrawVersion.java b/src/main/scala/io/izzel/taboolib/module/tellraw/TellrawVersion.java similarity index 76% rename from src/main/scala/me/skymc/taboolib/json/tellraw/TellrawVersion.java rename to src/main/scala/io/izzel/taboolib/module/tellraw/TellrawVersion.java index 81bc02d..c52526f 100644 --- a/src/main/scala/me/skymc/taboolib/json/tellraw/TellrawVersion.java +++ b/src/main/scala/io/izzel/taboolib/module/tellraw/TellrawVersion.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.json.tellraw; +package io.izzel.taboolib.module.tellraw; /** * @Author 坏黑 diff --git a/src/main/scala/me/skymc/taboolib/json/tellraw/internal/AbstractTellraw.java b/src/main/scala/io/izzel/taboolib/module/tellraw/internal/AbstractTellraw.java similarity index 82% rename from src/main/scala/me/skymc/taboolib/json/tellraw/internal/AbstractTellraw.java rename to src/main/scala/io/izzel/taboolib/module/tellraw/internal/AbstractTellraw.java index f20ad06..1dfa35c 100644 --- a/src/main/scala/me/skymc/taboolib/json/tellraw/internal/AbstractTellraw.java +++ b/src/main/scala/io/izzel/taboolib/module/tellraw/internal/AbstractTellraw.java @@ -1,6 +1,6 @@ -package me.skymc.taboolib.json.tellraw.internal; +package io.izzel.taboolib.module.tellraw.internal; -import me.skymc.taboolib.json.tellraw.TellrawVersion; +import io.izzel.taboolib.module.tellraw.TellrawVersion; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; diff --git a/src/main/scala/me/skymc/taboolib/json/tellraw/internal/InternalTellraw.java b/src/main/scala/io/izzel/taboolib/module/tellraw/internal/InternalTellraw.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/json/tellraw/internal/InternalTellraw.java rename to src/main/scala/io/izzel/taboolib/module/tellraw/internal/InternalTellraw.java index 32bf0ef..fd056fb 100644 --- a/src/main/scala/me/skymc/taboolib/json/tellraw/internal/InternalTellraw.java +++ b/src/main/scala/io/izzel/taboolib/module/tellraw/internal/InternalTellraw.java @@ -1,10 +1,10 @@ -package me.skymc.taboolib.json.tellraw.internal; +package io.izzel.taboolib.module.tellraw.internal; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.common.packet.TPacketHandler; -import me.skymc.taboolib.common.util.SimpleReflection; -import me.skymc.taboolib.inventory.ItemUtils; -import me.skymc.taboolib.json.tellraw.TellrawVersion; +import io.izzel.taboolib.Version; +import io.izzel.taboolib.module.item.Items; +import io.izzel.taboolib.module.lite.SimpleReflection; +import io.izzel.taboolib.module.packet.TPacketHandler; +import io.izzel.taboolib.module.tellraw.TellrawVersion; import net.minecraft.server.v1_8_R3.*; import org.bukkit.Material; import org.bukkit.block.ShulkerBox; @@ -13,6 +13,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BlockStateMeta; +import org.bukkit.inventory.meta.ItemMeta; import java.util.List; import java.util.Map; @@ -23,8 +24,6 @@ import java.util.Map; */ public class InternalTellraw implements AbstractTellraw { - private int bukkitVersion = TabooLib.getVersionNumber(); - public InternalTellraw() { SimpleReflection.saveField(NBTTagCompound.class, "map"); SimpleReflection.saveField(NBTTagList.class, "list"); @@ -74,10 +73,12 @@ public class InternalTellraw implements AbstractTellraw { ItemStack[] contentsClone = new ItemStack[contents.length]; for (int i = 0; i < contents.length; i++) { ItemStack content = contents[i]; - if (!ItemUtils.isNull(content)) { + if (!Items.isNull(content)) { ItemStack contentClone = new ItemStack(Material.STONE, content.getAmount(), content.getDurability()); if (content.getItemMeta().hasDisplayName()) { - ItemUtils.setName(contentClone, content.getItemMeta().getDisplayName()); + ItemMeta itemMeta = contentClone.getItemMeta(); + itemMeta.setDisplayName(content.getItemMeta().getDisplayName()); + contentClone.setItemMeta(itemMeta); } contentsClone[i] = contentClone; } @@ -127,7 +128,7 @@ public class InternalTellraw implements AbstractTellraw { if (i != 0) { builder.append(','); } - if (version == TellrawVersion.HIGH_VERSION || (this.bukkitVersion >= 11200 && version == TellrawVersion.CURRENT_VERSION)) { + if (version == TellrawVersion.HIGH_VERSION || (Version.isAfter(Version.v1_12) && version == TellrawVersion.CURRENT_VERSION)) { builder.append(list.get(i)); } else { builder.append(i).append(':').append(list.get(i)); diff --git a/src/main/scala/me/skymc/taboolib/bookformatter/BookAchievement.java b/src/main/scala/io/izzel/taboolib/origin/book/BookAchievement.java similarity index 98% rename from src/main/scala/me/skymc/taboolib/bookformatter/BookAchievement.java rename to src/main/scala/io/izzel/taboolib/origin/book/BookAchievement.java index c6fb671..4d289b5 100644 --- a/src/main/scala/me/skymc/taboolib/bookformatter/BookAchievement.java +++ b/src/main/scala/io/izzel/taboolib/origin/book/BookAchievement.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.bookformatter; +package io.izzel.taboolib.origin.book; import org.bukkit.Achievement; diff --git a/src/main/scala/me/skymc/taboolib/bookformatter/BookFormatter.java b/src/main/scala/io/izzel/taboolib/origin/book/BookFormatter.java similarity index 52% rename from src/main/scala/me/skymc/taboolib/bookformatter/BookFormatter.java rename to src/main/scala/io/izzel/taboolib/origin/book/BookFormatter.java index 0931219..137c649 100644 --- a/src/main/scala/me/skymc/taboolib/bookformatter/BookFormatter.java +++ b/src/main/scala/io/izzel/taboolib/origin/book/BookFormatter.java @@ -1,8 +1,6 @@ -package me.skymc.taboolib.bookformatter; +package io.izzel.taboolib.origin.book; -import me.skymc.taboolib.bookformatter.builder.BookBuilder; -import me.skymc.taboolib.events.CustomBookOpenEvent; -import org.bukkit.Bukkit; +import io.izzel.taboolib.origin.book.builder.BookBuilder; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -15,33 +13,6 @@ public final class BookFormatter { * @param p the player * @param book the book to be opened */ - public static void openPlayer(Player p, ItemStack book) { - CustomBookOpenEvent event = new CustomBookOpenEvent(p, book, false); - //Call the CustomBookOpenEvent - Bukkit.getPluginManager().callEvent(event); - //Check if it's cancelled - if(event.isCancelled()) { - return; - } - - //Close inventory currently - p.closeInventory(); - //Store the previous item - ItemStack hand = p.getItemInHand(); - p.setItemInHand(event.getBook()); - - //Opening the GUI - BookReflection.openBook(p, event.getBook(), event.getHand() == CustomBookOpenEvent.Hand.OFF_HAND); - - //Returning whatever was on hand. - p.setItemInHand(hand); - } - - /** - * Opens a book GUI to the player, Bypass the {@link CustomBookOpenEvent} - * @param p the player - * @param book the book to be opened - */ public static void forceOpen(Player p, ItemStack book) { //Close inventory currently p.closeInventory(); diff --git a/src/main/scala/me/skymc/taboolib/bookformatter/BookReflection.java b/src/main/scala/io/izzel/taboolib/origin/book/BookReflection.java similarity index 97% rename from src/main/scala/me/skymc/taboolib/bookformatter/BookReflection.java rename to src/main/scala/io/izzel/taboolib/origin/book/BookReflection.java index b090544..298f121 100644 --- a/src/main/scala/me/skymc/taboolib/bookformatter/BookReflection.java +++ b/src/main/scala/io/izzel/taboolib/origin/book/BookReflection.java @@ -1,10 +1,9 @@ -package me.skymc.taboolib.bookformatter; +package io.izzel.taboolib.origin.book; -import com.ilummc.tlib.bungee.api.chat.BaseComponent; -import com.ilummc.tlib.bungee.api.chat.TextComponent; -import com.ilummc.tlib.bungee.chat.ComponentSerializer; -import com.ilummc.tlib.logger.TLogger; -import com.ilummc.tlib.resources.TLocale; +import io.izzel.taboolib.util.chat.BaseComponent; +import io.izzel.taboolib.util.chat.TextComponent; +import io.izzel.taboolib.util.chat.ComponentSerializer; +import io.izzel.taboolib.module.logger.TLogger; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -14,7 +13,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/scala/me/skymc/taboolib/bookformatter/action/ClickAction.java b/src/main/scala/io/izzel/taboolib/origin/book/action/ClickAction.java similarity index 96% rename from src/main/scala/me/skymc/taboolib/bookformatter/action/ClickAction.java rename to src/main/scala/io/izzel/taboolib/origin/book/action/ClickAction.java index 428c447..79b1b88 100644 --- a/src/main/scala/me/skymc/taboolib/bookformatter/action/ClickAction.java +++ b/src/main/scala/io/izzel/taboolib/origin/book/action/ClickAction.java @@ -1,6 +1,6 @@ -package me.skymc.taboolib.bookformatter.action; +package io.izzel.taboolib.origin.book.action; -import com.ilummc.tlib.bungee.api.chat.ClickEvent; +import io.izzel.taboolib.util.chat.ClickEvent; /** * @author sky diff --git a/src/main/scala/me/skymc/taboolib/bookformatter/action/HoverAction.java b/src/main/scala/io/izzel/taboolib/origin/book/action/HoverAction.java similarity index 93% rename from src/main/scala/me/skymc/taboolib/bookformatter/action/HoverAction.java rename to src/main/scala/io/izzel/taboolib/origin/book/action/HoverAction.java index 48bad9f..a7605de 100644 --- a/src/main/scala/me/skymc/taboolib/bookformatter/action/HoverAction.java +++ b/src/main/scala/io/izzel/taboolib/origin/book/action/HoverAction.java @@ -1,10 +1,10 @@ -package me.skymc.taboolib.bookformatter.action; +package io.izzel.taboolib.origin.book.action; -import com.ilummc.tlib.bungee.api.chat.BaseComponent; -import com.ilummc.tlib.bungee.api.chat.HoverEvent; -import com.ilummc.tlib.bungee.api.chat.TextComponent; -import me.skymc.taboolib.bookformatter.BookAchievement; -import me.skymc.taboolib.bookformatter.BookReflection; +import io.izzel.taboolib.util.chat.BaseComponent; +import io.izzel.taboolib.util.chat.HoverEvent; +import io.izzel.taboolib.util.chat.TextComponent; +import io.izzel.taboolib.origin.book.BookAchievement; +import io.izzel.taboolib.origin.book.BookReflection; import org.bukkit.Achievement; import org.bukkit.entity.Entity; import org.bukkit.inventory.ItemStack; @@ -55,7 +55,7 @@ public interface HoverAction { * @return a new HoverAction instance */ static HoverAction showItem(ItemStack item) { - return new SimpleHoverAction(HoverEvent.Action.SHOW_ITEM, BookReflection.itemToComponents(item)); + return new SimpleHoverAction(HoverEvent.Action.SHOW_ITEM, io.izzel.taboolib.origin.book.BookReflection.itemToComponents(item)); } /** diff --git a/src/main/scala/me/skymc/taboolib/bookformatter/builder/BookBuilder.java b/src/main/scala/io/izzel/taboolib/origin/book/builder/BookBuilder.java similarity index 91% rename from src/main/scala/me/skymc/taboolib/bookformatter/builder/BookBuilder.java rename to src/main/scala/io/izzel/taboolib/origin/book/builder/BookBuilder.java index d79d6f5..154daff 100644 --- a/src/main/scala/me/skymc/taboolib/bookformatter/builder/BookBuilder.java +++ b/src/main/scala/io/izzel/taboolib/origin/book/builder/BookBuilder.java @@ -1,7 +1,7 @@ -package me.skymc.taboolib.bookformatter.builder; +package io.izzel.taboolib.origin.book.builder; -import com.ilummc.tlib.bungee.api.chat.BaseComponent; -import me.skymc.taboolib.bookformatter.BookReflection; +import io.izzel.taboolib.util.chat.BaseComponent; +import io.izzel.taboolib.origin.book.BookReflection; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BookMeta; @@ -93,7 +93,7 @@ public class BookBuilder { * @return the BookBuilder's calling instance */ public BookBuilder pages(BaseComponent[]... pages) { - BookReflection.setPages(meta, pages); + io.izzel.taboolib.origin.book.BookReflection.setPages(meta, pages); return this; } @@ -103,7 +103,7 @@ public class BookBuilder { * @return the BookBuilder's calling instance */ public BookBuilder pages(List pages) { - BookReflection.setPages(meta, pages.toArray(new BaseComponent[0][])); + io.izzel.taboolib.origin.book.BookReflection.setPages(meta, pages.toArray(new BaseComponent[0][])); return this; } diff --git a/src/main/scala/me/skymc/taboolib/bookformatter/builder/PageBuilder.java b/src/main/scala/io/izzel/taboolib/origin/book/builder/PageBuilder.java similarity index 82% rename from src/main/scala/me/skymc/taboolib/bookformatter/builder/PageBuilder.java rename to src/main/scala/io/izzel/taboolib/origin/book/builder/PageBuilder.java index f95e033..9f3f0bc 100644 --- a/src/main/scala/me/skymc/taboolib/bookformatter/builder/PageBuilder.java +++ b/src/main/scala/io/izzel/taboolib/origin/book/builder/PageBuilder.java @@ -1,12 +1,8 @@ -package me.skymc.taboolib.bookformatter.builder; +package io.izzel.taboolib.origin.book.builder; -import com.ilummc.tlib.bungee.api.chat.*; -import me.skymc.taboolib.string.ArrayUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; +import io.izzel.taboolib.util.ArrayUtil; +import io.izzel.taboolib.util.chat.BaseComponent; +import io.izzel.taboolib.util.chat.TextComponent; /** * @author sky @@ -22,7 +18,7 @@ public class PageBuilder { * @return the PageBuilder's calling instance */ public PageBuilder add(String text) { - Arrays.stream(TextComponent.fromLegacyText(text)).forEach(component -> this.text = ArrayUtils.arrayAppend(this.text, component)); + java.util.Arrays.stream(TextComponent.fromLegacyText(text)).forEach(component -> this.text = ArrayUtil.arrayAppend(this.text, component)); return this; } @@ -32,7 +28,7 @@ public class PageBuilder { * @return the PageBuilder's calling instance */ public PageBuilder add(BaseComponent component) { - this.text = ArrayUtils.arrayAppend(this.text, component); + this.text = ArrayUtil.arrayAppend(this.text, component); return this; } @@ -42,7 +38,7 @@ public class PageBuilder { * @return the PageBuilder's calling instance */ public PageBuilder add(BaseComponent... components) { - Arrays.stream(components).forEach(component -> this.text = ArrayUtils.arrayAppend(this.text, component)); + java.util.Arrays.stream(components).forEach(component -> this.text = ArrayUtil.arrayAppend(this.text, component)); return this; } diff --git a/src/main/scala/me/skymc/taboolib/bookformatter/builder/TextBuilder.java b/src/main/scala/io/izzel/taboolib/origin/book/builder/TextBuilder.java similarity index 81% rename from src/main/scala/me/skymc/taboolib/bookformatter/builder/TextBuilder.java rename to src/main/scala/io/izzel/taboolib/origin/book/builder/TextBuilder.java index 34a271c..bd39936 100644 --- a/src/main/scala/me/skymc/taboolib/bookformatter/builder/TextBuilder.java +++ b/src/main/scala/io/izzel/taboolib/origin/book/builder/TextBuilder.java @@ -1,8 +1,11 @@ -package me.skymc.taboolib.bookformatter.builder; +package io.izzel.taboolib.origin.book.builder; -import com.ilummc.tlib.bungee.api.chat.*; -import me.skymc.taboolib.bookformatter.action.ClickAction; -import me.skymc.taboolib.bookformatter.action.HoverAction; +import io.izzel.taboolib.util.chat.BaseComponent; +import io.izzel.taboolib.util.chat.ClickEvent; +import io.izzel.taboolib.util.chat.HoverEvent; +import io.izzel.taboolib.util.chat.TextComponent; +import io.izzel.taboolib.origin.book.action.ClickAction; +import io.izzel.taboolib.origin.book.action.HoverAction; /** * @author sky diff --git a/src/main/scala/me/skymc/taboolib/socket/TabooLibClient.java b/src/main/scala/io/izzel/taboolib/origin/client/TabooLibClient.java similarity index 74% rename from src/main/scala/me/skymc/taboolib/socket/TabooLibClient.java rename to src/main/scala/io/izzel/taboolib/origin/client/TabooLibClient.java index 9309e5d..9efb69f 100644 --- a/src/main/scala/me/skymc/taboolib/socket/TabooLibClient.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/TabooLibClient.java @@ -1,15 +1,15 @@ -package me.skymc.taboolib.socket; +package io.izzel.taboolib.origin.client; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.commands.builder.SimpleCommandBuilder; -import me.skymc.taboolib.other.NumberUtils; -import me.skymc.taboolib.socket.packet.Packet; -import me.skymc.taboolib.socket.packet.PacketSerializer; -import me.skymc.taboolib.socket.packet.impl.PacketCommand; -import me.skymc.taboolib.socket.packet.impl.PacketMessage; -import me.skymc.taboolib.string.ArrayUtils; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.module.command.lite.SimpleCommandBuilder; +import io.izzel.taboolib.origin.client.packet.Packet; +import io.izzel.taboolib.origin.client.packet.PacketSerializer; +import io.izzel.taboolib.origin.client.packet.impl.PacketCommand; +import io.izzel.taboolib.origin.client.packet.impl.PacketMessage; +import io.izzel.taboolib.util.ArrayUtil; import org.bukkit.Bukkit; +import org.bukkit.util.NumberConversions; import java.io.*; import java.net.Socket; @@ -34,7 +34,7 @@ public class TabooLibClient { public static void init() { if (TabooLibSettings.load()) { connect(); - Bukkit.getScheduler().runTaskTimerAsynchronously(TabooLib.instance(), TabooLibClient::reconnect, 0, 100); + Bukkit.getScheduler().runTaskTimerAsynchronously(TabooLib.getPlugin(), TabooLibClient::reconnect, 0, 100); } else { TLocale.sendToConsole("COMMUNICATION.FAILED-LOAD-SETTINGS", TabooLibSettings.getThrowable().toString()); } @@ -45,7 +45,7 @@ public class TabooLibClient { } public static void reconnect() { - if (System.currentTimeMillis() - latestResponse > NumberUtils.getInteger(TabooLibSettings.getSettings().getProperty("channel.timeout"))) { + if (System.currentTimeMillis() - latestResponse > NumberConversions.toInt(TabooLibSettings.getSettings().getProperty("channel.timeout"))) { connect(); } } @@ -59,19 +59,12 @@ public class TabooLibClient { } try { - socket = new Socket("localhost", NumberUtils.getInteger(TabooLibSettings.getSettings().getProperty("channel.port"))); + socket = new Socket("localhost", NumberConversions.toInt(TabooLibSettings.getSettings().getProperty("channel.port"))); reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), TabooLibSettings.getCharset())); writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), TabooLibSettings.getCharset()), true); notify = false; TLocale.sendToConsole("COMMUNICATION.SUCCESS-CONNECTED"); } catch (SocketException e) { - /* - 防止未启用终端服务器导致重复提示连接失败信息 - */ - if (!notify && !TabooLib.isSilent()) { - notify = true; - TLocale.sendToConsole("COMMUNICATION.FAILED-CONNECT-SERVER"); - } return; } catch (IOException e) { TLocale.sendToConsole("COMMUNICATION.FAILED-CONNECT-CLIENT", e.getMessage()); @@ -88,7 +81,7 @@ public class TabooLibClient { } }); - SimpleCommandBuilder.create("TabooLibClient", TabooLib.instance()) + SimpleCommandBuilder.create("TabooLibClient", TabooLib.getPlugin()) .aliases("tclient") .permission("*") .execute((sender, args) -> { @@ -96,13 +89,12 @@ public class TabooLibClient { sender.sendMessage("§c[TabooLibClient] §f/tclient message §7[TEXT] §8- §7发送测试信息"); sender.sendMessage("§c[TabooLibClient] §f/tclient command §7[TEXT] §8- §7发送测试命令"); } else if (args[0].equalsIgnoreCase("message") && args.length > 1) { - sendPacket(new PacketMessage(ArrayUtils.arrayJoin(args, 1))); + sendPacket(new PacketMessage(ArrayUtil.arrayJoin(args, 1))); } else if (args[0].equalsIgnoreCase("command") && args.length > 1) { - sendPacket(new PacketCommand(ArrayUtils.arrayJoin(args, 1))); + sendPacket(new PacketCommand(ArrayUtil.arrayJoin(args, 1))); } else { sender.sendMessage("§c[TabooLibClient] §7指令错误."); } - return true; }).build(); } diff --git a/src/main/scala/me/skymc/taboolib/socket/TabooLibServer.java b/src/main/scala/io/izzel/taboolib/origin/client/TabooLibServer.java similarity index 85% rename from src/main/scala/me/skymc/taboolib/socket/TabooLibServer.java rename to src/main/scala/io/izzel/taboolib/origin/client/TabooLibServer.java index ed2e92a..9e01726 100644 --- a/src/main/scala/me/skymc/taboolib/socket/TabooLibServer.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/TabooLibServer.java @@ -1,12 +1,12 @@ -package me.skymc.taboolib.socket; +package io.izzel.taboolib.origin.client; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.other.NumberUtils; -import me.skymc.taboolib.socket.packet.Packet; -import me.skymc.taboolib.socket.packet.PacketSerializer; -import me.skymc.taboolib.socket.packet.impl.PacketHeartbeat; -import me.skymc.taboolib.socket.packet.impl.PacketQuit; -import me.skymc.taboolib.socket.server.ClientConnection; +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.origin.client.packet.Packet; +import io.izzel.taboolib.origin.client.packet.PacketSerializer; +import io.izzel.taboolib.origin.client.packet.impl.PacketHeartbeat; +import io.izzel.taboolib.origin.client.packet.impl.PacketQuit; +import io.izzel.taboolib.origin.client.server.ClientConnection; +import org.bukkit.util.NumberConversions; import java.io.IOException; import java.net.ServerSocket; @@ -41,7 +41,7 @@ public class TabooLibServer { } try { - server = new ServerSocket(NumberUtils.getInteger(TabooLibSettings.getSettings().getProperty("channel.port"))); + server = new ServerSocket(NumberConversions.toInt(TabooLibSettings.getSettings().getProperty("channel.port"))); println("Starting TabooLib server on " + server.getInetAddress().getHostName() + ":" + server.getLocalPort()); } catch (IOException e) { println("Server starting failed: " + e.toString()); @@ -95,7 +95,7 @@ public class TabooLibServer { } public static void println(Object obj) { - System.out.println(TabooLib.isSpigot() ? obj : "[" + infoFormat.format(System.currentTimeMillis()) + " INFO]: " + obj); + System.out.println(TabooLibAPI.isBukkit() ? obj : "[" + infoFormat.format(System.currentTimeMillis()) + " INFO]: " + obj); } public static Optional> getConnection(int port) { diff --git a/src/main/scala/me/skymc/taboolib/socket/TabooLibSettings.java b/src/main/scala/io/izzel/taboolib/origin/client/TabooLibSettings.java similarity index 97% rename from src/main/scala/me/skymc/taboolib/socket/TabooLibSettings.java rename to src/main/scala/io/izzel/taboolib/origin/client/TabooLibSettings.java index fe39e1b..c7dc373 100644 --- a/src/main/scala/me/skymc/taboolib/socket/TabooLibSettings.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/TabooLibSettings.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.socket; +package io.izzel.taboolib.origin.client; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/scala/me/skymc/taboolib/socket/packet/Packet.java b/src/main/scala/io/izzel/taboolib/origin/client/packet/Packet.java similarity index 92% rename from src/main/scala/me/skymc/taboolib/socket/packet/Packet.java rename to src/main/scala/io/izzel/taboolib/origin/client/packet/Packet.java index dcdfcf4..9d2ea00 100644 --- a/src/main/scala/me/skymc/taboolib/socket/packet/Packet.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/packet/Packet.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.socket.packet; +package io.izzel.taboolib.origin.client.packet; import com.google.gson.JsonObject; diff --git a/src/main/scala/me/skymc/taboolib/socket/packet/PacketParser.java b/src/main/scala/io/izzel/taboolib/origin/client/packet/PacketParser.java similarity index 92% rename from src/main/scala/me/skymc/taboolib/socket/packet/PacketParser.java rename to src/main/scala/io/izzel/taboolib/origin/client/packet/PacketParser.java index c77cd31..21f95e2 100644 --- a/src/main/scala/me/skymc/taboolib/socket/packet/PacketParser.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/packet/PacketParser.java @@ -1,7 +1,8 @@ -package me.skymc.taboolib.socket.packet; +package io.izzel.taboolib.origin.client.packet; import com.google.gson.JsonObject; -import me.skymc.taboolib.fileutils.FileUtils; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.util.Files; import java.util.ArrayList; import java.util.Arrays; @@ -17,7 +18,7 @@ public class PacketParser { private List> packets = new ArrayList<>(); public PacketParser() { - FileUtils.getClasses(PacketParser.class).stream().filter(clazz -> clazz.isAnnotationPresent(PacketType.class)).forEach(clazz -> packets.add(clazz)); + Files.getClasses(TabooLib.getPlugin()).stream().filter(clazz -> clazz.isAnnotationPresent(PacketType.class)).forEach(clazz -> packets.add(clazz)); } public Packet parser(JsonObject json) { diff --git a/src/main/scala/me/skymc/taboolib/socket/packet/PacketSerializer.java b/src/main/scala/io/izzel/taboolib/origin/client/packet/PacketSerializer.java similarity index 89% rename from src/main/scala/me/skymc/taboolib/socket/packet/PacketSerializer.java rename to src/main/scala/io/izzel/taboolib/origin/client/packet/PacketSerializer.java index ddd5aeb..f01a907 100644 --- a/src/main/scala/me/skymc/taboolib/socket/packet/PacketSerializer.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/packet/PacketSerializer.java @@ -1,12 +1,12 @@ -package me.skymc.taboolib.socket.packet; +package io.izzel.taboolib.origin.client.packet; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonSyntaxException; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.TabooLibLoader; -import me.skymc.taboolib.listener.TListener; -import me.skymc.taboolib.socket.packet.impl.PacketEmpty; +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.TabooLibLoader; +import io.izzel.taboolib.module.inject.TListener; +import io.izzel.taboolib.origin.client.packet.impl.PacketEmpty; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -14,7 +14,6 @@ import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.plugin.Plugin; -import java.lang.reflect.Field; import java.util.Arrays; /** @@ -45,7 +44,7 @@ public class PacketSerializer implements Listener { } public static void loadPacket(Plugin plugin) { - if (TabooLib.isTabooLib(plugin) || TabooLib.isDependTabooLib(plugin)) { + if (plugin.getName().equals("TabooLib") || TabooLibAPI.isDependTabooLib(plugin)) { TabooLibLoader.getPluginClasses(plugin).ifPresent(classes -> classes.stream().filter(pluginClass -> pluginClass.isAnnotationPresent(PacketType.class)).forEach(pluginClass -> parser.getPackets().add(pluginClass))); } } @@ -55,7 +54,7 @@ public class PacketSerializer implements Listener { } public static void unloadPacket(Plugin plugin) { - if (TabooLib.isTabooLib(plugin) || TabooLib.isDependTabooLib(plugin)) { + if (plugin.getName().equals("TabooLib") || TabooLibAPI.isDependTabooLib(plugin)) { TabooLibLoader.getPluginClasses(plugin).ifPresent(classes -> classes.stream().filter(pluginClass -> pluginClass.isAnnotationPresent(PacketType.class)).forEach(pluginClass -> parser.getPackets().remove(pluginClass))); } } diff --git a/src/main/scala/me/skymc/taboolib/socket/packet/PacketType.java b/src/main/scala/io/izzel/taboolib/origin/client/packet/PacketType.java similarity index 87% rename from src/main/scala/me/skymc/taboolib/socket/packet/PacketType.java rename to src/main/scala/io/izzel/taboolib/origin/client/packet/PacketType.java index 10ead35..c8798c7 100644 --- a/src/main/scala/me/skymc/taboolib/socket/packet/PacketType.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/packet/PacketType.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.socket.packet; +package io.izzel.taboolib.origin.client.packet; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/scala/me/skymc/taboolib/socket/packet/PacketValue.java b/src/main/scala/io/izzel/taboolib/origin/client/packet/PacketValue.java similarity index 90% rename from src/main/scala/me/skymc/taboolib/socket/packet/PacketValue.java rename to src/main/scala/io/izzel/taboolib/origin/client/packet/PacketValue.java index c3166ea..ccdb7d3 100644 --- a/src/main/scala/me/skymc/taboolib/socket/packet/PacketValue.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/packet/PacketValue.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.socket.packet; +package io.izzel.taboolib.origin.client.packet; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketAlive.java b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketAlive.java similarity index 66% rename from src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketAlive.java rename to src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketAlive.java index ebd7c3a..8349ee6 100644 --- a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketAlive.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketAlive.java @@ -1,8 +1,8 @@ -package me.skymc.taboolib.socket.packet.impl; +package io.izzel.taboolib.origin.client.packet.impl; -import me.skymc.taboolib.socket.TabooLibServer; -import me.skymc.taboolib.socket.packet.Packet; -import me.skymc.taboolib.socket.packet.PacketType; +import io.izzel.taboolib.origin.client.TabooLibServer; +import io.izzel.taboolib.origin.client.packet.Packet; +import io.izzel.taboolib.origin.client.packet.PacketType; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketCommand.java b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketCommand.java similarity index 72% rename from src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketCommand.java rename to src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketCommand.java index ac1bcb4..cd74aff 100644 --- a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketCommand.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketCommand.java @@ -1,9 +1,9 @@ -package me.skymc.taboolib.socket.packet.impl; +package io.izzel.taboolib.origin.client.packet.impl; -import me.skymc.taboolib.socket.TabooLibServer; -import me.skymc.taboolib.socket.packet.Packet; -import me.skymc.taboolib.socket.packet.PacketType; -import me.skymc.taboolib.socket.packet.PacketValue; +import io.izzel.taboolib.origin.client.TabooLibServer; +import io.izzel.taboolib.origin.client.packet.Packet; +import io.izzel.taboolib.origin.client.packet.PacketType; +import io.izzel.taboolib.origin.client.packet.PacketValue; import org.bukkit.Bukkit; /** diff --git a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketEmpty.java b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketEmpty.java similarity index 64% rename from src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketEmpty.java rename to src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketEmpty.java index dfdce56..887b948 100644 --- a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketEmpty.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketEmpty.java @@ -1,7 +1,7 @@ -package me.skymc.taboolib.socket.packet.impl; +package io.izzel.taboolib.origin.client.packet.impl; -import me.skymc.taboolib.socket.packet.Packet; -import me.skymc.taboolib.socket.packet.PacketType; +import io.izzel.taboolib.origin.client.packet.Packet; +import io.izzel.taboolib.origin.client.packet.PacketType; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketHeartbeat.java b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketHeartbeat.java similarity index 70% rename from src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketHeartbeat.java rename to src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketHeartbeat.java index e28d06c..8acc7be 100644 --- a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketHeartbeat.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketHeartbeat.java @@ -1,9 +1,8 @@ -package me.skymc.taboolib.socket.packet.impl; +package io.izzel.taboolib.origin.client.packet.impl; -import me.skymc.taboolib.socket.TabooLibClient; -import me.skymc.taboolib.socket.packet.Packet; -import me.skymc.taboolib.socket.packet.PacketType; -import org.bukkit.Bukkit; +import io.izzel.taboolib.origin.client.TabooLibClient; +import io.izzel.taboolib.origin.client.packet.Packet; +import io.izzel.taboolib.origin.client.packet.PacketType; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketJoin.java b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketJoin.java similarity index 64% rename from src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketJoin.java rename to src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketJoin.java index d20ef1a..593b41f 100644 --- a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketJoin.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketJoin.java @@ -1,9 +1,9 @@ -package me.skymc.taboolib.socket.packet.impl; +package io.izzel.taboolib.origin.client.packet.impl; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.socket.TabooLibServer; -import me.skymc.taboolib.socket.packet.Packet; -import me.skymc.taboolib.socket.packet.PacketType; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.origin.client.TabooLibServer; +import io.izzel.taboolib.origin.client.packet.Packet; +import io.izzel.taboolib.origin.client.packet.PacketType; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketMessage.java b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketMessage.java similarity index 70% rename from src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketMessage.java rename to src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketMessage.java index 9cc9698..33e141e 100644 --- a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketMessage.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketMessage.java @@ -1,11 +1,10 @@ -package me.skymc.taboolib.socket.packet.impl; +package io.izzel.taboolib.origin.client.packet.impl; -import com.google.gson.JsonObject; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.socket.TabooLibServer; -import me.skymc.taboolib.socket.packet.Packet; -import me.skymc.taboolib.socket.packet.PacketType; -import me.skymc.taboolib.socket.packet.PacketValue; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.origin.client.TabooLibServer; +import io.izzel.taboolib.origin.client.packet.Packet; +import io.izzel.taboolib.origin.client.packet.PacketType; +import io.izzel.taboolib.origin.client.packet.PacketValue; import org.bukkit.Bukkit; /** diff --git a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketQuit.java b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketQuit.java similarity index 76% rename from src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketQuit.java rename to src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketQuit.java index fcb46fd..3eeba14 100644 --- a/src/main/scala/me/skymc/taboolib/socket/packet/impl/PacketQuit.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/packet/impl/PacketQuit.java @@ -1,10 +1,10 @@ -package me.skymc.taboolib.socket.packet.impl; +package io.izzel.taboolib.origin.client.packet.impl; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.socket.TabooLibServer; -import me.skymc.taboolib.socket.packet.Packet; -import me.skymc.taboolib.socket.packet.PacketType; -import me.skymc.taboolib.socket.packet.PacketValue; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.origin.client.TabooLibServer; +import io.izzel.taboolib.origin.client.packet.Packet; +import io.izzel.taboolib.origin.client.packet.PacketType; +import io.izzel.taboolib.origin.client.packet.PacketValue; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/socket/server/ClientConnection.java b/src/main/scala/io/izzel/taboolib/origin/client/server/ClientConnection.java similarity index 84% rename from src/main/scala/me/skymc/taboolib/socket/server/ClientConnection.java rename to src/main/scala/io/izzel/taboolib/origin/client/server/ClientConnection.java index 6c8a4a6..ce854df 100644 --- a/src/main/scala/me/skymc/taboolib/socket/server/ClientConnection.java +++ b/src/main/scala/io/izzel/taboolib/origin/client/server/ClientConnection.java @@ -1,10 +1,10 @@ -package me.skymc.taboolib.socket.server; +package io.izzel.taboolib.origin.client.server; -import me.skymc.taboolib.other.NumberUtils; -import me.skymc.taboolib.socket.TabooLibServer; -import me.skymc.taboolib.socket.TabooLibSettings; -import me.skymc.taboolib.socket.packet.impl.PacketJoin; -import me.skymc.taboolib.socket.packet.impl.PacketQuit; +import io.izzel.taboolib.origin.client.TabooLibServer; +import io.izzel.taboolib.origin.client.TabooLibSettings; +import io.izzel.taboolib.origin.client.packet.impl.PacketJoin; +import io.izzel.taboolib.origin.client.packet.impl.PacketQuit; +import org.bukkit.util.NumberConversions; import java.io.BufferedReader; import java.io.InputStreamReader; @@ -53,7 +53,7 @@ public class ClientConnection implements Runnable { } public boolean isAlive() { - return System.currentTimeMillis() - latestResponse < NumberUtils.getInteger(TabooLibSettings.getSettings().getProperty("channel.timeout")); + return System.currentTimeMillis() - latestResponse < NumberConversions.toInt(TabooLibSettings.getSettings().getProperty("channel.timeout")); } // ********************************* diff --git a/src/main/scala/me/skymc/taboolib/cronus/CronusParser.java b/src/main/scala/io/izzel/taboolib/origin/cronus/CronusParser.java similarity index 95% rename from src/main/scala/me/skymc/taboolib/cronus/CronusParser.java rename to src/main/scala/io/izzel/taboolib/origin/cronus/CronusParser.java index 82eb624..452ddd2 100644 --- a/src/main/scala/me/skymc/taboolib/cronus/CronusParser.java +++ b/src/main/scala/io/izzel/taboolib/origin/cronus/CronusParser.java @@ -1,7 +1,7 @@ -package me.skymc.taboolib.cronus; +package io.izzel.taboolib.origin.cronus; -import me.skymc.taboolib.cronus.bukkit.ItemStack; -import me.skymc.taboolib.cronus.bukkit.Location; +import io.izzel.taboolib.origin.cronus.bukkit.ItemStack; +import io.izzel.taboolib.origin.cronus.bukkit.Location; import org.bukkit.Bukkit; import org.bukkit.util.NumberConversions; diff --git a/src/main/scala/me/skymc/taboolib/cronus/CronusUtils.java b/src/main/scala/io/izzel/taboolib/origin/cronus/CronusUtils.java similarity index 98% rename from src/main/scala/me/skymc/taboolib/cronus/CronusUtils.java rename to src/main/scala/io/izzel/taboolib/origin/cronus/CronusUtils.java index dbf866e..99cb847 100644 --- a/src/main/scala/me/skymc/taboolib/cronus/CronusUtils.java +++ b/src/main/scala/io/izzel/taboolib/origin/cronus/CronusUtils.java @@ -1,6 +1,6 @@ -package me.skymc.taboolib.cronus; +package io.izzel.taboolib.origin.cronus; -import com.ilummc.tlib.util.Strings; +import io.izzel.taboolib.util.Strings; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; diff --git a/src/main/scala/me/skymc/taboolib/cronus/bukkit/ItemStack.java b/src/main/scala/io/izzel/taboolib/origin/cronus/bukkit/ItemStack.java similarity index 93% rename from src/main/scala/me/skymc/taboolib/cronus/bukkit/ItemStack.java rename to src/main/scala/io/izzel/taboolib/origin/cronus/bukkit/ItemStack.java index 1cebbde..a0d99f6 100644 --- a/src/main/scala/me/skymc/taboolib/cronus/bukkit/ItemStack.java +++ b/src/main/scala/io/izzel/taboolib/origin/cronus/bukkit/ItemStack.java @@ -1,6 +1,6 @@ -package me.skymc.taboolib.cronus.bukkit; +package io.izzel.taboolib.origin.cronus.bukkit; -import me.skymc.taboolib.inventory.ItemUtils; +import io.izzel.taboolib.module.item.Items; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -29,11 +29,11 @@ public class ItemStack { } public boolean isName(org.bukkit.inventory.ItemStack itemStack) { - return name == null || ItemUtils.getCustomName(itemStack).contains(name); + return name == null || Items.getName(itemStack).contains(name); } public boolean isLore(org.bukkit.inventory.ItemStack itemStack) { - return lore == null || ItemUtils.hasLore(itemStack, lore); + return lore == null || Items.hasLore(itemStack, lore); } public boolean isDamage(org.bukkit.inventory.ItemStack itemStack) { diff --git a/src/main/scala/me/skymc/taboolib/cronus/bukkit/Location.java b/src/main/scala/io/izzel/taboolib/origin/cronus/bukkit/Location.java similarity index 98% rename from src/main/scala/me/skymc/taboolib/cronus/bukkit/Location.java rename to src/main/scala/io/izzel/taboolib/origin/cronus/bukkit/Location.java index 58f6d75..e3a4279 100644 --- a/src/main/scala/me/skymc/taboolib/cronus/bukkit/Location.java +++ b/src/main/scala/io/izzel/taboolib/origin/cronus/bukkit/Location.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.cronus.bukkit; +package io.izzel.taboolib.origin.cronus.bukkit; import org.bukkit.Bukkit; diff --git a/src/main/scala/me/skymc/taboolib/cronus/util/StringExpression.java b/src/main/scala/io/izzel/taboolib/origin/cronus/util/StringExpression.java similarity index 94% rename from src/main/scala/me/skymc/taboolib/cronus/util/StringExpression.java rename to src/main/scala/io/izzel/taboolib/origin/cronus/util/StringExpression.java index afbfab8..e923da8 100644 --- a/src/main/scala/me/skymc/taboolib/cronus/util/StringExpression.java +++ b/src/main/scala/io/izzel/taboolib/origin/cronus/util/StringExpression.java @@ -1,8 +1,8 @@ -package me.skymc.taboolib.cronus.util; +package io.izzel.taboolib.origin.cronus.util; -import com.ilummc.tlib.logger.TLogger; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.common.inject.TInject; +import io.izzel.taboolib.module.logger.TLogger; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.module.inject.TInject; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/src/main/scala/me/skymc/taboolib/cronus/util/StringNumber.java b/src/main/scala/io/izzel/taboolib/origin/cronus/util/StringNumber.java similarity index 98% rename from src/main/scala/me/skymc/taboolib/cronus/util/StringNumber.java rename to src/main/scala/io/izzel/taboolib/origin/cronus/util/StringNumber.java index a903e68..72fb04c 100644 --- a/src/main/scala/me/skymc/taboolib/cronus/util/StringNumber.java +++ b/src/main/scala/io/izzel/taboolib/origin/cronus/util/StringNumber.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.cronus.util; +package io.izzel.taboolib.origin.cronus.util; /** * @Author 坏黑 diff --git a/src/main/scala/io/izzel/taboolib/origin/database/PlayerDataManager.java b/src/main/scala/io/izzel/taboolib/origin/database/PlayerDataManager.java new file mode 100644 index 0000000..a3c7742 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/origin/database/PlayerDataManager.java @@ -0,0 +1,95 @@ +package io.izzel.taboolib.origin.database; + +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.module.inject.TListener; +import io.izzel.taboolib.origin.event.PlayerLoadedEvent; +import io.izzel.taboolib.util.Files; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.io.File; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +@TListener +public class PlayerDataManager implements Listener { + + private static final ConcurrentHashMap PLAYER_DATA = new ConcurrentHashMap<>(); + + public static UsernameType getUsernameType() { + return TabooLib.getConfig().getBoolean("ENABLE-UUID") ? UsernameType.UUID : UsernameType.USERNAME; + } + + public static FileConfiguration getPlayerData(Player player) { + return getUsernameType() == UsernameType.UUID ? loadPlayerData(player.getUniqueId().toString()) : loadPlayerData(player.getName()); + } + + public static FileConfiguration loadPlayerData(String username) { + return PLAYER_DATA.computeIfAbsent(username, n -> YamlConfiguration.loadConfiguration(Files.file(TabooLib.getInst().getPlayerDataFolder(), username + ".yml"))); + } + + public static void savePlayerData(String username, boolean remove) { + // 没有数据 + if (!PLAYER_DATA.containsKey(username)) { + return; + } + // 读取文件 + File file = Files.file(TabooLib.getInst().getPlayerDataFolder(), username + ".yml"); + // 保存配置 + try { + PLAYER_DATA.get(username).save(file); + } catch (Throwable t) { + t.printStackTrace(); + } + // 获取玩家 + Player player = getUsernameType() == UsernameType.UUID ? Bukkit.getPlayer(UUID.fromString(username)) : Bukkit.getPlayerExact(username); + // 移除数据 + if (remove || player == null) { + PLAYER_DATA.remove(username); + } + } + + public static void saveAllCaches(boolean sync, boolean remove) { + if (sync) { + Bukkit.getScheduler().runTaskAsynchronously(TabooLib.getPlugin(), () -> PLAYER_DATA.keySet().forEach(name -> savePlayerData(name, false))); + } else { + PLAYER_DATA.keySet().forEach(name -> savePlayerData(name, false)); + } + } + + public static void saveAllPlayers(boolean sync, boolean remove) { + if (sync) { + Bukkit.getScheduler().runTaskAsynchronously(TabooLib.getPlugin(), () -> Bukkit.getOnlinePlayers().forEach(player -> savePlayerData(TabooLib.getConfig().getBoolean("ENABLE-UUID") ? player.getUniqueId().toString() : player.getName(), remove))); + } else { + Bukkit.getOnlinePlayers().forEach(player -> savePlayerData(TabooLib.getConfig().getBoolean("ENABLE-UUID") ? player.getUniqueId().toString() : player.getName(), remove)); + } + } + + @EventHandler + public void join(PlayerJoinEvent e) { + Bukkit.getScheduler().runTaskAsynchronously(TabooLib.getPlugin(), () -> { + // 载入数据 + loadPlayerData(TabooLib.getConfig().getBoolean("ENABLE-UUID") ? e.getPlayer().getUniqueId().toString() : e.getPlayer().getName()); + // 载入完成 + Bukkit.getPluginManager().callEvent(new PlayerLoadedEvent(e.getPlayer())); + }); + } + + @EventHandler + public void quit(PlayerQuitEvent e) { + Bukkit.getScheduler().runTaskAsynchronously(TabooLib.getPlugin(), () -> { + // 保存数据 + savePlayerData(TabooLib.getConfig().getBoolean("ENABLE-UUID") ? e.getPlayer().getUniqueId().toString() : e.getPlayer().getName(), true); + }); + } + + public enum UsernameType { + UUID, USERNAME + } +} diff --git a/src/main/scala/io/izzel/taboolib/origin/database/PluginDataManager.java b/src/main/scala/io/izzel/taboolib/origin/database/PluginDataManager.java new file mode 100644 index 0000000..744dc8b --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/origin/database/PluginDataManager.java @@ -0,0 +1,86 @@ +package io.izzel.taboolib.origin.database; + +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.util.Files; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.Plugin; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; + +public class PluginDataManager { + + public static final ConcurrentHashMap> CACHE_DATA_PLUGIN = new ConcurrentHashMap<>(); + + public static void saveAllCaches(Plugin plugin) { + saveAllCaches(plugin, false); + } + + public static void saveAllCaches(Plugin plugin, boolean remove) { + if (plugin == null || !CACHE_DATA_PLUGIN.containsKey(plugin.getName())) { + return; + } + for (String fileName : CACHE_DATA_PLUGIN.get(plugin.getName()).keySet()) { + saveConfiguration(CACHE_DATA_PLUGIN.get(plugin.getName()).get(fileName), Files.file(getDataSaveFolder(plugin), fileName)); + } + if (remove) { + CACHE_DATA_PLUGIN.remove(plugin.getName()); + } + } + + public static void saveAllCaches() { + saveAllCaches(false); + } + + public static void saveAllCaches(boolean remove) { + long time = System.currentTimeMillis(); + for (String plugin : CACHE_DATA_PLUGIN.keySet()) { + saveAllCaches(getFixedPlugin(plugin), remove); + } + } + + public static void saveConfiguration(FileConfiguration conf, File file) { + try { + conf.save(file); + } catch (IOException e) { + TLocale.Logger.error("DATA-UTILS.FAIL-SAVE-FILE", file.getName(), e.toString()); + } + } + + public static String getFixedFileName(String name) { + return name.contains(".") ? name : name + ".yml"; + } + + public static Plugin getFixedPlugin(String pluginName) { + return Bukkit.getPluginManager().getPlugin(pluginName) == null ? TabooLib.getPlugin() : Bukkit.getPluginManager().getPlugin(pluginName); + } + + public static File getDataSaveFolder(Plugin plugin) { + return plugin == null || plugin.getName().equals("TabooLib") ? TabooLib.getInst().getServerDataFolder() : plugin.getDataFolder(); + } + + public static String getDataSaveKey(Plugin plugin) { + return plugin == null ? "TabooLib" : plugin.getName(); + } + + public static FileConfiguration addPluginData(String name, Plugin plugin) { + return setPluginData(getFixedFileName(name), plugin, YamlConfiguration.loadConfiguration(Files.file(getDataSaveFolder(plugin), getFixedFileName(name)))); + } + + public static FileConfiguration getPluginData(String name, Plugin plugin) { + return !CACHE_DATA_PLUGIN.containsKey(getDataSaveKey(plugin)) ? new YamlConfiguration() : CACHE_DATA_PLUGIN.get(getDataSaveKey(plugin)).get(getFixedFileName(name)); + } + + public static FileConfiguration setPluginData(String name, Plugin plugin, FileConfiguration conf) { + if (!CACHE_DATA_PLUGIN.containsKey(getDataSaveKey(plugin))) { + CACHE_DATA_PLUGIN.put(getDataSaveKey(plugin), new HashMap<>()); + } + CACHE_DATA_PLUGIN.get(getDataSaveKey(plugin)).put(getFixedFileName(name), conf); + return conf; + } +} diff --git a/src/main/scala/me/skymc/taboolib/events/PlayerJumpEvent.java b/src/main/scala/io/izzel/taboolib/origin/event/PlayerJumpEvent.java similarity index 95% rename from src/main/scala/me/skymc/taboolib/events/PlayerJumpEvent.java rename to src/main/scala/io/izzel/taboolib/origin/event/PlayerJumpEvent.java index ba602e1..d8f158b 100644 --- a/src/main/scala/me/skymc/taboolib/events/PlayerJumpEvent.java +++ b/src/main/scala/io/izzel/taboolib/origin/event/PlayerJumpEvent.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.events; +package io.izzel.taboolib.origin.event; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; diff --git a/src/main/scala/me/skymc/taboolib/events/PlayerLoadedEvent.java b/src/main/scala/io/izzel/taboolib/origin/event/PlayerLoadedEvent.java similarity index 93% rename from src/main/scala/me/skymc/taboolib/events/PlayerLoadedEvent.java rename to src/main/scala/io/izzel/taboolib/origin/event/PlayerLoadedEvent.java index 9559be8..bf0e0d2 100644 --- a/src/main/scala/me/skymc/taboolib/events/PlayerLoadedEvent.java +++ b/src/main/scala/io/izzel/taboolib/origin/event/PlayerLoadedEvent.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.events; +package io.izzel.taboolib.origin.event; import org.bukkit.entity.Player; import org.bukkit.event.Event; diff --git a/src/main/scala/me/skymc/taboolib/scoreboard/ScoreboardUtil.java b/src/main/scala/io/izzel/taboolib/origin/lite/Boards.java similarity index 56% rename from src/main/scala/me/skymc/taboolib/scoreboard/ScoreboardUtil.java rename to src/main/scala/io/izzel/taboolib/origin/lite/Boards.java index 6085975..2a0c2ad 100644 --- a/src/main/scala/me/skymc/taboolib/scoreboard/ScoreboardUtil.java +++ b/src/main/scala/io/izzel/taboolib/origin/lite/Boards.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.scoreboard; +package io.izzel.taboolib.origin.lite; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -6,63 +6,45 @@ import org.bukkit.scoreboard.DisplaySlot; import org.bukkit.scoreboard.Scoreboard; import java.util.*; +import java.util.stream.IntStream; -public class ScoreboardUtil { +public class Boards { - private ScoreboardUtil() { - } - - public static String[] cutUnranked(String[] content) { - String[] elements = Arrays.copyOf(content, 16); - - if (elements[0] == null) { - elements[0] = "Unamed board"; - } - - if (elements[0].length() > 32) { - elements[0] = elements[0].substring(0, 32); - } - - for (int i = 1; i < elements.length; i++) { - if (elements[i] != null) { - if (elements[i].length() > 40) { - elements[i] = elements[i].substring(0, 40); - } - } - } - - return elements; - } - - public static String cutRankedTitle(String title) { + static String fixTitle(String title) { if (title == null) { return "Unamed board"; } - if (title.length() > 32) { return title.substring(0, 32); } - return title; } - public static HashMap cutRanked(Map content) { - HashMap elements = new HashMap<>(content); + static String[] fixLines(String[] content) { + String[] elements = Arrays.copyOf(content, 16); + if (elements[0] == null) { + elements[0] = "Unamed board"; + } + if (elements[0].length() > 32) { + elements[0] = elements[0].substring(0, 32); + } + IntStream.range(1, elements.length).filter(i -> elements[i] != null).filter(i -> elements[i].length() > 40).forEach(i -> elements[i] = elements[i].substring(0, 40)); + return elements; + } + static HashMap fixLines(Map content) { + HashMap elements = new HashMap<>(content); while (elements.size() > 15) { String minimumKey = (String) elements.keySet().toArray()[0]; int minimum = elements.get(minimumKey); - for (String string : elements.keySet()) { if (elements.get(string) < minimum || (elements.get(string) == minimum && string.compareTo(minimumKey) < 0)) { minimumKey = string; minimum = elements.get(string); } } - elements.remove(minimumKey); } - for (String string : new ArrayList<>(elements.keySet())) { if (string != null) { if (string.length() <= 40) { @@ -73,27 +55,20 @@ public class ScoreboardUtil { } } } - return elements; - } - public static Scoreboard unrankedSidebarDisplay(Player p, String... elements) { - elements = cutUnranked(elements); - + public static org.bukkit.scoreboard.Scoreboard display(Player p, String... elements) { + elements = fixLines(elements); try { if (p.getScoreboard() == null || p.getScoreboard() == Bukkit.getScoreboardManager().getMainScoreboard() || p.getScoreboard().getObjectives().size() != 1) { p.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard()); } - if (p.getScoreboard().getObjective(p.getUniqueId().toString().substring(0, 16)) == null) { p.getScoreboard().registerNewObjective(p.getUniqueId().toString().substring(0, 16), "dummy"); p.getScoreboard().getObjective(p.getUniqueId().toString().substring(0, 16)).setDisplaySlot(DisplaySlot.SIDEBAR); } - - p.getScoreboard().getObjective(DisplaySlot.SIDEBAR).setDisplayName(elements[0]); - for (int i = 1; i < elements.length; i++) { if (elements[i] != null) { if (p.getScoreboard().getObjective(DisplaySlot.SIDEBAR).getScore(elements[i]).getScore() != 16 - i) { @@ -105,11 +80,9 @@ public class ScoreboardUtil { } } } - } } } - for (String entry : p.getScoreboard().getEntries()) { boolean toErase = true; for (String element : elements) { @@ -118,53 +91,37 @@ public class ScoreboardUtil { break; } } - if (toErase) { p.getScoreboard().resetScores(entry); } - } - return p.getScoreboard(); } catch (Exception e) { return null; } } - public static boolean unrankedSidebarDisplay(Collection players, String[] elements) { - for (Player player : players) { - if (unrankedSidebarDisplay(player, elements) == null) { - return false; - } - } - - return true; + public static boolean display(Collection players, String[] elements) { + return players.stream().noneMatch(player -> display(player, elements) == null); } - public static boolean unrankedSidebarDisplay(Collection players, Scoreboard board, String... elements) { + public static boolean display(Collection players, org.bukkit.scoreboard.Scoreboard board, String... elements) { try { String objName = "COLLAB-SB-WINTER"; - if (board == null) { board = Bukkit.getScoreboardManager().getNewScoreboard(); } - - elements = cutUnranked(elements); - + elements = fixLines(elements); for (Player player : players) { if (player.getScoreboard() != board) { player.setScoreboard(board); } } - if (board.getObjective(objName) == null) { board.registerNewObjective(objName, "dummy"); board.getObjective(objName).setDisplaySlot(DisplaySlot.SIDEBAR); } - - board.getObjective(DisplaySlot.SIDEBAR).setDisplayName(elements[0]); - for (int i = 1; i < elements.length; i++) { if (elements[i] != null && board.getObjective(DisplaySlot.SIDEBAR).getScore(elements[i]).getScore() != 16 - i) { board.getObjective(DisplaySlot.SIDEBAR).getScore(elements[i]).setScore(16 - i); @@ -175,10 +132,8 @@ public class ScoreboardUtil { } } } - } } - for (String entry : board.getEntries()) { boolean toErase = true; for (String element : elements) { @@ -187,104 +142,10 @@ public class ScoreboardUtil { break; } } - if (toErase) { board.resetScores(entry); } - } - - return true; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - public static boolean rankedSidebarDisplay(Player p, String title, Map elements) { - try { - title = cutRankedTitle(title); - elements = cutRanked(elements); - - if (p.getScoreboard() == null || p.getScoreboard() == Bukkit.getScoreboardManager().getMainScoreboard() || p.getScoreboard().getObjectives().size() != 1) { - p.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard()); - } - - if (p.getScoreboard().getObjective(p.getUniqueId().toString().substring(0, 16)) == null) { - p.getScoreboard().registerNewObjective(p.getUniqueId().toString().substring(0, 16), "dummy"); - p.getScoreboard().getObjective(p.getUniqueId().toString().substring(0, 16)).setDisplaySlot(DisplaySlot.SIDEBAR); - } - p.getScoreboard().getObjective(DisplaySlot.SIDEBAR).setDisplayName(title); - - for (String string : elements.keySet()) { - if (p.getScoreboard().getObjective(DisplaySlot.SIDEBAR).getScore(string).getScore() != elements.get(string)) { - p.getScoreboard().getObjective(DisplaySlot.SIDEBAR).getScore(string).setScore(elements.get(string)); - } - } - - for (String string : new ArrayList<>(p.getScoreboard().getEntries())) { - if (!elements.keySet().contains(string)) { - p.getScoreboard().resetScores(string); - } - } - - return true; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - public static boolean rankedSidebarDisplay(Collection players, String title, Map elements) { - for (Player player : players) { - if (!rankedSidebarDisplay(player, title, elements)) { - return false; - } - } - - return true; - } - - public static boolean rankedSidebarDisplay(Collection players, String title, Map elements, Scoreboard board) { - try { - title = cutRankedTitle(title); - elements = cutRanked(elements); - - String objName = "COLLAB-SB-WINTER"; - - if (board == null) { - board = Bukkit.getScoreboardManager().getNewScoreboard(); - } - - - for (Player player : players) { - if (player.getScoreboard() != board) { - player.setScoreboard(board); - } - } - - if (board.getObjective(objName) == null) { - board.registerNewObjective(objName, "dummy"); - board.getObjective(objName).setDisplaySlot(DisplaySlot.SIDEBAR); - } - - - board.getObjective(DisplaySlot.SIDEBAR).setDisplayName(title); - - - for (String string : elements.keySet()) { - if (board.getObjective(DisplaySlot.SIDEBAR).getScore(string).getScore() != elements.get(string)) { - board.getObjective(DisplaySlot.SIDEBAR).getScore(string).setScore(elements.get(string)); - } - } - - for (String string : new ArrayList<>(board.getEntries())) { - if (!elements.keySet().contains(string)) { - board.resetScores(string); - } - } - - return true; } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/scala/io/izzel/taboolib/origin/lite/Catchers.java b/src/main/scala/io/izzel/taboolib/origin/lite/Catchers.java new file mode 100644 index 0000000..cf3f700 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/origin/lite/Catchers.java @@ -0,0 +1,70 @@ +package io.izzel.taboolib.origin.lite; + +import io.izzel.taboolib.TabooLib; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.HashMap; +import java.util.LinkedList; + +public class Catchers implements Listener { + + private static HashMap> playerdata = new HashMap<>(); + + public static HashMap> getPlayerdata() { + return playerdata; + } + + public static boolean contains(Player player) { + return playerdata.containsKey(player.getName()) && playerdata.get(player.getName()).size() > 0; + } + + public static void call(Player player, Catcher catcher) { + if (!playerdata.containsKey(player.getName())) { + playerdata.put(player.getName(), new LinkedList<>()); + } + playerdata.get(player.getName()).add(catcher.before()); + } + + @EventHandler + public void quit(PlayerQuitEvent e) { + playerdata.remove(e.getPlayer().getName()); + } + + @EventHandler + public void chat(AsyncPlayerChatEvent e) { + if (playerdata.containsKey(e.getPlayer().getName()) && contains(e.getPlayer())) { + e.setCancelled(true); + // 1.14 supported. + Bukkit.getScheduler().runTask(TabooLib.getPlugin(), () -> { + // 退出 + if (e.getMessage().equalsIgnoreCase("quit()")) { + playerdata.get(e.getPlayer().getName()).removeFirst().cancel(); + } + // 默认 + else { + Catcher catcher = playerdata.get(e.getPlayer().getName()).getFirst(); + // 如果终止引导 + if (!catcher.after(e.getMessage())) { + playerdata.get(e.getPlayer().getName()).removeFirst(); + } else { + catcher.before(); + } + } + }); + } + } + + public interface Catcher { + + Catcher before(); + + boolean after(String message); + + void cancel(); + } +} diff --git a/src/main/scala/io/izzel/taboolib/origin/lite/Effects.java b/src/main/scala/io/izzel/taboolib/origin/lite/Effects.java new file mode 100644 index 0000000..8f7fd63 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/origin/lite/Effects.java @@ -0,0 +1,967 @@ +package io.izzel.taboolib.origin.lite; + +import io.izzel.taboolib.Version; +import io.izzel.taboolib.module.nms.NMSHandler; +import io.izzel.taboolib.module.packet.TPacketHandler; +import io.izzel.taboolib.util.Reflection; +import org.bukkit.Bukkit; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.block.data.BlockData; +import org.bukkit.configuration.MemorySection; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.material.MaterialData; +import org.bukkit.util.NumberConversions; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Random; + +/** + * ParticleEffect Library + *

+ * This library was created by @DarkBlade12 and allows you to display all Minecraft particle effects on a Bukkit server + *

+ * You are welcome to use it, modify it and redistribute it under the following conditions: + *

+ *

+ * Special thanks: + *

    + *
  • @microgeek (original idea, names and packet parameters) + *
  • @ShadyPotato (1.8 names, ids and packet parameters) + *
  • @RingOfStorms (particle behavior) + *
  • @Cybermaxke (particle behavior) + *
  • @JamieSinn (hosting a jenkins server and documentation for particleeffect) + *
  • @SkytAsul (updating to 1.13) + *
+ *

+ * It would be nice if you provide credit to me if you use this class in a published project + * + * @author DarkBlade12 + * @version 1.8 + */ +public enum Effects { + + BARRIER, + BLOCK_CRACK(ParticleProperty.REQUIRES_DATA), + BLOCK_DUST(ParticleProperty.REQUIRES_DATA), + BUBBLE_COLUMN_UP(13), + BUBBLE_POP(13), + CLOUD, + CRIT, + CRIT_MAGIC, + CURRENT_DOWN(13), + DAMAGE_INDICATOR(9), + DOLPHIN(13), + DRAGON_BREATH(9), + DRIP_LAVA, + DRIP_WATER, + ENCHANTMENT_TABLE, + END_ROD(9), + EXPLOSION_HUGE, + EXPLOSION_LARGE, + EXPLOSION_NORMAL, + FALLING_DUST(10), + FIREWORKS_SPARK, + FLAME, + FOOTSTEP(0, 12), + HEART, + ITEM_CRACK(ParticleProperty.REQUIRES_DATA), + ITEM_TAKE, + LAVA, + MOB_APPEARANCE, + NAUTILUS(13), + NOTE(ParticleProperty.COLORABLE), + PORTAL, + REDSTONE(ParticleProperty.COLORABLE), + SLIME, + SMOKE_LARGE, + SMOKE_NORMAL, + SNOW_SHOVEL, + SNOWBALL, + SPELL, + SPELL_INSTANT, + SPELL_MOB(ParticleProperty.COLORABLE), + SPELL_MOB_AMBIENT(ParticleProperty.COLORABLE), + SPELL_WITCH, + SPIT(11), + SQUID_INK(13), + SUSPENDED, + SUSPENDED_DEPTH(0, 12), + SWEEP_ATTACK(9), + TOTEM(11), + TOWN_AURA, + VILLAGER_ANGRY, + VILLAGER_HAPPY, + WATER_BUBBLE, + WATER_DROP, + WATER_SPLASH, + WATER_WAKE, + ; + + private static int mcVersion = NumberConversions.toInt(Version.getBukkitVersion().split("_")[1]); + private org.bukkit.Particle bukkitParticle; + private final List properties; + private int min, max; + + Effects(ParticleProperty... properties) { + this(0, 0, properties); + } + + Effects(int min, ParticleProperty... properties) { + this(min, 0, properties); + } + + Effects(int min, int max, ParticleProperty... properties) { + this.properties = Arrays.asList(properties); + this.min = min; + this.max = max; + try { + bukkitParticle = org.bukkit.Particle.valueOf(this.name()); + } catch (IllegalArgumentException ex) { + bukkitParticle = null; + } + } + + public org.bukkit.Particle getBukkitParticle() { + return bukkitParticle; + } + + public int getMinimumVersion() { + return min; + } + + public int getMaximumVersion() { + return max; + } + + + /** + * Determine if this particle effect has a specific property + * + * @param property Property tested + * @return Whether it has the property or not + */ + public boolean hasProperty(ParticleProperty property) { + return properties.contains(property); + } + + /** + * Determine if this particle effect is supported by your current server version + * + * @return Whether the particle effect is supported or not + */ + public boolean isSupported() { + if (min != 0 && min > mcVersion) { + return false; + } + if (max != 0 && max < mcVersion) { + return false; + } + return bukkitParticle != null; + } + + /** + * Returns the particle effect with the given name + * + * @param name Name of the particle effect + * @return The particle effect + */ + public static Effects fromName(String name) { + for (Effects effect : values()) { + if (effect.name().equalsIgnoreCase(name)) { + if (!effect.isSupported()) { + throw new ParticleVersionException(); + } + return effect; + } + } + throw new IllegalArgumentException("ParticleEffect " + name + " doesn't exist."); + } + + /** + * Determine if the distance between @param location and one of the players exceeds 256 + * + * @param location Location to check + * @return Whether the distance exceeds 256 or not + */ + private static boolean isLongDistance(Location location, List players) { + String world = location.getWorld().getName(); + for (Player player : players) { + if (player == null) { + continue; + } + Location playerLocation = player.getLocation(); + if (!world.equals(playerLocation.getWorld().getName()) || playerLocation.distanceSquared(location) < 65536) { + continue; + } + return true; + } + return false; + } + + /** + * Determine if the data type for a particle effect is correct + * + * @param effect Particle effect + * @param data Particle data + * @return Whether the data type is correct or not + */ + private static boolean isDataCorrect(Effects effect, Object data) { + return ((effect == BLOCK_CRACK || effect == BLOCK_DUST) && (mcVersion < 13 ? data instanceof MaterialData : data instanceof BlockData)) || (effect == ITEM_CRACK && data instanceof ItemStack); + } + + /** + * Determine if the color type for a particle effect is correct + * + * @param effect Particle effect + * @param color Particle color + * @return Whether the color type is correct or not + */ + private static boolean isColorCorrect(Effects effect, ParticleColor color) { + return ((effect == SPELL_MOB || effect == SPELL_MOB_AMBIENT || effect == REDSTONE) && color instanceof OrdinaryColor) || (effect == NOTE && color instanceof NoteColor); + } + + /** + * Displays a particle effect which is only visible for all players within a certain range in the world of @param center + * + * @param offsetX Maximum distance particles can fly away from the center on the x-axis + * @param offsetY Maximum distance particles can fly away from the center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param range Range of the visibility + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ObjectException If the particle effect requires additional data + * @throws IllegalArgumentException If the particle effect requires water and none is at the center location + */ + public void display(double offsetX, double offsetY, double offsetZ, double speed, int amount, Location center, double range) throws ParticleVersionException, ObjectException, IllegalArgumentException { + if (!isSupported()) { + throw new ParticleVersionException(); + } + if (hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ObjectException("This particle effect requires additional data"); + } + /*if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { + throw new IllegalArgumentException("There is no water at the center location"); + }*/ + new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, range > 256, null).sendTo(center, range); + } + + /** + * Displays a particle effect which is only visible for the specified players + * + * @param offsetX Maximum distance particles can fly away from the center on the x-axis + * @param offsetY Maximum distance particles can fly away from the center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ObjectException If the particle effect requires additional data + * @throws IllegalArgumentException If the particle effect requires water and none is at the center location + */ + public void display(double offsetX, double offsetY, double offsetZ, double speed, int amount, Location center, List players) throws ParticleVersionException, ObjectException, IllegalArgumentException { + if (!isSupported()) { + throw new ParticleVersionException(); + } + if (hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ObjectException("This particle effect requires additional data"); + } + /*if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { + throw new IllegalArgumentException("There is no water at the center location"); + }*/ + new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, isLongDistance(center, players), null).sendTo(center, players); + } + + /** + * Displays a single particle which is colored and only visible for all players within a certain range in the world of @param center + * + * @param color Color of the particle + * @param offsetX Maximum distance particles can fly away from the center on the x-axis + * @param offsetY Maximum distance particles can fly away from the center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on the z-axis + * @param amount Amount of particles + * @param center Center location of the effect + * @param range Range of the visibility + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleColorException If the particle effect is not colorable or the color type is incorrect + */ + public void display(ParticleColor color, double offsetX, double offsetY, double offsetZ, int amount, Location center, double range) throws ParticleVersionException, ParticleColorException { + if (!isSupported()) { + throw new ParticleVersionException(); + } + if (!hasProperty(ParticleProperty.COLORABLE)) { + throw new ParticleColorException("This particle effect is not colorable"); + } + if (!isColorCorrect(this, color)) { + throw new ParticleColorException("The particle color type is incorrect"); + } + new ParticlePacket(this, offsetX, offsetY, offsetZ, 1, amount, range > 256, color).sendTo(center, range); + } + + /** + * Displays a single particle which is colored and only visible for the specified players + * + * @param color Color of the particle + * @param offsetX Maximum distance particles can fly away from the center on the x-axis + * @param offsetY Maximum distance particles can fly away from the center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on the z-axis + * @param amount Amount of particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ParticleColorException If the particle effect is not colorable or the color type is incorrect + */ + public void display(ParticleColor color, double offsetX, double offsetY, double offsetZ, int amount, Location center, List players) throws ParticleVersionException, ParticleColorException { + if (!isSupported()) { + throw new ParticleVersionException(); + } + if (!hasProperty(ParticleProperty.COLORABLE)) { + throw new ParticleColorException("This particle effect is not colorable"); + } + if (!isColorCorrect(this, color)) { + throw new ParticleColorException("The particle color type is incorrect"); + } + new ParticlePacket(this, offsetX, offsetY, offsetZ, 1, amount, isLongDistance(center, players), color).sendTo(center, players); + } + + /** + * Displays a particle effect which requires additional data and is only visible for the specified players + * + * @param data Data of the effect + * @param offsetX Maximum distance particles can fly away from the center on the x-axis + * @param offsetY Maximum distance particles can fly away from the center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param center Center location of the effect + * @param players Receivers of the effect + * @throws ParticleVersionException If the particle effect is not supported by the server version + * @throws ObjectException If the particle effect does not require additional data or if the data type is incorrect + */ + public void display(Object data, double offsetX, double offsetY, double offsetZ, double speed, int amount, Location center, List players) throws ParticleVersionException, ObjectException { + if (!isSupported()) { + throw new ParticleVersionException(); + } + if (!hasProperty(ParticleProperty.REQUIRES_DATA)) { + throw new ObjectException("This particle effect does not require additional data"); + } + if (!isDataCorrect(this, data)) { + throw new ObjectException("The particle data type is incorrect"); + } + new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, isLongDistance(center, players), data).sendTo(center, players); + } + + /** + * Represents the property of a particle effect + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public enum ParticleProperty { + /** + * The particle effect requires water to be displayed + */ + @Deprecated + REQUIRES_WATER, + /** + * The particle effect requires block or item data to be displayed + */ + REQUIRES_DATA, + /** + * The particle effect uses the offsets as direction values + */ + @Deprecated + DIRECTIONAL, + /** + * The particle effect uses the offsets as color values + */ + COLORABLE + } + + /** + * Represents the color for effects like {@link Effects#SPELL_MOB}, {@link Effects#SPELL_MOB_AMBIENT}, {@link Effects#REDSTONE} and {@link Effects#NOTE} + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static abstract class ParticleColor { + /** + * Returns the value for the offsetX field + * + * @return The offsetX value + */ + public abstract float getValueX(); + + /** + * Returns the value for the offsetY field + * + * @return The offsetY value + */ + public abstract float getValueY(); + + /** + * Returns the value for the offsetZ field + * + * @return The offsetZ value + */ + public abstract float getValueZ(); + } + + /** + * Represents the color for effects like {@link Effects#SPELL_MOB}, {@link Effects#SPELL_MOB_AMBIENT} and {@link Effects#NOTE} + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static class OrdinaryColor extends ParticleColor { + private final int red; + private final int green; + private final int blue; + + /** + * Construct a new ordinary color + * + * @param red Red value of the RGB format + * @param green Green value of the RGB format + * @param blue Blue value of the RGB format + * @throws IllegalArgumentException If one of the values is lower than 0 or higher than 255 + */ + public OrdinaryColor(int red, int green, int blue) throws IllegalArgumentException { + if (red < 0) { + throw new IllegalArgumentException("The red value is lower than 0"); + } + if (red > 255) { + throw new IllegalArgumentException("The red value is higher than 255"); + } + this.red = red; + if (green < 0) { + throw new IllegalArgumentException("The green value is lower than 0"); + } + if (green > 255) { + throw new IllegalArgumentException("The green value is higher than 255"); + } + this.green = green; + if (blue < 0) { + throw new IllegalArgumentException("The blue value is lower than 0"); + } + if (blue > 255) { + throw new IllegalArgumentException("The blue value is higher than 255"); + } + this.blue = blue; + } + + /** + * Construct a new ordinary color + * + * @param color Bukkit color + */ + public OrdinaryColor(Color color) { + this(color.getRed(), color.getGreen(), color.getBlue()); + } + + /** + * Returns the red value of the RGB format + * + * @return The red value + */ + public int getRed() { + return red; + } + + /** + * Returns the green value of the RGB format + * + * @return The green value + */ + public int getGreen() { + return green; + } + + /** + * Returns the blue value of the RGB format + * + * @return The blue value + */ + public int getBlue() { + return blue; + } + + /** + * Returns the red value divided by 255 + * + * @return The offsetX value + */ + + public float getValueX() { + return (float) red / 255F; + } + + /** + * Returns the green value divided by 255 + * + * @return The offsetY value + */ + + public float getValueY() { + return (float) green / 255F; + } + + /** + * Returns the blue value divided by 255 + * + * @return The offsetZ value + */ + + public float getValueZ() { + return (float) blue / 255F; + } + } + + /** + * Represents the color for the {@link Effects#NOTE} effect + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + public static final class NoteColor extends ParticleColor { + private final int note; + + /** + * Construct a new note color + * + * @param note Note id which determines color + * @throws IllegalArgumentException If the note value is lower than 0 or higher than 24 + */ + public NoteColor(int note) throws IllegalArgumentException { + if (note < 0) { + throw new IllegalArgumentException("The note value is lower than 0"); + } + if (note > 24) { + throw new IllegalArgumentException("The note value is higher than 24"); + } + this.note = note; + } + + /** + * Returns the note value divided by 24 + * + * @return The offsetX value + */ + + public float getValueX() { + return (float) note / 24F; + } + + /** + * Returns zero because the offsetY value is unused + * + * @return zero + */ + + public float getValueY() { + return 0; + } + + /** + * Returns zero because the offsetZ value is unused + * + * @return zero + */ + + public float getValueZ() { + return 0; + } + + } + + public enum ParticleShape { + POINT, NEAR, BAR, EXCLAMATION, SPOT + } + + public static class Particle { + private static Random random = new Random(); + + private Effects effect; + private ParticleShape shape; + private OrdinaryColor color; + + private byte typeCode; + + public Particle(Effects effect, ParticleShape shape, OrdinaryColor color) { + this.effect = effect; + this.shape = shape; + this.color = color; + + this.typeCode = (byte) (effect == Effects.NOTE ? 2 : (effect.hasProperty(ParticleProperty.COLORABLE) ? 1 : 0)); + } + + public String toString() { + return effect.name() + " in shape " + shape.name() + (typeCode != 0 ? " with color \"R" + (typeCode == 1 ? color.getRed() + " G" + color.getGreen() + " B" + color.getBlue() : "random") + "\"" : ""); + } + + public void send(LivingEntity en, List p) { + if (p.isEmpty()) { + return; + } + + Location lc = en.getEyeLocation(); + switch (shape) { + case POINT: + sendParticle(lc.add(0, 1, 0), p, 0.1, 0.1, 0.1, 1); + break; + case NEAR: + sendParticle(lc.add(random.nextDouble() * 1.2 - 0.6, random.nextDouble() * 2 - en.getEyeHeight(), random.nextDouble() * 1.2 - 0.6), p, 0.1, 0.1, 0.1, 1); + break; + case BAR: + sendParticle(lc.add(0, 1, 0), p, 0.01, 0.15, 0.01, 3); + break; + case EXCLAMATION: + sendParticle(lc.add(0, 0.9, 0), p, 0.001, 0.001, 0.001, 2); // POINT + sendParticle(lc.add(0, 0.7, 0), p, 0.01, 0.2, 0.01, 4); // BAR + break; + case SPOT: + sendParticle(lc.add(0, 0.2, 0), p, 0.2, 0.4, 0.2, 15); + break; + } + } + + private void sendParticle(Location lc, List p, double offX, double offY, double offZ, int amount) { + switch (typeCode) { + case 1: + effect.display(color, offX, offY, offZ, amount, lc, p); + break; + case 2: + Effects.NOTE.display(new Effects.NoteColor(random.nextInt(24)), offX, offY, offZ, amount, lc, /*p.getPlayer(),*/ p); + break; + case 0: + effect.display(offX, offY, offZ, 0.001, amount, lc, p); + break; + } + } + + public static Particle deserialize(Map map) { + return new Particle(Effects.fromName((String) map.get("particleEffect")), ParticleShape.valueOf(((String) map.get("particleShape")).toUpperCase()), new OrdinaryColor(Color.deserialize(((MemorySection) map.get("particleColor")).getValues(false)))); + } + } + + /** + * Represents a runtime exception that is thrown either if the displayed particle effect requires data and has none or vice-versa or if the data type is incorrect + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + private static final class ObjectException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new particle data exception + * + * @param message Message that will be logged + */ + public ObjectException(String message) { + super(message); + } + } + + /** + * Represents a runtime exception that is thrown either if the displayed particle effect is not colorable or if the particle color type is incorrect + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.7 + */ + private static final class ParticleColorException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new particle color exception + * + * @param message Message that will be logged + */ + public ParticleColorException(String message) { + super(message); + } + } + + /** + * Represents a runtime exception that is thrown if the displayed particle effect requires a newer version + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.6 + */ + private static final class ParticleVersionException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new particle version exception + */ + public ParticleVersionException() { + super("This particle effect is not supported by your server version"); + } + } + + /** + * Represents a particle effect packet with all attributes which is used for sending packets to the players + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.5 + */ + public static final class ParticlePacket { + private static boolean initialized; + /*private static Class enumParticle; + private static String ver; + private static String pack;*/ + private final Effects effect; + private float offsetX; + private float offsetY; + private float offsetZ; + private final float speed; + private int amount; + private int size = 1; + private final boolean longDistance; + private Object data; + private Object packet; + + private int timesSending = 1; + + /** + * Construct a new particle packet + * + * @param effect Particle effect + * @param offsetX Maximum distance particles can fly away from the center on the x-axis + * @param offsetY Maximum distance particles can fly away from the center on the y-axis + * @param offsetZ Maximum distance particles can fly away from the center on the z-axis + * @param speed Display speed of the particles + * @param amount Amount of particles + * @param longDistance Indicates whether the maximum distance is increased from 256 to 65536 + * @param data Data of the effect + * @throws IllegalArgumentException If the speed or amount is lower than 0 + */ + public ParticlePacket(Effects effect, double offsetX, double offsetY, double offsetZ, double speed, int amount, boolean longDistance, Object data) throws IllegalArgumentException { + initialize(); + if (speed < 0) { + throw new IllegalArgumentException("The speed is lower than 0"); + } + if (amount < 0) { + throw new IllegalArgumentException("The amount is lower than 0"); + } + this.effect = effect; + this.offsetX = (float) offsetX; + this.offsetY = (float) offsetY; + this.offsetZ = (float) offsetZ; + this.speed = (float) speed; + this.amount = amount; + this.longDistance = longDistance; + this.data = data; + } + + /** + * Construct a new particle packet of a single particle flying into a determined direction + * + * @param effect Particle effect + * @param direction Direction of the particle + * @param speed Display speed of the particle + * @param longDistance Indicates whether the maximum distance is increased from 256 to 65536 + * @param data Data of the effect + * @throws IllegalArgumentException If the speed is lower than 0 + */ + /*public ParticlePacket(ParticleEffect effect, Vector direction, float speed, boolean longDistance, Object data) throws IllegalArgumentException { + this(effect, (float) direction.getX(), (float) direction.getY(), (float) direction.getZ(), speed, 0, longDistance, data); + }*/ + + /** + * Initializes and sets initialized to true if it succeeds + *

+ * Note: These fields only have to be initialized once, so it will return if initialized is already set to true + */ + public static void initialize() { + if (initialized) { + return; + } + initialized = true; + } + + /** + * Determine if packet is initialized + * + * @return Whether these fields are initialized or not + */ + public static boolean isInitialized() { + return initialized; + } + + /** + * Initializes packet with all set values + * + * @param center Center location of the effect + * @throws PacketInstantiationException If instantion fails due to an unknown error + */ + private void initializePacket(Location center) throws PacketInstantiationException { + if (packet != null) { + return; + } + try { + //int tmpAmount = amount; + if (effect.hasProperty(ParticleProperty.COLORABLE) && data instanceof ParticleColor) { + if (mcVersion < 13 || data instanceof NoteColor) { + ParticleColor color = (ParticleColor) data; + offsetX = color.getValueX(); + offsetY = color.getValueY(); + offsetZ = color.getValueZ(); + timesSending = amount < 2 ? 1 : amount; + amount = 0; + data = null; + if (color instanceof OrdinaryColor && ((OrdinaryColor) color).getRed() == 0) { + offsetX = Float.MIN_NORMAL; + } + } else if (mcVersion >= 13 && data instanceof OrdinaryColor) { + data = getDustColor((OrdinaryColor) data, size); + } + } + this.packet = NMSHandler.getHandler().toPacketPlayOutWorldParticles(effect.getBukkitParticle(), longDistance, (float) center.getX(), (float) center.getY(), (float) center.getZ(), offsetX, offsetY, offsetZ, speed, amount, data); + } catch (Throwable exception) { + throw new PacketInstantiationException("Packet instantiation failed", exception); + } + } + + public static Object getDustColor(OrdinaryColor color, int size) { + try { + return Reflection.instantiateObject(Class.forName("org.bukkit.Particle$DustOptions"), Color.fromBGR(color.getBlue(), color.getGreen(), color.getRed()), size); + } catch (Throwable e) { + e.printStackTrace(); + } + return null; + } + + /** + * Sends the packet to a single player and caches it + * + * @param center Center location of the effect + * @param player Receiver of the packet + * @throws PacketInstantiationException If instantion fails due to an unknown error + * @throws PacketSendingException If sending fails due to an unknown error + */ + public void sendTo(Location center, Player player) throws PacketInstantiationException, PacketSendingException { + initializePacket(center); + try { + if (timesSending == 1) { + TPacketHandler.sendPacket(player, packet); + } else { + for (int i = 0; i < timesSending; i++) { + TPacketHandler.sendPacket(player, packet); + } + } + //sendPacket.invoke(playerConnection.get(getHandle.invoke(player)), packet); + //((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); + } catch (Throwable exception) { + throw new PacketSendingException("Failed to send the packet to player '" + player.getName() + "'", exception); + } + } + + /** + * Sends the packet to all players in the list + * + * @param center Center location of the effect + * @param players Receivers of the packet + * @throws IllegalArgumentException If the player list is empty + */ + public void sendTo(Location center, List players) throws IllegalArgumentException { + if (players.isEmpty()) { + throw new IllegalArgumentException("The player list is empty"); + } + for (Player player : players) { + sendTo(center, player); + } + } + + /** + * Sends the packet to all players in a certain range + * + * @param center Center location of the effect + * @param range Range in which players will receive the packet (Maximum range for particles is usually 16, but it can differ for some types) + * @throws IllegalArgumentException If the range is lower than 1 + */ + public void sendTo(Location center, double range) throws IllegalArgumentException { + if (range < 1) { + throw new IllegalArgumentException("The range is lower than 1"); + } + String worldName = center.getWorld().getName(); + double squared = range * range; + for (Player player : Bukkit.getOnlinePlayers()) { + if (!player.getWorld().getName().equals(worldName) || player.getLocation().distanceSquared(center) > squared) { + continue; + } + sendTo(center, player); + } + } + + /** + * Represents a runtime exception that is thrown if packet instantiation fails + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.4 + */ + private static final class PacketInstantiationException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new packet instantiation exception + * + * @param message Message that will be logged + * @param cause Cause of the exception + */ + public PacketInstantiationException(String message, Throwable cause) { + super(message, cause); + } + } + + /** + * Represents a runtime exception that is thrown if packet sending fails + *

+ * This class is part of the ParticleEffect Library and follows the same usage conditions + * + * @author DarkBlade12 + * @since 1.4 + */ + private static final class PacketSendingException extends RuntimeException { + private static final long serialVersionUID = 3203085387160737484L; + + /** + * Construct a new packet sending exception + * + * @param message Message that will be logged + * @param cause Cause of the exception + */ + public PacketSendingException(String message, Throwable cause) { + super(message, cause); + } + } + } +} \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/fileutils/TLogs.java b/src/main/scala/io/izzel/taboolib/origin/lite/Logs.java similarity index 86% rename from src/main/scala/me/skymc/taboolib/fileutils/TLogs.java rename to src/main/scala/io/izzel/taboolib/origin/lite/Logs.java index 49f6c89..8e97dba 100644 --- a/src/main/scala/me/skymc/taboolib/fileutils/TLogs.java +++ b/src/main/scala/io/izzel/taboolib/origin/lite/Logs.java @@ -1,13 +1,14 @@ -package me.skymc.taboolib.fileutils; +package io.izzel.taboolib.origin.lite; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.commands.internal.BaseMainCommand; -import me.skymc.taboolib.commands.internal.BaseSubCommand; -import me.skymc.taboolib.commands.internal.TCommand; -import me.skymc.taboolib.commands.internal.type.CommandArgument; -import me.skymc.taboolib.commands.internal.type.CommandRegister; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.module.command.TCommand; +import io.izzel.taboolib.module.command.base.BaseMainCommand; +import io.izzel.taboolib.module.command.base.BaseSubCommand; +import io.izzel.taboolib.module.command.base.CommandArgument; +import io.izzel.taboolib.module.command.base.CommandRegister; +import io.izzel.taboolib.util.Files; +import io.izzel.taboolib.util.Strings; import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -25,7 +26,7 @@ import java.text.SimpleDateFormat; aliases = {"tlog", "tlogs"}, permission = "taboolib.admin" ) -public class TLogs extends BaseMainCommand { +public class Logs extends BaseMainCommand { private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); @@ -146,9 +147,8 @@ public class TLogs extends BaseMainCommand { } public static void write(File file, String format, String text) { - Bukkit.getScheduler().runTask(TabooLib.instance(), () -> { - FileUtils.createNewFileAndPath(file); - try (FileWriter writer = new FileWriter(file, true)) { + Bukkit.getScheduler().runTask(TabooLib.getPlugin(), () -> { + try (FileWriter writer = new FileWriter(Files.file(file), true)) { writer.write(Strings.replaceWithOrder(format, dateFormat.format(System.currentTimeMillis()), text)); } catch (Exception ignored) { } diff --git a/src/main/scala/io/izzel/taboolib/origin/lite/Numbers.java b/src/main/scala/io/izzel/taboolib/origin/lite/Numbers.java new file mode 100644 index 0000000..352817b --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/origin/lite/Numbers.java @@ -0,0 +1,48 @@ +package io.izzel.taboolib.origin.lite; + +import java.text.DecimalFormat; +import java.util.Random; + +/** + * @Author 坏黑 + * @Since 2019-07-05 19:02 + */ +public class Numbers { + + private static Random random = new Random(); + private static DecimalFormat doubleFormat = new DecimalFormat("#.##"); + + public static Random getRandom() { + return random; + } + + public static Double format(Double num) { + return Double.valueOf(doubleFormat.format(num)); + } + + public static int getRandomInteger(Number num1, Number num2) { + int min = Math.min(num1.intValue(), num2.intValue()); + int max = Math.max(num1.intValue(), num2.intValue()); + return (int) (random.nextDouble() * (max - min) + min); + } + + public static double getRandomDouble(Number num1, Number num2) { + double min = Math.min(num1.doubleValue(), num2.doubleValue()); + double max = Math.max(num1.doubleValue(), num2.doubleValue()); + return random.nextDouble() * (max - min) + min; + } + + public static Boolean getBoolean(String str) { + if (str == null || str.isEmpty()) { + return false; + } + char var = str.charAt(0); + if (var == 'y' || var == 'Y' || var == 't' || var == 'T' || var == '1') { + return true; + } + if (var == 'n' || var == 'N' || var == 'f' || var == 'F' || var == '0') { + return false; + } + return false; + } +} diff --git a/src/main/scala/me/skymc/taboolib/javascript/ScriptHandler.java b/src/main/scala/io/izzel/taboolib/origin/lite/Scripts.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/javascript/ScriptHandler.java rename to src/main/scala/io/izzel/taboolib/origin/lite/Scripts.java index 3c61d93..da572e0 100644 --- a/src/main/scala/me/skymc/taboolib/javascript/ScriptHandler.java +++ b/src/main/scala/io/izzel/taboolib/origin/lite/Scripts.java @@ -1,9 +1,8 @@ -package me.skymc.taboolib.javascript; +package io.izzel.taboolib.origin.lite; -import com.ilummc.tlib.logger.TLogger; +import io.izzel.taboolib.module.logger.TLogger; import jdk.nashorn.api.scripting.NashornScriptEngineFactory; -import me.skymc.taboolib.common.function.TFunction; -import org.bukkit.configuration.file.FileConfiguration; +import io.izzel.taboolib.module.inject.TFunction; import javax.script.Compilable; import javax.script.CompiledScript; @@ -16,7 +15,7 @@ import java.util.Objects; * @Since 2018-06-02 22:48 */ @TFunction(enable = "init") -public class ScriptHandler { +public class Scripts { private static ScriptEngine scriptEngine; private static ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); diff --git a/src/main/scala/io/izzel/taboolib/origin/lite/Servers.java b/src/main/scala/io/izzel/taboolib/origin/lite/Servers.java new file mode 100644 index 0000000..1be7ded --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/origin/lite/Servers.java @@ -0,0 +1,47 @@ +package io.izzel.taboolib.origin.lite; + +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.event.entity.EntityDamageByEntityEvent; + +import java.lang.reflect.Field; + +/** + * @Author 坏黑 + * @Since 2019-07-05 18:53 + */ +public class Servers { + + public static void setEnchantmentAcceptingNew(boolean value) { + try { + Field f = Enchantment.class.getDeclaredField("acceptingNew"); + f.setAccessible(true); + f.set(null, value); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public static Player getAttackerInDamageEvent(EntityDamageByEntityEvent e) { + if (e.getDamager() instanceof Player) { + return (Player) e.getDamager(); + } else if (e.getDamager() instanceof Projectile && ((Projectile) e.getDamager()).getShooter() instanceof Player) { + return (Player) ((Projectile) e.getDamager()).getShooter(); + } else { + return null; + } + } + + public static LivingEntity getLivingAttackerInDamageEvent(EntityDamageByEntityEvent e) { + if (e.getDamager() instanceof LivingEntity) { + return (LivingEntity) e.getDamager(); + } else if (e.getDamager() instanceof Projectile && ((Projectile) e.getDamager()).getShooter() instanceof LivingEntity) { + return (LivingEntity) ((Projectile) e.getDamager()).getShooter(); + } else { + return null; + } + } +} diff --git a/src/main/scala/io/izzel/taboolib/origin/lite/Sounds.java b/src/main/scala/io/izzel/taboolib/origin/lite/Sounds.java new file mode 100644 index 0000000..c3c1501 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/origin/lite/Sounds.java @@ -0,0 +1,117 @@ +package io.izzel.taboolib.origin.lite; + +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.Version; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.Player; + +public class Sounds { + + private Sound sound; + private Float a; + private Float b; + private int delay; + + public Sounds() { + this.sound = Sound.valueOf(getModifiedSound("ENTITY_VILLAGER_NO")); + this.a = 1.0F; + this.b = 1.0F; + } + + public Sounds(Sound sound, float a, float b) { + this(sound, a, b, 0); + } + + public Sounds(Sound sound, float a, float b, int delay) { + this.sound = sound; + this.a = a; + this.b = b; + this.delay = delay; + } + + public Sounds(String s) { + parse(s); + } + + public void play(Player p) { + Bukkit.getScheduler().runTaskLater(TabooLib.getPlugin(), () -> p.playSound(p.getLocation(), this.sound, this.a, this.b), delay); + } + + public void play(Location l) { + Bukkit.getScheduler().runTaskLater(TabooLib.getPlugin(), () -> l.getWorld().playSound(l, this.sound, this.a, this.b), delay); + } + + public void parse(String s) { + try { + String[] split = s.split("-"); + this.sound = Sound.valueOf(getModifiedSound(split[0])); + this.a = Float.parseFloat(split[1]); + this.b = Float.parseFloat(split[2]); + this.delay = split.length > 3 ? Integer.parseInt(split[3]) : 0; + } catch (Exception var3) { + this.sound = Sound.valueOf(getModifiedSound("ENTITY_VILLAGER_NO")); + this.a = 1.0F; + this.b = 1.0F; + this.delay = 0; + } + } + + public static String getModifiedSound(String str) { + if (Version.isBefore(Version.v1_9)) { + str = str.replace("BLOCK_FIRE_EXTINGUISH", "FIZZ"); + str = str.replace("BLOCK_NOTE_HAT", "NOTE_STICKS"); + str = str.replace("ENTITY_SHEEP_DEATH", "SHEEP_IDLE"); + str = str.replace("ENTITY_LLAMA_ANGRY", "HORSE_HIT"); + str = str.replace("BLOCK_BREWING_STAND_BREW", "CREEPER_HISS"); + str = str.replace("ENTITY_SHULKER_TELEPORT", "ENDERMAN_TELEPORT"); + str = str.replace("ENTITY_ZOMBIE_ATTACK_IRON_DOOR", "ZOMBIE_METAL"); + str = str.replace("BLOCK_GRAVEL_BREAK", "DIG_GRAVEL"); + str = str.replace("BLOCK_SNOW_BREAK", "DIG_SNOW"); + str = str.replace("BLOCK_GRAVEL_BREAK", "DIG_GRAVEL"); + str = str.replace("ENTITY_PLAYER_LEVELUP", "LEVEL_UP"); + str = str.replace("ENTITY_SNOWBALL_THROW", "SHOOT_ARROW"); + str = str.replace("PLAYER_ATTACK_CRIT", "ITEM_BREAK"); + str = str.replace("ENDERMEN", "ENDERMAN"); + str = str.replace("ARROW_SHOOT", "SHOOT_ARROW"); + str = str.replace("ENDERMAN_HURT", "ENDERMAN_HIT"); + str = str.replace("BLAZE_HURT", "BLAZE_HIT"); + str = str.replace("_FLAP", "_WINGS"); + str = str.replaceAll("ENTITY_|GENERIC_|BLOCK_|_AMBIENT|_BREAK|UI_BUTTON_|EXPERIENCE_", ""); + } + return str; + } + + // ********************************* + // + // Getter and Setter + // + // ********************************* + + public Sound getSound() { + return sound; + } + + public Float getA() { + return a; + } + + public Float getB() { + return b; + } + + public int getDelay() { + return delay; + } + + @Override + public String toString() { + return "SoundPack{" + + "sound=" + sound + + ", a=" + a + + ", b=" + b + + ", delay=" + delay + + '}'; + } +} diff --git a/src/main/scala/me/skymc/taboolib/object/WeightCollection.java b/src/main/scala/io/izzel/taboolib/origin/lite/Weights.java similarity index 93% rename from src/main/scala/me/skymc/taboolib/object/WeightCollection.java rename to src/main/scala/io/izzel/taboolib/origin/lite/Weights.java index d5d48f9..ea37e57 100644 --- a/src/main/scala/me/skymc/taboolib/object/WeightCollection.java +++ b/src/main/scala/io/izzel/taboolib/origin/lite/Weights.java @@ -1,6 +1,4 @@ -package me.skymc.taboolib.object; - -import me.skymc.taboolib.other.NumberUtils; +package io.izzel.taboolib.origin.lite; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; @@ -13,7 +11,7 @@ import java.util.concurrent.CopyOnWriteArrayList; * @Since 2018-05-07 16:18 */ @ThreadSafe -public class WeightCollection { +public class Weights { private final List weightList = new CopyOnWriteArrayList<>(); @@ -37,7 +35,7 @@ public class WeightCollection { public WeightObject getWeight() { int weightSum = weightList.stream().mapToInt(WeightObject::getWeightNumber).sum(); if (weightSum > 0) { - Integer m = 0, n = NumberUtils.getRandom().nextInt(weightSum); + Integer m = 0, n = Numbers.getRandom().nextInt(weightSum); for (WeightObject weightObject : weightList) { if (m <= n && n < m + weightObject.getWeightNumber()) { return weightObject; diff --git a/src/main/scala/io/izzel/taboolib/origin/lite/cooldown/Cooldown.java b/src/main/scala/io/izzel/taboolib/origin/lite/cooldown/Cooldown.java new file mode 100644 index 0000000..f15fea8 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/origin/lite/cooldown/Cooldown.java @@ -0,0 +1,72 @@ +package io.izzel.taboolib.origin.lite.cooldown; + +import java.util.HashMap; + +public class Cooldown { + + private String plugin; + private String name; + private long seconds; + + private HashMap data = new HashMap<>(); + + public Cooldown(String n, int s) { + this.name = n; + this.seconds = s; + this.plugin = "null"; + } + + public Cooldown(String n, long s) { + this.name = n; + this.seconds = s; + this.plugin = "null"; + } + + public String getPackName() { + return name; + } + + public long getPackSeconds() { + return seconds; + } + + public String getPlugin() { + return plugin; + } + + public void setPlugin(String p) { + this.plugin = p; + } + + public void unRegister(String player) { + data.remove(player); + } + + public long getCooldown(String player) { + return getCooldown(player, 0); + } + + public long getCooldown(String player, long cutSeconds) { + if (!data.containsKey(player)) { + return 0; + } + long difference = ((System.currentTimeMillis() + cutSeconds) - data.get(player)); + return difference >= seconds ? 0 : seconds - difference; + } + + public boolean isCooldown(String player) { + return isCooldown(player, 0L); + } + + public boolean isCooldown(String player, long cutSeconds) { + if (!data.containsKey(player)) { + data.put(player, System.currentTimeMillis()); + return false; + } + if (getCooldown(player, cutSeconds) <= 0) { + data.put(player, System.currentTimeMillis()); + return false; + } + return true; + } +} diff --git a/src/main/scala/io/izzel/taboolib/origin/lite/cooldown/Cooldowns.java b/src/main/scala/io/izzel/taboolib/origin/lite/cooldown/Cooldowns.java new file mode 100644 index 0000000..6792d36 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/origin/lite/cooldown/Cooldowns.java @@ -0,0 +1,47 @@ +package io.izzel.taboolib.origin.lite.cooldown; + +import io.izzel.taboolib.module.inject.TListener; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.plugin.Plugin; + +import java.util.concurrent.ConcurrentHashMap; + +@TListener +public class Cooldowns implements Listener { + + private static ConcurrentHashMap list = new ConcurrentHashMap<>(); + + public static ConcurrentHashMap getCooldownPacks() { + return list; + } + + public static void register(Cooldown pack) { + list.put(pack.getPackName(), pack); + } + + public static void register(Cooldown pack, Plugin plugin) { + pack.setPlugin(plugin.getName()); + list.put(pack.getPackName(), pack); + } + + public static void unregister(String name) { + list.remove(name); + } + + private static void unregister(Cooldown pack) { + list.remove(pack.getPackName()); + } + + @EventHandler + public void quit(PlayerQuitEvent e) { + list.values().stream().filter(pack -> !pack.isCooldown(e.getPlayer().getName(), 0)).forEach(pack -> pack.unRegister(e.getPlayer().getName())); + } + + @EventHandler + public void disable(PluginDisableEvent e) { + list.values().stream().filter(pack -> pack.getPlugin().equals(e.getPlugin().getName())).forEach(Cooldowns::unregister); + } +} diff --git a/src/main/scala/me/skymc/taboolib/plugin/PluginLoadState.java b/src/main/scala/io/izzel/taboolib/origin/plugin/PluginLoadState.java similarity index 91% rename from src/main/scala/me/skymc/taboolib/plugin/PluginLoadState.java rename to src/main/scala/io/izzel/taboolib/origin/plugin/PluginLoadState.java index 59b7250..62b023c 100644 --- a/src/main/scala/me/skymc/taboolib/plugin/PluginLoadState.java +++ b/src/main/scala/io/izzel/taboolib/origin/plugin/PluginLoadState.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.plugin; +package io.izzel.taboolib.origin.plugin; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/plugin/PluginLoadStateType.java b/src/main/scala/io/izzel/taboolib/origin/plugin/PluginLoadStateType.java similarity index 90% rename from src/main/scala/me/skymc/taboolib/plugin/PluginLoadStateType.java rename to src/main/scala/io/izzel/taboolib/origin/plugin/PluginLoadStateType.java index 15c98b3..1d33633 100644 --- a/src/main/scala/me/skymc/taboolib/plugin/PluginLoadStateType.java +++ b/src/main/scala/io/izzel/taboolib/origin/plugin/PluginLoadStateType.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.plugin; +package io.izzel.taboolib.origin.plugin; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/plugin/PluginUnloadState.java b/src/main/scala/io/izzel/taboolib/origin/plugin/PluginUnloadState.java similarity index 90% rename from src/main/scala/me/skymc/taboolib/plugin/PluginUnloadState.java rename to src/main/scala/io/izzel/taboolib/origin/plugin/PluginUnloadState.java index 5e94809..226cdc4 100644 --- a/src/main/scala/me/skymc/taboolib/plugin/PluginUnloadState.java +++ b/src/main/scala/io/izzel/taboolib/origin/plugin/PluginUnloadState.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.plugin; +package io.izzel.taboolib.origin.plugin; /** * @Author sky diff --git a/src/main/scala/me/skymc/taboolib/plugin/PluginUtils.java b/src/main/scala/io/izzel/taboolib/origin/plugin/PluginUtils.java similarity index 93% rename from src/main/scala/me/skymc/taboolib/plugin/PluginUtils.java rename to src/main/scala/io/izzel/taboolib/origin/plugin/PluginUtils.java index e243c47..8914b3e 100644 --- a/src/main/scala/me/skymc/taboolib/plugin/PluginUtils.java +++ b/src/main/scala/io/izzel/taboolib/origin/plugin/PluginUtils.java @@ -1,9 +1,7 @@ -package me.skymc.taboolib.plugin; +package io.izzel.taboolib.origin.plugin; import com.google.common.base.Joiner; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.events.TPluginEnableEvent; -import me.skymc.taboolib.events.TPluginLoadEvent; +import io.izzel.taboolib.TabooLib; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.Command; @@ -51,7 +49,7 @@ public class PluginUtils { for (File pluginFile : new File("plugins").listFiles()) { if (pluginFile.getName().endsWith(".jar")) { try { - PluginDescriptionFile desc = Main.getInst().getPluginLoader().getPluginDescription(pluginFile); + PluginDescriptionFile desc = TabooLib.getPlugin().getPluginLoader().getPluginDescription(pluginFile); if (desc.getName().equalsIgnoreCase(name)) { return pluginFile; } @@ -184,7 +182,7 @@ public class PluginUtils { } public static boolean isIgnored(Plugin plugin) { - return plugin.equals(Main.getInst()); + return plugin.getName().equalsIgnoreCase("TabooLib"); } private static PluginLoadState load(Plugin plugin) { @@ -202,7 +200,7 @@ public class PluginUtils { for (File plugin : Objects.requireNonNull(pluginDir.listFiles())) { if (plugin.getName().endsWith(".jar")) { try { - PluginDescriptionFile desc = Main.getInst().getPluginLoader().getPluginDescription(plugin); + PluginDescriptionFile desc = TabooLib.getPlugin().getPluginLoader().getPluginDescription(plugin); if (desc.getName().equalsIgnoreCase(name)) { pluginFile = plugin; break; @@ -220,17 +218,7 @@ public class PluginUtils { } catch (InvalidPluginException e) { return new PluginLoadState(PluginLoadStateType.INVALID_PLUGIN, e.toString()); } - try { - Bukkit.getPluginManager().callEvent(new TPluginLoadEvent(target)); - } catch (Exception e) { - e.printStackTrace(); - } target.onLoad(); - try { - Bukkit.getPluginManager().callEvent(new TPluginEnableEvent(target)); - } catch (Exception e) { - e.printStackTrace(); - } Bukkit.getPluginManager().enablePlugin(target); return new PluginLoadState(PluginLoadStateType.LOADED, "null"); } diff --git a/src/main/scala/me/skymc/taboolib/itagapi/TagDataHandler.java b/src/main/scala/io/izzel/taboolib/origin/tag/TagDataHandler.java similarity index 64% rename from src/main/scala/me/skymc/taboolib/itagapi/TagDataHandler.java rename to src/main/scala/io/izzel/taboolib/origin/tag/TagDataHandler.java index d021ad5..2d100c6 100644 --- a/src/main/scala/me/skymc/taboolib/itagapi/TagDataHandler.java +++ b/src/main/scala/io/izzel/taboolib/origin/tag/TagDataHandler.java @@ -1,19 +1,15 @@ -package me.skymc.taboolib.itagapi; +package io.izzel.taboolib.origin.tag; -import com.google.common.base.Preconditions; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.common.function.TFunction; -import me.skymc.taboolib.packet.PacketUtils; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.module.inject.TFunction; +import io.izzel.taboolib.module.inject.TListener; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scoreboard.Scoreboard; import org.bukkit.scoreboard.Team; @@ -25,28 +21,12 @@ import java.util.UUID; * @Since 2018-05-23 0:37 */ @TFunction(enable = "init") +@TListener public class TagDataHandler implements Listener { - private static TagDataHandler handler; + private static TagDataHandler handler = new TagDataHandler() ; private HashMap playersData = new HashMap<>(); - static void init() { - Preconditions.checkArgument(handler == null, "TagDataHandler is already instanced!"); - handler = new TagDataHandler(); - // 注册监听 - Bukkit.getPluginManager().registerEvents(handler, TabooLib.instance()); - // 启动相关功能 - new BukkitRunnable() { - - @Override - public void run() { - if (PacketUtils.isProtocolLibEnabled() && Main.getInst().getConfig().getBoolean("TABLIST-PACKET", true)) { - TagPacket.inst(); - } - } - }.runTask(TabooLib.instance()); - } - public TagPlayerData unregisterPlayerData(Player player) { return playersData.remove(player.getUniqueId()); } @@ -86,27 +66,13 @@ public class TagDataHandler implements Listener { updatePlayerListName(player); } - public void setDisplay(Player player, String display) { - TagPlayerData playerData = getPlayerDataComputeIfAbsent(player); - cancelPlayerVariable(player, playerData); - player.setDisplayName(playerData.setNameDisplay(display).getNameDisplay()); - updatePlayerVariable(playerData); - updatePlayerListName(player); - Bukkit.getScheduler().runTask(Main.getInst(), () -> TagPacket.refreshPlayer(player)); - } - public void resetVariable(Player player) { updatePlayerVariable(getPlayerDataComputeIfAbsent(player).reset()); updatePlayerListName(player); } - public void resetDisplay(Player player) { - setDisplay(player, player.getName()); - } - public void reset(Player player) { updatePlayerVariable(getPlayerDataComputeIfAbsent(player).reset()); - setDisplay(player, player.getName()); } // ********************************* @@ -135,7 +101,7 @@ public class TagDataHandler implements Listener { entryTeam.setPrefix(playerData.getPrefix()); entryTeam.setSuffix(playerData.getSuffix()); // 傻逼 BedWarsRel 我草你妈的 - if (TabooLib.instance().getConfig().getBoolean("TABLIST-AUTO-CLEAN-TEAM", true)) { + if (TabooLib.getConfig().getBoolean("TABLIST-AUTO-CLEAN-TEAM", true)) { TagUtils.cleanEmptyTeamInScoreboard(scoreboard); } } @@ -148,7 +114,7 @@ public class TagDataHandler implements Listener { Scoreboard scoreboard = TagUtils.getScoreboardComputeIfAbsent(player); TagUtils.cleanEntryInScoreboard(scoreboard, playerData.getNameDisplay()); // 傻逼 BedWarsRel 我草你妈的 - if (TabooLib.instance().getConfig().getBoolean("TABLIST-AUTO-CLEAN-TEAM", true)) { + if (TabooLib.getConfig().getBoolean("TABLIST-AUTO-CLEAN-TEAM", true)) { TagUtils.cleanEmptyTeamInScoreboard(scoreboard); } } @@ -170,24 +136,6 @@ public class TagDataHandler implements Listener { cancelPlayerVariable(e.getPlayer(), unregisterPlayerData(e.getPlayer())); } - @EventHandler - public void onCommand(PlayerCommandPreprocessEvent e) { - if (e.getMessage().equalsIgnoreCase("/scoreboardinfo") && e.getPlayer().hasPermission("itagapi.info")) { - e.setCancelled(true); - - e.getPlayer().sendMessage("§7计分板信息:"); - Scoreboard scoreboard = TagUtils.getScoreboardComputeIfAbsent(e.getPlayer()); - - for (Team team : scoreboard.getTeams()) { - e.getPlayer().sendMessage("§7队伍: §f" + team.getName()); - e.getPlayer().sendMessage("§f - §7前缀: §f" + team.getPrefix()); - e.getPlayer().sendMessage("§f - §7后缀: §f" + team.getSuffix()); - e.getPlayer().sendMessage("§f - §7成员: §f"); - team.getEntries().forEach(entry -> e.getPlayer().sendMessage("§f - §f" + entry)); - } - } - } - // ********************************* // // Getter and Setter diff --git a/src/main/scala/me/skymc/taboolib/itagapi/TagPlayerData.java b/src/main/scala/io/izzel/taboolib/origin/tag/TagPlayerData.java similarity index 87% rename from src/main/scala/me/skymc/taboolib/itagapi/TagPlayerData.java rename to src/main/scala/io/izzel/taboolib/origin/tag/TagPlayerData.java index b7ceb67..0b861d0 100644 --- a/src/main/scala/me/skymc/taboolib/itagapi/TagPlayerData.java +++ b/src/main/scala/io/izzel/taboolib/origin/tag/TagPlayerData.java @@ -1,11 +1,9 @@ -package me.skymc.taboolib.itagapi; +package io.izzel.taboolib.origin.tag; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.Main; -import org.bukkit.Bukkit; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.util.Strings; import org.bukkit.entity.Player; -import java.text.MessageFormat; import java.util.Objects; import java.util.UUID; @@ -30,7 +28,7 @@ public class TagPlayerData { } public String getTeamHash() { - return Main.getInst().getConfig().getBoolean("TABLIST-SORT") ? String.valueOf(Objects.hash(prefix)) : nameOrigin; + return TabooLib.getPlugin().getConfig().getBoolean("TABLIST-SORT") ? String.valueOf(Objects.hash(prefix)) : nameOrigin; } public TagPlayerData reset() { diff --git a/src/main/scala/me/skymc/taboolib/itagapi/TagUtils.java b/src/main/scala/io/izzel/taboolib/origin/tag/TagUtils.java similarity index 95% rename from src/main/scala/me/skymc/taboolib/itagapi/TagUtils.java rename to src/main/scala/io/izzel/taboolib/origin/tag/TagUtils.java index e0bcb8d..8c25d54 100644 --- a/src/main/scala/me/skymc/taboolib/itagapi/TagUtils.java +++ b/src/main/scala/io/izzel/taboolib/origin/tag/TagUtils.java @@ -1,6 +1,6 @@ -package me.skymc.taboolib.itagapi; +package io.izzel.taboolib.origin.tag; -import com.ilummc.tlib.logger.TLogger; +import io.izzel.taboolib.module.logger.TLogger; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.scoreboard.Scoreboard; diff --git a/src/main/scala/io/izzel/taboolib/plugin/InternalJavaPlugin.java b/src/main/scala/io/izzel/taboolib/plugin/InternalJavaPlugin.java new file mode 100644 index 0000000..6e1e806 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/plugin/InternalJavaPlugin.java @@ -0,0 +1,10 @@ +package io.izzel.taboolib.plugin; + +import org.bukkit.plugin.java.JavaPlugin; + +/** + * @Author 坏黑 + * @Since 2019-07-05 14:13 + */ +public class InternalJavaPlugin extends JavaPlugin { +} diff --git a/src/main/scala/io/izzel/taboolib/plugin/InternalPlugin.java b/src/main/scala/io/izzel/taboolib/plugin/InternalPlugin.java new file mode 100644 index 0000000..f271614 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/plugin/InternalPlugin.java @@ -0,0 +1,139 @@ +package io.izzel.taboolib.plugin; + +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.util.Files; +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.generator.ChunkGenerator; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.PluginLoader; + +import java.io.File; +import java.io.InputStream; +import java.util.List; +import java.util.logging.Logger; + +/** + * @Author 坏黑 + * @Since 2019-07-05 14:02 + */ +public class InternalPlugin implements Plugin { + + private static InternalPlugin plugin; + + public static InternalPlugin getPlugin() { + return plugin; + } + + static { + plugin = new InternalPlugin(); + } + + @Override + public File getDataFolder() { + return new File("plugins/TabooLib"); + } + + @Override + public PluginDescriptionFile getDescription() { + return new PluginDescriptionFile("TabooLib", String.valueOf(TabooLib.getVersion()), "io.izzel.taboolib.plugin.InternalJavaPlugin"); + } + + @Override + public FileConfiguration getConfig() { + return null; + } + + @Override + public InputStream getResource(String s) { + return Files.getResourceTabooLib(s); + } + + @Override + public void saveConfig() { + } + + @Override + public void saveDefaultConfig() { + } + + @Override + public void saveResource(String s, boolean b) { + File file = new File(getDataFolder(), s); + if (!file.exists() || b) { + Files.toFile(getResource(s), Files.file(file)); + } + } + + @Override + public void reloadConfig() { + } + + @Override + public PluginLoader getPluginLoader() { + return InternalPluginLoader.getLoader(); + } + + @Override + public Server getServer() { + return Bukkit.getServer(); + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public void onDisable() { + + } + + @Override + public void onLoad() { + + } + + @Override + public void onEnable() { + + } + + @Override + public boolean isNaggable() { + return false; + } + + @Override + public void setNaggable(boolean b) { + } + + @Override + public ChunkGenerator getDefaultWorldGenerator(String s, String s1) { + return null; + } + + @Override + public Logger getLogger() { + return null; + } + + @Override + public String getName() { + return "TabooLib"; + } + + @Override + public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) { + return false; + } + + @Override + public List onTabComplete(CommandSender commandSender, Command command, String s, String[] strings) { + return null; + } +} diff --git a/src/main/scala/io/izzel/taboolib/plugin/InternalPluginLoader.java b/src/main/scala/io/izzel/taboolib/plugin/InternalPluginLoader.java new file mode 100644 index 0000000..f1a2a35 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/plugin/InternalPluginLoader.java @@ -0,0 +1,59 @@ +package io.izzel.taboolib.plugin; + +import org.bukkit.Bukkit; +import org.bukkit.event.Event; +import org.bukkit.event.Listener; +import org.bukkit.plugin.*; +import org.bukkit.plugin.java.JavaPluginLoader; + +import java.io.File; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * @Author 坏黑 + * @Since 2019-07-05 14:09 + */ +public class InternalPluginLoader implements PluginLoader { + + private static JavaPluginLoader loader; + + public static PluginLoader getLoader() { + return loader; + } + + static { + loader = new JavaPluginLoader(Bukkit.getServer()); + } + + @Override + public Plugin loadPlugin(File file) throws UnknownDependencyException, InvalidPluginException { + return loader.loadPlugin(file); + } + + @Override + public PluginDescriptionFile getPluginDescription(File file) throws InvalidDescriptionException { + return loader.getPluginDescription(file); + } + + @Override + public Pattern[] getPluginFileFilters() { + return loader.getPluginFileFilters(); + } + + @Override + public Map, Set> createRegisteredListeners(Listener listener, Plugin plugin) { + return loader.createRegisteredListeners(listener, plugin); + } + + @Override + public void enablePlugin(Plugin plugin) { + loader.enablePlugin(plugin); + } + + @Override + public void disablePlugin(Plugin plugin) { + loader.disablePlugin(plugin); + } +} diff --git a/src/main/scala/me/skymc/taboolib/string/ArrayUtils.java b/src/main/scala/io/izzel/taboolib/util/ArrayUtil.java similarity index 74% rename from src/main/scala/me/skymc/taboolib/string/ArrayUtils.java rename to src/main/scala/io/izzel/taboolib/util/ArrayUtil.java index b2da4df..17c96f5 100644 --- a/src/main/scala/me/skymc/taboolib/string/ArrayUtils.java +++ b/src/main/scala/io/izzel/taboolib/util/ArrayUtil.java @@ -1,9 +1,5 @@ -package me.skymc.taboolib.string; +package io.izzel.taboolib.util; -import com.ilummc.tlib.util.Strings; - -import java.io.*; -import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -14,7 +10,7 @@ import java.util.stream.IntStream; * @author Bkm016 * @since 2018-04-16 */ -public class ArrayUtils { +public class ArrayUtil { public static int indexOf(T[] array, T obj) { return array == null || array.length == 0 ? -1 : IntStream.range(0, array.length).filter(i -> array[i] != null && array[i].equals(obj)).findFirst().orElse(-1); @@ -47,29 +43,20 @@ public class ArrayUtils { @SuppressWarnings("SuspiciousSystemArraycopy") public static T arrayExpand(T oldArray, int expand) { - int length = Array.getLength(oldArray); - Object newArray = Array.newInstance(oldArray.getClass().getComponentType(), length + expand); + int length = java.lang.reflect.Array.getLength(oldArray); + Object newArray = java.lang.reflect.Array.newInstance(oldArray.getClass().getComponentType(), length + expand); System.arraycopy(oldArray, 0, newArray, 0, length); return (T) newArray; } @SuppressWarnings("SuspiciousSystemArraycopy") public static T arrayExpandAtFirst(T oldArray, int expand) { - int length = Array.getLength(oldArray); - Object newArray = Array.newInstance(oldArray.getClass().getComponentType(), length + expand); + int length = java.lang.reflect.Array.getLength(oldArray); + Object newArray = java.lang.reflect.Array.newInstance(oldArray.getClass().getComponentType(), length + expand); System.arraycopy(oldArray, 0, newArray, expand, length); return (T) newArray; } - public static T cloneAsByte(T obj) throws IOException, ClassNotFoundException { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); - objectOutputStream.writeObject(obj); - ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); - ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); - return (T) objectInputStream.readObject(); - } - public static T skipEmpty(T obj) { return skipEmpty(obj, null); } diff --git a/src/main/scala/io/izzel/taboolib/util/Files.java b/src/main/scala/io/izzel/taboolib/util/Files.java new file mode 100644 index 0000000..a686ecd --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/util/Files.java @@ -0,0 +1,297 @@ +package io.izzel.taboolib.util; + +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.locale.TLocale; +import io.izzel.taboolib.plugin.InternalPlugin; +import io.izzel.taboolib.util.eagletdl.EagletTask; +import io.izzel.taboolib.util.eagletdl.ProgressEvent; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.Plugin; +import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; + +import java.io.*; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.nio.channels.FileChannel; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * @author sky + */ +public class Files { + + public static List getClasses(Plugin plugin) { + return getClasses(plugin, new String[0]); + } + + public static List getClasses(Plugin plugin, String[] ignore) { + List classes = new CopyOnWriteArrayList<>(); + URL url = plugin.getClass().getProtectionDomain().getCodeSource().getLocation(); + try { + File src; + try { + src = new File(url.toURI()); + } catch (URISyntaxException e) { + src = new File(url.getPath()); + } + new JarFile(src).stream().filter(entry -> entry.getName().endsWith(".class")).forEach(entry -> { + String className = entry.getName().replace('/', '.').substring(0, entry.getName().length() - 6); + try { + if (Arrays.stream(ignore).noneMatch(className::startsWith)) { + classes.add(Class.forName(className, false, plugin.getClass().getClassLoader())); + } + } catch (Throwable ignored) { + } + }); + } catch (Throwable ignored) { + } + return classes; + } + + public static InputStream getResource(String filename) { + return getResource(TabooLib.getPlugin(), filename); + } + + public static InputStream getResource(Plugin plugin, String filename) { + return plugin instanceof InternalPlugin ? getResourceTabooLib(filename) : plugin.getClass().getClassLoader().getResourceAsStream(filename); + } + + public static InputStream getResourceTabooLib(String filename) { + try { + ZipFile zipFile = new ZipFile(new File("TabooLib.jar")); + ZipEntry entry = zipFile.getEntry(filename); + if (entry != null) { + return zipFile.getInputStream(entry); + } + } catch (IOException e) { + e.printStackTrace(); + } + return TabooLib.class.getResourceAsStream(filename); + } + + public static void releaseResource(Plugin plugin, String path, boolean replace) { + File file = new File(plugin.getDataFolder(), path); + if (!file.exists() || replace) { + toFile(getResource(plugin, path), Files.file(file)); + } + } + + public static void toFile(String in, File file) { + try (FileWriter fileWriter = new FileWriter(file); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) { + bufferedWriter.write(in); + bufferedWriter.flush(); + } catch (Exception ignored) { + } + } + + public static void toFile(InputStream inputStream, File file) { + try (FileOutputStream fos = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(fos)) { + byte[] buf = new byte[1024]; + int len; + while ((len = inputStream.read(buf)) > 0) { + bos.write(buf, 0, len); + } + bos.flush(); + } catch (Exception ignored) { + } + } + + public static File file(File path, String filePath) { + return file(new File(path, filePath)); + } + + public static File file(String filePath) { + return file(new File(filePath)); + } + + public static File file(File file) { + if (!file.exists()) { + folder(file); + try { + file.createNewFile(); + } catch (Throwable t) { + t.printStackTrace(); + } + } + return file; + } + + public static File folder(File path, String filePath) { + return folder(new File(path, filePath)); + } + + public static File folder(String filePath) { + return folder(new File(filePath)); + } + + public static File folder(File file) { + if (!file.exists()) { + String filePath = file.getPath(); + int index = filePath.lastIndexOf(File.separator); + String folderPath; + File folder; + if ((index >= 0) && (!(folder = new File(filePath.substring(0, index))).exists())) { + folder.mkdirs(); + } + } + return file; + } + + public static void deepDelete(File file) { + if (!file.exists()) { + return; + } + if (file.isFile()) { + file.delete(); + return; + } + for (File file1 : Objects.requireNonNull(file.listFiles())) { + deepDelete(file1); + } + file.delete(); + } + + public static void deepCopy(String originFileName, String targetFileName) { + File originFile = new File(originFileName); + File targetFile = new File(targetFileName); + if (!targetFile.exists()) { + if (!originFile.isDirectory()) { + file(targetFile); + } else { + targetFile.mkdirs(); + } + } + if (originFile.isDirectory()) { + for (File file : Objects.requireNonNull(originFile.listFiles())) { + if (file.isDirectory()) { + deepCopy(file.getAbsolutePath(), targetFileName + "/" + file.getName()); + } else { + weekCopy(file, new File(targetFileName + "/" + file.getName())); + } + } + } else { + weekCopy(originFile, targetFile); + } + } + + public static void weekCopy(File file1, File file2) { + try (FileInputStream fileIn = new FileInputStream(file1); + FileOutputStream fileOut = new FileOutputStream(file2); + FileChannel channelIn = fileIn.getChannel(); + FileChannel channelOut = fileOut.getChannel()) { + channelIn.transferTo(0, channelIn.size(), channelOut); + } catch (IOException t) { + t.printStackTrace(); + } + } + + public static String readFromURL(String url, String def) { + String s = readFromURL(url, 1024); + return s == null ? def : s; + } + + public static String readFromURL(String url, int size) { + URLConnection conn = null; + BufferedInputStream bin = null; + try { + conn = new URL(url).openConnection(); + bin = new BufferedInputStream(conn.getInputStream()); + return readFromStream(bin, size, conn.getContentEncoding() == null ? "UTF-8" : conn.getContentEncoding()); + } catch (IOException e) { + e.printStackTrace(); + } finally { + IO.close(conn); + IO.closeQuietly(bin); + } + return null; + } + + public static String readFromFile(File file, int size, String encode) { + try (FileInputStream fin = new FileInputStream(file); BufferedInputStream bin = new BufferedInputStream(fin)) { + return readFromStream(fin, size, encode); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public static String readFromStream(InputStream in, int size, String encode) { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + byte[] b = new byte[size]; + int i; + while ((i = in.read(b)) > 0) { + bos.write(b, 0, i); + } + return new String(bos.toByteArray(), encode); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public static void download(String url, File file) { + download(url, file, false); + } + + public static void download(String url, File file, boolean async) { + EagletTask eagletTask = new EagletTask() + .url(url) + .file(file) + .setThreads(8) + .setOnError(event -> { + }) + .setOnConnected(event -> TLocale.Logger.info("UTIL.DOWNLOAD-CONNECTED", file.getName(), ProgressEvent.format(event.getContentLength()))) + .setOnProgress(event -> TLocale.Logger.info("UTIL.DOWNLOAD-PROGRESS", event.getSpeedFormatted(), event.getPercentageFormatted())) + .setOnComplete(event -> { + if (event.isSuccess()) { + TLocale.Logger.info("UTIL.DOWNLOAD-SUCCESS", file.getName()); + } else { + TLocale.Logger.error("UTIL.DOWNLOAD-FAILED", file.getName()); + } + }).start(); + if (!async) { + eagletTask.waitUntil(); + } + } + + public static FileConfiguration decodeYAML(String args) { + return YamlConfiguration.loadConfiguration(new StringReader(Base64Coder.decodeString(args))); + } + + public static String encodeYAML(FileConfiguration file) { + return Base64Coder.encodeLines(file.saveToString().getBytes()).replaceAll("\\s+", ""); + } + + public static FileConfiguration load(Plugin plugin, File file) { + return loadYaml(plugin, file); + } + + public static YamlConfiguration loadYaml(Plugin plugin, File file) { + YamlConfiguration configuration = new YamlConfiguration(); + try { + String yaml = com.google.common.io.Files.toString(file, Charset.forName("utf-8")); + configuration.loadFromString(yaml); + return configuration; + } catch (Exception e) { + e.printStackTrace(); + } + return configuration; + } + + private static Class getCaller(Class obj) { + try { + return Class.forName(Thread.currentThread().getStackTrace()[3].getClassName(), false, obj.getClassLoader()); + } catch (ClassNotFoundException ignored) { + } + return null; + } +} diff --git a/src/main/scala/me/skymc/taboolib/common/io/IOUtils.java b/src/main/scala/io/izzel/taboolib/util/IO.java similarity index 74% rename from src/main/scala/me/skymc/taboolib/common/io/IOUtils.java rename to src/main/scala/io/izzel/taboolib/util/IO.java index 49f3da8..4dcd9e9 100644 --- a/src/main/scala/me/skymc/taboolib/common/io/IOUtils.java +++ b/src/main/scala/io/izzel/taboolib/util/IO.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.common.io; +package io.izzel.taboolib.util; import java.io.*; import java.net.HttpURLConnection; @@ -6,12 +6,23 @@ import java.net.ServerSocket; import java.net.Socket; import java.net.URLConnection; import java.nio.channels.Selector; +import java.nio.charset.Charset; -/** - * from org.apache.commons.io - * support for 1.14 - */ -public class IOUtils { +public class IO { + + public static String readFully(InputStream inputStream, Charset charset) throws IOException { + return new String(readFully(inputStream), charset); + } + + public static byte[] readFully(InputStream inputStream) throws IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + int len = 0; + while ((len = inputStream.read(buf)) > 0) { + stream.write(buf, 0, len); + } + return stream.toByteArray(); + } public static void close(URLConnection v) { if (v instanceof HttpURLConnection) { diff --git a/src/main/scala/com/ilummc/tlib/util/Ref.java b/src/main/scala/io/izzel/taboolib/util/Ref.java similarity index 93% rename from src/main/scala/com/ilummc/tlib/util/Ref.java rename to src/main/scala/io/izzel/taboolib/util/Ref.java index bd9c35b..8d05d90 100644 --- a/src/main/scala/com/ilummc/tlib/util/Ref.java +++ b/src/main/scala/io/izzel/taboolib/util/Ref.java @@ -1,9 +1,8 @@ -package com.ilummc.tlib.util; +package io.izzel.taboolib.util; import com.google.gson.annotations.SerializedName; -import com.ilummc.tlib.TLib; -import com.ilummc.tlib.util.asm.AsmAnalyser; -import me.skymc.taboolib.Main; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.util.asm.AsmAnalyser; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import org.objectweb.asm.ClassReader; @@ -38,12 +37,6 @@ public class Ref { public static List getDeclaredFields(Class clazz, int excludeModifiers, boolean cache) { try { - - // 特殊判断 - if (clazz == TLib.class) { - return Arrays.asList(clazz.getDeclaredFields()); - } - List fields; if ((fields = cachedFields.get(clazz.getName())) != null) { return fields; @@ -100,6 +93,9 @@ public class Ref { } public static Plugin getCallerPlugin(Class callerClass) { + if (callerClass.getName().startsWith("io.izzel.taboolib") || callerClass.getName().startsWith("io.izzel.tlibscala")) { + return TabooLib.getPlugin(); + } try { return JavaPlugin.getProvidingPlugin(callerClass); } catch (Exception ignored) { @@ -110,7 +106,7 @@ public class Ref { Object o = pluginF.get(loader); return (JavaPlugin) o; } catch (Exception e) { - return Main.getInst(); + return TabooLib.getPlugin(); } } } diff --git a/src/main/scala/me/skymc/taboolib/methods/ReflectionUtils.java b/src/main/scala/io/izzel/taboolib/util/Reflection.java similarity index 99% rename from src/main/scala/me/skymc/taboolib/methods/ReflectionUtils.java rename to src/main/scala/io/izzel/taboolib/util/Reflection.java index eede188..5ee962f 100644 --- a/src/main/scala/me/skymc/taboolib/methods/ReflectionUtils.java +++ b/src/main/scala/io/izzel/taboolib/util/Reflection.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.methods; +package io.izzel.taboolib.util; import org.bukkit.Bukkit; @@ -25,9 +25,9 @@ import java.util.Map; * @author DarkBlade12 * @version 1.1 */ -public final class ReflectionUtils { +public final class Reflection { // Prevent accidental construction - private ReflectionUtils() { + private Reflection() { } /** diff --git a/src/main/scala/me/skymc/taboolib/string/StringUtils.java b/src/main/scala/io/izzel/taboolib/util/Strings.java similarity index 67% rename from src/main/scala/me/skymc/taboolib/string/StringUtils.java rename to src/main/scala/io/izzel/taboolib/util/Strings.java index 20a24d5..8530124 100644 --- a/src/main/scala/me/skymc/taboolib/string/StringUtils.java +++ b/src/main/scala/io/izzel/taboolib/util/Strings.java @@ -1,15 +1,51 @@ -package me.skymc.taboolib.string; +package io.izzel.taboolib.util; + +import com.google.common.collect.Lists; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -/** - * @author sky - * @since 2018年2月6日 下午1:28:38 - */ -public class StringUtils { - - public static String hashKeyForDisk(String key) { +public class Strings { + + public static boolean isBlank(String var) { + return var == null || var.trim().isEmpty(); + } + + public static boolean isEmpty(CharSequence var) { + return var == null || var.length() == 0; + } + + public static String replaceWithOrder(String template, String... args) { + return replaceWithOrder(template, Lists.newArrayList(args).toArray()); + } + + /** + * 优化过的 String#replace,比默认快了大概 5 倍 + * + * @param template 模板替换文件 + * @param args 替换的参数 + * @return 替换好的字符串 + */ + public static String replaceWithOrder(String template, Object... args) { + if (args.length == 0 || template.length() == 0) { + return template; + } + char[] arr = template.toCharArray(); + StringBuilder stringBuilder = new StringBuilder(template.length()); + for (int i = 0; i < arr.length; i++) { + if (arr[i] == '{' && Character.isDigit(arr[Math.min(i + 1, arr.length - 1)]) + && arr[Math.min(i + 1, arr.length - 1)] - '0' < args.length + && arr[Math.min(i + 2, arr.length - 1)] == '}') { + stringBuilder.append(args[arr[i + 1] - '0']); + i += 2; + } else { + stringBuilder.append(arr[i]); + } + } + return stringBuilder.toString(); + } + + public static String hashKeyForDisk(String key) { String cacheKey; try { final MessageDigest mDigest = MessageDigest.getInstance("MD5"); @@ -21,18 +57,6 @@ public class StringUtils { return cacheKey; } - private static String bytesToHexString(byte[] bytes) { - StringBuilder sb = new StringBuilder(); - for (byte aByte : bytes) { - String hex = Integer.toHexString(0xFF & aByte); - if (hex.length() == 1) { - sb.append('0'); - } - sb.append(hex); - } - return sb.toString(); - } - public static double similarDegree(String strA, String strB){ String newStrA = removeSign(max(strA, strB)); String newStrB = removeSign(min(strA, strB)); @@ -45,6 +69,18 @@ public class StringUtils { } } + private static String bytesToHexString(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte aByte : bytes) { + String hex = Integer.toHexString(0xFF & aByte); + if (hex.length() == 1) { + sb.append('0'); + } + sb.append(hex); + } + return sb.toString(); + } + private static String max(String strA, String strB) { return strA.length() >= strB.length() ? strA : strB; } @@ -100,5 +136,4 @@ public class StringUtils { } return new String(result); } - } diff --git a/src/main/scala/me/skymc/taboolib/timeutil/TimeFormatter.java b/src/main/scala/io/izzel/taboolib/util/Times.java similarity index 93% rename from src/main/scala/me/skymc/taboolib/timeutil/TimeFormatter.java rename to src/main/scala/io/izzel/taboolib/util/Times.java index edb73d3..d4a184f 100644 --- a/src/main/scala/me/skymc/taboolib/timeutil/TimeFormatter.java +++ b/src/main/scala/io/izzel/taboolib/util/Times.java @@ -1,4 +1,4 @@ -package me.skymc.taboolib.timeutil; +package io.izzel.taboolib.util; import java.util.concurrent.TimeUnit; @@ -6,7 +6,7 @@ import java.util.concurrent.TimeUnit; * @author sky * @since 2018-04-10 22:11:04 */ -public class TimeFormatter { +public class Times { private long days; private long hours; @@ -14,7 +14,7 @@ public class TimeFormatter { private long seconds; private long milliseconds; - public TimeFormatter(long millisecond) { + public Times(long millisecond) { days = TimeUnit.MILLISECONDS.toDays(millisecond); hours = TimeUnit.MILLISECONDS.toHours(millisecond) - days * 24L; minutes = TimeUnit.MILLISECONDS.toMinutes(millisecond) - TimeUnit.MILLISECONDS.toHours(millisecond) * 60L; diff --git a/src/main/scala/me/skymc/taboolib/string/VariableFormatter.java b/src/main/scala/io/izzel/taboolib/util/Variables.java similarity index 88% rename from src/main/scala/me/skymc/taboolib/string/VariableFormatter.java rename to src/main/scala/io/izzel/taboolib/util/Variables.java index 84567e0..7ee842c 100644 --- a/src/main/scala/me/skymc/taboolib/string/VariableFormatter.java +++ b/src/main/scala/io/izzel/taboolib/util/Variables.java @@ -1,6 +1,4 @@ -package me.skymc.taboolib.string; - -import com.ilummc.tlib.util.Strings; +package io.izzel.taboolib.util; import java.util.ArrayList; import java.util.List; @@ -11,34 +9,34 @@ import java.util.regex.Pattern; * @Author sky * @Since 2018-05-27 11:33 */ -public class VariableFormatter { +public class Variables { private Pattern pattern; private String text; private String textOrigin; private List variableList = new ArrayList<>(); - public VariableFormatter(String text) { + public Variables(String text) { this(text, "<([^<>]+)>"); } - public VariableFormatter(String text, String regex) { + public Variables(String text, String regex) { this(text, Pattern.compile(regex)); } - public VariableFormatter(String text, Pattern pattern) { + public Variables(String text, Pattern pattern) { this.text = text; this.textOrigin = text; this.pattern = pattern; } - public VariableFormatter reset() { + public Variables reset() { text = textOrigin; variableList.clear(); return this; } - public VariableFormatter find() { + public Variables find() { reset(); Matcher matcher = pattern.matcher(text); while (matcher.find()) { diff --git a/src/main/scala/com/ilummc/tlib/util/asm/AsmAnalyser.java b/src/main/scala/io/izzel/taboolib/util/asm/AsmAnalyser.java similarity index 96% rename from src/main/scala/com/ilummc/tlib/util/asm/AsmAnalyser.java rename to src/main/scala/io/izzel/taboolib/util/asm/AsmAnalyser.java index 58ce0d5..e1a81e2 100644 --- a/src/main/scala/com/ilummc/tlib/util/asm/AsmAnalyser.java +++ b/src/main/scala/io/izzel/taboolib/util/asm/AsmAnalyser.java @@ -1,4 +1,4 @@ -package com.ilummc.tlib.util.asm; +package io.izzel.taboolib.util.asm; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; diff --git a/src/main/scala/com/ilummc/tlib/util/asm/AsmClassLoader.java b/src/main/scala/io/izzel/taboolib/util/asm/AsmClassLoader.java similarity index 93% rename from src/main/scala/com/ilummc/tlib/util/asm/AsmClassLoader.java rename to src/main/scala/io/izzel/taboolib/util/asm/AsmClassLoader.java index e65beeb..72ea750 100644 --- a/src/main/scala/com/ilummc/tlib/util/asm/AsmClassLoader.java +++ b/src/main/scala/io/izzel/taboolib/util/asm/AsmClassLoader.java @@ -1,4 +1,4 @@ -package com.ilummc.tlib.util.asm; +package io.izzel.taboolib.util.asm; public class AsmClassLoader extends ClassLoader { diff --git a/src/main/scala/com/ilummc/tlib/util/asm/AsmClassTransformer.java b/src/main/scala/io/izzel/taboolib/util/asm/AsmClassTransformer.java similarity index 99% rename from src/main/scala/com/ilummc/tlib/util/asm/AsmClassTransformer.java rename to src/main/scala/io/izzel/taboolib/util/asm/AsmClassTransformer.java index 7819a46..a4048d0 100644 --- a/src/main/scala/com/ilummc/tlib/util/asm/AsmClassTransformer.java +++ b/src/main/scala/io/izzel/taboolib/util/asm/AsmClassTransformer.java @@ -1,4 +1,4 @@ -package com.ilummc.tlib.util.asm; +package io.izzel.taboolib.util.asm; import org.bukkit.Bukkit; diff --git a/src/main/scala/com/ilummc/tlib/bungee/api/chat/BaseComponent.java b/src/main/scala/io/izzel/taboolib/util/chat/BaseComponent.java similarity index 93% rename from src/main/scala/com/ilummc/tlib/bungee/api/chat/BaseComponent.java rename to src/main/scala/io/izzel/taboolib/util/chat/BaseComponent.java index 493fc45..c16b044 100644 --- a/src/main/scala/com/ilummc/tlib/bungee/api/chat/BaseComponent.java +++ b/src/main/scala/io/izzel/taboolib/util/chat/BaseComponent.java @@ -1,7 +1,4 @@ -package com.ilummc.tlib.bungee.api.chat; - -import com.ilummc.tlib.bungee.api.ChatColor; -import com.ilummc.tlib.bungee.api.chat.ComponentBuilder.FormatRetention; +package io.izzel.taboolib.util.chat; import java.util.ArrayList; import java.util.List; @@ -129,7 +126,7 @@ public abstract class BaseComponent { } BaseComponent(BaseComponent old) { - copyFormatting(old, FormatRetention.ALL, true); + copyFormatting(old, ComponentBuilder.FormatRetention.ALL, true); if (old.getExtra() != null) { for (BaseComponent extra : old.getExtra()) { @@ -145,7 +142,7 @@ public abstract class BaseComponent { * @param component the component to copy from */ public void copyFormatting(BaseComponent component) { - copyFormatting(component, FormatRetention.ALL, true); + copyFormatting(component, ComponentBuilder.FormatRetention.ALL, true); } /** @@ -156,7 +153,7 @@ public abstract class BaseComponent { * component */ public void copyFormatting(BaseComponent component, boolean replace) { - copyFormatting(component, FormatRetention.ALL, replace); + copyFormatting(component, ComponentBuilder.FormatRetention.ALL, replace); } /** @@ -167,8 +164,8 @@ public abstract class BaseComponent { * @param replace if already set formatting should be replaced by the new * component */ - public void copyFormatting(BaseComponent component, FormatRetention retention, boolean replace) { - if (retention == FormatRetention.EVENTS || retention == FormatRetention.ALL) { + public void copyFormatting(BaseComponent component, ComponentBuilder.FormatRetention retention, boolean replace) { + if (retention == ComponentBuilder.FormatRetention.EVENTS || retention == ComponentBuilder.FormatRetention.ALL) { if (replace || clickEvent == null) { setClickEvent(component.getClickEvent()); } @@ -176,7 +173,7 @@ public abstract class BaseComponent { setHoverEvent(component.getHoverEvent()); } } - if (retention == FormatRetention.FORMATTING || retention == FormatRetention.ALL) { + if (retention == ComponentBuilder.FormatRetention.FORMATTING || retention == ComponentBuilder.FormatRetention.ALL) { if (replace || color == null) { setColor(component.getColorRaw()); } @@ -206,12 +203,12 @@ public abstract class BaseComponent { * * @param retention the formatting to retain */ - public void retain(FormatRetention retention) { - if (retention == FormatRetention.FORMATTING || retention == FormatRetention.NONE) { + public void retain(ComponentBuilder.FormatRetention retention) { + if (retention == ComponentBuilder.FormatRetention.FORMATTING || retention == ComponentBuilder.FormatRetention.NONE) { setClickEvent(null); setHoverEvent(null); } - if (retention == FormatRetention.EVENTS || retention == FormatRetention.NONE) { + if (retention == ComponentBuilder.FormatRetention.EVENTS || retention == ComponentBuilder.FormatRetention.NONE) { setColor(null); setBold(null); setItalic(null); @@ -238,7 +235,7 @@ public abstract class BaseComponent { @Deprecated public BaseComponent duplicateWithoutFormatting() { BaseComponent component = duplicate(); - component.retain(FormatRetention.NONE); + component.retain(ComponentBuilder.FormatRetention.NONE); return component; } diff --git a/src/main/scala/com/ilummc/tlib/bungee/chat/BaseComponentSerializer.java b/src/main/scala/io/izzel/taboolib/util/chat/BaseComponentSerializer.java similarity index 95% rename from src/main/scala/com/ilummc/tlib/bungee/chat/BaseComponentSerializer.java rename to src/main/scala/io/izzel/taboolib/util/chat/BaseComponentSerializer.java index e01e51a..a7be0db 100644 --- a/src/main/scala/com/ilummc/tlib/bungee/chat/BaseComponentSerializer.java +++ b/src/main/scala/io/izzel/taboolib/util/chat/BaseComponentSerializer.java @@ -1,13 +1,9 @@ -package com.ilummc.tlib.bungee.chat; +package io.izzel.taboolib.util.chat; import com.google.common.base.Preconditions; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; -import com.ilummc.tlib.bungee.api.ChatColor; -import com.ilummc.tlib.bungee.api.chat.BaseComponent; -import com.ilummc.tlib.bungee.api.chat.ClickEvent; -import com.ilummc.tlib.bungee.api.chat.HoverEvent; import java.util.Arrays; import java.util.HashSet; diff --git a/src/main/scala/com/ilummc/tlib/bungee/api/ChatColor.java b/src/main/scala/io/izzel/taboolib/util/chat/ChatColor.java similarity index 99% rename from src/main/scala/com/ilummc/tlib/bungee/api/ChatColor.java rename to src/main/scala/io/izzel/taboolib/util/chat/ChatColor.java index 752b7be..1a895f4 100644 --- a/src/main/scala/com/ilummc/tlib/bungee/api/ChatColor.java +++ b/src/main/scala/io/izzel/taboolib/util/chat/ChatColor.java @@ -1,4 +1,4 @@ -package com.ilummc.tlib.bungee.api; +package io.izzel.taboolib.util.chat; import java.util.HashMap; import java.util.Map; diff --git a/src/main/scala/com/ilummc/tlib/bungee/api/ChatMessageType.java b/src/main/scala/io/izzel/taboolib/util/chat/ChatMessageType.java similarity index 81% rename from src/main/scala/com/ilummc/tlib/bungee/api/ChatMessageType.java rename to src/main/scala/io/izzel/taboolib/util/chat/ChatMessageType.java index 788cf5e..4429e41 100644 --- a/src/main/scala/com/ilummc/tlib/bungee/api/ChatMessageType.java +++ b/src/main/scala/io/izzel/taboolib/util/chat/ChatMessageType.java @@ -1,4 +1,4 @@ -package com.ilummc.tlib.bungee.api; +package io.izzel.taboolib.util.chat; /** * Represents the position on the screen where a message will appear. diff --git a/src/main/scala/com/ilummc/tlib/bungee/api/chat/ClickEvent.java b/src/main/scala/io/izzel/taboolib/util/chat/ClickEvent.java similarity index 96% rename from src/main/scala/com/ilummc/tlib/bungee/api/chat/ClickEvent.java rename to src/main/scala/io/izzel/taboolib/util/chat/ClickEvent.java index c7124e8..1a302b2 100644 --- a/src/main/scala/com/ilummc/tlib/bungee/api/chat/ClickEvent.java +++ b/src/main/scala/io/izzel/taboolib/util/chat/ClickEvent.java @@ -1,4 +1,4 @@ -package com.ilummc.tlib.bungee.api.chat; +package io.izzel.taboolib.util.chat; /** * @author md_5 diff --git a/src/main/scala/com/ilummc/tlib/bungee/api/chat/ComponentBuilder.java b/src/main/scala/io/izzel/taboolib/util/chat/ComponentBuilder.java similarity index 99% rename from src/main/scala/com/ilummc/tlib/bungee/api/chat/ComponentBuilder.java rename to src/main/scala/io/izzel/taboolib/util/chat/ComponentBuilder.java index 1b0100f..b5bdf48 100644 --- a/src/main/scala/com/ilummc/tlib/bungee/api/chat/ComponentBuilder.java +++ b/src/main/scala/io/izzel/taboolib/util/chat/ComponentBuilder.java @@ -1,7 +1,6 @@ -package com.ilummc.tlib.bungee.api.chat; +package io.izzel.taboolib.util.chat; import com.google.common.base.Preconditions; -import com.ilummc.tlib.bungee.api.ChatColor; import java.util.ArrayList; import java.util.List; diff --git a/src/main/scala/com/ilummc/tlib/bungee/chat/ComponentSerializer.java b/src/main/scala/io/izzel/taboolib/util/chat/ComponentSerializer.java similarity index 89% rename from src/main/scala/com/ilummc/tlib/bungee/chat/ComponentSerializer.java rename to src/main/scala/io/izzel/taboolib/util/chat/ComponentSerializer.java index 6d19961..f91c0c0 100644 --- a/src/main/scala/com/ilummc/tlib/bungee/chat/ComponentSerializer.java +++ b/src/main/scala/io/izzel/taboolib/util/chat/ComponentSerializer.java @@ -1,12 +1,8 @@ -package com.ilummc.tlib.bungee.chat; +package io.izzel.taboolib.util.chat; import com.google.gson.*; -import com.ilummc.tlib.bungee.api.chat.BaseComponent; -import com.ilummc.tlib.bungee.api.chat.TextComponent; -import com.ilummc.tlib.bungee.api.chat.TranslatableComponent; import java.lang.reflect.Type; -import java.util.Arrays; import java.util.HashSet; /** diff --git a/src/main/scala/com/ilummc/tlib/bungee/api/chat/HoverEvent.java b/src/main/scala/io/izzel/taboolib/util/chat/HoverEvent.java similarity index 94% rename from src/main/scala/com/ilummc/tlib/bungee/api/chat/HoverEvent.java rename to src/main/scala/io/izzel/taboolib/util/chat/HoverEvent.java index 1825ce4..7313068 100644 --- a/src/main/scala/com/ilummc/tlib/bungee/api/chat/HoverEvent.java +++ b/src/main/scala/io/izzel/taboolib/util/chat/HoverEvent.java @@ -1,4 +1,4 @@ -package com.ilummc.tlib.bungee.api.chat; +package io.izzel.taboolib.util.chat; import java.util.Arrays; diff --git a/src/main/scala/com/ilummc/tlib/bungee/api/chat/TextComponent.java b/src/main/scala/io/izzel/taboolib/util/chat/TextComponent.java similarity index 98% rename from src/main/scala/com/ilummc/tlib/bungee/api/chat/TextComponent.java rename to src/main/scala/io/izzel/taboolib/util/chat/TextComponent.java index 28d935c..6c7652f 100644 --- a/src/main/scala/com/ilummc/tlib/bungee/api/chat/TextComponent.java +++ b/src/main/scala/io/izzel/taboolib/util/chat/TextComponent.java @@ -3,9 +3,7 @@ // (powered by Fernflower decompiler) // -package com.ilummc.tlib.bungee.api.chat; - -import com.ilummc.tlib.bungee.api.ChatColor; +package io.izzel.taboolib.util.chat; import java.beans.ConstructorProperties; import java.util.ArrayList; diff --git a/src/main/scala/com/ilummc/tlib/bungee/chat/TextComponentSerializer.java b/src/main/scala/io/izzel/taboolib/util/chat/TextComponentSerializer.java similarity index 89% rename from src/main/scala/com/ilummc/tlib/bungee/chat/TextComponentSerializer.java rename to src/main/scala/io/izzel/taboolib/util/chat/TextComponentSerializer.java index 9fccef9..4f6dee7 100644 --- a/src/main/scala/com/ilummc/tlib/bungee/chat/TextComponentSerializer.java +++ b/src/main/scala/io/izzel/taboolib/util/chat/TextComponentSerializer.java @@ -3,11 +3,9 @@ // (powered by Fernflower decompiler) // -package com.ilummc.tlib.bungee.chat; +package io.izzel.taboolib.util.chat; import com.google.gson.*; -import com.ilummc.tlib.bungee.api.chat.BaseComponent; -import com.ilummc.tlib.bungee.api.chat.TextComponent; import java.lang.reflect.Type; import java.util.List; diff --git a/src/main/scala/com/ilummc/tlib/bungee/api/chat/TranslatableComponent.java b/src/main/scala/io/izzel/taboolib/util/chat/TranslatableComponent.java similarity index 98% rename from src/main/scala/com/ilummc/tlib/bungee/api/chat/TranslatableComponent.java rename to src/main/scala/io/izzel/taboolib/util/chat/TranslatableComponent.java index 23e3864..1683af6 100644 --- a/src/main/scala/com/ilummc/tlib/bungee/api/chat/TranslatableComponent.java +++ b/src/main/scala/io/izzel/taboolib/util/chat/TranslatableComponent.java @@ -1,6 +1,4 @@ -package com.ilummc.tlib.bungee.api.chat; - -import com.ilummc.tlib.bungee.api.ChatColor; +package io.izzel.taboolib.util.chat; import java.util.ArrayList; import java.util.List; diff --git a/src/main/scala/com/ilummc/tlib/bungee/chat/TranslatableComponentSerializer.java b/src/main/scala/io/izzel/taboolib/util/chat/TranslatableComponentSerializer.java similarity index 90% rename from src/main/scala/com/ilummc/tlib/bungee/chat/TranslatableComponentSerializer.java rename to src/main/scala/io/izzel/taboolib/util/chat/TranslatableComponentSerializer.java index e2be31f..dfbd165 100644 --- a/src/main/scala/com/ilummc/tlib/bungee/chat/TranslatableComponentSerializer.java +++ b/src/main/scala/io/izzel/taboolib/util/chat/TranslatableComponentSerializer.java @@ -3,11 +3,9 @@ // (powered by Fernflower decompiler) // -package com.ilummc.tlib.bungee.chat; +package io.izzel.taboolib.util.chat; import com.google.gson.*; -import com.ilummc.tlib.bungee.api.chat.BaseComponent; -import com.ilummc.tlib.bungee.api.chat.TranslatableComponent; import java.lang.reflect.Type; import java.util.Arrays; diff --git a/src/main/scala/com/ilummc/eagletdl/AlreadyStartException.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/AlreadyStartException.java similarity index 61% rename from src/main/scala/com/ilummc/eagletdl/AlreadyStartException.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/AlreadyStartException.java index 2e1e0bc..9db8106 100644 --- a/src/main/scala/com/ilummc/eagletdl/AlreadyStartException.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/AlreadyStartException.java @@ -1,4 +1,4 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; public class AlreadyStartException extends RuntimeException { diff --git a/src/main/scala/com/ilummc/eagletdl/CompleteEvent.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/CompleteEvent.java similarity index 89% rename from src/main/scala/com/ilummc/eagletdl/CompleteEvent.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/CompleteEvent.java index 839625b..6163b3a 100644 --- a/src/main/scala/com/ilummc/eagletdl/CompleteEvent.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/CompleteEvent.java @@ -1,4 +1,4 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; public class CompleteEvent { private EagletTask task; diff --git a/src/main/scala/com/ilummc/eagletdl/ConnectedEvent.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/ConnectedEvent.java similarity index 92% rename from src/main/scala/com/ilummc/eagletdl/ConnectedEvent.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/ConnectedEvent.java index 5299f27..3185b26 100644 --- a/src/main/scala/com/ilummc/eagletdl/ConnectedEvent.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/ConnectedEvent.java @@ -1,4 +1,4 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; public class ConnectedEvent { diff --git a/src/main/scala/com/ilummc/eagletdl/DoNotSupportMultipleThreadException.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/DoNotSupportMultipleThreadException.java similarity index 65% rename from src/main/scala/com/ilummc/eagletdl/DoNotSupportMultipleThreadException.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/DoNotSupportMultipleThreadException.java index 0c59692..654fdd5 100644 --- a/src/main/scala/com/ilummc/eagletdl/DoNotSupportMultipleThreadException.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/DoNotSupportMultipleThreadException.java @@ -1,4 +1,4 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; public class DoNotSupportMultipleThreadException extends RuntimeException { } diff --git a/src/main/scala/com/ilummc/eagletdl/EagletHandler.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/EagletHandler.java similarity index 68% rename from src/main/scala/com/ilummc/eagletdl/EagletHandler.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/EagletHandler.java index ef63e4a..e3eb230 100644 --- a/src/main/scala/com/ilummc/eagletdl/EagletHandler.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/EagletHandler.java @@ -1,4 +1,4 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; @FunctionalInterface public interface EagletHandler { diff --git a/src/main/scala/com/ilummc/eagletdl/EagletTask.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/EagletTask.java similarity index 99% rename from src/main/scala/com/ilummc/eagletdl/EagletTask.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/EagletTask.java index c69e551..394b620 100644 --- a/src/main/scala/com/ilummc/eagletdl/EagletTask.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/EagletTask.java @@ -1,4 +1,6 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; + +import io.izzel.taboolib.util.Files; import java.io.File; import java.net.HttpURLConnection; @@ -83,9 +85,7 @@ public class EagletTask { } try { // create the target file - if (!dest.exists()) { - dest.createNewFile(); - } + Files.file(dest); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); // set the connection properties httpHeader.forEach(connection::addRequestProperty); diff --git a/src/main/scala/com/ilummc/eagletdl/ErrorEvent.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/ErrorEvent.java similarity index 88% rename from src/main/scala/com/ilummc/eagletdl/ErrorEvent.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/ErrorEvent.java index 801ac9d..115f140 100644 --- a/src/main/scala/com/ilummc/eagletdl/ErrorEvent.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/ErrorEvent.java @@ -1,4 +1,4 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; public class ErrorEvent { diff --git a/src/main/scala/com/ilummc/eagletdl/HashNotMatchException.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/HashNotMatchException.java similarity index 61% rename from src/main/scala/com/ilummc/eagletdl/HashNotMatchException.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/HashNotMatchException.java index bdb3bcd..eedbbc8 100644 --- a/src/main/scala/com/ilummc/eagletdl/HashNotMatchException.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/HashNotMatchException.java @@ -1,4 +1,4 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; public class HashNotMatchException extends RuntimeException { } diff --git a/src/main/scala/com/ilummc/eagletdl/HashUtil.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/HashUtil.java similarity index 98% rename from src/main/scala/com/ilummc/eagletdl/HashUtil.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/HashUtil.java index 10bf013..bb76807 100644 --- a/src/main/scala/com/ilummc/eagletdl/HashUtil.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/HashUtil.java @@ -1,4 +1,4 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; import java.io.File; import java.io.FileInputStream; diff --git a/src/main/scala/com/ilummc/eagletdl/ProgressEvent.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/ProgressEvent.java similarity index 97% rename from src/main/scala/com/ilummc/eagletdl/ProgressEvent.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/ProgressEvent.java index f6cf1b7..6cbbe09 100644 --- a/src/main/scala/com/ilummc/eagletdl/ProgressEvent.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/ProgressEvent.java @@ -1,4 +1,4 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; import java.text.DecimalFormat; diff --git a/src/main/scala/com/ilummc/eagletdl/RetryFailedException.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/RetryFailedException.java similarity index 85% rename from src/main/scala/com/ilummc/eagletdl/RetryFailedException.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/RetryFailedException.java index e8a022d..c9fb5f0 100644 --- a/src/main/scala/com/ilummc/eagletdl/RetryFailedException.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/RetryFailedException.java @@ -1,4 +1,4 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; public class RetryFailedException extends RuntimeException { diff --git a/src/main/scala/com/ilummc/eagletdl/SingleThreadDownload.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/SingleThreadDownload.java similarity index 97% rename from src/main/scala/com/ilummc/eagletdl/SingleThreadDownload.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/SingleThreadDownload.java index d03967e..1a4589d 100644 --- a/src/main/scala/com/ilummc/eagletdl/SingleThreadDownload.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/SingleThreadDownload.java @@ -1,4 +1,4 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; import java.io.*; import java.net.HttpURLConnection; diff --git a/src/main/scala/com/ilummc/eagletdl/SplitDownload.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/SplitDownload.java similarity index 98% rename from src/main/scala/com/ilummc/eagletdl/SplitDownload.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/SplitDownload.java index dd17663..bd4a65d 100644 --- a/src/main/scala/com/ilummc/eagletdl/SplitDownload.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/SplitDownload.java @@ -1,4 +1,4 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; import java.io.BufferedInputStream; import java.io.File; diff --git a/src/main/scala/com/ilummc/eagletdl/StartEvent.java b/src/main/scala/io/izzel/taboolib/util/eagletdl/StartEvent.java similarity index 82% rename from src/main/scala/com/ilummc/eagletdl/StartEvent.java rename to src/main/scala/io/izzel/taboolib/util/eagletdl/StartEvent.java index b0c7f61..4f95b7d 100644 --- a/src/main/scala/com/ilummc/eagletdl/StartEvent.java +++ b/src/main/scala/io/izzel/taboolib/util/eagletdl/StartEvent.java @@ -1,4 +1,4 @@ -package com.ilummc.eagletdl; +package io.izzel.taboolib.util.eagletdl; public class StartEvent { diff --git a/src/main/scala/com/ilummc/tlibscala/AsyncTask.scala b/src/main/scala/io/lzzel/tlibscala/AsyncTask.scala similarity index 94% rename from src/main/scala/com/ilummc/tlibscala/AsyncTask.scala rename to src/main/scala/io/lzzel/tlibscala/AsyncTask.scala index 274372d..f9b788c 100644 --- a/src/main/scala/com/ilummc/tlibscala/AsyncTask.scala +++ b/src/main/scala/io/lzzel/tlibscala/AsyncTask.scala @@ -1,4 +1,4 @@ -package com.ilummc.tlibscala +package io.lzzel.tlibscala import org.bukkit.plugin.Plugin diff --git a/src/main/scala/com/ilummc/tlibscala/Example.scala b/src/main/scala/io/lzzel/tlibscala/Example.scala similarity index 67% rename from src/main/scala/com/ilummc/tlibscala/Example.scala rename to src/main/scala/io/lzzel/tlibscala/Example.scala index 2453916..aed96f6 100644 --- a/src/main/scala/com/ilummc/tlibscala/Example.scala +++ b/src/main/scala/io/lzzel/tlibscala/Example.scala @@ -1,4 +1,4 @@ -package com.ilummc.tlibscala +package io.lzzel.tlibscala import Prelude._ import org.bukkit.Material @@ -14,15 +14,10 @@ class Example extends JavaPlugin with Listener { @EventHandler def onJoin(event: PlayerJoinEvent): Unit = { event.getPlayer.sendActionBar("2333") - val tick = event.getPlayer.getFishTicks - event.getPlayer.setFishTicks(tick + 10) - event.getPlayer.displaySidebar("标题", Map("2333" -> 1)) event.getPlayer.displaySidebarUnranked("", "", "") - event.getPlayer.openSign(event.getPlayer.getWorld.getBlockAt(0, 0, 0)) event.getPlayer.setVelocity(1.0, 2.0, 3.0) - if (event.getPlayer.withdraw(100)) - event.getPlayer.getInventory.addItem(new ItemStack(Material.DIAMOND)) - event.getPlayer.openAnvil() + event.getPlayer.withdraw(100) + event.getPlayer.getInventory.addItem(new ItemStack(Material.DIAMOND)) event.getPlayer << "locale.node" << "node.2" event.getPlayer.teleport(event.getPlayer.getLocation + (1, 2, 3)) Task { diff --git a/src/main/scala/com/ilummc/tlibscala/Implicits.scala b/src/main/scala/io/lzzel/tlibscala/Implicits.scala similarity index 87% rename from src/main/scala/com/ilummc/tlibscala/Implicits.scala rename to src/main/scala/io/lzzel/tlibscala/Implicits.scala index 9ed88a5..1568974 100644 --- a/src/main/scala/com/ilummc/tlibscala/Implicits.scala +++ b/src/main/scala/io/lzzel/tlibscala/Implicits.scala @@ -1,6 +1,6 @@ -package com.ilummc.tlibscala +package io.lzzel.tlibscala -import com.ilummc.tlibscala.runtime.{RichLocation, RichOfflinePlayer, RichPlayer, RichVector} +import io.lzzel.tlibscala.runtime.{RichLocation, RichOfflinePlayer, RichPlayer, RichVector} import org.bukkit.entity.Player import org.bukkit.util.Vector import org.bukkit.{Location, OfflinePlayer, World, util} diff --git a/src/main/scala/com/ilummc/tlibscala/Prelude.scala b/src/main/scala/io/lzzel/tlibscala/Prelude.scala similarity index 95% rename from src/main/scala/com/ilummc/tlibscala/Prelude.scala rename to src/main/scala/io/lzzel/tlibscala/Prelude.scala index 443365a..464505a 100644 --- a/src/main/scala/com/ilummc/tlibscala/Prelude.scala +++ b/src/main/scala/io/lzzel/tlibscala/Prelude.scala @@ -1,6 +1,6 @@ -package com.ilummc.tlibscala +package io.lzzel.tlibscala -import com.ilummc.tlib.resources.TLocale.Logger +import io.izzel.taboolib.locale.TLocale.Logger import org.bukkit.Bukkit import org.bukkit.event.{Event, EventException, EventPriority, Listener} import org.bukkit.plugin.{EventExecutor, Plugin} diff --git a/src/main/scala/com/ilummc/tlibscala/ScalaTaskExecutor.scala b/src/main/scala/io/lzzel/tlibscala/ScalaTaskExecutor.scala similarity index 94% rename from src/main/scala/com/ilummc/tlibscala/ScalaTaskExecutor.scala rename to src/main/scala/io/lzzel/tlibscala/ScalaTaskExecutor.scala index da1b997..35eed5c 100644 --- a/src/main/scala/com/ilummc/tlibscala/ScalaTaskExecutor.scala +++ b/src/main/scala/io/lzzel/tlibscala/ScalaTaskExecutor.scala @@ -1,4 +1,4 @@ -package com.ilummc.tlibscala +package io.lzzel.tlibscala import org.bukkit.scheduler.BukkitRunnable @@ -10,7 +10,6 @@ private[tlibscala] class ScalaTaskExecutor(task: => Any) extends BukkitRunnable case e: Throwable => throw e } } - } object ScalaTaskExecutor { diff --git a/src/main/scala/com/ilummc/tlibscala/Task.scala b/src/main/scala/io/lzzel/tlibscala/Task.scala similarity index 94% rename from src/main/scala/com/ilummc/tlibscala/Task.scala rename to src/main/scala/io/lzzel/tlibscala/Task.scala index 267ff07..a34b8a5 100644 --- a/src/main/scala/com/ilummc/tlibscala/Task.scala +++ b/src/main/scala/io/lzzel/tlibscala/Task.scala @@ -1,4 +1,4 @@ -package com.ilummc.tlibscala +package io.lzzel.tlibscala import org.bukkit.plugin.Plugin diff --git a/src/main/scala/com/ilummc/tlibscala/runtime/RichLocation.scala b/src/main/scala/io/lzzel/tlibscala/runtime/RichLocation.scala similarity index 93% rename from src/main/scala/com/ilummc/tlibscala/runtime/RichLocation.scala rename to src/main/scala/io/lzzel/tlibscala/runtime/RichLocation.scala index ef8bcf2..8e74abb 100644 --- a/src/main/scala/com/ilummc/tlibscala/runtime/RichLocation.scala +++ b/src/main/scala/io/lzzel/tlibscala/runtime/RichLocation.scala @@ -1,4 +1,4 @@ -package com.ilummc.tlibscala.runtime +package io.lzzel.tlibscala.runtime import org.bukkit.Location diff --git a/src/main/scala/io/lzzel/tlibscala/runtime/RichOfflinePlayer.scala b/src/main/scala/io/lzzel/tlibscala/runtime/RichOfflinePlayer.scala new file mode 100644 index 0000000..2f17104 --- /dev/null +++ b/src/main/scala/io/lzzel/tlibscala/runtime/RichOfflinePlayer.scala @@ -0,0 +1,28 @@ +package io.lzzel.tlibscala.runtime + +import io.izzel.taboolib.module.compat.EconomyHook +import io.izzel.taboolib.module.item.ItemBuilder +import org.bukkit.OfflinePlayer +import org.bukkit.inventory.ItemStack + +class RichOfflinePlayer(private val offlinePlayer: OfflinePlayer) { + + def getSkullItem: ItemStack = new ItemBuilder(offlinePlayer).build() + + def getMoney: Double = EconomyHook.get(offlinePlayer) + + def withdraw(x: Double): Unit = EconomyHook.remove(offlinePlayer, x) + + def deposit(x: Double): Unit = EconomyHook.add(offlinePlayer, x) + + def hasMoney(x: Double): Boolean = EconomyHook.get(offlinePlayer) >= x + +} + +object RichOfflinePlayer { + + implicit def player2rich(player: OfflinePlayer): RichOfflinePlayer = new RichOfflinePlayer(player) + + implicit def rich2player(player: RichOfflinePlayer): OfflinePlayer = player.offlinePlayer + +} \ No newline at end of file diff --git a/src/main/scala/io/lzzel/tlibscala/runtime/RichPlayer.scala b/src/main/scala/io/lzzel/tlibscala/runtime/RichPlayer.scala new file mode 100644 index 0000000..e594edf --- /dev/null +++ b/src/main/scala/io/lzzel/tlibscala/runtime/RichPlayer.scala @@ -0,0 +1,40 @@ +package io.lzzel.tlibscala.runtime + +import io.izzel.taboolib.locale.TLocale +import io.izzel.taboolib.module.compat.PermissionHook +import io.izzel.taboolib.origin.lite.Boards +import org.bukkit.entity.Player + +class RichPlayer(private val player: Player) extends RichOfflinePlayer(player) { + + def sendActionBar(x: String): Unit = TLocale.Display.sendActionBar(player, x) + + def displaySidebarUnranked(title: String, elements: Array[String]): Unit = Boards.display(player, elements: _*) + + def displaySidebarUnranked(title: String, elements: List[String]): Unit = Boards.display(player, elements: _*) + + def displaySidebarUnranked(title: String, elements: String*): Unit = Boards.display(player, elements: _*) + + def addPermission(perm: String): Unit = PermissionHook.addPermission(player, perm) + + def removePermission(perm: String): Unit = PermissionHook.removePermission(player, perm) + + def sendTitle(title: String, subtitle: String, fadein: Int, stay: Int, fadeout: Int): Unit = TLocale.Display.sendTitle(player, title, subtitle, fadein, stay, fadeout) + + def sendLocalizedMessage(node: String, params: String*): Unit = TLocale.sendTo(player, node, params: _*) + + def locale(node: String, params: String*): Unit = sendLocalizedMessage(node, params: _*) + + def <<(text: String): RichPlayer = { + player.sendMessage(text) + this + } +} + +object RichPlayer { + + implicit def player2rich(player: Player): RichPlayer = new RichPlayer(player) + + implicit def rich2player(player: RichPlayer): Player = player.player + +} diff --git a/src/main/scala/com/ilummc/tlibscala/runtime/RichVector.scala b/src/main/scala/io/lzzel/tlibscala/runtime/RichVector.scala similarity index 71% rename from src/main/scala/com/ilummc/tlibscala/runtime/RichVector.scala rename to src/main/scala/io/lzzel/tlibscala/runtime/RichVector.scala index 557dd3d..f12a79a 100644 --- a/src/main/scala/com/ilummc/tlibscala/runtime/RichVector.scala +++ b/src/main/scala/io/lzzel/tlibscala/runtime/RichVector.scala @@ -1,19 +1,16 @@ -package com.ilummc.tlibscala.runtime +package io.lzzel.tlibscala.runtime import org.bukkit.util.Vector class RichVector(private val vector: Vector) { - def +(vec: (Double, Double, Double)): Vector = - vector.setX(vector.getX + vec._1).setY(vector.getY + vec._2).setZ(vector.getZ + vec._3) - + def +(vec: (Double, Double, Double)): Vector = vector.setX(vector.getX + vec._1).setY(vector.getY + vec._2).setZ(vector.getZ + vec._3) def -(vec: (Double, Double, Double)): Vector = this.+(-vec._1, -vec._2, -vec._3) def *(x: Double): Vector = vector.multiply(x) def /(x: Double): Vector = this * (1 / x) - } object RichVector { diff --git a/src/main/scala/me/skymc/taboolib/Main.java b/src/main/scala/me/skymc/taboolib/Main.java deleted file mode 100644 index 175fe03..0000000 --- a/src/main/scala/me/skymc/taboolib/Main.java +++ /dev/null @@ -1,269 +0,0 @@ -package me.skymc.taboolib; - -import com.ilummc.tlib.TLib; -import com.ilummc.tlib.filter.TLoggerFilter; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.util.IO; -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.database.GlobalDataManager; -import me.skymc.taboolib.database.PlayerDataManager; -import me.skymc.taboolib.economy.EcoUtils; -import me.skymc.taboolib.fileutils.ConfigUtils; -import me.skymc.taboolib.fileutils.FileUtils; -import me.skymc.taboolib.listener.TListenerHandler; -import me.skymc.taboolib.mysql.hikari.HikariHandler; -import me.skymc.taboolib.mysql.protect.MySQLConnection; -import me.skymc.taboolib.other.NumberUtils; -import me.skymc.taboolib.playerdata.DataUtils; -import me.skymc.taboolib.socket.TabooLibClient; -import me.skymc.taboolib.socket.TabooLibServer; -import org.bukkit.Bukkit; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.BukkitRunnable; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.Random; - -/** - * @author sky - */ -public class Main extends JavaPlugin { - - public Main() { - inst = this; - } - - public enum StorageType { - LOCAL, SQL - } - - private static Plugin inst; - private static File playerDataFolder; - private static File serverDataFolder; - private static StorageType storageType = StorageType.LOCAL; - private static boolean disable = false; - private static boolean started = false; - private static boolean isInternetOnline = false; - private FileConfiguration config = null; - - @Override - public FileConfiguration getConfig() { - return config; - } - - @Override - public void saveDefaultConfig() { - reloadConfig(); - } - - @Override - public void reloadConfig() { - File file = new File(getDataFolder(), "config.yml"); - if (!file.exists()) { - saveResource("config.yml", true); - } - config = ConfigUtils.load(this, file); - } - - @Override - public void onLoad() { - disable = false; - // 载入配置文件 - saveDefaultConfig(); - // 载入日志过滤 - TLoggerFilter.preInit(); - // 载入扩展 - TabooLibLoader.setupAddons(); - // 载入牛逼东西 - TLib.init(); - TLib.injectPluginManager(); - // 载入插件设置 - TabooLibLoader.setup(); - // 载入大饼 - TLib.initPost(); - } - - @Override - public void onEnable() { - // 载入日志过滤 - TLoggerFilter.postInit(); - // 注册插件配置 - TabooLibLoader.register(); - // 启动数据库储存方法 - if (getStorageType() == StorageType.SQL) { - GlobalDataManager.SQLMethod.startSQLMethod(); - } - // 载入完成 - TLocale.Logger.info("NOTIFY.SUCCESS-LOADED", getDescription().getAuthors().toString(), getDescription().getVersion(), String.valueOf(TabooLib.getVersion())); - // 文件保存 - Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> DataUtils.saveAllCaches(), 20, 20 * 120); - Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> PlayerDataManager.saveAllCaches(true, false), 20, 20 * 60); - // 文件监控 - TLib.getTLib().getConfigWatcher().addSimpleListener(new File(getDataFolder(), "config.yml"), () -> { - reloadConfig(); - TLocale.Logger.info("CONFIG.RELOAD-SUCCESS", inst.getName(), "config.yml"); - }); - // 插件联动 - new BukkitRunnable() { - - @Override - public void run() { - // 面子工程 - if (!TabooLib.isSilent()) { - InputStream inputStream = FileUtils.getResource("motd.txt"); - try { - String text = new String(IO.readFully(inputStream), Charset.forName("utf-8")); - if (text != null) { - Arrays.stream(text.split("\n")).forEach(line -> Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(line, getDescription().getVersion()))); - } - } catch (IOException ignored) { - } - } - // 本地通讯网络终端 - if (getConfig().getBoolean("SERVER")) { - TabooLibServer.main(new String[0]); - } - // 本地通讯网络 - TabooLibClient.init(); - } - }.runTask(this); - // 启动 - started = true; - } - - @Override - public void onDisable() { - disable = true; - // 如果插件尚未启动完成 - if (!started) { - TLocale.Logger.error("NOTIFY.FAIL-DISABLE"); - return; - } - // 注销插件 - TabooLibLoader.unregister(); - // 保存数据 - Bukkit.getOnlinePlayers().forEach(x -> DataUtils.saveOnline(x.getName())); - // 结束线程 - Bukkit.getScheduler().cancelTasks(this); - // 保存插件数据 - DataUtils.saveAllCaches(); - // 保存玩家数据 - PlayerDataManager.saveAllPlayers(false, true); - // 注销连接池 - HikariHandler.closeDataSourceForce(); - // 注销监听器 - TListenerHandler.cancelListeners(); - // 结束数据库储存方法 - if (getStorageType() == StorageType.SQL) { - GlobalDataManager.SQLMethod.cancelSQLMethod(); - } - // 清理数据 - if (getStorageType() == StorageType.LOCAL && getConfig().getBoolean("DELETE-DATA")) { - getPlayerDataFolder().delete(); - } - // 清理数据 - if (getStorageType() == StorageType.SQL && getConfig().getBoolean("DELETE-VARIABLE")) { - GlobalDataManager.clearInvalidVariables(); - } - // 提示信息 - TLocale.Logger.info("NOTIFY.SUCCESS-DISABLE"); - // 卸载牛逼玩意儿 - TLib.unload(); - // 关闭服务器 - Bukkit.shutdown(); - } - - // ********************************* - // - // Getter and Setter - // - // ********************************* - - public static Plugin getInst() { - return inst; - } - - public static String getPrefix() { - return "§8[§3§lTabooLib§8] §7"; - } - - public static File getPlayerDataFolder() { - return playerDataFolder; - } - - public static File getServerDataFolder() { - return serverDataFolder; - } - - public static StorageType getStorageType() { - return storageType; - } - - public static boolean isDisable() { - return disable; - } - - public static boolean isStarted() { - return started; - } - - public static boolean isInternetOnline() { - return isInternetOnline; - } - - public static boolean isOfflineVersion() { - return inst.getResource("libs") != null; - } - - public static boolean isLibrariesExists() { - return TLib.getTLib().getLibsFolder().listFiles().length > 0; - } - - @Deprecated - public static Random getRandom() { - return NumberUtils.getRandom(); - } - - @Deprecated - public static String getTablePrefix() { - return inst.getConfig().getString("MYSQL.PREFIX"); - } - - @Deprecated - public static MySQLConnection getConnection() { - return null; - } - - @Deprecated - public static net.milkbowl.vault.economy.Economy getEconomy() { - return EcoUtils.getEconomy(); - } - - // ********************************* - // - // Private Setter - // - // ********************************* - - static void setIsInternetOnline(boolean isInternetOnline) { - Main.isInternetOnline = isInternetOnline; - } - - static void setPlayerDataFolder(File playerDataFolder) { - Main.playerDataFolder = playerDataFolder; - } - - static void setServerDataFolder(File serverDataFolder) { - Main.serverDataFolder = serverDataFolder; - } - - static void setStorageType(StorageType storageType) { - Main.storageType = storageType; - } -} diff --git a/src/main/scala/me/skymc/taboolib/TabooLib.java b/src/main/scala/me/skymc/taboolib/TabooLib.java deleted file mode 100644 index 6c41809..0000000 --- a/src/main/scala/me/skymc/taboolib/TabooLib.java +++ /dev/null @@ -1,169 +0,0 @@ -package me.skymc.taboolib; - -import me.skymc.taboolib.common.nms.NMSHandler; -import me.skymc.taboolib.other.NumberUtils; -import me.skymc.taboolib.playerdata.DataUtils; -import net.md_5.bungee.api.ChatColor; -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; - -import java.util.Arrays; -import java.util.UUID; - -/** - * @author sky - */ -public class TabooLib { - - private static boolean spigot = false; - private static boolean silent = false; - - static { - try { - // 判断是否为独立客户端运行,不是判断 Bukkit 与 Spigot - Class.forName("org.bukkit.Bukkit"); - spigot = true; - } catch (Exception ignored) { - } - } - - /** - * 获取主类对象,因 Main 名称容易造成混淆所以转移至此 - */ - public static Main instance() { - return (Main) Main.getInst(); - } - - /** - * 插件是否为 TabooLib(沙雕方法) - */ - public static boolean isTabooLib(Plugin plugin) { - return plugin.equals(instance()) || plugin.getName().equals("TabooLib"); - } - - /** - * 插件是否依赖于 TabooLib(依赖或软兼容) - */ - public static boolean isDependTabooLib(Plugin plugin) { - return plugin.getDescription().getDepend().contains("TabooLib") || plugin.getDescription().getSoftDepend().contains("TabooLib"); - } - - /** - * 是否为 Spigot 核心,因 TabooLib 可在 BungeeCord 上运行所以添加此方法 - */ - public static boolean isSpigot() { - return spigot; - } - - /** - * 是否为静默模式 - */ - public static boolean isSilent() { - return silent; - } - - /** - * 设置静默模式,启用后将关闭部分提示 - */ - public static void setSilent(boolean silent) { - TabooLib.silent = silent; - } - - /** - * 获取 TabooLib 插件版本 - */ - public static double getPluginVersion() { - return NumberUtils.getDouble(Main.getInst().getDescription().getVersion()); - } - - /** - * 获取服务端版本 - */ - public static String getVersion() { - return Bukkit.getServer().getClass().getName().split("\\.")[3]; - } - - /** - * 获取服务端版本数字 - */ - public static int getVersionNumber() { - return getVerint(); - } - - /** - * 重置服务器序列号 - */ - public static void resetServerUID() { - DataUtils.getPluginData("TabooLibrary", null).set("serverUID", UUID.randomUUID().toString()); - } - - /** - * 是否为调试模式 - */ - public static boolean isDebug() { - return DataUtils.getPluginData("TabooLibrary", instance()).getBoolean("debug"); - } - - /** - * 切换调试模式 - */ - public static void setDebug(boolean debug) { - DataUtils.getPluginData("TabooLibrary", instance()).set("debug", debug); - } - - /** - * 发送调试信息 - */ - public static void debug(String... args) { - debug(instance(), args); - } - - /** - * 发送调试信息 - */ - public static void debug(Plugin plugin, String... args) { - if (TabooLib.isDebug()) { - Arrays.stream(args).forEach(var -> Bukkit.getConsoleSender().sendMessage(ChatColor.DARK_RED + "[TabooLib - DEBUG][" + plugin.getName() + "] " + ChatColor.RED + var)); - } - } - - /** - * 获取服务器序列号 - */ - public static String getServerUID() { - if (!DataUtils.getPluginData("TabooLibrary", null).contains("serverUID")) { - DataUtils.getPluginData("TabooLibrary", null).set("serverUID", UUID.randomUUID().toString()); - } - return DataUtils.getPluginData("TabooLibrary", null).getString("serverUID"); - } - - /** - * 获取服务器 TPS - */ - public static double[] getTPS() { - return NMSHandler.getHandler().getTPS(); - } - - @Deprecated - public static int getVerint() { - String version = getVersion(); - if (version.startsWith("v1_7")) { - return 10700; - } else if (version.startsWith("v1_8")) { - return 10800; - } else if (version.startsWith("v1_9")) { - return 10900; - } else if (version.startsWith("v1_10")) { - return 11000; - } else if (version.startsWith("v1_11")) { - return 11100; - } else if (version.startsWith("v1_12")) { - return 11200; - } else if (version.startsWith("v1_13")) { - return 11300; - } else if (version.startsWith("v1_14")) { - return 11400; - } - return 0; - } -} diff --git a/src/main/scala/me/skymc/taboolib/TabooLibDatabase.java b/src/main/scala/me/skymc/taboolib/TabooLibDatabase.java deleted file mode 100644 index 772b759..0000000 --- a/src/main/scala/me/skymc/taboolib/TabooLibDatabase.java +++ /dev/null @@ -1,128 +0,0 @@ -package me.skymc.taboolib; - -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.mysql.builder.SQLColumn; -import me.skymc.taboolib.mysql.builder.SQLColumnType; -import me.skymc.taboolib.mysql.builder.SQLHost; -import me.skymc.taboolib.mysql.builder.SQLTable; -import me.skymc.taboolib.mysql.hikari.HikariHandler; -import me.skymc.taboolib.string.StringUtils; -import org.bukkit.Bukkit; - -import javax.sql.DataSource; -import java.util.HashMap; - -/** - * @Author sky - * @Since 2018-08-23 17:15 - */ -public class TabooLibDatabase { - - private static SQLHost host; - private static DataSource dataSource; - private static HashMap tables = new HashMap<>(); - - static void init() { - if (Main.getStorageType() != Main.StorageType.SQL) { - return; - } - // 数据库地址 - host = new SQLHost( - // 地址 - Main.getInst().getConfig().getString("MYSQL.HOST"), - // 用户 - Main.getInst().getConfig().getString("MYSQL.USER"), - // 端口 - Main.getInst().getConfig().getString("MYSQL.POST"), - // 密码 - Main.getInst().getConfig().getString("MYSQL.PASSWORD"), - // 数据库 - Main.getInst().getConfig().getString("MYSQL.DATABASE"), TabooLib.instance()); - // 连接数据库 - try { - dataSource = HikariHandler.createDataSource(host); - } catch (Exception ignored) { - TLocale.Logger.error("NOTIFY.ERROR-CONNECTION-FAIL"); - return; - } - // 创建各项数据表 - createTableWithPlayerData(); - createTableWithPluginData(); - createTableWithServerUUID(); - } - - /** - * 创建玩家数据表 - */ - static void createTableWithPlayerData() { - SQLTable table = new SQLTable(Main.getTablePrefix() + "_playerdata", SQLColumn.PRIMARY_KEY_ID, new SQLColumn(SQLColumnType.TEXT, "username"), new SQLColumn(SQLColumnType.TEXT, "configuration")); - table.executeUpdate(table.createQuery()).dataSource(dataSource).run(); - tables.put("playerdata", table); - } - - /** - * 创建插件数据表 - */ - static void createTableWithPluginData() { - SQLTable table = new SQLTable(Main.getTablePrefix() + "_plugindata", SQLColumn.PRIMARY_KEY_ID, new SQLColumn(SQLColumnType.TEXT, "name"), new SQLColumn(SQLColumnType.TEXT, "variable"), new SQLColumn(SQLColumnType.TEXT, "upgrade")); - table.executeUpdate(table.createQuery()).dataSource(dataSource).run(); - tables.put("plugindata", table); - } - - /** - * 创建服务器数据表 - */ - static void createTableWithServerUUID() { - SQLTable table = new SQLTable(Main.getTablePrefix() + "_serveruuid", SQLColumn.PRIMARY_KEY_ID, new SQLColumn(SQLColumnType.TEXT, "uuid"), new SQLColumn(SQLColumnType.TEXT, "hash")); - table.executeUpdate(table.createQuery()).dataSource(dataSource).run(); - tables.put("serveruuid", table); - // 获取当前服务器信息 - String hash = getServerHash(TabooLib.getServerUID()); - if (hash == null) { - // 写入序列号 - table.executeUpdate("insert into " + table.getTableName() + " values(null, ?, ?)") - .dataSource(dataSource) - .statement(s -> { - s.setString(1, TabooLib.getServerUID()); - s.setString(2, StringUtils.hashKeyForDisk(Main.getInst().getDataFolder().getPath())); - }).run(); - } else if (!hash.equals(StringUtils.hashKeyForDisk(Main.getInst().getDataFolder().getPath()))) { - TLocale.Logger.error("NOTIFY.ERROR-SERVER-KEY"); - TabooLib.resetServerUID(); - Bukkit.shutdown(); - } - } - - /** - * 获取服务器序列号对应的目录哈希值 - * - * @param uuid 服务器序列号 - * @return 目录哈希值 - */ - public static String getServerHash(String uuid) { - SQLTable table = tables.get("serveruuid"); - return table.executeQuery("select * from " + table.getTableName() + " where uuid = ?") - .dataSource(dataSource) - .statement(s -> s.setString(1, uuid)) - .resultNext(r -> r.getString("hash")) - .run(null, ""); - } - - // ********************************* - // - // Getter and Setter - // - // ********************************* - - public static SQLHost getHost() { - return host; - } - - public static HashMap getTables() { - return tables; - } - - public static DataSource getDataSource() { - return dataSource; - } -} diff --git a/src/main/scala/me/skymc/taboolib/TabooLibLoader.java b/src/main/scala/me/skymc/taboolib/TabooLibLoader.java deleted file mode 100644 index 8048b8f..0000000 --- a/src/main/scala/me/skymc/taboolib/TabooLibLoader.java +++ /dev/null @@ -1,305 +0,0 @@ -package me.skymc.taboolib; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.ilummc.tlib.TLib; -import com.ilummc.tlib.annotations.Dependency; -import com.ilummc.tlib.dependency.TDependencyLoader; -import com.ilummc.tlib.inject.TDependencyInjector; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.bstats.Metrics; -import me.skymc.taboolib.deprecated.TabooLibDeprecated; -import me.skymc.taboolib.events.TPluginEnableEvent; -import me.skymc.taboolib.fileutils.FileUtils; -import me.skymc.taboolib.listener.TListener; -import me.skymc.taboolib.listener.TListenerHandler; -import me.skymc.taboolib.methods.ReflectionUtils; -import me.skymc.taboolib.playerdata.DataUtils; -import org.bukkit.Bukkit; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.server.PluginDisableEvent; -import org.bukkit.plugin.Plugin; - -import java.io.File; -import java.io.InputStream; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.net.InetAddress; -import java.util.*; - -/** - * @Author sky - * @Since 2018-08-23 17:04 - */ -@TListener -public class TabooLibLoader implements Listener { - - /* - 关于 TabooLib 各项自动化接口的执行顺序 - - [ENABLING] - 第一阶段:运行 @TInject(Instance Inject) - 第二阶段(先后):实例化 @TListener -> 实例化 @Instantiable - 第三阶段(并行):运行 @TFunction & 运行 @TInject - - [ENABLED] - 第三阶段:注册 @TListener - */ - - static TabooLibDeprecated tabooLibDeprecated; - static Map> pluginClasses = Maps.newHashMap(); - static List loaders = Lists.newArrayList(); - static List tasks = Lists.newArrayList(); - static boolean started; - - static void setup() { - testInternet(); - setupDataFolder(); - setupDatabase(); - setupLibraries(); - } - - static void register() { - setupClasses(); - preLoadClasses(); - registerListener(); - registerMetrics(); - postLoadClasses(); - try { - tabooLibDeprecated = new TabooLibDeprecated(); - } catch (Exception e) { - e.printStackTrace(); - } - Bukkit.getScheduler().runTask(TabooLib.instance(), () -> { - for (Runnable task : tasks) { - try { - task.run(); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - } - - static void unregister() { - unloadClasses(); - try { - tabooLibDeprecated.unregister(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public static TabooLibDeprecated getTabooLibDeprecated() { - return tabooLibDeprecated; - } - - public static Optional> getPluginClasses(Plugin plugin) { - return Optional.ofNullable(pluginClasses.get(plugin.getName())); - } - - public static List getPluginClassSafely(Plugin plugin) { - List classes = pluginClasses.get(plugin.getName()); - return classes == null ? new ArrayList<>() : new ArrayList<>(classes); - } - - public static void runTaskOnEnabled(Runnable runnable) { - if (Main.isStarted()) { - Bukkit.getScheduler().runTask(TabooLib.instance(), () -> { - try { - runnable.run(); - } catch (Throwable t) { - t.printStackTrace(); - } - }); - } else { - tasks.add(runnable); - } - } - - static boolean isLoader(Class pluginClass) { - return !Loader.class.equals(pluginClass) && Loader.class.isAssignableFrom(pluginClass); - } - - static void preLoadClasses() { - pluginClasses.forEach((key, classes) -> classes.forEach(pluginClass -> preLoadClass(Bukkit.getPluginManager().getPlugin(key), pluginClass))); - } - - static void postLoadClasses() { - pluginClasses.forEach((key, classes) -> classes.forEach(pluginClass -> postLoadClass(Bukkit.getPluginManager().getPlugin(key), pluginClass))); - } - - static void unloadClasses() { - pluginClasses.forEach((key, classes) -> classes.forEach(pluginClass -> unloadClass(Bukkit.getPluginManager().getPlugin(key), pluginClass))); - } - - static void registerListener() { - TListenerHandler.setupListeners(); - Bukkit.getScheduler().runTask(TabooLib.instance(), TListenerHandler::registerListeners); - } - - static void registerMetrics() { - Metrics metrics = new Metrics(TabooLib.instance()); - metrics.addCustomChart(new Metrics.SingleLineChart("plugins_using_taboolib", () -> Math.toIntExact(Arrays.stream(Bukkit.getPluginManager().getPlugins()).filter(plugin -> plugin.getDescription().getDepend().contains("TabooLib")).count()))); - } - - static void setupDataFolder() { - Main.setPlayerDataFolder(FileUtils.folder(Main.getInst().getConfig().getString("DATAURL.PLAYER-DATA"))); - Main.setServerDataFolder(FileUtils.folder(Main.getInst().getConfig().getString("DATAURL.SERVER-DATA"))); - } - - static void setupDatabase() { - DataUtils.addPluginData("TabooLibrary", null); - Main.setStorageType(Main.StorageType.LOCAL); -// Main.setStorageType(Main.getInst().getConfig().getBoolean("MYSQL.ENABLE") ? Main.StorageType.SQL : Main.StorageType.LOCAL); -// TabooLibDatabase.init(); - } - - static void setupAddons() { - File origin = new File(TabooLib.instance().getDataFolder(), "Addons/TabooLibDeprecated.jar"); - origin.delete(); - // 傻逼 Gradle 的 shadow 插件会将所有 jar 排除 - // https://github.com/johnrengelman/shadow/issues/276 - TabooLib.instance().saveResource("Addons/TabooLibDeprecated", true); - File from = new File(TabooLib.instance().getDataFolder(), "Addons/TabooLibDeprecated"); - from.renameTo(origin); - from.delete(); - File file = new File(TabooLib.instance().getDataFolder(), "Addons"); - if (file.exists()) { - Arrays.stream(file.listFiles()).forEach(listFile -> TDependencyLoader.addToPath(TabooLib.instance(), listFile)); - } - } - - static void setupLibraries() { - if (Main.isOfflineVersion()) { - Arrays.stream(TDependencyInjector.getDependencies(TLib.getTLib())).filter(dependency -> dependency.type() == Dependency.Type.LIBRARY && dependency.maven().matches(".*:.*:.*")).map(dependency -> String.join("-", dependency.maven().split(":")) + ".jar").forEach(fileName -> { - File targetFile = FileUtils.file(TLib.getTLib().getLibsFolder(), fileName); - InputStream inputStream = FileUtils.getResource("libs/" + fileName); - if (!targetFile.exists() && inputStream != null) { - FileUtils.inputStreamToFile(inputStream, FileUtils.file(TLib.getTLib().getLibsFolder(), fileName)); - } - }); - } - } - - static void testInternet() { - try { - InetAddress inetAddress = InetAddress.getByName(Main.getInst().getConfig().getString("TEST-URL", "aliyun.com")); - Main.setIsInternetOnline(inetAddress.isReachable(10000)); - } catch (Exception ignored) { - } - if (!Main.isInternetOnline() && !Main.isOfflineVersion() && !Main.isLibrariesExists()) { - TLocale.Logger.error("TLIB.LOAD-FAIL-OFFLINE", Main.getInst().getDescription().getVersion()); - for (; ; ) { - // 停止主线程 - } - } - } - - static void setupClasses(Plugin plugin) { - if (TabooLib.isTabooLib(plugin) || TabooLib.isDependTabooLib(plugin)) { - try { - long time = System.currentTimeMillis(); - List classes; - IgnoreClasses annotation = plugin.getClass().getAnnotation(IgnoreClasses.class); - if (annotation != null) { - classes = FileUtils.getClasses(plugin, annotation.value()); - } else { - classes = FileUtils.getClasses(plugin); - } - TabooLib.debug("Saved " + classes.size() + " classes (" + plugin.getName() + ") (" + (System.currentTimeMillis() - time) + "ms)"); - pluginClasses.put(plugin.getName(), classes); - } catch (Exception ignored) { - } - } - } - - static void setupClasses() { - Arrays.stream(Bukkit.getPluginManager().getPlugins()).forEach(TabooLibLoader::setupClasses); - pluginClasses.get("TabooLib").stream().filter(TabooLibLoader::isLoader).forEach(pluginClass -> { - try { - loaders.add((Loader) ReflectionUtils.instantiateObject(pluginClass)); - } catch (Exception e) { - e.printStackTrace(); - } - loaders.sort(Comparator.comparingInt(Loader::priority)); - }); - } - - static void preLoadClass(Plugin plugin, Class loadClass) { - loaders.forEach(loader -> { - try { - loader.preLoad(plugin, loadClass); - } catch (NoClassDefFoundError ignore) { - } catch (Throwable e) { - e.printStackTrace(); - } - }); - } - - static void postLoadClass(Plugin plugin, Class loadClass) { - loaders.forEach(loader -> { - try { - loader.postLoad(plugin, loadClass); - } catch (NoClassDefFoundError ignore) { - } catch (Throwable e) { - e.printStackTrace(); - } - }); - } - - static void unloadClass(Plugin plugin, Class loadClass) { - loaders.forEach(loader -> { - try { - loader.unload(plugin, loadClass); - } catch (NoClassDefFoundError ignore) { - } catch (Throwable e) { - e.printStackTrace(); - } - }); - } - - @EventHandler(priority = EventPriority.LOWEST) - public void onEnablePre(TPluginEnableEvent e) { - setupClasses(e.getPlugin()); - Optional.ofNullable(pluginClasses.get(e.getPlugin().getName())).ifPresent(classes -> classes.forEach(pluginClass -> preLoadClass(e.getPlugin(), pluginClass))); - } - - @EventHandler - public void onEnablePost(TPluginEnableEvent e) { - Optional.ofNullable(pluginClasses.get(e.getPlugin().getName())).ifPresent(classes -> classes.forEach(pluginClass -> postLoadClass(e.getPlugin(), pluginClass))); - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onDisable(PluginDisableEvent e) { - Optional.ofNullable(pluginClasses.remove(e.getPlugin().getName())).ifPresent(classes -> classes.forEach(pluginClass -> unloadClass(e.getPlugin(), pluginClass))); - } - - public interface Loader { - - default void preLoad(Plugin plugin, Class loadClass) { - } - - default void postLoad(Plugin plugin, Class loadClass) { - } - - default void unload(Plugin plugin, Class cancelClass) { - } - - default int priority() { - return 0; - } - } - - @Target(ElementType.TYPE) - @Retention(RetentionPolicy.RUNTIME) - public @interface IgnoreClasses { - - String[] value(); - - } -} diff --git a/src/main/scala/me/skymc/taboolib/anvil/AnvilContainer.java b/src/main/scala/me/skymc/taboolib/anvil/AnvilContainer.java deleted file mode 100644 index 0ebfc47..0000000 --- a/src/main/scala/me/skymc/taboolib/anvil/AnvilContainer.java +++ /dev/null @@ -1,29 +0,0 @@ -package me.skymc.taboolib.anvil; - -import org.bukkit.entity.Player; - -/** - * @Author sky - * @Since 2018-09-08 15:47 - */ -public class AnvilContainer extends net.minecraft.server.v1_12_R1.ContainerAnvil { - - public AnvilContainer(net.minecraft.server.v1_12_R1.EntityHuman player) { - super(player.inventory, player.world, new net.minecraft.server.v1_12_R1.BlockPosition(0, 0, 0), player); - } - - @Override - public boolean a(net.minecraft.server.v1_12_R1.EntityHuman player) { - return true; - } - - public static void openAnvil(Player p) { - net.minecraft.server.v1_12_R1.EntityPlayer player = ((org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer) p).getHandle(); - AnvilContainer container = new AnvilContainer(player); - int c = player.nextContainerCounter(); - player.playerConnection.sendPacket(new net.minecraft.server.v1_12_R1.PacketPlayOutOpenWindow(c, "minecraft:anvil", new net.minecraft.server.v1_12_R1.ChatMessage("Repairing"), 0)); - player.activeContainer = container; - player.activeContainer.windowId = c; - player.activeContainer.addSlotListener(player); - } -} \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/anvil/AnvilContainerAPI.java b/src/main/scala/me/skymc/taboolib/anvil/AnvilContainerAPI.java deleted file mode 100644 index 904910c..0000000 --- a/src/main/scala/me/skymc/taboolib/anvil/AnvilContainerAPI.java +++ /dev/null @@ -1,44 +0,0 @@ -package me.skymc.taboolib.anvil; - -import com.ilummc.tlib.util.asm.AsmClassLoader; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.common.loader.Instantiable; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; - -/** - * @author sky - */ -@Instantiable("AnvilContainerAPI") -public class AnvilContainerAPI implements Listener { - - private static Class impl; - - public AnvilContainerAPI() { - try { - impl = AsmClassLoader.createNewClass("me.skymc.taboolib.anvil.AnvilContainer", AnvilContainerGenerator.generate()); - Bukkit.getPluginManager().registerEvents(this, TabooLib.instance()); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public static void openAnvil(Player player) { - try { - impl.getMethod("openAnvil", Player.class).invoke(impl, player); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @EventHandler - public void example(PlayerCommandPreprocessEvent e) { - if (e.getMessage().equalsIgnoreCase("/anvilExample") && e.getPlayer().hasPermission("taboolib.admin")) { - e.setCancelled(true); - openAnvil(e.getPlayer()); - } - } -} diff --git a/src/main/scala/me/skymc/taboolib/anvil/AnvilContainerGenerator.java b/src/main/scala/me/skymc/taboolib/anvil/AnvilContainerGenerator.java deleted file mode 100644 index eda7cf3..0000000 --- a/src/main/scala/me/skymc/taboolib/anvil/AnvilContainerGenerator.java +++ /dev/null @@ -1,142 +0,0 @@ -package me.skymc.taboolib.anvil; - -import me.skymc.taboolib.TabooLib; -import org.objectweb.asm.*; - -/** - * @author idea - */ -public class AnvilContainerGenerator { - - public static byte[] generate() { - String version = TabooLib.getVersion(); - ClassWriter cw = new ClassWriter(0); - FieldVisitor fv; - MethodVisitor mv; - AnnotationVisitor av0; - cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, "me/skymc/taboolib/anvil/AnvilContainer", null, "net/minecraft/server/" + version + "/ContainerAnvil", null); - cw.visitSource("AnvilContainer.java", null); - { - mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "(Lnet/minecraft/server/" + version + "/EntityHuman;)V", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitLineNumber(12, l0); - mv.visitVarInsn(Opcodes.ALOAD, 0); - mv.visitVarInsn(Opcodes.ALOAD, 1); - mv.visitFieldInsn(Opcodes.GETFIELD, "net/minecraft/server/" + version + "/EntityHuman", "inventory", "Lnet/minecraft/server/" + version + "/PlayerInventory;"); - mv.visitVarInsn(Opcodes.ALOAD, 1); - mv.visitFieldInsn(Opcodes.GETFIELD, "net/minecraft/server/" + version + "/EntityHuman", "world", "Lnet/minecraft/server/" + version + "/World;"); - mv.visitTypeInsn(Opcodes.NEW, "net/minecraft/server/" + version + "/BlockPosition"); - mv.visitInsn(Opcodes.DUP); - mv.visitInsn(Opcodes.ICONST_0); - mv.visitInsn(Opcodes.ICONST_0); - mv.visitInsn(Opcodes.ICONST_0); - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "net/minecraft/server/" + version + "/BlockPosition", "", "(III)V", false); - mv.visitVarInsn(Opcodes.ALOAD, 1); - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "net/minecraft/server/" + version + "/ContainerAnvil", "", "(Lnet/minecraft/server/" + version + "/PlayerInventory;Lnet/minecraft/server/" + version + "/World;Lnet/minecraft/server/" + version + "/BlockPosition;Lnet/minecraft/server/" + version + "/EntityHuman;)V", false); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitLineNumber(13, l1); - mv.visitInsn(Opcodes.RETURN); - Label l2 = new Label(); - mv.visitLabel(l2); - mv.visitLocalVariable("this", "Lme/skymc/taboolib/anvil/AnvilContainer;", null, l0, l2, 0); - mv.visitLocalVariable("player", "Lnet/minecraft/server/" + version + "/EntityHuman;", null, l0, l2, 1); - mv.visitMaxs(8, 2); - mv.visitEnd(); - } - { - mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "a", "(Lnet/minecraft/server/" + version + "/EntityHuman;)Z", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitLineNumber(17, l0); - mv.visitInsn(Opcodes.ICONST_1); - mv.visitInsn(Opcodes.IRETURN); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitLocalVariable("this", "Lme/skymc/taboolib/anvil/AnvilContainer;", null, l0, l1, 0); - mv.visitLocalVariable("player", "Lnet/minecraft/server/" + version + "/EntityHuman;", null, l0, l1, 1); - mv.visitMaxs(1, 2); - mv.visitEnd(); - } - { - mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "openAnvil", "(Lorg/bukkit/entity/Player;)V", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitLineNumber(21, l0); - mv.visitVarInsn(Opcodes.ALOAD, 0); - mv.visitTypeInsn(Opcodes.CHECKCAST, "org/bukkit/craftbukkit/" + version + "/entity/CraftPlayer"); - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/bukkit/craftbukkit/" + version + "/entity/CraftPlayer", "getHandle", "()Lnet/minecraft/server/" + version + "/EntityPlayer;", false); - mv.visitVarInsn(Opcodes.ASTORE, 1); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitLineNumber(22, l1); - mv.visitTypeInsn(Opcodes.NEW, "me/skymc/taboolib/anvil/AnvilContainer"); - mv.visitInsn(Opcodes.DUP); - mv.visitVarInsn(Opcodes.ALOAD, 1); - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "me/skymc/taboolib/anvil/AnvilContainer", "", "(Lnet/minecraft/server/" + version + "/EntityHuman;)V", false); - mv.visitVarInsn(Opcodes.ASTORE, 2); - Label l2 = new Label(); - mv.visitLabel(l2); - mv.visitLineNumber(23, l2); - mv.visitVarInsn(Opcodes.ALOAD, 1); - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "net/minecraft/server/" + version + "/EntityPlayer", "nextContainerCounter", "()I", false); - mv.visitVarInsn(Opcodes.ISTORE, 3); - Label l3 = new Label(); - mv.visitLabel(l3); - mv.visitLineNumber(24, l3); - mv.visitVarInsn(Opcodes.ALOAD, 1); - mv.visitFieldInsn(Opcodes.GETFIELD, "net/minecraft/server/" + version + "/EntityPlayer", "playerConnection", "Lnet/minecraft/server/" + version + "/PlayerConnection;"); - mv.visitTypeInsn(Opcodes.NEW, "net/minecraft/server/" + version + "/PacketPlayOutOpenWindow"); - mv.visitInsn(Opcodes.DUP); - mv.visitVarInsn(Opcodes.ILOAD, 3); - mv.visitLdcInsn("minecraft:anvil"); - mv.visitTypeInsn(Opcodes.NEW, "net/minecraft/server/" + version + "/ChatMessage"); - mv.visitInsn(Opcodes.DUP); - mv.visitLdcInsn("Repairing"); - mv.visitInsn(Opcodes.ICONST_0); - mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "net/minecraft/server/" + version + "/ChatMessage", "", "(Ljava/lang/String;[Ljava/lang/Object;)V", false); - mv.visitInsn(Opcodes.ICONST_0); - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "net/minecraft/server/" + version + "/PacketPlayOutOpenWindow", "", "(ILjava/lang/String;Lnet/minecraft/server/" + version + "/IChatBaseComponent;I)V", false); - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "net/minecraft/server/" + version + "/PlayerConnection", "sendPacket", "(Lnet/minecraft/server/" + version + "/Packet;)V", false); - Label l4 = new Label(); - mv.visitLabel(l4); - mv.visitLineNumber(25, l4); - mv.visitVarInsn(Opcodes.ALOAD, 1); - mv.visitVarInsn(Opcodes.ALOAD, 2); - mv.visitFieldInsn(Opcodes.PUTFIELD, "net/minecraft/server/" + version + "/EntityPlayer", "activeContainer", "Lnet/minecraft/server/" + version + "/Container;"); - Label l5 = new Label(); - mv.visitLabel(l5); - mv.visitLineNumber(26, l5); - mv.visitVarInsn(Opcodes.ALOAD, 1); - mv.visitFieldInsn(Opcodes.GETFIELD, "net/minecraft/server/" + version + "/EntityPlayer", "activeContainer", "Lnet/minecraft/server/" + version + "/Container;"); - mv.visitVarInsn(Opcodes.ILOAD, 3); - mv.visitFieldInsn(Opcodes.PUTFIELD, "net/minecraft/server/" + version + "/Container", "windowId", "I"); - Label l6 = new Label(); - mv.visitLabel(l6); - mv.visitLineNumber(27, l6); - mv.visitVarInsn(Opcodes.ALOAD, 1); - mv.visitFieldInsn(Opcodes.GETFIELD, "net/minecraft/server/" + version + "/EntityPlayer", "activeContainer", "Lnet/minecraft/server/" + version + "/Container;"); - mv.visitVarInsn(Opcodes.ALOAD, 1); - mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "net/minecraft/server/" + version + "/Container", "addSlotListener", "(Lnet/minecraft/server/" + version + "/ICrafting;)V", false); - Label l7 = new Label(); - mv.visitLabel(l7); - mv.visitLineNumber(28, l7); - mv.visitInsn(Opcodes.RETURN); - Label l8 = new Label(); - mv.visitLabel(l8); - mv.visitLocalVariable("p", "Lorg/bukkit/entity/Player;", null, l0, l8, 0); - mv.visitLocalVariable("player", "Lnet/minecraft/server/" + version + "/EntityPlayer;", null, l1, l8, 1); - mv.visitLocalVariable("container", "Lme/skymc/taboolib/anvil/AnvilContainer;", null, l2, l8, 2); - mv.visitLocalVariable("c", "I", null, l3, l8, 3); - mv.visitMaxs(9, 4); - mv.visitEnd(); - } - cw.visitEnd(); - return cw.toByteArray(); - } -} diff --git a/src/main/scala/me/skymc/taboolib/bungee/TabooLibBungee.java b/src/main/scala/me/skymc/taboolib/bungee/TabooLibBungee.java deleted file mode 100644 index 1709569..0000000 --- a/src/main/scala/me/skymc/taboolib/bungee/TabooLibBungee.java +++ /dev/null @@ -1,11 +0,0 @@ -package me.skymc.taboolib.bungee; - -import net.md_5.bungee.api.plugin.Plugin; - -/** - * @Author sky - * @Since 2018-08-09 11:47 - */ -public class TabooLibBungee extends Plugin { - -} diff --git a/src/main/scala/me/skymc/taboolib/cloud/TCloudCommand.java b/src/main/scala/me/skymc/taboolib/cloud/TCloudCommand.java deleted file mode 100644 index dd6a2cf..0000000 --- a/src/main/scala/me/skymc/taboolib/cloud/TCloudCommand.java +++ /dev/null @@ -1,250 +0,0 @@ -package me.skymc.taboolib.cloud; - -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.cloud.expansion.Expansion; -import me.skymc.taboolib.cloud.expansion.ExpansionType; -import me.skymc.taboolib.commands.internal.BaseMainCommand; -import me.skymc.taboolib.commands.internal.BaseSubCommand; -import me.skymc.taboolib.commands.internal.TCommand; -import me.skymc.taboolib.commands.internal.plugin.TLibLocale; -import me.skymc.taboolib.commands.internal.type.CommandArgument; -import me.skymc.taboolib.commands.internal.type.CommandRegister; -import me.skymc.taboolib.common.util.SimpleIterator; -import me.skymc.taboolib.fileutils.FileUtils; -import me.skymc.taboolib.plugin.PluginUtils; -import org.bukkit.Bukkit; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.util.NumberConversions; - -import java.util.Arrays; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * @Author sky - * @Since 2018-09-30 19:17 - */ -@TCommand( - name = "taboolibcloud", - permission = "taboolib.admin", - aliases = "tcloud" -) -public class TCloudCommand extends BaseMainCommand { - - @CommandRegister - BaseSubCommand refresh = new BaseSubCommand() { - @Override - public String getLabel() { - return "refresh"; - } - - @Override - public String getDescription() { - return TLibLocale.description("TCLOUD", "REFRESH"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[0]; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.REFRESH.SUCCESS"); - TCloudLoader.refresh(); - } - }; - @CommandRegister(priority = 1) - BaseSubCommand status = new BaseSubCommand() { - @Override - public String getLabel() { - return "status"; - } - - @Override - public String getDescription() { - return TLibLocale.description("TCLOUD", "STATUS"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[0]; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!TCloudLoader.isConnected()) { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.STATUS.CONNECT-FAILED"); - } else { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.STATUS.STATUS", String.valueOf(TCloudLoader.getExpansionInternal().size() + TCloudLoader.getExpansionPlugins().size()), String.valueOf(TCloudLoader.getExpansionInternal().size()), String.valueOf(TCloudLoader.getExpansionPlugins().size())); - } - } - }; - @CommandRegister(priority = 2) - BaseSubCommand info = new BaseSubCommand() { - @Override - public String getLabel() { - return "info"; - } - - @Override - public String getDescription() { - return TLibLocale.description("TCLOUD", "INFO"); - } - - @Override - public CommandArgument[] getArguments() { - return TLibLocale.arguments("TCLOUD", "INFO", 1); - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - Expansion expansion = TCloudLoader.getExpansion(args[0]); - if (expansion == null) { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.INFO.EXPANSION-NOT-FOUND", args[0]); - } else { - String builder = Arrays.stream(expansion.getAuthor()).map(author -> author + ", ").collect(Collectors.joining()); - TLocale.sendTo(sender, "COMMANDS.TCLOUD.INFO.EXPANSION-INFO", expansion.getName(), builder.substring(0, builder.length() - 2), expansion.getVersion(), expansion.getDescription(), expansion.getLastUpdate(), expansion.getLastUpdateNote()); - TLocale.sendTo(sender, "COMMANDS.TCLOUD.INFO.EXPANSION-INFO-DETAIL.0"); - Arrays.stream(expansion.getDetail()).forEach(detail -> TLocale.sendTo(sender, "COMMANDS.TCLOUD.INFO.EXPANSION-INFO-DETAIL.1", detail)); - } - } - }; - - @CommandRegister(priority = 3) - BaseSubCommand download = new BaseSubCommand() { - @Override - public String getLabel() { - return "download"; - } - - @Override - public String getDescription() { - return TLibLocale.description("TCLOUD", "DOWNLOAD"); - } - - @Override - public CommandArgument[] getArguments() { - return TLibLocale.arguments("TCLOUD", "DOWNLOAD", 1); - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - Expansion expansion = TCloudLoader.getExpansion(args[0]); - if (expansion == null) { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.DOWNLOAD.EXPANSION-NOT-FOUND", args[0]); - } else if (!expansion.canUse()) { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.DOWNLOAD.EXPANSION-VERSION", args[0], String.valueOf(expansion.getDependVersion())); - } else if (TCloudLoader.isExpansionExists(expansion)) { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.DOWNLOAD.EXPANSION-EXISTS", args[0]); - } else { - Bukkit.getScheduler().runTaskAsynchronously(TabooLib.instance(), () -> { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.DOWNLOAD.DOWNLOAD-START", args[0], expansion.getLink()); - FileUtils.download(expansion.getLink(), expansion.getFile()); - TLocale.sendTo(sender, "COMMANDS.TCLOUD.DOWNLOAD.DOWNLOAD-SUCCESS", args[0]); - }); - } - } - }; - - @CommandRegister(priority = 4) - BaseSubCommand update = new BaseSubCommand() { - @Override - public String getLabel() { - return "update"; - } - - @Override - public String getDescription() { - return TLibLocale.description("TCLOUD", "UPDATE"); - } - - @Override - public CommandArgument[] getArguments() { - return TLibLocale.arguments("TCLOUD", "UPDATE", 1); - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - Expansion expansion = TCloudLoader.getExpansion(args[0]); - if (expansion == null) { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.UPDATE.EXPANSION-NOT-FOUND", args[0]); - } else if (!TCloudLoader.isExpansionExists(expansion)) { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.UPDATE.EXPANSION-NOT-EXISTS", args[0]); - } else if (!expansion.canUpdate()) { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.UPDATE.EXPANSION-NO-UPDATE", args[0]); - } else if (!expansion.canUse()) { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.UPDATE.EXPANSION-VERSION", args[0], String.valueOf(expansion.getDependVersion())); - } else { - Bukkit.getScheduler().runTaskAsynchronously(TabooLib.instance(), () -> { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.UPDATE.UPDATE-START", args[0], expansion.getVersion(), expansion.getLink()); - FileUtils.download(expansion.getLink(), PluginUtils.getPluginFile(expansion.getName())); - TLocale.sendTo(sender, "COMMANDS.TCLOUD.UPDATE.UPDATE-SUCCESS", args[0]); - }); - } - } - }; - - @CommandRegister(priority = 5) - BaseSubCommand list = new BaseSubCommand() { - @Override - public String getLabel() { - return "list"; - } - - @Override - public String getDescription() { - return TLibLocale.description("TCLOUD", "LIST"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[] { - TLibLocale.argument("TCLOUD", "LIST", 0), - TLibLocale.argument("TCLOUD", "LIST", 1, false) - }; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - ExpansionType type; - switch (args[0].toLowerCase()) { - case "plugins": - type = ExpansionType.PLUGIN; - break; - case "internal": - type = ExpansionType.INTERNAL; - break; - default: - TLocale.sendTo(sender, "COMMANDS.TCLOUD.LIST.INVALID-TYPE.0"); - return; - } - Map expansions = type == ExpansionType.PLUGIN ? TCloudLoader.getExpansionPlugins() : TCloudLoader.getExpansionInternal(); - int page = args.length < 2 ? 1 : NumberConversions.toInt(args[1]); - int pageMax = (expansions.size() / 5) + ((expansions.size() % 5) == 0 ? 0 : 1); - if (page < 1 || page > pageMax) { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.LIST.INVALID-TYPE.1"); - return; - } - TLocale.sendTo(sender, "COMMANDS.TCLOUD.LIST.LIST-HEAD", type.name(), String.valueOf(page), String.valueOf(pageMax)); - int i = (page - 1) * 5; - for (Map.Entry entry : new SimpleIterator(expansions).mapIterator((page - 1) * 5, page * 5)) { - if (!TCloudLoader.isExpansionExists(entry.getValue())) { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.LIST.LIST-EXPANSION.0", String.valueOf(++i), entry.getValue().getName(), Arrays.toString(entry.getValue().getAuthor())); - } else if (entry.getValue().canUpdate()) { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.LIST.LIST-EXPANSION.1", String.valueOf(++i), entry.getValue().getName(), Arrays.toString(entry.getValue().getAuthor())); - } else { - TLocale.sendTo(sender, "COMMANDS.TCLOUD.LIST.LIST-EXPANSION.2", String.valueOf(++i), entry.getValue().getName(), Arrays.toString(entry.getValue().getAuthor())); - } - } - TLocale.sendTo(sender, "COMMANDS.TCLOUD.LIST.LIST-BOTTOM"); - } - }; - - @Override - public String getCommandTitle() { - return TLocale.asString("COMMANDS.TCLOUD.COMMAND-TITLE"); - } -} diff --git a/src/main/scala/me/skymc/taboolib/cloud/TCloudLoader.java b/src/main/scala/me/skymc/taboolib/cloud/TCloudLoader.java deleted file mode 100644 index c498e7f..0000000 --- a/src/main/scala/me/skymc/taboolib/cloud/TCloudLoader.java +++ /dev/null @@ -1,133 +0,0 @@ -package me.skymc.taboolib.cloud; - -import com.google.common.collect.Maps; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.cloud.expansion.Expansion; -import me.skymc.taboolib.cloud.expansion.ExpansionType; -import me.skymc.taboolib.common.function.TFunction; -import me.skymc.taboolib.common.schedule.TSchedule; -import me.skymc.taboolib.fileutils.FileUtils; -import me.skymc.taboolib.plugin.PluginUtils; -import org.bukkit.Bukkit; - -import java.io.File; -import java.util.Map; - -/** - * @Author sky - * @Since 2018-09-30 17:30 - */ -@TFunction(enable = "init") -public class TCloudLoader { - - private static String url = "https://gitee.com/bkm016/TabooLibCloud/raw/master/cloud.json"; - private static String latestJsonOrigin; - private static JsonObject latestJsonObject; - private static Map expansionPlugins = Maps.newTreeMap(); - private static Map expansionInternal = Maps.newTreeMap(); - private static File expansionInternalFolder; - - static void init() { - createFolder(); - refresh(); - } - - public static void createFolder() { - if (!(expansionInternalFolder = new File(TabooLib.instance().getDataFolder(), "TCloud")).exists()) { - expansionInternalFolder.mkdirs(); - } - } - - @TSchedule(async = true, period = 20 * 60 * 60) - public static void refresh() { - Bukkit.getScheduler().runTaskAsynchronously(TabooLib.instance(), () -> { - long time = System.currentTimeMillis(); - latestJsonOrigin = FileUtils.getStringFromURL(url, 1024); - if (latestJsonOrigin == null) { - if (!TabooLib.isSilent()) { - TLocale.Logger.error("TCLOUD.LIST-CONNECT-FAILED"); - } - return; - } - try { - latestJsonObject = new JsonParser().parse(latestJsonOrigin).getAsJsonObject(); - } catch (Exception e) { - if (!TabooLib.isSilent()) { - TLocale.Logger.info("TCLOUD.LIST-PARSE-FAILED", e.getMessage()); - } - return; - } - if (latestJsonObject.has("plugins")) { - for (Map.Entry pluginEntry : latestJsonObject.getAsJsonObject("plugins").entrySet()) { - try { - expansionPlugins.put(pluginEntry.getKey(), Expansion.unSerialize(ExpansionType.PLUGIN, pluginEntry.getKey(), pluginEntry.getValue().getAsJsonObject())); - } catch (Exception e) { - if (!TabooLib.isSilent()) { - TLocale.Logger.info("TCLOUD.LIST-LOAD-FAILED", pluginEntry.getKey(), e.getMessage()); - } - } - } - } - if (latestJsonObject.has("internal")) { - for (Map.Entry pluginEntry : latestJsonObject.getAsJsonObject("internal").entrySet()) { - try { - expansionInternal.put(pluginEntry.getKey(), Expansion.unSerialize(ExpansionType.INTERNAL, pluginEntry.getKey(), pluginEntry.getValue().getAsJsonObject())); - } catch (Exception e) { - if (!TabooLib.isSilent()) { - TLocale.Logger.info("TCLOUD.LIST-LOAD-FAILED", pluginEntry.getKey(), e.getMessage()); - } - } - } - } - if (!TabooLib.isSilent()) { - TLocale.Logger.info("TCLOUD.LIST-LOAD-SUCCESS", String.valueOf(System.currentTimeMillis() - time)); - } - }); - } - - public static boolean isConnected() { - return latestJsonOrigin != null; - } - - public static String getLatestJsonOrigin() { - return latestJsonOrigin; - } - - public static JsonObject getLatestJsonObject() { - return latestJsonObject; - } - - public static Map getExpansionPlugins() { - return expansionPlugins; - } - - public static Map getExpansionInternal() { - return expansionInternal; - } - - public static File getExpansionInternalFolder() { - return expansionInternalFolder; - } - - public static boolean isExpansionExists(Expansion expansion) { - return expansion.getType() == ExpansionType.PLUGIN && PluginUtils.isPluginExists(expansion.getName()); - } - - public static Expansion getExpansion(String name) { - for (Map.Entry stringExpansionEntry : expansionPlugins.entrySet()) { - if (stringExpansionEntry.getKey().equalsIgnoreCase(name)) { - return stringExpansionEntry.getValue(); - } - } - for (Map.Entry stringExpansionEntry : expansionInternal.entrySet()) { - if (stringExpansionEntry.getKey().equalsIgnoreCase(name)) { - return stringExpansionEntry.getValue(); - } - } - return null; - } -} diff --git a/src/main/scala/me/skymc/taboolib/cloud/expansion/Expansion.java b/src/main/scala/me/skymc/taboolib/cloud/expansion/Expansion.java deleted file mode 100644 index 47b327f..0000000 --- a/src/main/scala/me/skymc/taboolib/cloud/expansion/Expansion.java +++ /dev/null @@ -1,118 +0,0 @@ -package me.skymc.taboolib.cloud.expansion; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.ilummc.eagletdl.EagletTask; -import com.ilummc.eagletdl.ProgressEvent; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.cloud.TCloudLoader; -import me.skymc.taboolib.fileutils.FileUtils; -import me.skymc.taboolib.string.ArrayUtils; -import org.bukkit.Bukkit; -import org.bukkit.util.NumberConversions; - -import java.io.File; -import java.util.stream.IntStream; - -/** - * @Author sky - * @Since 2018-09-30 16:39 - */ -public class Expansion { - - private final String name; - private final String[] author; - private final String description; - private final String[] detail; - private final String version; - private final String lastUpdate; - private final String lastUpdateNote; - private final String link; - private final double dependVersion; - private final ExpansionType type; - - public Expansion(String name, String[] author, String description, String[] detail, String version, String lastUpdate, String lastUpdateNote, String link, double dependVersion, ExpansionType type) { - this.name = name; - this.author = author; - this.description = description; - this.detail = detail; - this.version = version; - this.lastUpdate = lastUpdate; - this.lastUpdateNote = lastUpdateNote; - this.link = link; - this.dependVersion = dependVersion; - this.type = type; - } - - public static Expansion unSerialize(ExpansionType type, String name, JsonObject object) { - String[] author = object.get("author").isJsonArray() ? toArray(object.get("author").getAsJsonArray()) : ArrayUtils.asArray(object.get("author").getAsString()); - String description = object.get("description").getAsString(); - String[] detail = object.get("detail").isJsonArray() ? toArray(object.get("detail").getAsJsonArray()) : ArrayUtils.asArray(object.get("detail").getAsString()); - String version = object.get("version").getAsString(); - String lastUpdate = object.get("last_update").getAsString(); - String lastUpdateNote = object.get("last_update_note").getAsString(); - String link = object.get("link").getAsString(); - double dependVersion = object.has("depend-version") ? object.get("depend-version").getAsDouble() : 0D; - return new Expansion(name, author, description, detail, version, lastUpdate, lastUpdateNote, link, dependVersion, type); - } - - public static String[] toArray(JsonArray json) { - return IntStream.range(0, json.size()).mapToObj(i -> json.get(i).getAsString()).toArray(String[]::new); - } - - public String getName() { - return name; - } - - public String[] getAuthor() { - return author; - } - - public String getDescription() { - return description; - } - - public String[] getDetail() { - return detail; - } - - public String getVersion() { - return version; - } - - public String getLastUpdate() { - return lastUpdate; - } - - public String getLastUpdateNote() { - return lastUpdateNote; - } - - public String getLink() { - return link; - } - - public double getDependVersion() { - return dependVersion; - } - - public ExpansionType getType() { - return type; - } - - public File getFile() { - return type == ExpansionType.INTERNAL ? new File(TCloudLoader.getExpansionInternalFolder(), "[TCLOUD] " + name + ".jar") : new File("plugins/[TCLOUD] " + name + ".jar"); - } - - public boolean canUse() { - return TabooLib.getPluginVersion() >= dependVersion; - } - - public boolean canUpdate() { - if (!TCloudLoader.isExpansionExists(this)) { - return false; - } - return type == ExpansionType.PLUGIN && NumberConversions.toDouble(Bukkit.getPluginManager().getPlugin(name).getDescription().getVersion()) < NumberConversions.toDouble(version); - } -} diff --git a/src/main/scala/me/skymc/taboolib/cloud/expansion/ExpansionType.java b/src/main/scala/me/skymc/taboolib/cloud/expansion/ExpansionType.java deleted file mode 100644 index a59b388..0000000 --- a/src/main/scala/me/skymc/taboolib/cloud/expansion/ExpansionType.java +++ /dev/null @@ -1,10 +0,0 @@ -package me.skymc.taboolib.cloud.expansion; - -/** - * @Author sky - * @Since 2018-09-30 16:39 - */ -public enum ExpansionType { - - INTERNAL, PLUGIN -} \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/commands/TabooLibMainCommand.java b/src/main/scala/me/skymc/taboolib/commands/TabooLibMainCommand.java deleted file mode 100644 index 9247f44..0000000 --- a/src/main/scala/me/skymc/taboolib/commands/TabooLibMainCommand.java +++ /dev/null @@ -1,883 +0,0 @@ -package me.skymc.taboolib.commands; - -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.commands.internal.BaseMainCommand; -import me.skymc.taboolib.commands.internal.BaseSubCommand; -import me.skymc.taboolib.commands.internal.TCommand; -import me.skymc.taboolib.commands.internal.type.CommandArgument; -import me.skymc.taboolib.commands.internal.type.CommandRegister; -import me.skymc.taboolib.commands.internal.type.CommandType; -import me.skymc.taboolib.commands.taboolib.*; -import me.skymc.taboolib.database.GlobalDataManager; -import me.skymc.taboolib.inventory.ItemUtils; -import me.skymc.taboolib.other.DateUtils; -import me.skymc.taboolib.other.NumberUtils; -import me.skymc.taboolib.timecycle.TimeCycle; -import me.skymc.taboolib.timecycle.TimeCycleEvent; -import me.skymc.taboolib.timecycle.TimeCycleInitializeEvent; -import me.skymc.taboolib.timecycle.TimeCycleManager; -import me.skymc.taboolib.update.UpdateTask; -import org.bukkit.Bukkit; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.scheduler.BukkitRunnable; - -import java.util.concurrent.TimeUnit; - -/** - * @Author sky - * @Since 2018-05-09 21:38 - */ -@TCommand( - name = "taboolib", - permission = "taboolib.admin", - aliases = "tlib" -) -public class TabooLibMainCommand extends BaseMainCommand { - - @Override - public String getCommandTitle() { - return TLocale.asString("COMMANDS.TABOOLIB.COMMAND-TITLE"); - } - - @CommandRegister(priority = 1) - BaseSubCommand save = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "save"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.SAVE.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[]{new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.SAVE.ARGUMENTS.0"))}; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new SaveCommand(sender, args); - } - - @Override - public boolean ignoredLabel() { - return false; - } - }; - - @CommandRegister(priority = 2) - BaseSubCommand item = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "item"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.ITEM.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[]{ - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.ITEM.ARGUMENTS.0")), - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.ITEM.ARGUMENTS.1"), false), - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.ITEM.ARGUMENTS.2"), false) - }; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new ItemCommand(sender, args); - } - - @Override - public boolean ignoredLabel() { - return false; - } - }; - - @CommandRegister(priority = 3) - BaseSubCommand itemInfo = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "itemInfo"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.INFO.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[0]; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new InfoCommand(sender, args); - } - }; - - @CommandRegister(priority = 3.1) - BaseSubCommand infoList = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "itemList"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.ITEMLIST.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[0]; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new ItemListCommand(sender, args); - } - - @Override - public boolean ignoredLabel() { - return false; - } - }; - - @CommandRegister(priority = 4) - BaseSubCommand itemReload = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "itemReload"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.ITEMRELOAD.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[0]; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - ItemUtils.reloadItemCache(); - TLocale.sendTo(sender, "COMMANDS.TABOOLIB.ITEMRELOAD.SUCCESS-RELOAD"); - } - }; - - @CommandRegister(priority = 6) - BaseSubCommand attributes = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "attributes"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.ATTRIBUTES.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[0]; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new AttributesCommand(sender, args); - } - }; - - @CommandRegister(priority = 7) - BaseSubCommand enchants = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "enchants"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.ENCHANTS.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[0]; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new EnchantCommand(sender, args); - } - }; - - @CommandRegister(priority = 8) - BaseSubCommand potions = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "potions"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.POTIONS.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[0]; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new PotionCommand(sender, args); - } - }; - - @CommandRegister(priority = 9) - BaseSubCommand flags = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "flags"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.FLAGS.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[0]; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new FlagCommand(sender, args); - } - }; - - @CommandRegister(priority = 10) - BaseSubCommand slots = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "slots"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.SLOTS.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[0]; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new AttributesCommand(sender, args); - } - }; - - @CommandRegister(priority = 11) - BaseSubCommand sounds = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "sounds"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.SOUNDS.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[0]; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new SoundsCommand(sender, args); - } - - @Override - public boolean ignoredLabel() { - return false; - } - }; - - @CommandRegister(priority = 13) - BaseSubCommand getVariable = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "getVariable"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.VARIABLE.DESCRIPTION.GET"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[]{ - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.VARIABLE.ARGUMENTS.GET.0")), - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.VARIABLE.ARGUMENTS.GET.1")) - }; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new VariableGetCommand(sender, args); - } - - @Override - public boolean ignoredLabel() { - return false; - } - }; - - @CommandRegister(priority = 13.1) - BaseSubCommand setVariable = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "setVariable"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.VARIABLE.DESCRIPTION.SET"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[]{ - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.VARIABLE.ARGUMENTS.SET.0")), - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.VARIABLE.ARGUMENTS.SET.1")), - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.VARIABLE.ARGUMENTS.SET.2")) - }; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new VariableSetCommand(sender, args); - } - - @Override - public boolean ignoredLabel() { - return false; - } - }; - - @CommandRegister(priority = 13.3) - BaseSubCommand cycleList = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "cycleList"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.TIMECYCLE.DESCRIPTION.LIST"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[0]; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - TLocale.sendTo(sender, "COMMANDS.TABOOLIB.TIMECYCLE.LIST.HEAD"); - TimeCycleManager.getTimeCycles().forEach(cycle -> TLocale.sendTo(sender, "COMMANDS.TABOOLIB.TIMECYCLE.LIST.BODY", cycle.getName())); - TLocale.sendTo(sender, "COMMANDS.TABOOLIB.TIMECYCLE.LIST.FOOT"); - } - }; - - @CommandRegister(priority = 14) - BaseSubCommand cycleInfo = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "cycleInfo"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.TIMECYCLE.DESCRIPTION.INFO"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[]{ - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.TIMECYCLE.ARGUMENTS.INFO.0")) - }; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - TimeCycle cycle = TimeCycleManager.getTimeCycle(args[0]); - if (cycle == null) { - TLocale.sendTo(sender, "COMMANDS.TABOOLIB.TIMECYCLE.INVALID-CYCLE", args[0]); - } else { - TLocale.sendTo(sender, "COMMANDS.TABOOLIB.TIMECYCLE.CYCLE-INFO", - asString(cycle.getCycle() / 1000L), - cycle.getPlugin().getName(), - DateUtils.CH_ALL.format(TimeCycleManager.getBeforeTimeline(cycle.getName())), - DateUtils.CH_ALL.format(TimeCycleManager.getAfterTimeline(cycle.getName()))); - } - } - - private String asString(long seconds) { - long day = TimeUnit.SECONDS.toDays(seconds); - long hours = TimeUnit.SECONDS.toHours(seconds) - day * 24; - long minute = TimeUnit.SECONDS.toMinutes(seconds) - TimeUnit.SECONDS.toHours(seconds) * 60L; - long second = TimeUnit.SECONDS.toSeconds(seconds) - TimeUnit.SECONDS.toMinutes(seconds) * 60L; - return "§f" + day + "§7 天, §f" + hours + "§7 小时, §f" + minute + "§7 分钟, §f" + second + "§7 秒"; - } - }; - - @CommandRegister(priority = 15) - BaseSubCommand cycleReset = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "cycleReset"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.TIMECYCLE.DESCRIPTION.RESET"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[]{ - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.TIMECYCLE.ARGUMENTS.RESET.0")) - }; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - TimeCycle cycle = TimeCycleManager.getTimeCycle(args[0]); - if (cycle == null) { - TLocale.sendTo(sender, "COMMANDS.TABOOLIB.TIMECYCLE.INVALID-CYCLE", args[0]); - return; - } - new BukkitRunnable() { - - @Override - public void run() { - long time = new TimeCycleInitializeEvent(cycle, System.currentTimeMillis()).call().getTimeline(); - // 初始化 - GlobalDataManager.setVariable("timecycle:" + cycle.getName(), String.valueOf(time)); - // 触发器 - Bukkit.getPluginManager().callEvent(new TimeCycleEvent(cycle)); - // 提示 - TLocale.sendTo(sender, "COMMANDS.TABOOLIB.TIMECYCLE.CYCLE-RESET", args[0]); - } - }.runTaskAsynchronously(Main.getInst()); - } - }; - - @CommandRegister(priority = 16) - BaseSubCommand cycleUpdate = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "cycleUpdate"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.TIMECYCLE.DESCRIPTION.UPDATE"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[]{ - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.TIMECYCLE.ARGUMENTS.UPDATE.0")) - }; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - TimeCycle cycle = TimeCycleManager.getTimeCycle(args[0]); - if (cycle == null) { - TLocale.sendTo(sender, "COMMANDS.TABOOLIB.TIMECYCLE.INVALID-CYCLE", args[0]); - return; - } - new BukkitRunnable() { - - @Override - public void run() { - // 重置 - GlobalDataManager.setVariable("timecycle:" + cycle.getName(), String.valueOf(System.currentTimeMillis())); - // 触发器 - Bukkit.getPluginManager().callEvent(new TimeCycleEvent(cycle)); - // 提示 - TLocale.sendTo(sender, "COMMANDS.TABOOLIB.TIMECYCLE.CYCLE-UPDATE", args[0]); - } - }.runTaskAsynchronously(Main.getInst()); - } - }; - - @CommandRegister(priority = 20) - BaseSubCommand tagDisplay = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "tagDisplay"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.PLAYERTAG.DESCRIPTION.DISPLAY"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[]{ - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.PLAYERTAG.ARGUMENTS.DISPLAY.0")), - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.PLAYERTAG.ARGUMENTS.DISPLAY.1")) - }; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new TagDisplayCommand(sender, args); - } - - @Override - public boolean ignoredLabel() { - return false; - } - }; - - @CommandRegister(priority = 21) - BaseSubCommand tagPrefix = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "tagPrefix"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.PLAYERTAG.DESCRIPTION.PREFIX"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[]{ - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.PLAYERTAG.ARGUMENTS.PREFIX.0")), - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.PLAYERTAG.ARGUMENTS.PREFIX.1")) - }; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new TagPrefixCommand(sender, args); - } - - @Override - public boolean ignoredLabel() { - return false; - } - }; - - @CommandRegister(priority = 22) - BaseSubCommand tagSuffix = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "tagSuffix"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.PLAYERTAG.DESCRIPTION.SUFFIX"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[]{ - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.PLAYERTAG.ARGUMENTS.SUFFIX.0")), - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.PLAYERTAG.ARGUMENTS.SUFFIX.1")) - }; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new TagSuffixCommand(sender, args); - } - - @Override - public boolean ignoredLabel() { - return false; - } - }; - - @CommandRegister(priority = 23) - BaseSubCommand tagDelete = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "tagDelete"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.PLAYERTAG.DESCRIPTION.DELETE"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[]{ - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.PLAYERTAG.ARGUMENTS.DELETE.0")) - }; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new TagDeleteCommand(sender, args); - } - - @Override - public boolean ignoredLabel() { - return false; - } - }; - - @CommandRegister(priority = 24.1) - BaseSubCommand lagServer = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "lagServer"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.LAGSERVER.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[] { - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.LAGSERVER.ARGUMENTS.0")) - }; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - if (NumberUtils.getInteger(args[0]) > 300000) { - TLocale.sendTo(sender, "COMMANDS.TABOOLIB.LAGSERVER.INVALID-TIME"); - } else { - TLocale.sendTo(sender, "COMMANDS.TABOOLIB.LAGSERVER.START"); - try { - Thread.sleep(NumberUtils.getInteger(args[0])); - } catch (Exception ignored) { - } - TLocale.sendTo(sender, "COMMANDS.TABOOLIB.LAGSERVER.STOP"); - } - } - }; - - @CommandRegister(priority = 27) - BaseSubCommand importData = new BaseSubCommand() { - - @Override - public boolean hideInHelp() { - return true; - } - - @Override - public String getLabel() { - return "importData"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.IMPORTDATA.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[0]; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - new ImportCommand(sender, args); - } - }; - - @CommandRegister(priority = 28) - BaseSubCommand updatePlugin = new BaseSubCommand() { - - @Override - public String getLabel() { - return "updatePlugin"; - } - - @Override - public String getDescription() { - return TLocale.asString("COMMANDS.TABOOLIB.UPDATEPLUGIN.DESCRIPTION"); - } - - @Override - public CommandArgument[] getArguments() { - return new CommandArgument[] { - new CommandArgument(TLocale.asString("COMMANDS.TABOOLIB.UPDATEPLUGIN.ARGUMENTS.0"), false) - }; - } - - @Override - public void onCommand(CommandSender sender, Command command, String label, String[] args) { - UpdateTask.updatePlugin(true, args.length > 0); - } - - @Override - public CommandType getType() { - return CommandType.CONSOLE; - } - }; -} diff --git a/src/main/scala/me/skymc/taboolib/commands/internal/TBaseCommand.java b/src/main/scala/me/skymc/taboolib/commands/internal/TBaseCommand.java deleted file mode 100644 index c107ed6..0000000 --- a/src/main/scala/me/skymc/taboolib/commands/internal/TBaseCommand.java +++ /dev/null @@ -1,20 +0,0 @@ -package me.skymc.taboolib.commands.internal; - -/** - * 歪日删错了 - * - * @author sky - */ -public class TBaseCommand { - - /** - * 向服务端注册 BaseMainCommand 类 - * - * @param command 命令全称(需在 plugin.yml 内注册) - * @param baseMainCommand 命令对象 - * @return {@link BaseMainCommand} - */ - public static BaseMainCommand registerCommand(String command, BaseMainCommand baseMainCommand) { - return BaseMainCommand.createCommandExecutor(command, baseMainCommand); - } -} \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/commands/internal/plugin/TLibLocale.java b/src/main/scala/me/skymc/taboolib/commands/internal/plugin/TLibLocale.java deleted file mode 100644 index a8b9623..0000000 --- a/src/main/scala/me/skymc/taboolib/commands/internal/plugin/TLibLocale.java +++ /dev/null @@ -1,33 +0,0 @@ -package me.skymc.taboolib.commands.internal.plugin; - -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.commands.internal.type.CommandArgument; - -import java.util.stream.IntStream; - -/** - * @Author sky - * @Since 2018-09-30 19:26 - */ -public class TLibLocale { - - public static String title(String name) { - return TLocale.asString("COMMANDS." + name + ".COMMAND-TITLE"); - } - - public static String description(String name, String label) { - return TLocale.asString("COMMANDS." + name + "." + label + ".DESCRIPTION"); - } - - public static CommandArgument[] arguments(String name, String label, int size) { - return IntStream.range(0, size).mapToObj(i -> new CommandArgument(TLocale.asString("COMMANDS." + name + "." + label + ".ARGUMENTS." + i))).toArray(CommandArgument[]::new); - } - - public static CommandArgument argument(String name, String label, int index) { - return new CommandArgument(TLocale.asString("COMMANDS." + name + "." + label + ".ARGUMENTS." + index)); - } - - public static CommandArgument argument(String name, String label, int index, boolean required) { - return new CommandArgument(TLocale.asString("COMMANDS." + name + "." + label + ".ARGUMENTS." + index), required); - } -} diff --git a/src/main/scala/me/skymc/taboolib/common/json/TJsonArray.java b/src/main/scala/me/skymc/taboolib/common/json/TJsonArray.java deleted file mode 100644 index f23a63e..0000000 --- a/src/main/scala/me/skymc/taboolib/common/json/TJsonArray.java +++ /dev/null @@ -1,350 +0,0 @@ -package me.skymc.taboolib.common.json; - -import com.google.gson.*; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Spliterator; -import java.util.function.Consumer; - -/** - * 让 JsonObject 有更加人性化的操作,目前版本只能获取数据。 - * - * @Author 坏黑 - * @Since 2018-10-27 23:46 - */ -public class TJsonArray implements Iterable { - - private JsonArray jsonArray; - - TJsonArray(JsonArray jsonArray) { - this.jsonArray = jsonArray; - } - - /** - * 从 Json 原代码中获取 - * - * @param json 源代码 - * @return {@link TJsonArray} - * @throws JsonParseException if the specified text is not valid JSON - * @throws IllegalStateException This is not a JSON Array. - */ - public static TJsonArray fromJson(String json) throws JsonParseException, IllegalStateException { - return new TJsonArray(new JsonParser().parse(json).getAsJsonArray()); - } - - /** - * 从 JsonArray 创建 - * - * @param jsonArray JsonArray 对象 - * @return {@link TJsonObject} - */ - public static TJsonArray fromJsonArray(JsonArray jsonArray) { - return new TJsonArray(jsonArray); - } - - /** - * 添加成员 - * - * @param obj 成员 - */ - public void add(TJsonObject obj) { - jsonArray.add(obj.asOriginJsonElement()); - } - - /** - * 添加成员 - * - * @param obj 成员 - */ - public void add(Boolean obj) { - jsonArray.add(new JsonPrimitive(obj)); - } - - /** - * 添加成员 - * - * @param obj 成员 - */ - public void add(Character obj) { - jsonArray.add(new JsonPrimitive(obj)); - } - - /** - * 添加成员 - * - * @param obj 成员 - */ - public void add(Number obj) { - jsonArray.add(new JsonPrimitive(obj)); - } - - /** - * 添加成员 - * - * @param obj 成员 - */ - public void add(String obj) { - jsonArray.add(new JsonPrimitive(obj)); - } - - /** - * 添加所有成员 - * - * @param array 成员集合 - */ - public void addAll(TJsonArray array) { - jsonArray.add(array.asOriginJsonArray()); - } - - /** - * 设置成员 - * - * @param index 位置 - * @param obj 成员 - */ - public void set(int index, TJsonObject obj) { - jsonArray.set(index, obj.asOriginJsonElement()); - } - - /** - * 设置成员 - * - * @param index 位置 - * @param obj 成员 - */ - public void set(int index, Boolean obj) { - jsonArray.set(index, new JsonPrimitive(obj)); - } - - /** - * 设置成员 - * - * @param index 位置 - * @param obj 成员 - */ - public void set(int index, Number obj) { - jsonArray.set(index, new JsonPrimitive(obj)); - } - - /** - * 设置成员 - * - * @param index 位置 - * @param obj 成员 - */ - public void set(int index, String obj) { - jsonArray.set(index, new JsonPrimitive(obj)); - } - - /** - * 移除成员 - * - * @param obj 成员 - */ - public void remove(JsonElement obj) { - jsonArray.remove(obj); - } - - /** - * 移除成员 - * - * @param obj 成员 - */ - public void remove(Boolean obj) { - jsonArray.remove(new JsonPrimitive(obj)); - } - - /** - * 移除成员 - * - * @param obj 成员 - */ - public void remove(Number obj) { - jsonArray.remove(new JsonPrimitive(obj)); - } - - /** - * 移除成员 - * - * @param obj 成员 - */ - public void remove(String obj) { - jsonArray.remove(new JsonPrimitive(obj)); - } - - /** - * 含有成员 - * - * @param obj 成员 - * @return boolean - */ - public boolean contains(JsonElement obj) { - return jsonArray.contains(obj); - } - - /** - * 含有成员 - * - * @param obj 成员 - * @return boolean - */ - public boolean contains(Boolean obj) { - return jsonArray.contains(new JsonPrimitive(obj)); - } - - /** - * 含有成员 - * - * @param obj 成员 - * @return boolean - */ - public boolean contains(Number obj) { - return jsonArray.contains(new JsonPrimitive(obj)); - } - - /** - * 含有成员 - * - * @param obj 成员 - * @return boolean - */ - public boolean contains(String obj) { - return jsonArray.contains(new JsonPrimitive(obj)); - } - - /** - * 获取成员,默认值:null - * - * @param index 序号 - * @return {@link TJsonObject} - */ - public TJsonObject getJsonObject(int index) { - return jsonArray.get(index).isJsonObject() ? TJsonObject.fromJsonObject(jsonArray.get(index).getAsJsonObject()) : null; - } - - /** - * 获取成员,默认值:null - * - * @param index 序号 - * @return {@link TJsonArray} - */ - public TJsonArray getJsonArray(int index) { - return jsonArray.get(index).isJsonArray() ? TJsonArray.fromJsonArray(jsonArray.get(index).getAsJsonArray()) : null; - } - - /** - * 获取成员,默认值:false - * - * @param index 序号 - * @return boolean - */ - public Boolean getBoolean(int index) { - return jsonArray.get(index).isJsonPrimitive() && jsonArray.get(index).getAsBoolean(); - } - - /** - * 获取成员 - * - * @param index 序号 - * @param def 默认值 - * @return boolean - */ - public Boolean getBoolean(int index, boolean def) { - return jsonArray.get(index).isJsonPrimitive() ? jsonArray.get(index).getAsBoolean() : def; - } - - /** - * 获取成员,默认值:0 - * - * @param index 序号 - * @return number - */ - public Number getNumber(int index) { - return jsonArray.get(index).isJsonPrimitive() ? jsonArray.get(index).getAsNumber() : 0; - } - - /** - * 获取成员 - * - * @param index 序号 - * @param def 默认值 - * @return number - */ - public Number getNumber(int index, Number def) { - return jsonArray.get(index).isJsonPrimitive() ? jsonArray.get(index).getAsNumber() : def; - } - - /** - * 获取成员,默认值:null - * - * @param index 序号 - * @return string - */ - public String getString(int index) { - return jsonArray.get(index).isJsonPrimitive() ? jsonArray.get(index).getAsString() : null; - } - - /** - * 获取成员 - * - * @param index 序号 - * @param def 默认值 - * @return string - */ - public String getString(int index, String def) { - return jsonArray.get(index).isJsonPrimitive() ? jsonArray.get(index).getAsString() : def; - } - - /** - * 成员数量 - * - * @return int - */ - public int size() { - return jsonArray.size(); - } - - /** - * 转换为 JsonArray 类型 - * - * @return {@link JsonArray} - */ - public JsonArray asOriginJsonArray() { - return jsonArray; - } - - @Override - public Iterator iterator() { - List jsonObjectList = new ArrayList<>(); - for (JsonElement jsonElement : jsonArray) { - jsonObjectList.add(TJsonObject.fromJsonObject(jsonElement)); - } - return jsonObjectList.iterator(); - } - - @Override - public void forEach(Consumer action) { - List jsonObjectList = new ArrayList<>(); - for (JsonElement jsonElement : jsonArray) { - jsonObjectList.add(TJsonObject.fromJsonObject(jsonElement)); - } - jsonObjectList.forEach(action); - } - - @Override - public Spliterator spliterator() { - List jsonObjectList = new ArrayList<>(); - for (JsonElement jsonElement : jsonArray) { - jsonObjectList.add(TJsonObject.fromJsonObject(jsonElement)); - } - return jsonObjectList.spliterator(); - } - - @Override - public String toString() { - return jsonArray.toString(); - } - -} diff --git a/src/main/scala/me/skymc/taboolib/common/json/TJsonObject.java b/src/main/scala/me/skymc/taboolib/common/json/TJsonObject.java deleted file mode 100644 index fb24546..0000000 --- a/src/main/scala/me/skymc/taboolib/common/json/TJsonObject.java +++ /dev/null @@ -1,253 +0,0 @@ -package me.skymc.taboolib.common.json; - -import com.google.gson.*; - -import java.util.*; -import java.util.stream.Collectors; - -/** - * 让 JsonObject 有更加人性化的操作,目前版本只能获取数据。 - * - * @Author 坏黑 - * @Since 2018-10-27 23:06 - */ -public class TJsonObject { - - private JsonElement jsonObject; - - TJsonObject(JsonElement jsonObject) { - this.jsonObject = jsonObject; - } - - /** - * 从 Json 原代码中获取 - * - * @param json 源代码 - * @return {@link TJsonObject} - * @throws JsonParseException if the specified text is not valid JSON - */ - public static TJsonObject fromJson(String json) throws JsonParseException { - return new TJsonObject(new JsonParser().parse(json)); - } - - /** - * 从 JsonElement 创建 - * - * @param jsonElement JsonElement 对象 - * @return {@link TJsonObject} - */ - public static TJsonObject fromJsonObject(JsonElement jsonElement) { - return new TJsonObject(jsonElement); - } - - /** - * 是否含有该节点 - * - * @param path 地址 - * @return boolean - */ - public boolean contains(String path) { - return get(path) != null; - } - - /** - * 获取文本,默认值:空 - * - * @param path 地址 - * @return String - */ - public String getString(String path) { - return getString(path, ""); - } - - /** - * 获取文本 - * - * @param path 地址 - * @param def 默认值 - * @return String - */ - public String getString(String path, String def) { - JsonElement jsonElement = get(path); - return !(jsonElement instanceof JsonPrimitive) || jsonElement == null ? def : jsonElement.getAsString(); - } - - /** - * 获取数字,默认值:0 - * - * @param path 地址 - * @return Number - */ - public Number getNumber(String path) { - return getNumber(path, 0); - } - - /** - * 获取数字 - * - * @param path 地址 - * @param def 默认值 - * @return Number - */ - public Number getNumber(String path, Number def) { - JsonElement jsonElement = get(path); - return !(jsonElement instanceof JsonPrimitive) || jsonElement == null ? def : jsonElement.getAsNumber(); - } - - /** - * 获取布尔值,默认值:false - * - * @param path 地址 - * @return boolean - */ - public boolean getBoolean(String path) { - return getBoolean(path, false); - } - - /** - * 获取布尔值 - * - * @param path 地址 - * @param def 默认值 - * @return boolean - */ - public boolean getBoolean(String path, boolean def) { - JsonElement jsonElement = get(path); - return !(jsonElement instanceof JsonPrimitive) || jsonElement == null ? def : jsonElement.getAsBoolean(); - } - - /** - * 获取 TJsonObject 对象,默认值:null - * - * @param path 地址 - * @return {@link TJsonObject} - */ - public TJsonObject getJsonObject(String path) { - JsonElement jsonElement = get(path); - return !(jsonElement instanceof JsonObject) || jsonElement == null ? null : TJsonObject.fromJsonObject(jsonElement); - } - - /** - * 获取 TJsonArray 对象,默认值:null - * - * @param path 地址 - * @return {@link TJsonArray} - */ - public TJsonArray getJsonArray(String path) { - JsonElement jsonElement = get(path); - return !(jsonElement instanceof JsonArray) || jsonElement == null ? null : TJsonArray.fromJsonArray((JsonArray) jsonElement); - } - - /** - * 获取所有成员 - * - * @return {@link Map.Entry} - */ - public Set> entrySet() { - return !(jsonObject instanceof JsonObject) ? new HashSet<>() : ((JsonObject) jsonObject).entrySet().stream().map(jsonElementEntry -> new HashMap.SimpleEntry<>(jsonElementEntry.getKey(), fromJsonObject(jsonElementEntry.getValue()))).collect(Collectors.toCollection(HashSet::new)); - } - - /** - * 获取所有键 - * - * @return {@link Set} - */ - public Set keySet() { - return !(jsonObject instanceof JsonObject) ? new HashSet<>() : ((JsonObject) jsonObject).entrySet().stream().map(Map.Entry::getKey).collect(Collectors.toCollection(HashSet::new)); - } - - /** - * 获取所有值 - * - * @return {@link Collection} - */ - public Collection values() { - return !(jsonObject instanceof JsonObject) ? new ArrayList<>() : ((JsonObject) jsonObject).entrySet().stream().map(jsonElementEntry -> new TJsonObject(jsonElementEntry.getValue())).collect(Collectors.toList()); - } - - /** - * 是否为 JsonObject 类型 - * - * @return boolean - */ - public boolean isJsonObject() { - return jsonObject instanceof JsonObject; - } - - /** - * 是否为 JsonArray 类型 - * - * @return boolean - */ - public boolean isJsonArray() { - return jsonObject instanceof JsonArray; - } - - /** - * 是否为 JsonPrimitive 类型 - * - * @return boolean - */ - public boolean isJsonPrimitive() { - return jsonObject instanceof JsonPrimitive; - } - - /** - * 转换为 JsonObject 类型 - * - * @return {@link JsonObject} - */ - public JsonObject asOriginJsonObject() { - return (JsonObject) jsonObject; - } - - /** - * 转换为 JsonArray 类型 - * - * @return {@link JsonArray} - */ - public JsonArray asOriginJsonArray() { - return (JsonArray) jsonObject; - } - - /** - * 转换为 JsonElement 类型 - * - * @return {@link JsonElement} - */ - public JsonElement asOriginJsonElement() { - return jsonObject; - } - - /** - * 转换为 JsonPrimitive 类型 - * - * @return {@link JsonPrimitive} - */ - public JsonPrimitive asOriginJsonPrimitive() { - return (JsonPrimitive) jsonObject; - } - - @Override - public String toString() { - return jsonObject.toString(); - } - - // ********************************* - // - // Private Methods - // - // ********************************* - - private JsonElement get(String path) { - JsonElement subElement = jsonObject; - for (String p : path.split("/")) { - if (subElement instanceof JsonObject && ((JsonObject) subElement).has(p)) { - subElement = ((JsonObject) subElement).get(p); - } else { - return null; - } - } - return subElement; - } -} diff --git a/src/main/scala/me/skymc/taboolib/common/loader/Instantiable.java b/src/main/scala/me/skymc/taboolib/common/loader/Instantiable.java deleted file mode 100644 index 9ffadc4..0000000 --- a/src/main/scala/me/skymc/taboolib/common/loader/Instantiable.java +++ /dev/null @@ -1,18 +0,0 @@ -package me.skymc.taboolib.common.loader; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @Author sky - * @Since 2018-08-27 10:04 - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface Instantiable { - - String value(); - -} diff --git a/src/main/scala/me/skymc/taboolib/common/loader/InstantiableLoader.java b/src/main/scala/me/skymc/taboolib/common/loader/InstantiableLoader.java deleted file mode 100644 index 7ab178e..0000000 --- a/src/main/scala/me/skymc/taboolib/common/loader/InstantiableLoader.java +++ /dev/null @@ -1,86 +0,0 @@ -package me.skymc.taboolib.common.loader; - -import com.ilummc.tlib.logger.TLogger; -import com.ilummc.tlib.util.Ref; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.TabooLibLoader; -import me.skymc.taboolib.listener.TListener; -import me.skymc.taboolib.methods.ReflectionUtils; -import org.bukkit.Bukkit; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.server.PluginDisableEvent; -import org.bukkit.event.server.PluginEnableEvent; -import org.bukkit.plugin.Plugin; - -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; - -/** - * @Author sky - * @Since 2018-08-27 10:04 - */ -@TListener -public class InstantiableLoader implements Listener { - - private static ConcurrentHashMap instance = new ConcurrentHashMap<>(); - - public InstantiableLoader() { - loadInstantiable(); - } - - @EventHandler - public void onEnable(PluginEnableEvent e) { - loadInstantiable(e.getPlugin()); - } - - @EventHandler - public void onDisable(PluginDisableEvent e) { - clear(e.getPlugin()); - } - - public static void clear(Plugin plugin) { - instance.entrySet().stream().filter(entry -> Ref.getCallerPlugin(entry.getValue().getClass()).equals(plugin)).forEach(entry -> instance.remove(entry.getKey())); - } - - public static void loadInstantiable() { - for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) { - try { - loadInstantiable(plugin); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - public static void loadInstantiable(Plugin plugin) { - TabooLibLoader.getPluginClasses(plugin).ifPresent(classes -> { - for (Class pluginClass : classes) { - if (pluginClass.isAnnotationPresent(Instantiable.class)) { - Instantiable instantiable = (Instantiable) pluginClass.getAnnotation(Instantiable.class); - try { - instance.put(instantiable.value(), ReflectionUtils.instantiateObject(pluginClass)); - TabooLib.debug("Instantiable " + pluginClass.getSimpleName() + " instanced. (" + plugin.getName() + ")"); - } catch (Exception e) { - TLogger.getGlobalLogger().warn("Instance Failed: " + pluginClass.getName()); - e.printStackTrace(); - } - } - } - }); - } - - // ********************************* - // - // Getter and Setter - // - // ********************************* - - public static ConcurrentHashMap getInstance() { - return instance; - } - - public static Optional getInstance(String name) { - return Optional.ofNullable(instance.get(name)); - } -} diff --git a/src/main/scala/me/skymc/taboolib/database/GlobalDataManager.java b/src/main/scala/me/skymc/taboolib/database/GlobalDataManager.java deleted file mode 100644 index 1fffb19..0000000 --- a/src/main/scala/me/skymc/taboolib/database/GlobalDataManager.java +++ /dev/null @@ -1,415 +0,0 @@ -package me.skymc.taboolib.database; - -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.Main.StorageType; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.playerdata.DataUtils; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.scheduler.BukkitRunnable; - -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.concurrent.ConcurrentHashMap; - -public class GlobalDataManager { - - public static FileConfiguration data = DataUtils.addPluginData("TabooLibrary-Variable.yml", null); - - /** - * 获取变量 - * - * @param name 名称 - * @param defaultVariable 默认值 - * @return - */ - public static String getVariable(String name, String defaultVariable) { - if (Main.getStorageType() == StorageType.SQL) { - Object obj = Main.getConnection().getValueLast(Main.getTablePrefix() + "_plugindata", "name", name, "variable"); - return obj != null ? "null".equals(obj.toString()) ? defaultVariable : obj.toString() : defaultVariable; - } else { - return data.contains(name) ? data.getString(name) : defaultVariable; - } - } - - /** - * 获取缓存变量(该方法仅限数据库储存方式) - * - * @param name 名称 - * @param defaultVariable 默认值 - * @return - */ - public static String getVariableAsynchronous(String name, String defaultVariable) { - if (Main.getStorageType() == StorageType.SQL) { - SQLVariable variable = SQLMethod.getSQLVariable(name); - return variable == null ? defaultVariable : "null".equals(variable.getVariable()) ? defaultVariable : variable.getVariable(); - } else { - return getVariable(name, defaultVariable); - } - } - - /** - * 设置变量 - * - * @param name 名称 - * @param variable 变量 - */ - public static void setVariable(String name, String variable) { - if (Main.getStorageType() == StorageType.SQL) { - Main.getConnection().intoValue(Main.getTablePrefix() + "_plugindata", name, variable == null ? "null" : variable, TabooLib.getServerUID()); - } else { - data.set(name, variable); - } - } - - /** - * 设置缓存变量(该方法仅限数据库储存方式) - * - * @param name - * @param variable - */ - public static void setVariableAsynchronous(String name, String variable) { - if (Main.getStorageType() == StorageType.SQL) { - SQLVariable _variable = SQLMethod.contains(name) ? SQLMethod.getSQLVariable(name).setVariable(variable == null ? "null" : variable) : SQLMethod.addSQLVariable(name, variable == null ? "null" : variable); - // 更新数据 - SQLMethod.uploadVariable(_variable, true); - } else { - setVariable(name, variable); - } - } - - /** - * 检查变量是否存在 - * - * @param name 名称 - */ - public static boolean contains(String name) { - if (Main.getStorageType() == StorageType.SQL) { - return getVariable(name, null) != null; - } else { - return data.contains(name); - } - } - - /** - * 检查变量是否被缓存(该方法仅限数据库储存方式) - * - * @param name 名称 - * @return - */ - public static boolean containsAsynchronous(String name) { - if (Main.getStorageType() == StorageType.SQL) { - return getVariableAsynchronous(name, null) != null; - } else { - return contains(name); - } - } - - /** - * 清理所有失效的变量 - * 该方法仅限数据库储存时有效 - */ - public static void clearInvalidVariables() { - if (Main.getStorageType() == StorageType.SQL) { - HashMap map = getVariables(); - Main.getConnection().truncateTable(Main.getTablePrefix() + "_plugindata"); - for (String name : map.keySet()) { - Main.getConnection().intoValue(Main.getTablePrefix() + "_plugindata", name, map.get(name), TabooLib.getServerUID()); - } - } - } - - /** - * 获取所有有效变量 - * - * @return - */ - public static HashMap getVariables() { - HashMap map = new HashMap<>(); - if (Main.getStorageType() == StorageType.SQL) { - LinkedList> list = Main.getConnection().getValues(Main.getTablePrefix() + "_plugindata", "id", -1, false, "name", "variable"); - for (HashMap _map : list) { - if (!"null".equals(_map.get("variable").toString())) { - map.put(_map.get("name").toString(), _map.get("variable").toString()); - } - } - } else { - for (String name : data.getConfigurationSection("").getKeys(false)) { - map.put(name, data.getString(name)); - } - } - return map; - } - - /** - * 获取缓存变量(该方法仅限数据库储存方式) - * - * @return - */ - public static HashMap getVariablesAsynchronous() { - if (Main.getStorageType() == StorageType.SQL) { - HashMap map = new HashMap<>(); - for (SQLVariable variable : SQLMethod.getSQLVariables()) { - if (!"null".equals(variable.getVariable())) { - map.put(variable.getName(), variable.getVariable()); - } - } - return map; - } else { - return getVariables(); - } - } - - /** - * 数据库变量 - * - * @author sky - */ - public static class SQLVariable { - - public String name = ""; - public String variable = ""; - public String upgradeUID = ""; - - public SQLVariable(String name, String variable, String upgradeUID) { - this.name = name; - this.variable = variable; - this.upgradeUID = upgradeUID; - } - - public String getName() { - return name; - } - - public String getVariable() { - return variable; - } - - public SQLVariable setVariable(String args) { - this.variable = args; - return this; - } - - public String getUpgradeUID() { - return upgradeUID; - } - } - - /** - * 数据库方法 - * - * @author sky - */ - public static class SQLMethod { - - private static ConcurrentHashMap variables = new ConcurrentHashMap<>(); - - /** - * 获取数据 - * - * @param name 名字 - */ - public static SQLVariable getSQLVariable(String name) { - return variables.get(name); - } - - /** - * 获取所有变量 - * - * @return - */ - public static Collection getSQLVariables() { - return variables.values(); - } - - /** - * 添加一个变量 - * - * @param name 名字 - * @param value 值 - * @return - */ - public static SQLVariable addSQLVariable(String name, String value) { - SQLVariable variable = new SQLVariable(name, value, TabooLib.getServerUID()); - variables.put(name, variable); - return variable; - } - - /** - * 移除一个变量 - * - * @param name 名字 - * @return - */ - public static SQLVariable removeSQLVariable(String name) { - if (variables.contains(name)) { - variables.get(name).setVariable("null"); - } - return variables.get(name); - } - - /** - * 是否包含变量 - * - * @param name 名字 - * @return - */ - public static boolean contains(String name) { - return variables.containsKey(name); - } - - /** - * 载入数据库中的所有变量缓存 - * - * @param sync 是否异步 - */ - public static void loadVariables(boolean sync) { - if (Main.getStorageType() == StorageType.LOCAL) { - return; - } - - BukkitRunnable runnable = new BukkitRunnable() { - - @Override - public void run() { - LinkedList> list = Main.getConnection().getValues(Main.getTablePrefix() + "_plugindata", "id", -1, false, "name", "variable", "upgrade"); - for (HashMap _map : list) { - if (!"null".equals(_map.get("variable").toString())) { - variables.put(_map.get("name").toString(), new SQLVariable(_map.get("name").toString(), _map.get("variable").toString(), _map.get("upgrade").toString())); - } - } - } - }; - - if (sync) { - runnable.runTaskAsynchronously(Main.getInst()); - } else { - runnable.run(); - } - } - - /** - * 检查当前变量是否被其他服务器更新 - * - * @param sync 是否异步 - */ - public static void checkVariable(boolean sync) { - if (Main.getStorageType() == StorageType.LOCAL) { - return; - } - - BukkitRunnable runnable = new BukkitRunnable() { - - @Override - public void run() { - LinkedList> list = Main.getConnection().getValues(Main.getTablePrefix() + "_plugindata", "id", -1, false, "name", "variable", "upgrade"); - // 循环变量 - for (HashMap value : list) { - Object name = value.get("name"); - try { - // 如果变量存在 - if (variables.containsKey(name)) { - // 如果变量不是由本服更新 - if (!value.get("upgrade").equals(variables.get(name).getUpgradeUID())) { - // 如果变量是空 - if ("null".equals(value.get("variable"))) { - // 删除变量 - variables.remove(name); - } else { - // 更新变量 - variables.get(name).setVariable(value.get("variable").toString()); - } - } - } - // 如果变量存在则下载到本地 - else if (!"null".equals(value.get("variable"))) { - variables.put(value.get("name").toString(), new SQLVariable(value.get("name").toString(), value.get("variable").toString(), value.get("upgrade").toString())); - } - } catch (Exception e) { - // 移除 - variables.remove(name); - // 提示 - TLocale.Logger.error("GLOBAL-DATAMANAGER.ERROR-CHECK-VARIABLE", String.valueOf(name), e.toString()); - } - } - } - }; - - if (sync) { - runnable.runTaskAsynchronously(Main.getInst()); - } else { - runnable.run(); - } - } - - /** - * 向数据库上传所有数据 - * - * @param sync 是否异步 - */ - public static void uploadVariables(boolean sync) { - if (Main.getStorageType() == StorageType.LOCAL) { - return; - } - - for (SQLVariable variable : variables.values()) { - uploadVariable(variable, sync); - } - } - - /** - * 向数据库上传当前数据 - * - * @param variable 数据 - * @param sync 是否异步 - */ - public static void uploadVariable(SQLVariable variable, boolean sync) { - if (Main.getStorageType() == StorageType.LOCAL) { - return; - } - - BukkitRunnable runnable = new BukkitRunnable() { - - @Override - public void run() { - Main.getConnection().intoValue(Main.getTablePrefix() + "_plugindata", variable.getName(), variable.getVariable() == null ? "null" : variable.getVariable(), TabooLib.getServerUID()); - } - }; - - if (sync) { - runnable.runTaskAsynchronously(Main.getInst()); - } else { - runnable.run(); - } - } - - /** - * 启动数据库储存方法 - */ - public static void startSQLMethod() { - long time = System.currentTimeMillis(); - // 载入数据 - loadVariables(false); - // 提示信息 - TLocale.Logger.info("GLOBAL-DATAMANAGER.SUCCESS-LOADED-VARIABLE", String.valueOf(variables.size()), String.valueOf(System.currentTimeMillis() - time)); - - // 检查更新 - new BukkitRunnable() { - - @Override - public void run() { - checkVariable(true); - } - }.runTaskTimerAsynchronously(Main.getInst(), Main.getInst().getConfig().getInt("PluginData.CHECK-DELAY") * 20, Main.getInst().getConfig().getInt("PluginData.CHECK-DELAY") * 20); - } - - /** - * 结束数据库储存方法 - */ - public static void cancelSQLMethod() { - // 上传数据 - uploadVariables(false); - } - } -} diff --git a/src/main/scala/me/skymc/taboolib/database/PlayerDataManager.java b/src/main/scala/me/skymc/taboolib/database/PlayerDataManager.java deleted file mode 100644 index 93871a7..0000000 --- a/src/main/scala/me/skymc/taboolib/database/PlayerDataManager.java +++ /dev/null @@ -1,262 +0,0 @@ -package me.skymc.taboolib.database; - -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.Main.StorageType; -import me.skymc.taboolib.events.PlayerLoadedEvent; -import me.skymc.taboolib.exception.PlayerOfflineException; -import me.skymc.taboolib.fileutils.ConfigUtils; -import me.skymc.taboolib.fileutils.FileUtils; -import me.skymc.taboolib.listener.TListener; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.scheduler.BukkitRunnable; - -import java.io.File; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -@TListener -public class PlayerDataManager implements Listener { - - private static final ConcurrentHashMap PLAYER_DATA = new ConcurrentHashMap<>(); - - /** - * 获取用户储存方式 - * - * @return - */ - public static UsernameType getUsernameType() { - return Main.getInst().getConfig().getBoolean("ENABLE-UUID") ? UsernameType.UUID : UsernameType.USERNAME; - } - - /** - * 获取玩家数据 - * - * @param player 玩家 - * @return - * @throws PlayerOfflineException - */ - public static FileConfiguration getPlayerData(Player player) { - if (getUsernameType() == UsernameType.UUID) { - return getPlayerData(player.getUniqueId().toString(), false); - } else { - return getPlayerData(player.getName(), false); - } - } - - /** - * 获取玩家数据 - * - * @param player - * @return - */ - public static FileConfiguration getPlayerData(OfflinePlayer player) { - if (!player.isOnline()) { - return null; - } - if (getUsernameType() == UsernameType.UUID) { - return getPlayerData(player.getUniqueId().toString(), false); - } else { - return getPlayerData(player.getName(), false); - } - } - - /** - * 读取玩家数据 - * - * @param username 玩家 - * @return - * @throws PlayerOfflineException - */ - public static FileConfiguration getPlayerData(String username, boolean offline) { - if (PLAYER_DATA.containsKey(username)) { - return PLAYER_DATA.get(username); - } else if (offline) { - if (Main.getStorageType() == StorageType.SQL) { - throw new PlayerOfflineException(TLocale.asString("PLAYER-DATAMANAGER.ERROR-STORAGE-SQL")); - } - return loadPlayerData(username); - } - return null; - } - - /** - * 载入玩家数据 - * - * @param username 玩家 - * @return - */ - public static FileConfiguration loadPlayerData(String username) { - // 本地储存 - if (Main.getStorageType() == StorageType.LOCAL) { - // 读取文件 - File file = FileUtils.file(Main.getPlayerDataFolder(), username + ".yml"); - // 载入配置 - PLAYER_DATA.put(username, YamlConfiguration.loadConfiguration(file)); - } else { - // 数据是否存在 - if (Main.getConnection().isExists(Main.getTablePrefix() + "_playerdata", "username", username)) { - // 获取数据 - String code = Main.getConnection().getValue(Main.getTablePrefix() + "_playerdata", "username", username, "configuration").toString(); - try { - // 载入配置 - PLAYER_DATA.put(username, ConfigUtils.decodeYAML(code)); - } catch (Exception e) { - // 创建空数据 - PLAYER_DATA.put(username, new YamlConfiguration()); - // 反馈信息 - TLocale.Logger.error("PLAYER-DATAMANAGER.ERROR-PLAYER-DATA", username, e.toString()); - } - } else { - // 创建空数据 - PLAYER_DATA.put(username, new YamlConfiguration()); - } - } - return PLAYER_DATA.get(username); - } - - /** - * 保存玩家数据 - * - * @param username 玩家 - * @param remove 是否移除缓存 - */ - public static void savePlayerData(String username, boolean remove) { - // 没有数据 - if (!PLAYER_DATA.containsKey(username)) { - return; - } - // 本地储存 - if (Main.getStorageType() == StorageType.LOCAL) { - // 读取文件 - File file = FileUtils.file(Main.getPlayerDataFolder(), username + ".yml"); - // 保存配置 - try { - PLAYER_DATA.get(username).save(file); - } catch (Exception e) { - // TODO: handle exception - } - } - // 如果是数据库储存且有数据 - else if (PLAYER_DATA.get(username).getConfigurationSection("").getKeys(false).size() > 0) { - // 数据是否存在 - if (Main.getConnection().isExists(Main.getTablePrefix() + "_playerdata", "username", username)) { - // 写入数据 - Main.getConnection().setValue(Main.getTablePrefix() + "_playerdata", "username", username, "configuration", ConfigUtils.encodeYAML(PLAYER_DATA.get(username))); - } else { - // 插入数据 - Main.getConnection().intoValue(Main.getTablePrefix() + "_playerdata", username, ConfigUtils.encodeYAML(PLAYER_DATA.get(username))); - } - } - // 获取这个属性对应的玩家 - Player player; - if (getUsernameType() == UsernameType.UUID) { - player = Bukkit.getPlayer(UUID.fromString(username)); - } else { - player = Bukkit.getPlayerExact(username); - } - // 如果移除数据 或 玩家不在线 - if (remove || player == null) { - PLAYER_DATA.remove(username); - } - } - - /** - * 保存所有玩家的缓存 - * - * @param sync 是否异步进行 - * @param remove 是否移除数据 - */ - public static void saveAllCaches(boolean sync, boolean remove) { - BukkitRunnable runnable = new BukkitRunnable() { - - @Override - public void run() { - long time = System.currentTimeMillis(); - // 保存 - for (String name : PLAYER_DATA.keySet()) { - savePlayerData(name, false); - } - // 提示 - if (!Main.getInst().getConfig().getBoolean("HIDE-NOTIFY")) { - TLocale.Logger.info("PLAYER-DATAMANAGER.SUCCESS-SAVE-DATA", String.valueOf(PLAYER_DATA.size()), String.valueOf(System.currentTimeMillis() - time)); - } - } - }; - // 如果异步 - if (sync) { - runnable.runTaskAsynchronously(Main.getInst()); - } - // 如果同步 - else { - runnable.run(); - } - } - - /** - * 保存所有玩家的数据 - * - * @param sync 是否异步进行 - * @param remove 是否移除数据 - */ - public static void saveAllPlayers(boolean sync, boolean remove) { - // 创建任务 - BukkitRunnable runnable = new BukkitRunnable() { - - @Override - public void run() { - for (Player player : Bukkit.getOnlinePlayers()) { - savePlayerData(Main.getInst().getConfig().getBoolean("ENABLE-UUID") ? player.getUniqueId().toString() : player.getName(), remove); - } - } - }; - // 如果异步 - if (sync) { - runnable.runTaskAsynchronously(Main.getInst()); - } - // 如果同步 - else { - runnable.run(); - } - } - - @EventHandler - public void join(PlayerJoinEvent e) { - new BukkitRunnable() { - - @Override - public void run() { - // 载入数据 - loadPlayerData(Main.getInst().getConfig().getBoolean("ENABLE-UUID") ? e.getPlayer().getUniqueId().toString() : e.getPlayer().getName()); - // 载入完成 - Bukkit.getPluginManager().callEvent(new PlayerLoadedEvent(e.getPlayer())); - } - }.runTaskAsynchronously(Main.getInst()); - } - - @EventHandler - public void quit(PlayerQuitEvent e) { - if (!Main.isDisable()) { - new BukkitRunnable() { - - @Override - public void run() { - // 保存数据 - savePlayerData(Main.getInst().getConfig().getBoolean("ENABLE-UUID") ? e.getPlayer().getUniqueId().toString() : e.getPlayer().getName(), true); - } - }.runTaskAsynchronously(Main.getInst()); - } - } - - public enum UsernameType { - UUID, USERNAME - } -} diff --git a/src/main/scala/me/skymc/taboolib/events/CustomBookOpenEvent.java b/src/main/scala/me/skymc/taboolib/events/CustomBookOpenEvent.java deleted file mode 100644 index ac8ad24..0000000 --- a/src/main/scala/me/skymc/taboolib/events/CustomBookOpenEvent.java +++ /dev/null @@ -1,81 +0,0 @@ -package me.skymc.taboolib.events; - -import org.bukkit.entity.Player; -import org.bukkit.event.Cancellable; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; -import org.bukkit.inventory.ItemStack; - -/** - * The event called when a book is opened trough this Util - */ -public class CustomBookOpenEvent extends Event implements Cancellable { - - private static final HandlerList handlers = new HandlerList(); - - private boolean cancelled; - - /** - * The player - */ - private final Player player; - - /** - * The hand used to open the book (the previous item will be restored after the opening) - */ - private Hand hand; - - /** - * The actual book to be opened - */ - private ItemStack book; - - public Player getPlayer() { - return player; - } - - public Hand getHand() { - return hand; - } - - public void setHand(Hand hand) { - this.hand = hand; - } - - public ItemStack getBook() { - return book; - } - - public void setBook(ItemStack book) { - this.book = book; - } - - public CustomBookOpenEvent(Player player, ItemStack book, boolean offHand) { - this.player = player; - this.book = book; - this.hand = offHand ? Hand.OFF_HAND : Hand.MAIN_HAND; - } - - @Override - public boolean isCancelled() { - return cancelled; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - - @Override - public void setCancelled(boolean cancelled) { - this.cancelled = cancelled; - } - - public static HandlerList getHandlerList() { - return handlers; - } - - public enum Hand { - MAIN_HAND, OFF_HAND - } -} diff --git a/src/main/scala/me/skymc/taboolib/events/TPluginEnableEvent.java b/src/main/scala/me/skymc/taboolib/events/TPluginEnableEvent.java deleted file mode 100644 index 3efff37..0000000 --- a/src/main/scala/me/skymc/taboolib/events/TPluginEnableEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -package me.skymc.taboolib.events; - -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; -import org.bukkit.plugin.Plugin; - -public class TPluginEnableEvent extends Event { - - private static final HandlerList handlers = new HandlerList(); - private Plugin plugin; - - public TPluginEnableEvent(Plugin plugin) { - this.plugin = plugin; - } - - public static HandlerList getHandlerList() { - return handlers; - } - - public Plugin getPlugin() { - return this.plugin; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } -} diff --git a/src/main/scala/me/skymc/taboolib/events/TPluginLoadEvent.java b/src/main/scala/me/skymc/taboolib/events/TPluginLoadEvent.java deleted file mode 100644 index 8e2a07e..0000000 --- a/src/main/scala/me/skymc/taboolib/events/TPluginLoadEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -package me.skymc.taboolib.events; - -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; -import org.bukkit.plugin.Plugin; - -public class TPluginLoadEvent extends Event { - - private static final HandlerList handlers = new HandlerList(); - private Plugin plugin; - - public TPluginLoadEvent(Plugin plugin) { - this.plugin = plugin; - } - - public static HandlerList getHandlerList() { - return handlers; - } - - public Plugin getPlugin() { - return this.plugin; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } -} diff --git a/src/main/scala/me/skymc/taboolib/events/itag/AsyncPlayerReceiveNameTagEvent.java b/src/main/scala/me/skymc/taboolib/events/itag/AsyncPlayerReceiveNameTagEvent.java deleted file mode 100644 index 6d765de..0000000 --- a/src/main/scala/me/skymc/taboolib/events/itag/AsyncPlayerReceiveNameTagEvent.java +++ /dev/null @@ -1,85 +0,0 @@ -package me.skymc.taboolib.events.itag; - -import com.google.common.base.Preconditions; -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -import java.util.UUID; - -/** - * @author md_5 - */ -public class AsyncPlayerReceiveNameTagEvent extends Event { - - private static final HandlerList handlers = new HandlerList(); - - private final Player player; - private final Player namedPlayer; - private String tag; - private UUID UUID; - private boolean tagModified; - private boolean UUIDModified; - - public Player getPlayer() { - return player; - } - - public Player getNamedPlayer() { - return namedPlayer; - } - - public String getTag() { - return tag; - } - - public java.util.UUID getUUID() { - return UUID; - } - - public boolean isTagModified() { - return tagModified; - } - - public boolean isUUIDModified() { - return UUIDModified; - } - - public AsyncPlayerReceiveNameTagEvent(Player who, Player namedPlayer, String initialName, UUID uuid) { - Preconditions.checkNotNull(who, "who"); - Preconditions.checkNotNull(namedPlayer, "namedPlayer"); - Preconditions.checkNotNull(initialName, "initialName"); - Preconditions.checkNotNull(uuid, "uuid"); - - this.player = who; - this.namedPlayer = namedPlayer; - this.tag = initialName; - this.tagModified = namedPlayer.getName().equals(initialName); - this.UUID = uuid; - } - - public boolean setTag(String tag) { - Preconditions.checkNotNull(tag, "tag"); - - this.tag = tag; - this.tagModified = true; - - return tag.length() < 16; - } - - public void setUUID(UUID uuid) { - Preconditions.checkNotNull(uuid, "uuid"); - - this.UUID = uuid; - this.UUIDModified = true; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - - public static HandlerList getHandlerList() { - return handlers; - } -} diff --git a/src/main/scala/me/skymc/taboolib/events/itag/PlayerReceiveNameTagEvent.java b/src/main/scala/me/skymc/taboolib/events/itag/PlayerReceiveNameTagEvent.java deleted file mode 100644 index 7ea835e..0000000 --- a/src/main/scala/me/skymc/taboolib/events/itag/PlayerReceiveNameTagEvent.java +++ /dev/null @@ -1,57 +0,0 @@ -package me.skymc.taboolib.events.itag; - -import com.google.common.base.Preconditions; -import org.bukkit.entity.Player; -import org.bukkit.event.HandlerList; -import org.bukkit.event.player.PlayerEvent; - -/** - * @author md_5 - */ -public class PlayerReceiveNameTagEvent extends PlayerEvent { - - private static final HandlerList handlers = new HandlerList(); - private final Player namedPlayer; - private String tag; - private boolean modified; - - public Player getNamedPlayer() { - return namedPlayer; - } - - public String getTag() { - return tag; - } - - public boolean isModified() { - return modified; - } - - public PlayerReceiveNameTagEvent(Player who, Player namedPlayer, String initialName) { - super(who); - Preconditions.checkNotNull(who, "who"); - Preconditions.checkNotNull(namedPlayer, "namedPlayer"); - Preconditions.checkNotNull(initialName, "initialName"); - - this.namedPlayer = namedPlayer; - this.tag = initialName; - } - - public boolean setTag(String tag) { - Preconditions.checkNotNull(tag, "tag"); - - this.tag = tag; - this.modified = true; - - return tag.length() < 16; - } - - @Override - public HandlerList getHandlers() { - return handlers; - } - - public static HandlerList getHandlerList() { - return handlers; - } -} diff --git a/src/main/scala/me/skymc/taboolib/exception/PlayerOfflineException.java b/src/main/scala/me/skymc/taboolib/exception/PlayerOfflineException.java deleted file mode 100644 index 1dd431e..0000000 --- a/src/main/scala/me/skymc/taboolib/exception/PlayerOfflineException.java +++ /dev/null @@ -1,10 +0,0 @@ -package me.skymc.taboolib.exception; - -public class PlayerOfflineException extends Error { - - private static final long serialVersionUID = 4129402767538548807L; - - public PlayerOfflineException(String message) { - super(message); - } -} diff --git a/src/main/scala/me/skymc/taboolib/exception/PluginNotFoundException.java b/src/main/scala/me/skymc/taboolib/exception/PluginNotFoundException.java deleted file mode 100644 index 0fec22b..0000000 --- a/src/main/scala/me/skymc/taboolib/exception/PluginNotFoundException.java +++ /dev/null @@ -1,10 +0,0 @@ -package me.skymc.taboolib.exception; - -public class PluginNotFoundException extends Error { - - private static final long serialVersionUID = -475540326950009346L; - - public PluginNotFoundException(String message) { - super(message); - } -} diff --git a/src/main/scala/me/skymc/taboolib/fileutils/ConfigUtils.java b/src/main/scala/me/skymc/taboolib/fileutils/ConfigUtils.java deleted file mode 100644 index d31635b..0000000 --- a/src/main/scala/me/skymc/taboolib/fileutils/ConfigUtils.java +++ /dev/null @@ -1,212 +0,0 @@ -package me.skymc.taboolib.fileutils; - -import com.google.common.collect.Maps; -import com.google.common.io.Files; -import com.ilummc.tlib.bean.Property; -import com.ilummc.tlib.resources.TLocale; -import com.ilummc.tlib.util.Ref; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.MemoryConfiguration; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.Plugin; -import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; - -import java.io.File; -import java.io.StringReader; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.nio.charset.Charset; -import java.util.Map; - -public class ConfigUtils { - - private static final Yaml YAML; - - static { - DumperOptions options = new DumperOptions(); - options.setAllowUnicode(false); - options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - YAML = new Yaml(options); - } - - @SuppressWarnings("unchecked") - public static Map yamlToMap(String yamlText) { - return (Map) YAML.load(yamlText); - } - - public static MemoryConfiguration objToConf(Object object) { - return mapToConf(objToMap(object)); - } - - public static MemoryConfiguration objToConf(Object object, int excludedModifiers) { - return mapToConf(objToMap(object, excludedModifiers)); - } - - public static Object confToObj(MemoryConfiguration configuration, Class clazz) { - try { - return mapToObj(configuration.getValues(false), clazz.newInstance()); - } catch (InstantiationException | IllegalAccessException e) { - return null; - } - } - - public static Object confToObj(MemoryConfiguration configuration, T obj) { - return mapToObj(configuration.getValues(false), obj); - } - - public static String mapToYaml(Map map) { - String dump = YAML.dump(map); - if ("{}\n".equals(dump)) { - dump = ""; - } - return dump; - } - - public static MemoryConfiguration mapToConf(Map map) { - YamlConfiguration configuration = new YamlConfiguration(); - convertMapsToSections(map, configuration); - return configuration; - } - - public static Map confToMap(MemoryConfiguration configuration) { - return configuration.getValues(false); - } - - /** - * 将会在该类无默认构造方法时返回 null - */ - public static T mapToObj(Map map, Class clazz) { - try { - return mapToObj(map, clazz.newInstance()); - } catch (InstantiationException | IllegalAccessException e) { - return null; - } - } - - @SuppressWarnings("unchecked") - public static T mapToObj(Map map, T obj) { - Class clazz = obj.getClass(); - map.forEach((string, value) -> Ref.getFieldBySerializedName(clazz, string).ifPresent(field -> { - if (!field.isAccessible()) { - field.setAccessible(true); - } - try { - if (Property.class.isAssignableFrom(field.getType())) { - Property property = (Property) field.get(obj); - if (property != null) { - property.set(value); - } else { - field.set(obj, Property.of(value)); - } - } else { - field.set(obj, value); - } - } catch (IllegalAccessException ignored) { - } - })); - return obj; - } - - public static Map objToMap(Object object) { - return objToMap(object, Modifier.TRANSIENT & Modifier.STATIC & Ref.ACC_SYNTHETIC); - } - - @SuppressWarnings("unchecked") - public static Map objToMap(Object object, int excludedModifiers) { - Map map = Maps.newHashMap(); - if (object instanceof Map) { - ((Map) object).forEach((k, v) -> map.put(k, objToMap(v, excludedModifiers))); - return map; - } - if (object instanceof ConfigurationSection) { - map.putAll(objToMap(((ConfigurationSection) object).getValues(false), excludedModifiers)); - return map; - } - for (Field field : Ref.getDeclaredFields(object.getClass(), excludedModifiers, false)) { - try { - if (!field.isAccessible()) { - field.setAccessible(true); - } - Object obj = field.get(object); - if (obj instanceof Property) { - obj = ((Property) obj).get(); - } - if (obj instanceof ConfigurationSection) { - obj = objToMap(((ConfigurationSection) obj).getValues(false), excludedModifiers); - } - map.put(Ref.getSerializedName(field), obj); - } catch (IllegalAccessException ignored) { - } - } - return map; - } - - private static void convertMapsToSections(Map input, ConfigurationSection section) { - for (Object o : input.entrySet()) { - Map.Entry entry = (Map.Entry) o; - String key = entry.getKey().toString(); - Object value = entry.getValue(); - if (value instanceof Map) { - convertMapsToSections((Map) value, section.createSection(key)); - } else { - section.set(key, value); - } - } - } - - public static FileConfiguration decodeYAML(String args) { - return YamlConfiguration.loadConfiguration(new StringReader(Base64Coder.decodeString(args))); - } - - public static String encodeYAML(FileConfiguration file) { - return Base64Coder.encodeLines(file.saveToString().getBytes()).replaceAll("\\s+", ""); - } - - /** - * 以 UTF-8 的格式释放配置文件并载入 - *

- * 录入时间:2018年2月10日21:28:30 - * 录入版本:3.49 - * - * @param plugin - * @return - */ - public static FileConfiguration saveDefaultConfig(Plugin plugin, String name) { - File file = new File(plugin.getDataFolder(), name); - if (!file.exists()) { - plugin.saveResource(name, true); - } - return load(plugin, file); - } - - /** - * 以 UTF-8 的格式载入配置文件 - * - * @return - */ - public static FileConfiguration load(Plugin plugin, File file) { - return loadYaml(plugin, file); - } - - public static YamlConfiguration loadYaml(Plugin plugin, File file) { - YamlConfiguration configuration = new YamlConfiguration(); - try { - String yaml = Files.toString(file, Charset.forName("utf-8")); - configuration.loadFromString(yaml); - return configuration; - } catch (Exception e) { - TLocale.Logger.error("FILE-UTILS.FAIL-LOAD-CONFIGURATION", plugin.getName(), file.getPath()); - e.printStackTrace(); - } - return configuration; - } - - - @Deprecated - public static FileConfiguration load(Plugin plugin, String file) { - return load(plugin, FileUtils.file(file)); - } -} diff --git a/src/main/scala/me/skymc/taboolib/fileutils/FileUtils.java b/src/main/scala/me/skymc/taboolib/fileutils/FileUtils.java deleted file mode 100644 index c16ab30..0000000 --- a/src/main/scala/me/skymc/taboolib/fileutils/FileUtils.java +++ /dev/null @@ -1,481 +0,0 @@ -package me.skymc.taboolib.fileutils; - -import ch.njol.util.Closeable; -import com.ilummc.eagletdl.EagletTask; -import com.ilummc.eagletdl.ProgressEvent; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.common.io.IOUtils; -import org.bukkit.plugin.Plugin; - -import java.io.*; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; -import java.nio.channels.FileChannel; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.jar.JarFile; - -/** - * @author sky - */ -public class FileUtils { - - /** - * 获取本地 IP 地址 - * - * @return {@link String} - */ - public static String ip() { - URL url; - URLConnection con; - try { - url = new URL("http://1212.ip138.com/ic.asp"); - con = url.openConnection(); - } catch (Exception ignored) { - return "[IP ERROR]"; - } - InputStream ins = null; - InputStreamReader inputStreamReader = null; - BufferedReader bufferedReader = null; - try { - ins = con.getInputStream(); - inputStreamReader = new InputStreamReader(ins, "GB2312"); - bufferedReader = new BufferedReader(inputStreamReader); - StringBuilder webContent = new StringBuilder(); - bufferedReader.lines().forEach(webContent::append); - int start = webContent.indexOf("[") + 1; - int end = webContent.indexOf("]"); - return webContent.substring(start, end); - } catch (Exception ignored) { - return "[IP ERROR]"; - } finally { - IOUtils.close(con); - IOUtils.closeQuietly(bufferedReader); - IOUtils.closeQuietly(inputStreamReader); - IOUtils.closeQuietly(ins); - } - } - - /** - * 获取插件所有类 - * - * @return {@link List} - */ - public static List getClasses(Class obj) { - List classes = new ArrayList<>(); - URL url = getCaller(obj).getProtectionDomain().getCodeSource().getLocation(); - try { - File src; - try { - src = new File(url.toURI()); - } catch (URISyntaxException e) { - src = new File(url.getPath()); - } - new JarFile(src).stream().filter(entry -> entry.getName().endsWith(".class")).forEach(entry -> { - String className = entry.getName().replace('/', '.').substring(0, entry.getName().length() - 6); - try { - classes.add(Class.forName(className, false, obj.getClassLoader())); - } catch (Throwable ignored) { - } - }); - } catch (Throwable ignored) { - } - return classes; - } - - /** - * 获取插件所有类 - * - * @param plugin 插件 - */ - public static List getClasses(Plugin plugin) { - return getClasses(plugin, new String[0]); - } - - /** - * 获取插件所有类 - * - * @param plugin 插件 - * @param ignore 忽略包名 - */ - public static List getClasses(Plugin plugin, String[] ignore) { - List classes = new CopyOnWriteArrayList<>(); - URL url = plugin.getClass().getProtectionDomain().getCodeSource().getLocation(); - try { - File src; - try { - src = new File(url.toURI()); - } catch (URISyntaxException e) { - src = new File(url.getPath()); - } - new JarFile(src).stream().filter(entry -> entry.getName().endsWith(".class")).forEach(entry -> { - String className = entry.getName().replace('/', '.').substring(0, entry.getName().length() - 6); - try { - if (Arrays.stream(ignore).noneMatch(className::startsWith)) { - classes.add(Class.forName(className, false, plugin.getClass().getClassLoader())); - } - } catch (Throwable ignored) { - } - }); - } catch (Throwable ignored) { - } - return classes; - } - - /** - * 获取资源文件 - * - * @param filename 文件名 - * @return {@link InputStream} - */ - public static InputStream getResource(String filename) { - return getResource(Main.getInst(), filename); - } - - /** - * 获取插件资源文件 - * - * @param plugin 插件 - * @param filename 文件名 - * @return {@link InputStream} - */ - public static InputStream getResource(Plugin plugin, String filename) { - return plugin.getClass().getClassLoader().getResourceAsStream(filename); - } - - /** - * 写入文件 - * - * @param inputStream 输入流 - * @param file 文件 - */ - public static void inputStreamToFile(InputStream inputStream, File file) { - try (FileOutputStream fos = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(fos)) { - byte[] buf = new byte[1024]; - int len; - while ((len = inputStream.read(buf)) > 0) { - bos.write(buf, 0, len); - } - bos.flush(); - } catch (Exception ignored) { - } - } - - /** - * 释放资源文件 - * - * @param plugin 所属插件 - * @param path 地址 - * @param replace 是否替换 - */ - public static void releaseResource(Plugin plugin, String path, boolean replace) { - File file = new File(plugin.getDataFolder(), path); - if (!file.exists() || replace) { - inputStreamToFile(getResource(plugin, path), file); - } - } - - /** - * 检测文件并创建 - * - * @param file 文件 - */ - public static File createNewFile(File file) { - if (file != null && !file.exists()) { - try { - file.createNewFile(); - } catch (Exception ignored) { - } - } - return file; - } - - /** - * 检测文件并创建(目录) - * - * @param file 文件 - */ - public static void createNewFileAndPath(File file) { - if (!file.exists()) { - String filePath = file.getPath(); - int index = filePath.lastIndexOf(File.separator); - String folderPath; - File folder; - if ((index >= 0) && (!(folder = new File(filePath.substring(0, index))).exists())) { - folder.mkdirs(); - } - try { - file.createNewFile(); - } catch (IOException ignored) { - } - } - } - - /** - * 创建并获取目录 - * - * @param path 目录文件 - * @return - */ - public static File folder(File path) { - if (!path.exists()) { - path.mkdirs(); - } - return path; - } - - /** - * 创建并获取目录 - * - * @param path 目录地址 - * @return - */ - public static File folder(String path) { - return folder(new File(path)); - } - - /** - * 创建并获取文件 - * - * @param path 目录 - * @param filePath 地址 - * @return - */ - public static File file(File path, String filePath) { - return createNewFile(new File(path, filePath)); - } - - /** - * 创建并获取文件 - * - * @param filePath 地址 - * @return {@link File} - */ - public static File file(String filePath) { - return createNewFile(new File(filePath)); - } - - /** - * 删除文件夹 - * - * @param file 文件夹 - */ - public static void deleteAllFile(File file) { - if (!file.exists()) { - return; - } - if (file.isFile()) { - file.delete(); - return; - } - for (File file1 : Objects.requireNonNull(file.listFiles())) { - deleteAllFile(file1); - } - file.delete(); - } - - /** - * 复制文件夹 - * - * @param originFileName 文件1 - * @param targetFileName 文件2 - */ - public static void copyAllFile(String originFileName, String targetFileName) { - File originFile = new File(originFileName); - File targetFile = new File(targetFileName); - if (!targetFile.exists()) { - if (!originFile.isDirectory()) { - createNewFile(targetFile); - } else { - targetFile.mkdirs(); - } - } - if (originFile.isDirectory()) { - for (File file : Objects.requireNonNull(originFile.listFiles())) { - if (file.isDirectory()) { - copyAllFile(file.getAbsolutePath(), targetFileName + "/" + file.getName()); - } else { - fileChannelCopy(file, new File(targetFileName + "/" + file.getName())); - } - } - } else { - fileChannelCopy(originFile, targetFile); - } - } - - /** - * 复制文件(通道) - * - * @param file1 文件1 - * @param file2 文件2 - */ - public static void fileChannelCopy(File file1, File file2) { - try (FileInputStream fileIn = new FileInputStream(file1); - FileOutputStream fileOut = new FileOutputStream(file2); - FileChannel channelIn = fileIn.getChannel(); - FileChannel channelOut = fileOut.getChannel()) { - channelIn.transferTo(0, channelIn.size(), channelOut); - } catch (IOException ignored) { - } - } - - /** - * 通过 URL 读取文本 - * - * @param url 地址 - * @param def 默认值 - * @return 文本 - */ - public static String getStringFromURL(String url, String def) { - String s = getStringFromURL(url, 1024); - return s == null ? def : s; - } - - /** - * 通过 URL 读取文本 - * - * @param url 地址 - * @param size 大小 - * @return 文本 - */ - public static String getStringFromURL(String url, int size) { - URLConnection conn = null; - BufferedInputStream bin = null; - try { - conn = new URL(url).openConnection(); - bin = new BufferedInputStream(conn.getInputStream()); - return getStringFromInputStream(bin, size, conn.getContentEncoding() == null ? "UTF-8" : conn.getContentEncoding()); - } catch (IOException e) { - e.printStackTrace(); - } finally { - IOUtils.close(conn); - IOUtils.closeQuietly(bin); - } - return null; - } - - /** - * 通过文件读取文本 - * - * @param file 文件 - * @param size 大小 - * @param encode 编码 - * @return 文本 - */ - public static String getStringFromFile(File file, int size, String encode) { - try (FileInputStream fin = new FileInputStream(file); BufferedInputStream bin = new BufferedInputStream(fin)) { - return getStringFromInputStream(fin, size, encode); - } catch (IOException e) { - e.printStackTrace(); - } - return null; - } - - /** - * 通过输入流读取文本 - * - * @param in 输入流 - * @param size 大小 - * @param encode 编码 - * @return 文本 - */ - public static String getStringFromInputStream(InputStream in, int size, String encode) { - try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { - byte[] b = new byte[size]; - int i; - while ((i = in.read(b)) > 0) { - bos.write(b, 0, i); - } - return new String(bos.toByteArray(), encode); - } catch (IOException e) { - e.printStackTrace(); - } - return null; - } - - /** - * 下载文件 - * - * @param url 下载地址 - * @param file 下载位置 - */ - public static void download(String url, File file) { - download(url, file, false); - } - - /** - * 下载文件 - * - * @param url 下载地址 - * @param file 下载位置 - * @param async 是否异步 - */ - public static void download(String url, File file, boolean async) { - EagletTask eagletTask = new EagletTask() - .url(url) - .file(file) - .setThreads(8) - .setOnError(event -> { - }) - .setOnConnected(event -> TLocale.Logger.info("UTIL.DOWNLOAD-CONNECTED", file.getName(), ProgressEvent.format(event.getContentLength()))) - .setOnProgress(event -> TLocale.Logger.info("UTIL.DOWNLOAD-PROGRESS", event.getSpeedFormatted(), event.getPercentageFormatted())) - .setOnComplete(event -> { - if (event.isSuccess()) { - TLocale.Logger.info("UTIL.DOWNLOAD-SUCCESS", file.getName()); - } else { - TLocale.Logger.error("UTIL.DOWNLOAD-FAILED", file.getName()); - } - }).start(); - if (!async) { - eagletTask.waitUntil(); - } - } - - @Deprecated - public static void download(String url, String filename, File saveDir) { - download(url, new File(saveDir, filename)); - } - - @Deprecated - public static void close(Closeable closeable) { - try { - if (closeable != null) { - closeable.close(); - } - } catch (Exception ignored) { - } - } - - @Deprecated - public static byte[] read(InputStream in) { - byte[] buffer = new byte[1024]; - int len; - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - try { - while ((len = in.read(buffer)) != -1) { - bos.write(buffer, 0, len); - } - } catch (Exception ignored) { - } - return bos.toByteArray(); - } - - // ********************************* - // - // Private Methods - // - // ********************************* - - private static Class getCaller(Class obj) { - try { - return Class.forName(Thread.currentThread().getStackTrace()[3].getClassName(), false, obj.getClassLoader()); - } catch (ClassNotFoundException ignored) { - } - return null; - } -} diff --git a/src/main/scala/me/skymc/taboolib/inventory/ItemUtils.java b/src/main/scala/me/skymc/taboolib/inventory/ItemUtils.java deleted file mode 100644 index 4e2e131..0000000 --- a/src/main/scala/me/skymc/taboolib/inventory/ItemUtils.java +++ /dev/null @@ -1,493 +0,0 @@ -package me.skymc.taboolib.inventory; - -import com.ilummc.tlib.resources.TLocale; -import me.clip.placeholderapi.PlaceholderAPI; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.common.function.TFunction; -import me.skymc.taboolib.common.nms.NMSHandler; -import me.skymc.taboolib.common.nms.nbt.NBTBase; -import me.skymc.taboolib.common.nms.nbt.NBTCompound; -import me.skymc.taboolib.common.nms.nbt.NBTList; -import me.skymc.taboolib.common.util.SimpleI18n; -import me.skymc.taboolib.fileutils.ConfigUtils; -import me.skymc.taboolib.itemnbtapi.NBTItem; -import me.skymc.taboolib.other.NumberUtils; -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemFlag; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.LeatherArmorMeta; -import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import org.bukkit.util.NumberConversions; - -import java.io.File; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.stream.IntStream; - -/** - * @author sky - */ -@TFunction(enable = "init") -public class ItemUtils { - - private static File finalItemsFolder; - private static FileConfiguration itemDir; - private static FileConfiguration itemCache; - private static LinkedHashMap itemLib = new LinkedHashMap<>(); - private static LinkedHashMap itemCaches = new LinkedHashMap<>(); - private static LinkedHashMap itemCachesFinal = new LinkedHashMap<>(); - - public static void init() { - try { - reloadItemDir(); - reloadItemCache(); - } catch (Exception e) { - TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-ITEMS", e.toString()); - } - } - - public static void reloadItemDir() { - File file = new File(Main.getInst().getConfig().getString("DATAURL.ITEMDIR")); - if (file.exists()) { - itemDir = YamlConfiguration.loadConfiguration(file); - } - } - - public static void reloadItemCache() { - itemCaches.clear(); - itemCachesFinal.clear(); - loadItemsFile(getItemCacheFile(), false); - finalItemsFolder = new File(Main.getInst().getDataFolder(), "FinalItems"); - if (!finalItemsFolder.exists()) { - finalItemsFolder.mkdir(); - } - Arrays.stream(finalItemsFolder.listFiles()).forEach(file -> loadItemsFile(file, true)); - TabooLib.debug("Loaded " + (itemCaches.size() + itemCachesFinal.size()) + " items."); -// TLocale.Logger.info("ITEM-UTILS.SUCCESS-LOAD-CACHES", String.valueOf(itemCaches.size() + itemCachesFinal.size())); - } - - public static File getItemCacheFile() { - File itemCacheFile = new File(Main.getInst().getDataFolder(), "items.yml"); - if (!itemCacheFile.exists()) { - Main.getInst().saveResource("items.yml", true); - } - return itemCacheFile; - } - - public static void loadItemsFile(File file, boolean finalFile) { - FileConfiguration conf = ConfigUtils.load(Main.getInst(), file); - for (String name : conf.getConfigurationSection("").getKeys(false)) { - if (isExists(name)) { - TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-ITEMS", name); - } else if (finalFile) { - itemCachesFinal.put(name, loadItem(conf, name)); - } else { - itemCaches.put(name, loadItem(conf, name)); - } - } - } - - // ********************************* - // - // API - // - // ********************************* - - public static boolean isExists(String name) { - return itemCachesFinal.containsKey(name) || itemCaches.containsKey(name); - } - - public static ItemStack getCacheItem(String name) { - return itemCachesFinal.containsKey(name) ? itemCachesFinal.get(name) : itemCaches.get(name); - } - - public static ItemStack getItemFromDir(String name) { - return itemDir != null ? itemDir.getItemStack("item." + name) : null; - } - - public static String getCustomName(ItemStack item) { - return SimpleI18n.getCustomName(item); - } - - public static ItemStack setName(ItemStack i, String n) { - ItemMeta meta = i.getItemMeta(); - meta.setDisplayName(n); - i.setItemMeta(meta); - return i; - } - - public static ItemStack enchant(ItemStack i, Enchantment e, int l) { - ItemMeta meta = i.getItemMeta(); - meta.addEnchant(e, l, false); - i.setItemMeta(meta); - return i; - } - - public static ItemStack addFlag(ItemStack i, ItemFlag f) { - ItemMeta meta = i.getItemMeta(); - meta.addItemFlags(f); - i.setItemMeta(meta); - return i; - } - - public static boolean isNull(ItemStack item) { - return item == null || item.getType().equals(Material.AIR); - } - - public static boolean isName(ItemStack i, String a) { - return isNamed(i) && i.getItemMeta() != null && i.getItemMeta().getDisplayName() != null && i.getItemMeta().getDisplayName().equals(a); - } - - public static boolean isNameAs(ItemStack i, String a) { - return isNamed(i) && i.getItemMeta().getDisplayName().contains(a); - } - - public static String asString(String args, Player placeholderPlayer) { - return placeholderPlayer == null ? args.replace("&", "§") : PlaceholderAPI.setPlaceholders(placeholderPlayer, args.replace("&", "§")); - } - - public static List asString(List args, Player placeholderPlayer) { - for (int i = 0; i < args.size(); i++) { - args.set(i, asString(args.get(i), placeholderPlayer)); - } - return args; - } - - public static ItemFlag asItemFlag(String flag) { - try { - return ItemFlag.valueOf(flag); - } catch (Exception e) { - return null; - } - } - - @SuppressWarnings("deprecation") - public static Material asMaterial(String args) { - try { - Material material = Material.getMaterial(args.toUpperCase()); - return material != null ? material : Material.getMaterial(Integer.valueOf(args)); - } catch (Exception e) { - return Material.STONE; - } - } - - @SuppressWarnings({"deprecation"}) - public static Enchantment asEnchantment(String enchant) { - try { - Enchantment enchantment = Enchantment.getByName(enchant); - return enchantment != null ? enchantment : Enchantment.getById(Integer.valueOf(enchant)); - } catch (Exception e) { - return null; - } - } - - @SuppressWarnings("deprecation") - public static PotionEffectType asPotionEffectType(String potion) { - try { - PotionEffectType type = PotionEffectType.getByName(potion); - return type != null ? type : PotionEffectType.getById(Integer.valueOf(potion)); - } catch (Exception e) { - return null; - } - } - - public static Color asColor(String color) { - try { - return Color.fromBGR(Integer.valueOf(color.split("-")[0]), Integer.valueOf(color.split("-")[1]), Integer.valueOf(color.split("-")[2])); - } catch (Exception e) { - return Color.fromBGR(0, 0, 0); - } - } - - public static String asAttribute(String name) { - switch (name.toLowerCase()) { - case "damage": - return "generic.attackDamage"; - case "attackspeed": - return "generic.attackSpeed"; - case "health": - return "generic.maxHealth"; - case "speed": - return "generic.movementSpeed"; - case "knockback": - return "generic.knockbackResistance"; - case "armor": - return "generic.armor"; - case "luck": - return "generic.luck"; - default: - return null; - } - } - - public static int getLore(ItemStack i, String a) { - return isLored(i) ? IntStream.range(0, i.getItemMeta().getLore().size()).filter(j -> i.getItemMeta().getLore().get(j).contains(a)).findFirst().orElse(0) : 0; - } - - public static boolean hasLore(ItemStack i, String a) { - return isLored(i) && i.getItemMeta().getLore().toString().contains(a); - } - - public static boolean isLored(ItemStack i) { - return i != null && i.getItemMeta() != null && i.getItemMeta().getLore() != null; - } - - public static boolean isNamed(ItemStack i) { - return i != null && i.getItemMeta() != null && i.getItemMeta().getDisplayName() != null; - } - - public static ItemStack addLore(ItemStack is, String line) { - ItemMeta meta = is.getItemMeta(); - List lore = meta.hasLore() ? meta.getLore() : Collections.emptyList(); - lore.add(TLocale.Translate.setColored(line)); - is.setItemMeta(meta); - return is; - } - - public static ItemStack delLore(ItemStack is, int line) { - ItemMeta meta = is.getItemMeta(); - if (meta.hasLore()) { - List l = meta.getLore(); - if (l.size() >= line) { - l.remove(line); - meta.setLore(l); - is.setItemMeta(meta); - } - } - return is; - } - - public static ItemStack replaceLore(ItemStack i, String l1, String l2) { - if (!isLored(i)) { - return i; - } else { - ItemMeta meta = i.getItemMeta(); - List lore = meta.getLore(); - IntStream.range(0, lore.size()).forEach(j -> lore.set(j, lore.get(j).replace(l1, l2))); - meta.setLore(lore); - i.setItemMeta(meta); - } - return i; - } - - public static ItemStack addDurability(ItemStack i, int d) { - i.setDurability((short) (i.getDurability() + d)); - int min = i.getDurability(); - int max = i.getType().getMaxDurability(); - if (min >= max) { - i.setType(Material.AIR); - } - return i; - } - - public static ItemStack loadItem(FileConfiguration f, String s) { - return loadItem(f, s, null); - } - - public static ItemStack loadItem(FileConfiguration f, String s, Player papiPlayer) { - return loadItem(f.getConfigurationSection(s), papiPlayer); - } - - public static ItemStack loadItem(ConfigurationSection section, Player papiPlayer) { - if (section.get("bukkit") instanceof ItemStack) { - return section.getItemStack("bukkit"); - } - // 材质 - ItemStack item = new ItemStack(asMaterial(section.getString("material"))); - // 数量 - item.setAmount(section.contains("amount") ? section.getInt("amount") : 1); - // 耐久 - item.setDurability((short) section.getInt("data")); - // 元数据 - ItemMeta meta = item.getItemMeta(); - // 展示名 - if (section.contains("name")) { - meta.setDisplayName(asString(section.getString("name"), papiPlayer)); - } - // 描述 - if (section.contains("lore")) { - meta.setLore(asString(section.getStringList("lore"), papiPlayer)); - } - // 附魔 - if (section.contains("enchant")) { - for (String preEnchant : section.getConfigurationSection("enchant").getKeys(false)) { - Enchantment enchant = asEnchantment(preEnchant); - if (enchant != null) { - meta.addEnchant(enchant, section.getInt("enchant." + preEnchant), true); - } else { - TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-ENCHANTS", preEnchant); - } - } - } - // 标签 - if (section.contains("flags") && TabooLib.getVerint() > 10700) { - for (String preFlag : section.getStringList("flags")) { - ItemFlag flag = asItemFlag(preFlag); - if (flag != null) { - meta.addItemFlags(flag); - } else { - TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-FLAG", preFlag); - } - } - } - // 皮革 - if (meta instanceof LeatherArmorMeta && section.contains("color")) { - ((LeatherArmorMeta) meta).setColor(asColor(section.getString("color"))); - } - // 药水 - if (meta instanceof PotionMeta && section.contains("potions")) { - PotionMeta potionMeta = (PotionMeta) meta; - for (String prePotionName : section.getConfigurationSection("potions").getKeys(false)) { - PotionEffectType potionEffectType = asPotionEffectType(prePotionName); - if (potionEffectType != null) { - potionMeta.addCustomEffect(new PotionEffect( - potionEffectType, - NumberUtils.getInteger(section.getString("potions." + prePotionName).split("-")[0]), - NumberUtils.getInteger(section.getString("potions." + prePotionName).split("-")[1]) - 1), true); - } else { - TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-POTION", prePotionName); - } - } - } - // 元数据 - item.setItemMeta(meta); - // 数据 - NBTCompound nbt = NMSHandler.getHandler().loadNBT(item); - // 物品标签 - if (section.contains("nbt")) { - for (String name : section.getConfigurationSection("nbt").getKeys(false)) { - Object obj = section.get("nbt." + name); - if (obj instanceof String) { - nbt.put(name, new NBTBase(obj.toString())); - } else if (obj instanceof Double) { - nbt.put(name, new NBTBase(NumberConversions.toDouble(obj))); - } else if (obj instanceof Integer) { - nbt.put(name, new NBTBase(NumberConversions.toInt(obj))); - } else if (obj instanceof Long) { - nbt.put(name, new NBTBase(NumberConversions.toLong(obj))); - } - } - } - // 物品属性 - if (section.contains("attributes")) { - NBTList attr = new NBTList(); - for (String hand : section.getConfigurationSection("attributes").getKeys(false)) { - for (String name : section.getConfigurationSection("attributes." + hand).getKeys(false)) { - if (asAttribute(name) != null) { - try { - NBTCompound a = new NBTCompound(); - String num = section.getString("attributes." + hand + "." + name); - if (num.endsWith("%")) { - a.put("Amount", new NBTBase(NumberConversions.toDouble(num.substring(0, num.length() - 1)) / 100D)); - a.put("Operation", new NBTBase(1)); - } else { - a.put("Amount", new NBTBase(NumberConversions.toDouble(num))); - a.put("Operation", new NBTBase(0)); - } - a.put("AttributeName", new NBTBase(asAttribute(name))); - a.put("UUIDMost", new NBTBase(NumberUtils.getRandom().nextInt(Integer.MAX_VALUE))); - a.put("UUIDLeast", new NBTBase(NumberUtils.getRandom().nextInt(Integer.MAX_VALUE))); - a.put("Name", new NBTBase(asAttribute(name))); - if (!hand.equals("all")) { - a.put("Slot", new NBTBase(hand)); - } - attr.add(a); - } catch (Exception ignored) { - } - } else { - TLocale.Logger.error("ITEM-UTILS.FAIL-LOAD-POTION", name); - } - } - } - nbt.put("AttributeModifiers", attr); - } - return NMSHandler.getHandler().saveNBT(item, nbt); - } - - // ********************************* - // - // Getter and Setter - // - // ********************************* - - public static FileConfiguration getItemDir() { - return itemDir; - } - - public static LinkedHashMap getItemLib() { - return itemLib; - } - - public static FileConfiguration getItemCache() { - return itemCache; - } - - public static File getFinalItemsFolder() { - return finalItemsFolder; - } - - public static LinkedHashMap getItemCaches() { - return itemCaches; - } - - public static LinkedHashMap getItemCachesFinal() { - return itemCachesFinal; - } - - // ********************************* - // - // Deprecated - // - // ********************************* - - @Deprecated - public static NBTItem setAttribute(NBTItem nbt, String name, Object num, String hand) { - return nbt; - } - - @Deprecated - public static FileConfiguration getItemdir() { - return itemDir; - } - - @Deprecated - public static LinkedHashMap getItemlib() { - return itemLib; - } - - @Deprecated - public static ItemStack item(int n, int a, int d) { - return new ItemStack(n, a, (short) d); - } - - @Deprecated - public static ItemStack repalceLore(ItemStack i, String l1, String l2) { - return replaceLore(i, l1, l2); - } - - @Deprecated - public static void putO(ItemStack item, Inventory inv, int i) { - inv.setItem(i, item); - inv.setItem(i + 1, item); - inv.setItem(i + 2, item); - inv.setItem(i + 9, item); - inv.setItem(i + 10, null); - inv.setItem(i + 11, item); - inv.setItem(i + 18, item); - inv.setItem(i + 19, item); - inv.setItem(i + 20, item); - } -} diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/MenuBuilder.java b/src/main/scala/me/skymc/taboolib/inventory/builder/MenuBuilder.java deleted file mode 100644 index f064bc9..0000000 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/MenuBuilder.java +++ /dev/null @@ -1,71 +0,0 @@ -package me.skymc.taboolib.inventory.builder; - -import me.skymc.taboolib.inventory.builder.menu.MenuBuilderCallable; -import me.skymc.taboolib.inventory.builder.menu.MenuBuilderHolder; -import me.skymc.taboolib.inventory.builder.menu.MenuBuilderItem; -import org.bukkit.Bukkit; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; - -import java.util.Arrays; -import java.util.HashMap; - -/** - * @Author sky - * @Since 2018-08-22 13:40 - * @BuilderVersion 1.0 - */ -@Deprecated -public class MenuBuilder { - - private boolean lock; - private String name; - private int rows = 9; - private Inventory parent; - - private HashMap items = new HashMap<>(); - - public MenuBuilder() { - this(true); - } - - public MenuBuilder(boolean lock) { - this.lock = lock; - } - - public MenuBuilder lock(boolean lock) { - this.lock = lock; - return this; - } - - public MenuBuilder name(String name) { - this.name = name; - return this; - } - - public MenuBuilder rows(int rows) { - this.rows = rows * 9; - return this; - } - - public MenuBuilder item(ItemStack itemStack, int... slots) { - Arrays.stream(slots).forEach(slot -> items.put(slot, new MenuBuilderItem(itemStack, null))); - return this; - } - - public MenuBuilder item(ItemStack itemStack, MenuBuilderCallable callable, int... slots) { - Arrays.stream(slots).forEach(slot -> items.put(slot, new MenuBuilderItem(itemStack, callable))); - return this; - } - - public MenuBuilder parent(Inventory parent) { - this.parent = parent; - return this; - } - - public Inventory build() { - Inventory inventory = Bukkit.createInventory(new MenuBuilderHolder(lock, items, parent), rows, name); - items.forEach((key, value) -> inventory.setItem(key, value.getItemStack())); - return inventory; - } -} diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderCallable.java b/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderCallable.java deleted file mode 100644 index 8a0beb6..0000000 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderCallable.java +++ /dev/null @@ -1,10 +0,0 @@ -package me.skymc.taboolib.inventory.builder.menu; - -/** - * @Author sky - * @Since 2018-08-22 15:41 - */ -public interface MenuBuilderCallable { - - void call(MenuBuilderEvent event); -} diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderEvent.java b/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderEvent.java deleted file mode 100644 index 692896c..0000000 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderEvent.java +++ /dev/null @@ -1,48 +0,0 @@ -package me.skymc.taboolib.inventory.builder.menu; - -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.inventory.ItemStack; - -/** - * @Author sky - * @Since 2018-08-22 15:44 - */ -public class MenuBuilderEvent { - - private final InventoryClickEvent parentEvent; - private final Player player; - private final ItemStack clickItem; - private final int clickSlot; - - public MenuBuilderEvent(InventoryClickEvent parentEvent, Player player, ItemStack clickItem, int clickSlot) { - this.parentEvent = parentEvent; - this.player = player; - this.clickItem = clickItem; - this.clickSlot = clickSlot; - } - - public InventoryClickEvent getParentEvent() { - return parentEvent; - } - - public Player getPlayer() { - return player; - } - - public ItemStack getClickItem() { - return clickItem; - } - - public int getClickSlot() { - return clickSlot; - } - - public void setCancelled(boolean canceled) { - parentEvent.setCancelled(canceled); - } - - public boolean isCancelled() { - return parentEvent.isCancelled(); - } -} diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderHolder.java b/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderHolder.java deleted file mode 100644 index b54684d..0000000 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderHolder.java +++ /dev/null @@ -1,50 +0,0 @@ -package me.skymc.taboolib.inventory.builder.menu; - -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryHolder; - -import java.util.HashMap; - -/** - * @author sky - * @Since 2018-08-22 13:40 - */ -public class MenuBuilderHolder implements InventoryHolder { - - private final boolean lock; - private final HashMap items; - private final Inventory parent; - - public MenuBuilderHolder(boolean lock, HashMap items, Inventory parent) { - this.lock = lock; - this.items = items; - this.parent = parent; - } - - public MenuBuilderHolder(boolean lock, HashMap items) { - this(lock, items, null); - } - - @Override - public Inventory getInventory() { - return null; - } - - // ********************************* - // - // Getter and Setter - // - // ********************************* - - public boolean isLock() { - return lock; - } - - public HashMap getItems() { - return items; - } - - public Inventory getParent() { - return parent; - } -} \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderItem.java b/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderItem.java deleted file mode 100644 index 17e0cce..0000000 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderItem.java +++ /dev/null @@ -1,26 +0,0 @@ -package me.skymc.taboolib.inventory.builder.menu; - -import org.bukkit.inventory.ItemStack; - -/** - * @Author sky - * @Since 2018-08-22 15:36 - */ -public class MenuBuilderItem { - - private final ItemStack itemStack; - private final MenuBuilderCallable callable; - - public MenuBuilderItem(ItemStack itemStack, MenuBuilderCallable callable) { - this.itemStack = itemStack; - this.callable = callable; - } - - public ItemStack getItemStack() { - return itemStack; - } - - public MenuBuilderCallable getCallable() { - return callable; - } -} diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderListener.java b/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderListener.java deleted file mode 100644 index 3eba630..0000000 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/menu/MenuBuilderListener.java +++ /dev/null @@ -1,49 +0,0 @@ -package me.skymc.taboolib.inventory.builder.menu; - -import me.skymc.taboolib.Main; -import me.skymc.taboolib.listener.TListener; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.InventoryAction; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryCloseEvent; - -import java.util.Optional; - -/** - * @Author sky - * @Since 2018-08-22 13:40 - */ -@TListener -public class MenuBuilderListener implements Listener { - - @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) - public void onClick(InventoryClickEvent e) { - if (!(e.getInventory().getHolder() instanceof MenuBuilderHolder)) { - return; - } - MenuBuilderHolder holder = (MenuBuilderHolder) e.getInventory().getHolder(); - if (holder.isLock() || e.getAction() == InventoryAction.COLLECT_TO_CURSOR) { - e.setCancelled(true); - } - Optional.ofNullable(holder.getItems().get(e.getRawSlot())).ifPresent(item -> { - if (item.getCallable() != null) { - item.getCallable().call(new MenuBuilderEvent(e, (Player) e.getWhoClicked(), e.getCurrentItem(), e.getRawSlot())); - } - }); - } - - @EventHandler - public void onClose(InventoryCloseEvent event) { - if (event.getInventory().getHolder() instanceof MenuBuilderHolder) { - MenuBuilderHolder holder = (MenuBuilderHolder) event.getInventory().getHolder(); - if (holder.getParent() != null) { - Bukkit.getScheduler().runTask(Main.getInst(), () -> event.getPlayer().openInventory(holder.getParent())); - } - } - } - -} diff --git a/src/main/scala/me/skymc/taboolib/itagapi/TagPacket.java b/src/main/scala/me/skymc/taboolib/itagapi/TagPacket.java deleted file mode 100644 index ca76c61..0000000 --- a/src/main/scala/me/skymc/taboolib/itagapi/TagPacket.java +++ /dev/null @@ -1,134 +0,0 @@ -package me.skymc.taboolib.itagapi; - -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.events.PacketAdapter; -import com.comphenix.protocol.events.PacketEvent; -import com.comphenix.protocol.wrappers.EnumWrappers; -import com.comphenix.protocol.wrappers.PlayerInfoData; -import com.comphenix.protocol.wrappers.WrappedGameProfile; -import com.google.common.base.Preconditions; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.events.itag.AsyncPlayerReceiveNameTagEvent; -import me.skymc.taboolib.events.itag.PlayerReceiveNameTagEvent; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -import java.util.*; -import java.util.stream.IntStream; - -/** - * @Author sky - * @Since 2018-05-09 21:03 - */ -class TagPacket implements Listener { - - private static final int[] uuidSplit = new int[]{0, 8, 12, 16, 20, 32}; - - private static boolean loaded = false; - private static HashMap entityIdMap = new HashMap<>(); - - TagPacket() { - } - - public static void inst() { - Preconditions.checkArgument(!loaded, "TagAPI is already instanced!"); - loaded = true; - - Bukkit.getServer().getOnlinePlayers().forEach(player -> entityIdMap.put(player.getEntityId(), player)); - Bukkit.getPluginManager().registerEvents(new TagPacket(), Main.getInst()); - ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(Main.getInst(), PacketType.Play.Server.PLAYER_INFO) { - - @Override - public void onPacketSending(PacketEvent event) { - if (event.getPacket().getPlayerInfoAction().read(0) != EnumWrappers.PlayerInfoAction.ADD_PLAYER) { - return; - } - - List newPlayerInfo = new ArrayList<>(); - for (PlayerInfoData playerInfo : event.getPacket().getPlayerInfoDataLists().read(0)) { - Player player; - if (playerInfo == null || playerInfo.getProfile() == null || (player = Bukkit.getServer().getPlayer(playerInfo.getProfile().getUUID())) == null) { - // Unknown Player - newPlayerInfo.add(playerInfo); - continue; - } - newPlayerInfo.add(new PlayerInfoData(getSentName(player.getEntityId(), playerInfo.getProfile(), event.getPlayer()), playerInfo.getPing(), playerInfo.getGameMode(), playerInfo.getDisplayName())); - } - event.getPacket().getPlayerInfoDataLists().write(0, newPlayerInfo); - } - }); - } - - static String getPlayerDisplayName(Player player) { - return TagDataHandler.getHandler().getPlayerDataComputeIfAbsent(player).getNameDisplay(); - } - - static void refreshPlayer(Player player) { - Preconditions.checkState(Main.getInst().isEnabled(), "Not Enabled!"); - Preconditions.checkNotNull(player, "player"); - player.getWorld().getPlayers().forEach(playerFor -> refreshPlayer(player, playerFor)); - } - - static void refreshPlayer(final Player player, final Player forWhom) { - Preconditions.checkState(Main.getInst().isEnabled(), "Not Enabled!"); - Preconditions.checkNotNull(player, "player"); - Preconditions.checkNotNull(forWhom, "forWhom"); - if (player != forWhom && player.getWorld() == forWhom.getWorld() && forWhom.canSee(player)) { - forWhom.hidePlayer(player); - Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Main.getInst(), () -> forWhom.showPlayer(player), 2); - } - } - - static void refreshPlayer(Player player, Set forWhom) { - Preconditions.checkState(Main.getInst().isEnabled(), "Not Enabled!"); - Preconditions.checkNotNull(player, "player"); - Preconditions.checkNotNull(forWhom, "forWhom"); - forWhom.forEach(playerFor -> refreshPlayer(player, playerFor)); - } - - private static WrappedGameProfile getSentName(int sentEntityId, WrappedGameProfile sent, Player destinationPlayer) { -// Preconditions.checkState(Bukkit.getServer().isPrimaryThread(), "Can only process events on main thread."); - Player namedPlayer = entityIdMap.get(sentEntityId); - if (namedPlayer == null) { - // They probably were dead when we reloaded - return sent; - } - - PlayerReceiveNameTagEvent oldEvent = new PlayerReceiveNameTagEvent(destinationPlayer, namedPlayer, sent.getName()); - Bukkit.getServer().getPluginManager().callEvent(oldEvent); - - StringBuilder builtUUID = new StringBuilder(); - if (!sent.getId().contains("-")) { - IntStream.range(0, uuidSplit.length - 1).forEach(i -> builtUUID.append(sent.getId(), uuidSplit[i], uuidSplit[i + 1]).append("-")); - } else { - builtUUID.append(sent.getId()); - } - - AsyncPlayerReceiveNameTagEvent newEvent = new AsyncPlayerReceiveNameTagEvent(destinationPlayer, namedPlayer, getPlayerDisplayName(namedPlayer), UUID.fromString(builtUUID.toString())); - Bukkit.getServer().getPluginManager().callEvent(newEvent); - - return new WrappedGameProfile(newEvent.getUUID(), newEvent.getTag().substring(0, Math.min(newEvent.getTag().length(), 16))); - } - - // ********************************* - // - // Listeners - // - // ********************************* - - @EventHandler - public void onJoin(PlayerJoinEvent event) { - entityIdMap.put(event.getPlayer().getEntityId(), event.getPlayer()); - } - - @EventHandler - public void onQuit(PlayerQuitEvent event) { - entityIdMap.remove(event.getPlayer().getEntityId()); - } -} diff --git a/src/main/scala/me/skymc/taboolib/listener/ListenerPlayerCommand.java b/src/main/scala/me/skymc/taboolib/listener/ListenerPlayerCommand.java deleted file mode 100644 index 0b0f990..0000000 --- a/src/main/scala/me/skymc/taboolib/listener/ListenerPlayerCommand.java +++ /dev/null @@ -1,104 +0,0 @@ -package me.skymc.taboolib.listener; - -import com.ilummc.tlib.filter.TLoggerFilter; -import com.ilummc.tlib.logger.TLogger; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.commands.builder.SimpleCommandBuilder; -import me.skymc.taboolib.common.inject.TInject; -import me.skymc.taboolib.database.PlayerDataManager; -import me.skymc.taboolib.inventory.ItemUtils; -import me.skymc.taboolib.itemnbtapi.NBTItem; -import me.skymc.taboolib.json.tellraw.TellrawJson; -import me.skymc.taboolib.message.MsgUtils; -import me.skymc.taboolib.permission.PermissionUtils; -import me.skymc.taboolib.playerdata.DataUtils; -import org.bukkit.Bukkit; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.server.ServerCommandEvent; - -/** - * @author sky - */ -@TListener -public class ListenerPlayerCommand implements Listener { - - private static boolean nextException; - - public ListenerPlayerCommand() { - Bukkit.getScheduler().runTaskTimer(TabooLib.instance(), () -> { - if (nextException) { - nextException = false; - throw new IllegalStateException("TabooLib Example Exception"); - } - }, 0, 20); - } - - @TInject - static SimpleCommandBuilder tExceptionCommand = SimpleCommandBuilder.create("tExceptionCommand", TabooLib.instance()) - .execute((sender, args) -> { - throw new IllegalStateException("TabooLib Example Exception"); - }); - - @TInject - static SimpleCommandBuilder tExceptionSchedule = SimpleCommandBuilder.create("tExceptionSchedule", TabooLib.instance()) - .execute((sender, args) -> { - nextException = true; - return true; - }); - - @EventHandler - public void cmd(ServerCommandEvent e) { - if (e.getCommand().equalsIgnoreCase("saveFiles")) { - if (TabooLib.getVerint() > 10700) { - e.setCancelled(true); - } - Bukkit.getScheduler().runTask(Main.getInst(), () -> { - DataUtils.saveAllCaches(); - PlayerDataManager.saveAllCaches(true, false); - }); - TLogger.getGlobalLogger().info("Successfully."); - } else if (e.getCommand().equalsIgnoreCase("tDebug")) { - if (TabooLib.getVerint() > 10700) { - e.setCancelled(true); - } - if (TabooLib.isDebug()) { - TabooLib.setDebug(false); - TLogger.getGlobalLogger().info("&cDisabled."); - } else { - TabooLib.setDebug(true); - TLogger.getGlobalLogger().info("&aEnabled."); - } - } else if (e.getCommand().equalsIgnoreCase("tExceptionEvent")) { - e.setCancelled(true); - throw new IllegalStateException("TabooLib Example Exception"); - } - } - - @SuppressWarnings("deprecation") - @EventHandler - public void cmd(PlayerCommandPreprocessEvent e) { - // 注入异常拦截器 - TLoggerFilter.inject0(); - // 其他指令 - if (e.getMessage().equals("/unbreakable") && PermissionUtils.hasPermission(e.getPlayer(), "taboolib.unbreakable")) { - e.setCancelled(true); - NBTItem nbt = new NBTItem(e.getPlayer().getItemInHand()); - nbt.setInteger("Unbreakable", 1); - e.getPlayer().setItemInHand(nbt.getItem()); - MsgUtils.send(e.getPlayer(), "Success!"); - } else if (e.getMessage().equals("/tellrawTest") && PermissionUtils.hasPermission(e.getPlayer(), "taboolib.tellraw")) { - e.setCancelled(true); - TellrawJson.create() - .append("§8[§3§lTabooLib§8] §7TellrawJson Test: §f[") - .append(ItemUtils.getCustomName(e.getPlayer().getItemInHand())).hoverItem(e.getPlayer().getItemInHand()) - .append("§f]") - .send(e.getPlayer()); - } else if (e.getMessage().equalsIgnoreCase("/tExceptionEvent")) { - e.setCancelled(true); - throw new IllegalStateException("TabooLib Example Exception"); - } - } -} diff --git a/src/main/scala/me/skymc/taboolib/listener/ListenerPlayerJoinAndQuit.java b/src/main/scala/me/skymc/taboolib/listener/ListenerPlayerJoinAndQuit.java deleted file mode 100644 index e2488a9..0000000 --- a/src/main/scala/me/skymc/taboolib/listener/ListenerPlayerJoinAndQuit.java +++ /dev/null @@ -1,33 +0,0 @@ -package me.skymc.taboolib.listener; - -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.playerdata.DataUtils; -import me.skymc.taboolib.translateuuid.TranslateUUID; -import me.skymc.taboolib.update.UpdateTask; -import org.bukkit.Bukkit; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -@TListener -public class ListenerPlayerJoinAndQuit implements Listener { - - @EventHandler - public void onJoin(PlayerJoinEvent e) { - if (UpdateTask.isHaveUpdate() && e.getPlayer().hasPermission("taboolib.update.notify")) { - TLocale.Logger.sendTo(e.getPlayer(), "UPDATETASK.VERSION-OUTDATED", String.valueOf(TabooLib.getPluginVersion()), String.valueOf(UpdateTask.getNewVersion())); - } - if (TranslateUUID.isEnabled()) { - Bukkit.getScheduler().runTaskAsynchronously(Main.getInst(), () -> TranslateUUID.updateUsername(e.getPlayer().getUniqueId(), e.getPlayer().getName())); - } - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onQuit(PlayerQuitEvent e) { - DataUtils.saveOnline(e.getPlayer().getName()); - } -} diff --git a/src/main/scala/me/skymc/taboolib/listener/ListenerPlugin.java b/src/main/scala/me/skymc/taboolib/listener/ListenerPlugin.java deleted file mode 100644 index 61a017d..0000000 --- a/src/main/scala/me/skymc/taboolib/listener/ListenerPlugin.java +++ /dev/null @@ -1,106 +0,0 @@ -package me.skymc.taboolib.listener; - -import com.ilummc.tlib.TLib; -import com.ilummc.tlib.filter.TLoggerFilter; -import com.ilummc.tlib.inject.TConfigWatcher; -import com.ilummc.tlib.inject.TDependencyInjector; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.common.configuration.TConfiguration; -import me.skymc.taboolib.events.TPluginEnableEvent; -import me.skymc.taboolib.events.TPluginLoadEvent; -import me.skymc.taboolib.mysql.MysqlUtils; -import me.skymc.taboolib.mysql.hikari.HikariHandler; -import me.skymc.taboolib.mysql.protect.MySQLConnection; -import me.skymc.taboolib.timecycle.TimeCycleManager; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.server.PluginDisableEvent; -import org.bukkit.scheduler.BukkitRunnable; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; - -/** - * @author sky - */ -@TListener -public class ListenerPlugin implements Listener { - - @EventHandler - public void load(TPluginLoadEvent e) { - if (TabooLib.isDependTabooLib(e.getPlugin())) { - TLoggerFilter.inject(new TLoggerFilter(), e.getPlugin().getLogger()); - } - } - - @EventHandler (priority = EventPriority.LOWEST) - public void enable(TPluginEnableEvent e) { - if (!TLib.getTLib().isInjectEnabled() || !TLib.getTLib().isBlackListPluginExists()) { - try { - TDependencyInjector.inject(e.getPlugin(), e.getPlugin()); - } catch (Exception err) { - err.printStackTrace(); - } - } - } - - @EventHandler - public void disable(PluginDisableEvent e) { - TabooLib.debug("Plugin \"" + e.getPlugin().getName() + "\" was disabled."); - // 注销插件注入 - if (!TLib.getTLib().isInjectEnabled() || !TLib.getTLib().isBlackListPluginExists()) { - TDependencyInjector.eject(e.getPlugin(), e.getPlugin()); - } - // 注销时间周期 - TimeCycleManager.cancel(e.getPlugin()); - // 注销插件配置 - Optional.ofNullable(TConfiguration.getFiles().get(e.getPlugin().getName())).ifPresent(files -> { - TConfigWatcher tConfigWatcher = TLib.getTLib().getConfigWatcher(); - for (File file : files) { - tConfigWatcher.removeListener(file); - TabooLib.debug("Remove TConfiguration \"" + file.getName() + "\" from Plugin \"" + e.getPlugin().getName() + "\""); - } - }); - // 注销数据库连接 - new HashSet<>(HikariHandler.getDataSource().keySet()).stream().filter(host -> e.getPlugin().equals(host.getPlugin()) && host.isAutoClose()).forEach(HikariHandler::closeDataSource); - // 获取连接 - List connection = new ArrayList<>(); - for (MySQLConnection conn : MysqlUtils.CONNECTIONS) { - if (conn.getPlugin().equals(e.getPlugin())) { - connection.add(conn); - MysqlUtils.CONNECTIONS.remove(conn); - } - } - // 异步注销 - BukkitRunnable runnable = new BukkitRunnable() { - - @Override - public void run() { - int i = 0; - for (MySQLConnection conn : connection) { - conn.setFallReconnection(false); - conn.closeConnection(); - i++; - } - if (i > 0) { - TLocale.Logger.info("MYSQL-CONNECTION.SUCCESS-CONNECTION-CANCEL", e.getPlugin().getName(), String.valueOf(i)); - } - } - }; - // 如果插件关闭 - try { - runnable.runTaskLater(Main.getInst(), 40); - } catch (Exception err) { - TLocale.Logger.error("MYSQL-CONNECTION.FAIL-EXECUTE-TASK"); - runnable.run(); - } - // 注销异常拦截 - TLoggerFilter.eject(e.getPlugin()); - } -} diff --git a/src/main/scala/me/skymc/taboolib/listener/TListenerCommand.java b/src/main/scala/me/skymc/taboolib/listener/TListenerCommand.java deleted file mode 100644 index 32317bc..0000000 --- a/src/main/scala/me/skymc/taboolib/listener/TListenerCommand.java +++ /dev/null @@ -1,9 +0,0 @@ -package me.skymc.taboolib.listener; - -/** - * @Author sky - * @Since 2018-08-25 10:16 - */ -public class TListenerCommand { - -} diff --git a/src/main/scala/me/skymc/taboolib/particle/EffLib.java b/src/main/scala/me/skymc/taboolib/particle/EffLib.java deleted file mode 100644 index 18e0cef..0000000 --- a/src/main/scala/me/skymc/taboolib/particle/EffLib.java +++ /dev/null @@ -1,1677 +0,0 @@ -package me.skymc.taboolib.particle; - -import me.skymc.taboolib.methods.ReflectionUtils; -import me.skymc.taboolib.methods.ReflectionUtils.PackageType; -import org.bukkit.*; -import org.bukkit.entity.Player; -import org.bukkit.util.Vector; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -/** - * ParticleEffect Library - *

- * This library was created by @DarkBlade12 and allows you to display all Minecraft particle effects on a Bukkit server - *

- * You are welcome to use it, modify it and redistribute it under the following conditions: - *

    - *
  • Don't claim this class as your own - *
  • Don't remove this disclaimer - *
- *

- * Special thanks: - *

    - *
  • @microgeek (original idea, names and packet parameters) - *
  • @ShadyPotato (1.8 names, ids and packet parameters) - *
  • @RingOfStorms (particle behavior) - *
  • @Cybermaxke (particle behavior) - *
  • @JamieSinn (hosting a jenkins server and documentation for particleeffect) - *
- *

- * It would be nice if you provide credit to me if you use this class in a published project - * - * @author DarkBlade12 - * @version 1.7 - */ -public enum EffLib { - - /** - * A particle effect which is displayed by exploding tnt and creepers: - *

    - *
  • It looks like a white cloud - *
  • The speed value influences the velocity at which the particle flies off - *
- */ - EXPLOSION_NORMAL("explode", 0, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed by exploding ghast fireballs and wither skulls: - *
    - *
  • It looks like a gray ball which is fading away - *
  • The speed value slightly influences the size of this particle effect - *
- */ - EXPLOSION_LARGE("largeexplode", 1, -1), - /** - * A particle effect which is displayed by exploding tnt and creepers: - *
    - *
  • It looks like a crowd of gray balls which are fading away - *
  • The speed value has no influence on this particle effect - *
- */ - EXPLOSION_HUGE("hugeexplosion", 2, -1), - /** - * A particle effect which is displayed by launching fireworks: - *
    - *
  • It looks like a white star which is sparkling - *
  • The speed value influences the velocity at which the particle flies off - *
- */ - FIREWORKS_SPARK("fireworksSpark", 3, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed by swimming entities and arrows in water: - *
    - *
  • It looks like a bubble - *
  • The speed value influences the velocity at which the particle flies off - *
- */ - WATER_BUBBLE("bubble", 4, -1, ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_WATER), - /** - * A particle effect which is displayed by swimming entities and shaking wolves: - *
    - *
  • It looks like a blue drop - *
  • The speed value has no influence on this particle effect - *
- */ - WATER_SPLASH("splash", 5, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed on water when fishing: - *
    - *
  • It looks like a blue droplet - *
  • The speed value influences the velocity at which the particle flies off - *
- */ - WATER_WAKE("wake", 6, 7, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed by water: - *
    - *
  • It looks like a tiny blue square - *
  • The speed value has no influence on this particle effect - *
- */ - SUSPENDED("suspended", 7, -1, ParticleProperty.REQUIRES_WATER), - /** - * A particle effect which is displayed by air when close to bedrock and the in the void: - *
    - *
  • It looks like a tiny gray square - *
  • The speed value has no influence on this particle effect - *
- */ - SUSPENDED_DEPTH("depthSuspend", 8, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed when landing a critical hit and by arrows: - *
    - *
  • It looks like a light brown cross - *
  • The speed value influences the velocity at which the particle flies off - *
- */ - CRIT("crit", 9, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed when landing a hit with an enchanted weapon: - *
    - *
  • It looks like a cyan star - *
  • The speed value influences the velocity at which the particle flies off - *
- */ - CRIT_MAGIC("magicCrit", 10, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed by primed tnt, torches, droppers, dispensers, end portals, brewing stands and monster spawners: - *
    - *
  • It looks like a little gray cloud - *
  • The speed value influences the velocity at which the particle flies off - *
- */ - SMOKE_NORMAL("smoke", 11, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed by fire, minecarts with furnace and blazes: - *
    - *
  • It looks like a large gray cloud - *
  • The speed value influences the velocity at which the particle flies off - *
- */ - SMOKE_LARGE("largesmoke", 12, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed when splash potions or bottles o' enchanting hit something: - *
    - *
  • It looks like a white swirl - *
  • The speed value causes the particle to only move upwards when set to 0 - *
  • Only the motion on the y-axis can be controlled, the motion on the x- and z-axis are multiplied by 0.1 when setting the values to 0 - *
- */ - SPELL("spell", 13, -1), - /** - * A particle effect which is displayed when instant splash potions hit something: - *
    - *
  • It looks like a white cross - *
  • The speed value causes the particle to only move upwards when set to 0 - *
  • Only the motion on the y-axis can be controlled, the motion on the x- and z-axis are multiplied by 0.1 when setting the values to 0 - *
- */ - SPELL_INSTANT("instantSpell", 14, -1), - /** - * A particle effect which is displayed by entities with active potion effects: - *
    - *
  • It looks like a colored swirl - *
  • The speed value causes the particle to be colored black when set to 0 - *
  • The particle color gets lighter when increasing the speed and darker when decreasing the speed - *
- */ - SPELL_MOB("mobSpell", 15, -1, ParticleProperty.COLORABLE), - /** - * A particle effect which is displayed by entities with active potion effects applied through a beacon: - *
    - *
  • It looks like a transparent colored swirl - *
  • The speed value causes the particle to be always colored black when set to 0 - *
  • The particle color gets lighter when increasing the speed and darker when decreasing the speed - *
- */ - SPELL_MOB_AMBIENT("mobSpellAmbient", 16, -1, ParticleProperty.COLORABLE), - /** - * A particle effect which is displayed by witches: - *
    - *
  • It looks like a purple cross - *
  • The speed value causes the particle to only move upwards when set to 0 - *
  • Only the motion on the y-axis can be controlled, the motion on the x- and z-axis are multiplied by 0.1 when setting the values to 0 - *
- */ - SPELL_WITCH("witchMagic", 17, -1), - /** - * A particle effect which is displayed by blocks beneath a water source: - *
    - *
  • It looks like a blue drip - *
  • The speed value has no influence on this particle effect - *
- */ - DRIP_WATER("dripWater", 18, -1), - /** - * A particle effect which is displayed by blocks beneath a lava source: - *
    - *
  • It looks like an orange drip - *
  • The speed value has no influence on this particle effect - *
- */ - DRIP_LAVA("dripLava", 19, -1), - /** - * A particle effect which is displayed when attacking a villager in a village: - *
    - *
  • It looks like a cracked gray heart - *
  • The speed value has no influence on this particle effect - *
- */ - VILLAGER_ANGRY("angryVillager", 20, -1), - /** - * A particle effect which is displayed when using bone meal and trading with a villager in a village: - *
    - *
  • It looks like a green star - *
  • The speed value has no influence on this particle effect - *
- */ - VILLAGER_HAPPY("happyVillager", 21, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed by mycelium: - *
    - *
  • It looks like a tiny gray square - *
  • The speed value has no influence on this particle effect - *
- */ - TOWN_AURA("townaura", 22, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed by note blocks: - *
    - *
  • It looks like a colored note - *
  • The speed value causes the particle to be colored green when set to 0 - *
- */ - NOTE("note", 23, -1, ParticleProperty.COLORABLE), - /** - * A particle effect which is displayed by nether portals, endermen, ender pearls, eyes of ender, ender chests and dragon eggs: - *
    - *
  • It looks like a purple cloud - *
  • The speed value influences the spread of this particle effect - *
- */ - PORTAL("portal", 24, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed by enchantment tables which are nearby bookshelves: - *
    - *
  • It looks like a cryptic white letter - *
  • The speed value influences the spread of this particle effect - *
- */ - ENCHANTMENT_TABLE("enchantmenttable", 25, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed by torches, active furnaces, magma cubes and monster spawners: - *
    - *
  • It looks like a tiny flame - *
  • The speed value influences the velocity at which the particle flies off - *
- */ - FLAME("flame", 26, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed by lava: - *
    - *
  • It looks like a spark - *
  • The speed value has no influence on this particle effect - *
- */ - LAVA("lava", 27, -1), - /** - * A particle effect which is currently unused: - *
    - *
  • It looks like a transparent gray square - *
  • The speed value has no influence on this particle effect - *
- */ - FOOTSTEP("footstep", 28, -1), - /** - * A particle effect which is displayed when a mob dies: - *
    - *
  • It looks like a large white cloud - *
  • The speed value influences the velocity at which the particle flies off - *
- */ - CLOUD("cloud", 29, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed by redstone ore, powered redstone, redstone torches and redstone repeaters: - *
    - *
  • It looks like a tiny colored cloud - *
  • The speed value causes the particle to be colored red when set to 0 - *
- */ - REDSTONE("reddust", 30, -1, ParticleProperty.COLORABLE), - /** - * A particle effect which is displayed when snowballs hit a block: - *
    - *
  • It looks like a little piece with the snowball texture - *
  • The speed value has no influence on this particle effect - *
- */ - SNOWBALL("snowballpoof", 31, -1), - /** - * A particle effect which is currently unused: - *
    - *
  • It looks like a tiny white cloud - *
  • The speed value influences the velocity at which the particle flies off - *
- */ - SNOW_SHOVEL("snowshovel", 32, -1, ParticleProperty.DIRECTIONAL), - /** - * A particle effect which is displayed by slimes: - *
    - *
  • It looks like a tiny part of the slimeball icon - *
  • The speed value has no influence on this particle effect - *
- */ - SLIME("slime", 33, -1), - /** - * A particle effect which is displayed when breeding and taming animals: - *
    - *
  • It looks like a red heart - *
  • The speed value has no influence on this particle effect - *
- */ - HEART("heart", 34, -1), - /** - * A particle effect which is displayed by barriers: - *
    - *
  • It looks like a red box with a slash through it - *
  • The speed value has no influence on this particle effect - *
- */ - BARRIER("barrier", 35, 8), - /** - * A particle effect which is displayed when breaking a tool or eggs hit a block: - *
    - *
  • It looks like a little piece with an item texture - *
- */ - ITEM_CRACK("iconcrack", 36, -1, ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_DATA), - /** - * A particle effect which is displayed when breaking blocks or sprinting: - *
    - *
  • It looks like a little piece with a block texture - *
  • The speed value has no influence on this particle effect - *
- */ - BLOCK_CRACK("blockcrack", 37, -1, ParticleProperty.REQUIRES_DATA), - /** - * A particle effect which is displayed when falling: - *
    - *
  • It looks like a little piece with a block texture - *
- */ - BLOCK_DUST("blockdust", 38, 7, ParticleProperty.DIRECTIONAL, ParticleProperty.REQUIRES_DATA), - /** - * A particle effect which is displayed when rain hits the ground: - *
    - *
  • It looks like a blue droplet - *
  • The speed value has no influence on this particle effect - *
- */ - WATER_DROP("droplet", 39, 8), - /** - * A particle effect which is currently unused: - *
    - *
  • It has no visual effect - *
- */ - ITEM_TAKE("take", 40, 8), - /** - * A particle effect which is displayed by elder guardians: - *
    - *
  • It looks like the shape of the elder guardian - *
  • The speed value has no influence on this particle effect - *
  • The offset values have no influence on this particle effect - *
- */ - MOB_APPEARANCE("mobappearance", 41, 8), - - /** - * 龙息 - */ - DRAGON_BREATH("dragonbreath", 42, 9), - - /** - * 末地烛 - */ - END_ROD("endrod", 43, 9), - - /** - * 伤害 - */ - DAMAGE_INDICATOR("damageIndicator", 44, 9), - - /** - * 挥砍 - */ - SWEEP_ATTACK("sweepAttack", 45, 9), - - /** - * 掉落方块 - */ - FALLING_DUST("fallingdust", 46, 11, ParticleProperty.REQUIRES_DATA), - - /** - * 不死图腾 - */ - TOTEM("totem", 47, 11); - - private static final Map NAME_MAP = new HashMap<>(); - private static final Map ID_MAP = new HashMap<>(); - private final String name; - private final int id; - private final int requiredVersion; - private final List properties; - - // Initialize map for quick name and id lookup - static { - for (EffLib effect : values()) { - NAME_MAP.put(effect.name, effect); - ID_MAP.put(effect.id, effect); - } - } - - /** - * Construct a new particle effect - * - * @param name Name of this particle effect - * @param id Id of this particle effect - * @param requiredVersion Version which is required (1.x) - * @param properties Properties of this particle effect - */ - EffLib(String name, int id, int requiredVersion, ParticleProperty... properties) { - this.name = name; - this.id = id; - this.requiredVersion = requiredVersion; - this.properties = Arrays.asList(properties); - } - - /** - * Returns the name of this particle effect - * - * @return The name - */ - public String getName() { - return name; - } - - /** - * Returns the id of this particle effect - * - * @return The id - */ - public int getId() { - return id; - } - - /** - * Returns the required version for this particle effect (1.x) - * - * @return The required version - */ - public int getRequiredVersion() { - return requiredVersion; - } - - /** - * Determine if this particle effect has a specific property - * - * @return Whether it has the property or not - */ - public boolean hasProperty(ParticleProperty property) { - return properties.contains(property); - } - - /** - * Determine if this particle effect is supported by your current server version - * - * @return Whether the particle effect is supported or not - */ - public boolean isSupported() { - return requiredVersion == -1 || ParticlePacket.getVersion() >= requiredVersion; - } - - /** - * Returns the particle effect with the given name - * - * @param name Name of the particle effect - * @return The particle effect - */ - public static EffLib fromName(String name) { - for (Entry entry : NAME_MAP.entrySet()) { - if (!entry.getKey().equalsIgnoreCase(name)) { - continue; - } - return entry.getValue(); - } - return null; - } - - /** - * Returns the particle effect with the given id - * - * @param id Id of the particle effect - * @return The particle effect - */ - public static EffLib fromId(int id) { - for (Entry entry : ID_MAP.entrySet()) { - if (entry.getKey() != id) { - continue; - } - return entry.getValue(); - } - return null; - } - - /** - * Determine if water is at a certain location - * - * @param location Location to check - * @return Whether water is at this location or not - */ - private static boolean isWater(Location location) { - Material material = location.getBlock().getType(); - return material == Material.WATER || material == Material.STATIONARY_WATER; - } - - /** - * Determine if the distance between @param location and one of the players exceeds 256 - * - * @param location Location to check - * @return Whether the distance exceeds 256 or not - */ - private static boolean isLongDistance(Location location, List players) { - String world = location.getWorld().getName(); - for (Player player : players) { - Location playerLocation = player.getLocation(); - if (!world.equals(playerLocation.getWorld().getName()) || playerLocation.distanceSquared(location) < 65536) { - continue; - } - return true; - } - return false; - } - - /** - * Determine if the data type for a particle effect is correct - * - * @param effect Particle effect - * @param data Particle data - * @return Whether the data type is correct or not - */ - private static boolean isDataCorrect(EffLib effect, ParticleData data) { - return ((effect == BLOCK_CRACK || effect == BLOCK_DUST || effect == FALLING_DUST) && data instanceof BlockData) || ((effect == ITEM_CRACK) && data instanceof ItemData); - } - - /** - * Determine if the color type for a particle effect is correct - * - * @param effect Particle effect - * @param color Particle color - * @return Whether the color type is correct or not - */ - private static boolean isColorCorrect(EffLib effect, ParticleColor color) { - return ((effect == SPELL_MOB || effect == SPELL_MOB_AMBIENT || effect == REDSTONE) && color instanceof OrdinaryColor) || (effect == NOTE && color instanceof NoteColor); - } - - /** - * Displays a particle effect which is only visible for all players within a certain range in the world of @param center - * - * @param offsetX Maximum distance particles can fly away from the center on the x-axis - * @param offsetY Maximum distance particles can fly away from the center on the y-axis - * @param offsetZ Maximum distance particles can fly away from the center on the z-axis - * @param speed Display speed of the particles - * @param amount Amount of particles - * @param center Center location of the effect - * @param range Range of the visibility - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleDataException If the particle effect requires additional data - * @throws IllegalArgumentException If the particle effect requires water and none is at the center location - * @see ParticlePacket - * @see ParticlePacket#sendTo(Location, double) - */ - public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, double range) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { - if (!isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect requires additional data"); - } - if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { - throw new IllegalArgumentException("There is no water at the center location"); - } - new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, range > 256, null).sendTo(center, range); - } - - /** - * Displays a particle effect which is only visible for the specified players - * - * @param offsetX Maximum distance particles can fly away from the center on the x-axis - * @param offsetY Maximum distance particles can fly away from the center on the y-axis - * @param offsetZ Maximum distance particles can fly away from the center on the z-axis - * @param speed Display speed of the particles - * @param amount Amount of particles - * @param center Center location of the effect - * @param players Receivers of the effect - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleDataException If the particle effect requires additional data - * @throws IllegalArgumentException If the particle effect requires water and none is at the center location - * @see ParticlePacket - * @see ParticlePacket#sendTo(Location, List) - */ - public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, List players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { - if (!isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect requires additional data"); - } - if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { - throw new IllegalArgumentException("There is no water at the center location"); - } - new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, isLongDistance(center, players), null).sendTo(center, players); - } - - /** - * Displays a particle effect which is only visible for the specified players - * - * @param offsetX Maximum distance particles can fly away from the center on the x-axis - * @param offsetY Maximum distance particles can fly away from the center on the y-axis - * @param offsetZ Maximum distance particles can fly away from the center on the z-axis - * @param speed Display speed of the particles - * @param amount Amount of particles - * @param center Center location of the effect - * @param players Receivers of the effect - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleDataException If the particle effect requires additional data - * @throws IllegalArgumentException If the particle effect requires water and none is at the center location - * @see #display(float, float, float, float, int, Location, List) - */ - public void display(float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, Player... players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { - display(offsetX, offsetY, offsetZ, speed, amount, center, Arrays.asList(players)); - } - - /** - * Displays a single particle which flies into a determined direction and is only visible for all players within a certain range in the world of @param center - * - * @param direction Direction of the particle - * @param speed Display speed of the particle - * @param center Center location of the effect - * @param range Range of the visibility - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleDataException If the particle effect requires additional data - * @throws IllegalArgumentException If the particle effect is not directional or if it requires water and none is at the center location - * @see ParticlePacket#ParticlePacket(EffLib, Vector, float, boolean, ParticleData) - * @see ParticlePacket#sendTo(Location, double) - */ - public void display(Vector direction, float speed, Location center, double range) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { - if (!isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect requires additional data"); - } - if (!hasProperty(ParticleProperty.DIRECTIONAL)) { - throw new IllegalArgumentException("This particle effect is not directional"); - } - if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { - throw new IllegalArgumentException("There is no water at the center location"); - } - new ParticlePacket(this, direction, speed, range > 256, null).sendTo(center, range); - } - - /** - * Displays a single particle which flies into a determined direction and is only visible for the specified players - * - * @param direction Direction of the particle - * @param speed Display speed of the particle - * @param center Center location of the effect - * @param players Receivers of the effect - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleDataException If the particle effect requires additional data - * @throws IllegalArgumentException If the particle effect is not directional or if it requires water and none is at the center location - * @see ParticlePacket#ParticlePacket(EffLib, Vector, float, boolean, ParticleData) - * @see ParticlePacket#sendTo(Location, List) - */ - public void display(Vector direction, float speed, Location center, List players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { - if (!isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect requires additional data"); - } - if (!hasProperty(ParticleProperty.DIRECTIONAL)) { - throw new IllegalArgumentException("This particle effect is not directional"); - } - if (hasProperty(ParticleProperty.REQUIRES_WATER) && !isWater(center)) { - throw new IllegalArgumentException("There is no water at the center location"); - } - new ParticlePacket(this, direction, speed, isLongDistance(center, players), null).sendTo(center, players); - } - - /** - * Displays a single particle which flies into a determined direction and is only visible for the specified players - * - * @param direction Direction of the particle - * @param speed Display speed of the particle - * @param center Center location of the effect - * @param players Receivers of the effect - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleDataException If the particle effect requires additional data - * @throws IllegalArgumentException If the particle effect is not directional or if it requires water and none is at the center location - * @see #display(Vector, float, Location, List) - */ - public void display(Vector direction, float speed, Location center, Player... players) throws ParticleVersionException, ParticleDataException, IllegalArgumentException { - display(direction, speed, center, Arrays.asList(players)); - } - - /** - * Displays a single particle which is colored and only visible for all players within a certain range in the world of @param center - * - * @param color Color of the particle - * @param center Center location of the effect - * @param speed Display speed of the particle - * @param amount Amount of particles - * @param range Range of the visibility - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleColorException If the particle effect is not colorable or the color type is incorrect - * @see ParticlePacket#ParticlePacket(EffLib, ParticleColor, boolean) - * @see ParticlePacket#sendTo(Location, double) - */ - public void display(ParticleColor color, Location center, float speed, int amount, double range) throws ParticleVersionException, ParticleColorException { - if (!isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (!hasProperty(ParticleProperty.COLORABLE)) { - throw new ParticleColorException("This particle effect is not colorable"); - } - if (!isColorCorrect(this, color)) { - throw new ParticleColorException("The particle color type is incorrect"); - } - new ParticlePacket(this, color, speed, amount, range > 256).sendTo(center, range); - } - - /** - * Displays a single particle which is colored and only visible for the specified players - * - * @param color Color of the particle - * @param center Center location of the effect - * @param players Receivers of the effect - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleColorException If the particle effect is not colorable or the color type is incorrect - * @see ParticlePacket#ParticlePacket(EffLib, ParticleColor, boolean) - * @see ParticlePacket#sendTo(Location, List) - */ - public void display(ParticleColor color, Location center, List players) throws ParticleVersionException, ParticleColorException { - display(color, center, 1, 0, players); - } - - /** - * Displays a single particle which is colored and only visible for the specified players - * - * @param color Color of the particle - * @param center Center location of the effect - * @param speed Display speed of the particle - * @param amount Amount of particles - * @param players Receivers of the effect - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleColorException If the particle effect is not colorable or the color type is incorrect - * @see ParticlePacket#ParticlePacket(EffLib, ParticleColor, boolean) - * @see ParticlePacket#sendTo(Location, List) - */ - public void display(ParticleColor color, Location center, float speed, int amount, List players) throws ParticleVersionException, ParticleColorException { - if (!isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (!hasProperty(ParticleProperty.COLORABLE)) { - throw new ParticleColorException("This particle effect is not colorable"); - } - if (!isColorCorrect(this, color)) { - throw new ParticleColorException("The particle color type is incorrect"); - } - new ParticlePacket(this, color, isLongDistance(center, players)).sendTo(center, players); - } - - /** - * Displays a single particle which is colored and only visible for the specified players - * - * @param color Color of the particle - * @param center Center location of the effect - * @param players Receivers of the effect - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleColorException If the particle effect is not colorable or the color type is incorrect - * @see #display(ParticleColor, Location, List) - */ - public void display(ParticleColor color, Location center, Player... players) throws ParticleVersionException, ParticleColorException { - display(color, center, Arrays.asList(players)); - } - - /** - * Displays a single particle which is colored and only visible for the specified players - * - * @param color Color of the particle - * @param center Center location of the effect - * @param speed Display speed of the particle - * @param amount Amount of particles - * @param players Receivers of the effect - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleColorException If the particle effect is not colorable or the color type is incorrect - * @see #display(ParticleColor, Location, List) - */ - public void display(ParticleColor color, Location center, float speed, int amount, Player... players) throws ParticleVersionException, ParticleColorException { - display(color, center, speed, amount, Arrays.asList(players)); - } - - /** - * Displays a particle effect which requires additional data and is only visible for all players within a certain range in the world of @param center - * - * @param data Data of the effect - * @param offsetX Maximum distance particles can fly away from the center on the x-axis - * @param offsetY Maximum distance particles can fly away from the center on the y-axis - * @param offsetZ Maximum distance particles can fly away from the center on the z-axis - * @param speed Display speed of the particles - * @param amount Amount of particles - * @param center Center location of the effect - * @param range Range of the visibility - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleDataException If the particle effect does not require additional data or if the data type is incorrect - * @see ParticlePacket - * @see ParticlePacket#sendTo(Location, double) - */ - public void display(ParticleData data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, double range) throws ParticleVersionException, ParticleDataException { - if (!isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (!hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect does not require additional data"); - } - if (!isDataCorrect(this, data)) { - throw new ParticleDataException("The particle data type is incorrect"); - } - new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, range > 256, data).sendTo(center, range); - } - - /** - * Displays a particle effect which requires additional data and is only visible for the specified players - * - * @param data Data of the effect - * @param offsetX Maximum distance particles can fly away from the center on the x-axis - * @param offsetY Maximum distance particles can fly away from the center on the y-axis - * @param offsetZ Maximum distance particles can fly away from the center on the z-axis - * @param speed Display speed of the particles - * @param amount Amount of particles - * @param center Center location of the effect - * @param players Receivers of the effect - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleDataException If the particle effect does not require additional data or if the data type is incorrect - * @see ParticlePacket - * @see ParticlePacket#sendTo(Location, List) - */ - public void display(ParticleData data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, List players) throws ParticleVersionException, ParticleDataException { - if (!isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (!hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect does not require additional data"); - } - if (!isDataCorrect(this, data)) { - throw new ParticleDataException("The particle data type is incorrect"); - } - new ParticlePacket(this, offsetX, offsetY, offsetZ, speed, amount, isLongDistance(center, players), data).sendTo(center, players); - } - - /** - * Displays a particle effect which requires additional data and is only visible for the specified players - * - * @param data Data of the effect - * @param offsetX Maximum distance particles can fly away from the center on the x-axis - * @param offsetY Maximum distance particles can fly away from the center on the y-axis - * @param offsetZ Maximum distance particles can fly away from the center on the z-axis - * @param speed Display speed of the particles - * @param amount Amount of particles - * @param center Center location of the effect - * @param players Receivers of the effect - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleDataException If the particle effect does not require additional data or if the data type is incorrect - * @see #display(ParticleData, float, float, float, float, int, Location, List) - */ - public void display(ParticleData data, float offsetX, float offsetY, float offsetZ, float speed, int amount, Location center, Player... players) throws ParticleVersionException, ParticleDataException { - display(data, offsetX, offsetY, offsetZ, speed, amount, center, Arrays.asList(players)); - } - - /** - * Displays a single particle which requires additional data that flies into a determined direction and is only visible for all players within a certain range in the world of @param center - * - * @param data Data of the effect - * @param direction Direction of the particle - * @param speed Display speed of the particles - * @param center Center location of the effect - * @param range Range of the visibility - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleDataException If the particle effect does not require additional data or if the data type is incorrect - * @see ParticlePacket - * @see ParticlePacket#sendTo(Location, double) - */ - public void display(ParticleData data, Vector direction, float speed, Location center, double range) throws ParticleVersionException, ParticleDataException { - if (!isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (!hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect does not require additional data"); - } - if (!isDataCorrect(this, data)) { - throw new ParticleDataException("The particle data type is incorrect"); - } - new ParticlePacket(this, direction, speed, range > 256, data).sendTo(center, range); - } - - /** - * Displays a single particle which requires additional data that flies into a determined direction and is only visible for the specified players - * - * @param data Data of the effect - * @param direction Direction of the particle - * @param speed Display speed of the particles - * @param center Center location of the effect - * @param players Receivers of the effect - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleDataException If the particle effect does not require additional data or if the data type is incorrect - * @see ParticlePacket - * @see ParticlePacket#sendTo(Location, List) - */ - public void display(ParticleData data, Vector direction, float speed, Location center, List players) throws ParticleVersionException, ParticleDataException { - if (!isSupported()) { - throw new ParticleVersionException("This particle effect is not supported by your server version"); - } - if (!hasProperty(ParticleProperty.REQUIRES_DATA)) { - throw new ParticleDataException("This particle effect does not require additional data"); - } - if (!isDataCorrect(this, data)) { - throw new ParticleDataException("The particle data type is incorrect"); - } - new ParticlePacket(this, direction, speed, isLongDistance(center, players), data).sendTo(center, players); - } - - /** - * Displays a single particle which requires additional data that flies into a determined direction and is only visible for the specified players - * - * @param data Data of the effect - * @param direction Direction of the particle - * @param speed Display speed of the particles - * @param center Center location of the effect - * @param players Receivers of the effect - * @throws ParticleVersionException If the particle effect is not supported by the server version - * @throws ParticleDataException If the particle effect does not require additional data or if the data type is incorrect - * @see #display(ParticleData, Vector, float, Location, List) - */ - public void display(ParticleData data, Vector direction, float speed, Location center, Player... players) throws ParticleVersionException, ParticleDataException { - display(data, direction, speed, center, Arrays.asList(players)); - } - - /** - * Represents the property of a particle effect - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.7 - */ - public enum ParticleProperty { - /** - * The particle effect requires water to be displayed - */ - REQUIRES_WATER, - /** - * The particle effect requires block or item data to be displayed - */ - REQUIRES_DATA, - /** - * The particle effect uses the offsets as direction values - */ - DIRECTIONAL, - /** - * The particle effect uses the offsets as color values - */ - COLORABLE - } - - /** - * Represents the particle data for effects like {@link EffLib#ITEM_CRACK}, {@link EffLib#BLOCK_CRACK} and {@link EffLib#BLOCK_DUST} - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.6 - */ - public static abstract class ParticleData { - private final Material material; - private final byte data; - private final int[] packetData; - - /** - * Construct a new particle data - * - * @param material Material of the item/block - * @param data Data value of the item/block - */ - @SuppressWarnings("deprecation") - public ParticleData(Material material, byte data) { - this.material = material; - this.data = data; - this.packetData = new int[] {material.getId(), data}; - } - - /** - * Returns the material of this data - * - * @return The material - */ - public Material getMaterial() { - return material; - } - - /** - * Returns the data value of this data - * - * @return The data value - */ - public byte getData() { - return data; - } - - /** - * Returns the data as an int array for packet construction - * - * @return The data for the packet - */ - public int[] getPacketData() { - return packetData; - } - - /** - * Returns the data as a string for pre 1.8 versions - * - * @return The data string for the packet - */ - public String getPacketDataString() { - return "_" + packetData[0] + "_" + packetData[1]; - } - } - - /** - * Represents the item data for the {@link EffLib#ITEM_CRACK} effect - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.6 - */ - public static final class ItemData extends ParticleData { - /** - * Construct a new item data - * - * @param material Material of the item - * @param data Data value of the item - * @see ParticleData#ParticleData(Material, byte) - */ - public ItemData(Material material, byte data) { - super(material, data); - } - } - - /** - * Represents the block data for the {@link EffLib#BLOCK_CRACK} and {@link EffLib#BLOCK_DUST} effects - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.6 - */ - public static final class BlockData extends ParticleData { - /** - * Construct a new block data - * - * @param material Material of the block - * @param data Data value of the block - * @throws IllegalArgumentException If the material is not a block - * @see ParticleData#ParticleData(Material, byte) - */ - public BlockData(Material material, byte data) throws IllegalArgumentException { - super(material, data); - if (!material.isBlock()) { - throw new IllegalArgumentException("The material is not a block"); - } - } - } - - /** - * Represents the color for effects like {@link EffLib#SPELL_MOB}, {@link EffLib#SPELL_MOB_AMBIENT}, {@link EffLib#REDSTONE} and {@link EffLib#NOTE} - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.7 - */ - public static abstract class ParticleColor { - /** - * Returns the value for the offsetX field - * - * @return The offsetX value - */ - public abstract float getValueX(); - - /** - * Returns the value for the offsetY field - * - * @return The offsetY value - */ - public abstract float getValueY(); - - /** - * Returns the value for the offsetZ field - * - * @return The offsetZ value - */ - public abstract float getValueZ(); - } - - /** - * Represents the color for effects like {@link EffLib#SPELL_MOB}, {@link EffLib#SPELL_MOB_AMBIENT} and {@link EffLib#NOTE} - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.7 - */ - public static final class OrdinaryColor extends ParticleColor { - private final int red; - private final int green; - private final int blue; - - /** - * Construct a new ordinary color - * - * @param red Red value of the RGB format - * @param green Green value of the RGB format - * @param blue Blue value of the RGB format - * @throws IllegalArgumentException If one of the values is lower than 0 or higher than 255 - */ - public OrdinaryColor(int red, int green, int blue) throws IllegalArgumentException { - if (red < 0) { - throw new IllegalArgumentException("The red value is lower than 0"); - } - if (red > 255) { - throw new IllegalArgumentException("The red value is higher than 255"); - } - this.red = red; - if (green < 0) { - throw new IllegalArgumentException("The green value is lower than 0"); - } - if (green > 255) { - throw new IllegalArgumentException("The green value is higher than 255"); - } - this.green = green; - if (blue < 0) { - throw new IllegalArgumentException("The blue value is lower than 0"); - } - if (blue > 255) { - throw new IllegalArgumentException("The blue value is higher than 255"); - } - this.blue = blue; - } - - /** - * Construct a new ordinary color - * - * @param color Bukkit color - */ - public OrdinaryColor(Color color) { - this(color.getRed(), color.getGreen(), color.getBlue()); - } - - /** - * Returns the red value of the RGB format - * - * @return The red value - */ - public int getRed() { - return red; - } - - /** - * Returns the green value of the RGB format - * - * @return The green value - */ - public int getGreen() { - return green; - } - - /** - * Returns the blue value of the RGB format - * - * @return The blue value - */ - public int getBlue() { - return blue; - } - - /** - * Returns the red value divided by 255 - * - * @return The offsetX value - */ - @Override - public float getValueX() { - return red / 255F; - } - - /** - * Returns the green value divided by 255 - * - * @return The offsetY value - */ - @Override - public float getValueY() { - return green / 255F; - } - - /** - * Returns the blue value divided by 255 - * - * @return The offsetZ value - */ - @Override - public float getValueZ() { - return blue / 255F; - } - } - - /** - * Represents the color for the {@link EffLib#NOTE} effect - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.7 - */ - public static final class NoteColor extends ParticleColor { - private final int note; - - /** - * Construct a new note color - * - * @param note Note id which determines color - * @throws IllegalArgumentException If the note value is lower than 0 or higher than 24 - */ - public NoteColor(int note) throws IllegalArgumentException { - if (note < 0) { - throw new IllegalArgumentException("The note value is lower than 0"); - } - if (note > 24) { - throw new IllegalArgumentException("The note value is higher than 24"); - } - this.note = note; - } - - /** - * Returns the note value divided by 24 - * - * @return The offsetX value - */ - @Override - public float getValueX() { - return note / 24F; - } - - /** - * Returns zero because the offsetY value is unused - * - * @return zero - */ - @Override - public float getValueY() { - return 0; - } - - /** - * Returns zero because the offsetZ value is unused - * - * @return zero - */ - @Override - public float getValueZ() { - return 0; - } - - } - - /** - * Represents a runtime exception that is thrown either if the displayed particle effect requires data and has none or vice-versa or if the data type is incorrect - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.6 - */ - private static final class ParticleDataException extends RuntimeException { - private static final long serialVersionUID = 3203085387160737484L; - - /** - * Construct a new particle data exception - * - * @param message Message that will be logged - */ - public ParticleDataException(String message) { - super(message); - } - } - - /** - * Represents a runtime exception that is thrown either if the displayed particle effect is not colorable or if the particle color type is incorrect - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.7 - */ - private static final class ParticleColorException extends RuntimeException { - private static final long serialVersionUID = 3203085387160737484L; - - /** - * Construct a new particle color exception - * - * @param message Message that will be logged - */ - public ParticleColorException(String message) { - super(message); - } - } - - /** - * Represents a runtime exception that is thrown if the displayed particle effect requires a newer version - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.6 - */ - private static final class ParticleVersionException extends RuntimeException { - private static final long serialVersionUID = 3203085387160737484L; - - /** - * Construct a new particle version exception - * - * @param message Message that will be logged - */ - public ParticleVersionException(String message) { - super(message); - } - } - - /** - * Represents a particle effect packet with all attributes which is used for sending packets to the players - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.5 - */ - public static final class ParticlePacket { - private static int version; - private static Class enumParticle; - private static Constructor packetConstructor; - private static Method getHandle; - private static Field playerConnection; - private static Method sendPacket; - private static boolean initialized; - private final EffLib effect; - private float offsetX; - private final float offsetY; - private final float offsetZ; - private final float speed; - private final int amount; - private final boolean longDistance; - private final ParticleData data; - private Object packet; - - /** - * Construct a new particle packet - * - * @param effect Particle effect - * @param offsetX Maximum distance particles can fly away from the center on the x-axis - * @param offsetY Maximum distance particles can fly away from the center on the y-axis - * @param offsetZ Maximum distance particles can fly away from the center on the z-axis - * @param speed Display speed of the particles - * @param amount Amount of particles - * @param longDistance Indicates whether the maximum distance is increased from 256 to 65536 - * @param data Data of the effect - * @throws IllegalArgumentException If the speed or amount is lower than 0 - * @see #initialize() - */ - public ParticlePacket(EffLib effect, float offsetX, float offsetY, float offsetZ, float speed, int amount, boolean longDistance, ParticleData data) throws IllegalArgumentException { - initialize(); - if (speed < 0) { - throw new IllegalArgumentException("The speed is lower than 0"); - } - if (amount < 0) { - throw new IllegalArgumentException("The amount is lower than 0"); - } - this.effect = effect; - this.offsetX = offsetX; - this.offsetY = offsetY; - this.offsetZ = offsetZ; - this.speed = speed; - this.amount = amount; - this.longDistance = longDistance; - this.data = data; - } - - /** - * Construct a new particle packet of a single particle flying into a determined direction - * - * @param effect Particle effect - * @param direction Direction of the particle - * @param speed Display speed of the particle - * @param longDistance Indicates whether the maximum distance is increased from 256 to 65536 - * @param data Data of the effect - * @throws IllegalArgumentException If the speed is lower than 0 - */ - public ParticlePacket(EffLib effect, Vector direction, float speed, boolean longDistance, ParticleData data) throws IllegalArgumentException { - this(effect, (float) direction.getX(), (float) direction.getY(), (float) direction.getZ(), speed, 0, longDistance, data); - } - - /** - * Construct a new particle packet of a single colored particle - * - * @param effect Particle effect - * @param color Color of the particle - * @param longDistance Indicates whether the maximum distance is increased from 256 to 65536 - */ - public ParticlePacket(EffLib effect, ParticleColor color, boolean longDistance) { - this(effect, color, 1, 0, longDistance); - } - - /** - * Construct a new particle packet of a single colored particle - * - * @param effect Particle effect - * @param color Color of the particle - * @param speed Display speed of the particle - * @param amount Amount of particles - * @param longDistance Indicates whether the maximum distance is increased from 256 to 65536 - */ - public ParticlePacket(EffLib effect, ParticleColor color, float speed, int amount, boolean longDistance) { - this(effect, color.getValueX(), color.getValueY(), color.getValueZ(), speed, amount, longDistance, null); - if (effect == EffLib.REDSTONE && color instanceof OrdinaryColor && ((OrdinaryColor) color).getRed() == 0) { - offsetX = Float.MIN_NORMAL; - } - } - - /** - * Initializes {@link #packetConstructor}, {@link #getHandle}, {@link #playerConnection} and {@link #sendPacket} and sets {@link #initialized} to true if it succeeds - *

- * Note: These fields only have to be initialized once, so it will return if {@link #initialized} is already set to true - * - * @throws VersionIncompatibleException if your bukkit version is not supported by this library - */ - public static void initialize() throws VersionIncompatibleException { - if (initialized) { - return; - } - try { - version = Integer.valueOf(PackageType.getServerVersion().split("_")[1]); - if (version > 7) { - enumParticle = PackageType.MINECRAFT_SERVER.getClass("EnumParticle"); - } - Class packetClass = PackageType.MINECRAFT_SERVER.getClass(version < 7 ? "Packet63WorldParticles" : "PacketPlayOutWorldParticles"); - packetConstructor = ReflectionUtils.getConstructor(packetClass); - getHandle = ReflectionUtils.getMethod("CraftPlayer", PackageType.CRAFTBUKKIT_ENTITY, "getHandle"); - playerConnection = ReflectionUtils.getField("EntityPlayer", PackageType.MINECRAFT_SERVER, false, "playerConnection"); - sendPacket = ReflectionUtils.getMethod(playerConnection.getType(), "sendPacket", PackageType.MINECRAFT_SERVER.getClass("Packet")); - } catch (Exception exception) { - throw new VersionIncompatibleException("Your current bukkit version seems to be incompatible with this library", exception); - } - initialized = true; - } - - /** - * Returns the version of your server (1.x) - * - * @return The version number - */ - public static int getVersion() { - if (!initialized) { - initialize(); - } - return version; - } - - /** - * Determine if {@link #packetConstructor}, {@link #getHandle}, {@link #playerConnection} and {@link #sendPacket} are initialized - * - * @return Whether these fields are initialized or not - * @see #initialize() - */ - public static boolean isInitialized() { - return initialized; - } - - /** - * Initializes {@link #packet} with all set values - * - * @param center Center location of the effect - * @throws PacketInstantiationException If instantion fails due to an unknown error - */ - private void initializePacket(Location center) throws PacketInstantiationException { - if (packet != null) { - return; - } - try { - packet = packetConstructor.newInstance(); - if (version < 8) { - String name = effect.getName(); - if (data != null) { - name += data.getPacketDataString(); - } - ReflectionUtils.setValue(packet, true, "a", name); - } else { - ReflectionUtils.setValue(packet, true, "a", enumParticle.getEnumConstants()[effect.getId()]); - ReflectionUtils.setValue(packet, true, "j", longDistance); - if (data != null) { - int[] packetData = data.getPacketData(); - ReflectionUtils.setValue(packet, true, "k", effect == EffLib.ITEM_CRACK ? packetData : new int[] {packetData[0] | (packetData[1] << 12)}); - } - } - ReflectionUtils.setValue(packet, true, "b", (float) center.getX()); - ReflectionUtils.setValue(packet, true, "c", (float) center.getY()); - ReflectionUtils.setValue(packet, true, "d", (float) center.getZ()); - ReflectionUtils.setValue(packet, true, "e", offsetX); - ReflectionUtils.setValue(packet, true, "f", offsetY); - ReflectionUtils.setValue(packet, true, "g", offsetZ); - ReflectionUtils.setValue(packet, true, "h", speed); - ReflectionUtils.setValue(packet, true, "i", amount); - } catch (Exception exception) { - throw new PacketInstantiationException("Packet instantiation failed", exception); - } - } - - /** - * Sends the packet to a single player and caches it - * - * @param center Center location of the effect - * @param player Receiver of the packet - * @throws PacketInstantiationException If instantion fails due to an unknown error - * @throws PacketSendingException If sending fails due to an unknown error - * @see #initializePacket(Location) - */ - public void sendTo(Location center, Player player) throws PacketInstantiationException, PacketSendingException { - initializePacket(center); - try { - sendPacket.invoke(playerConnection.get(getHandle.invoke(player)), packet); - } catch (Exception exception) { - throw new PacketSendingException("Failed to send the packet to player '" + player.getName() + "'", exception); - } - } - - /** - * Sends the packet to all players in the list - * - * @param center Center location of the effect - * @param players Receivers of the packet - * @throws IllegalArgumentException If the player list is empty - * @see #sendTo(Location center, Player player) - */ - public void sendTo(Location center, List players) throws IllegalArgumentException { - if (players.isEmpty()) { - throw new IllegalArgumentException("The player list is empty"); - } - for (Player player : players) { - sendTo(center, player); - } - } - - /** - * Sends the packet to all players in a certain range - * - * @param center Center location of the effect - * @param range Range in which players will receive the packet (Maximum range for particles is usually 16, but it can differ for some types) - * @throws IllegalArgumentException If the range is lower than 1 - * @see #sendTo(Location center, Player player) - */ - public void sendTo(Location center, double range) throws IllegalArgumentException { - if (range < 1) { - throw new IllegalArgumentException("The range is lower than 1"); - } - String worldName = center.getWorld().getName(); - double squared = range * range; - for (Player player : Bukkit.getOnlinePlayers()) { - if (!player.getWorld().getName().equals(worldName) || player.getLocation().distanceSquared(center) > squared) { - continue; - } - sendTo(center, player); - } - } - - /** - * Represents a runtime exception that is thrown if a bukkit version is not compatible with this library - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.5 - */ - private static final class VersionIncompatibleException extends RuntimeException { - private static final long serialVersionUID = 3203085387160737484L; - - /** - * Construct a new version incompatible exception - * - * @param message Message that will be logged - * @param cause Cause of the exception - */ - public VersionIncompatibleException(String message, Throwable cause) { - super(message, cause); - } - } - - /** - * Represents a runtime exception that is thrown if packet instantiation fails - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.4 - */ - private static final class PacketInstantiationException extends RuntimeException { - private static final long serialVersionUID = 3203085387160737484L; - - /** - * Construct a new packet instantiation exception - * - * @param message Message that will be logged - * @param cause Cause of the exception - */ - public PacketInstantiationException(String message, Throwable cause) { - super(message, cause); - } - } - - /** - * Represents a runtime exception that is thrown if packet sending fails - *

- * This class is part of the ParticleEffect Library and follows the same usage conditions - * - * @author DarkBlade12 - * @since 1.4 - */ - private static final class PacketSendingException extends RuntimeException { - private static final long serialVersionUID = 3203085387160737484L; - - /** - * Construct a new packet sending exception - * - * @param message Message that will be logged - * @param cause Cause of the exception - */ - public PacketSendingException(String message, Throwable cause) { - super(message, cause); - } - } - } -} \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/particle/pack/ParticleData.java b/src/main/scala/me/skymc/taboolib/particle/pack/ParticleData.java deleted file mode 100644 index 2d16501..0000000 --- a/src/main/scala/me/skymc/taboolib/particle/pack/ParticleData.java +++ /dev/null @@ -1,77 +0,0 @@ -package me.skymc.taboolib.particle.pack; - -import com.ilummc.tlib.util.Strings; -import me.skymc.taboolib.inventory.ItemUtils; -import me.skymc.taboolib.particle.EffLib; -import org.bukkit.Location; -import org.bukkit.util.NumberConversions; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * @Author 坏黑 - * @Since 2019-01-11 17:37 - */ -public class ParticleData { - - private static final Pattern ITEM_PATTERN = Pattern.compile("(\\S+)\\((\\S+):(\\S+)\\)", Pattern.CASE_INSENSITIVE); - - private ParticleType particleType = ParticleType.NORMAL; - private EffLib particle = EffLib.BARRIER; - private EffLib.ParticleData particleData; - private float x = 0; - private float y = 0; - private float z = 0; - private float speed = 0; - private int amount = 0; - - /** - * NORMAL: - * frame-0.1-0.1-0.1-0-10 - * ITEM_CRACK: - * iconcrack(Stone:0)-0.1-0.1-0.1-0-10 - */ - public ParticleData(String str) { - if (!Strings.isEmpty(str)) { - try { - String[] split = str.split("-"); - Matcher matcher = ITEM_PATTERN.matcher(split[0]); - if (matcher.find()) { - particle = EffLib.fromName(matcher.group(1)); - particleType = ParticleType.ITEM; - particleData = isBlockParticle(particle.getName()) ? new EffLib.BlockData(ItemUtils.asMaterial(matcher.group(2).toUpperCase()), NumberConversions.toByte(matcher.group(3))) : new EffLib.ItemData(ItemUtils.asMaterial(matcher.group(2).toUpperCase()), NumberConversions.toByte(matcher.group(3))); - } else { - particle = EffLib.fromName(split[0]); - } - x = NumberConversions.toFloat(split[1]); - y = NumberConversions.toFloat(split[2]); - z = NumberConversions.toFloat(split[3]); - speed = NumberConversions.toFloat(split[4]); - amount = NumberConversions.toInt(split[5]); - } catch (Throwable t) { - t.printStackTrace(); - } - } - } - - public void play(Location location) { - try { - switch (particleType) { - case NORMAL: - particle.display(x, y, z, speed, amount, location, 50); - break; - case ITEM: - particle.display(particleData, x, y, z, speed, amount, location, 50); - break; - default: - } - } catch (Throwable t) { - t.printStackTrace(); - } - } - - private boolean isBlockParticle(String name) { - return name.equalsIgnoreCase("blockdust") || name.equalsIgnoreCase("blockcrack") || name.equalsIgnoreCase("fallingdust"); - } -} diff --git a/src/main/scala/me/skymc/taboolib/particle/pack/ParticlePack.java b/src/main/scala/me/skymc/taboolib/particle/pack/ParticlePack.java deleted file mode 100644 index 6f1212c..0000000 --- a/src/main/scala/me/skymc/taboolib/particle/pack/ParticlePack.java +++ /dev/null @@ -1,40 +0,0 @@ -package me.skymc.taboolib.particle.pack; - -import com.google.common.collect.Lists; -import me.skymc.taboolib.TabooLib; -import org.bukkit.Bukkit; -import org.bukkit.Location; - -import java.util.Arrays; -import java.util.List; - -/** - * @Author 坏黑 - * @Since 2019-01-11 17:35 - */ -public class ParticlePack { - - private List particles = Lists.newArrayList(); - - public ParticlePack(String str) { - Arrays.stream(str.split(";")).forEach(this::add); - } - - public void add(String str) { - particles.add(new ParticleData(str)); - } - - public void play(Location location) { - Bukkit.getScheduler().runTaskAsynchronously(TabooLib.instance(), () -> particles.forEach(p -> p.play(location))); - } - - // ********************************* - // - // Getter and Setter - // - // ********************************* - - public List getParticles() { - return particles; - } -} diff --git a/src/main/scala/me/skymc/taboolib/particle/pack/ParticleType.java b/src/main/scala/me/skymc/taboolib/particle/pack/ParticleType.java deleted file mode 100644 index f98f2cf..0000000 --- a/src/main/scala/me/skymc/taboolib/particle/pack/ParticleType.java +++ /dev/null @@ -1,11 +0,0 @@ -package me.skymc.taboolib.particle.pack; - -/** - * @Author 坏黑 - * @Since 2019-01-11 17:45 - */ -public enum ParticleType { - - NORMAL, ITEM - -} diff --git a/src/main/scala/me/skymc/taboolib/playerdata/DataUtils.java b/src/main/scala/me/skymc/taboolib/playerdata/DataUtils.java deleted file mode 100644 index d5e0abb..0000000 --- a/src/main/scala/me/skymc/taboolib/playerdata/DataUtils.java +++ /dev/null @@ -1,154 +0,0 @@ -package me.skymc.taboolib.playerdata; - -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.database.PlayerDataManager; -import me.skymc.taboolib.exception.PlayerOfflineException; -import me.skymc.taboolib.fileutils.FileUtils; -import me.skymc.taboolib.listener.TListener; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.server.PluginDisableEvent; -import org.bukkit.plugin.Plugin; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.concurrent.ConcurrentHashMap; - -@TListener -public class DataUtils implements Listener { - - public static final ConcurrentHashMap> CACHE_DATA_PLUGIN = new ConcurrentHashMap<>(); - - public static void saveAllCaches(Plugin plugin) { - saveAllCaches(plugin, false); - } - - public static void saveAllCaches(Plugin plugin, boolean remove) { - if (plugin == null || !CACHE_DATA_PLUGIN.containsKey(plugin.getName())) { - return; - } - for (String fileName : CACHE_DATA_PLUGIN.get(plugin.getName()).keySet()) { - saveConfiguration(CACHE_DATA_PLUGIN.get(plugin.getName()).get(fileName), FileUtils.file(getDataSaveFolder(plugin), fileName)); - } - if (remove) { - CACHE_DATA_PLUGIN.remove(plugin.getName()); - } - } - - public static void saveAllCaches() { - saveAllCaches(false); - } - - public static void saveAllCaches(boolean remove) { - long time = System.currentTimeMillis(); - for (String plugin : CACHE_DATA_PLUGIN.keySet()) { - saveAllCaches(getFixedPlugin(plugin), remove); - } - if (!Main.getInst().getConfig().getBoolean("HIDE-NOTIFY")) { - TLocale.Logger.info("DATA-UTILS.SUCCESS-SAVE-DATA", String.valueOf(DataUtils.CACHE_DATA_PLUGIN.size()), String.valueOf(System.currentTimeMillis() - time)); - } - } - - public static void saveConfiguration(FileConfiguration conf, File file) { - try { - conf.save(file); - } catch (IOException e) { - TLocale.Logger.error("DATA-UTILS.FAIL-SAVE-FILE", file.getName(), e.toString()); - } - } - - public static String getFixedFileName(String name) { - return name.contains(".") ? name : name + ".yml"; - } - - public static Plugin getFixedPlugin(String pluginName) { - return Bukkit.getPluginManager().getPlugin(pluginName) == null ? Main.getInst() : Bukkit.getPluginManager().getPlugin(pluginName); - } - - public static File getDataSaveFolder(Plugin plugin) { - return plugin == null || plugin.equals(Main.getInst()) ? Main.getServerDataFolder() : plugin.getDataFolder(); - } - - public static String getDataSaveKey(Plugin plugin) { - return plugin == null || plugin.equals(Main.getInst()) ? Main.getInst().getName() : plugin.getName(); - } - - public static FileConfiguration addPluginData(String name, Plugin plugin) { - return setPluginData(getFixedFileName(name), plugin, YamlConfiguration.loadConfiguration(FileUtils.file(getDataSaveFolder(plugin), getFixedFileName(name)))); - } - - public static FileConfiguration getPluginData(String name, Plugin plugin) { - return !CACHE_DATA_PLUGIN.containsKey(getDataSaveKey(plugin)) ? new YamlConfiguration() : CACHE_DATA_PLUGIN.get(getDataSaveKey(plugin)).get(getFixedFileName(name)); - } - - public static FileConfiguration setPluginData(String name, Plugin plugin, FileConfiguration conf) { - if (!CACHE_DATA_PLUGIN.containsKey(getDataSaveKey(plugin))) { - CACHE_DATA_PLUGIN.put(getDataSaveKey(plugin), new HashMap<>()); - } - CACHE_DATA_PLUGIN.get(getDataSaveKey(plugin)).put(getFixedFileName(name), conf); - return conf; - } - - @Deprecated - public static FileConfiguration getPlayerData(String name) { - try { - return PlayerDataManager.getPlayerData(name, true); - } catch (PlayerOfflineException e) { - return new YamlConfiguration(); - } - } - - @Deprecated - public static FileConfiguration addPlayerData(String name) { - return PlayerDataManager.loadPlayerData(name); - } - - @Deprecated - public static void savePlayerData(String name, boolean remove) { - PlayerDataManager.savePlayerData(name, remove); - } - - @Deprecated - public static FileConfiguration registerServerData(String name) { - return addPluginData(name, null); - } - - @Deprecated - public static FileConfiguration getPlayerData(OfflinePlayer p) { - return getPlayerData(p.getName()); - } - - @Deprecated - public static void setPlayerData(OfflinePlayer p, String s, Object o) { - getPlayerData(p.getName()).set(s, o); - } - - @Deprecated - public static void saveData(OfflinePlayer p) { - saveOnline(p.getName()); - } - - public static Long getOnline(OfflinePlayer p) { - return getPlayerData(p).getLong("TabooLib.Offline"); - } - - public static void saveOnline(String p) { - getPlayerData(p).set("TabooLib.Offline", System.currentTimeMillis()); - } - - @EventHandler - public void disable(PluginDisableEvent e) { - if (e.getPlugin().equals(Main.getInst())) { - return; - } - if (CACHE_DATA_PLUGIN.containsKey(e.getPlugin().getName())) { - saveAllCaches(e.getPlugin(), true); - } - } -} diff --git a/src/main/scala/me/skymc/taboolib/scoreboard/SimpleScoreboard.java b/src/main/scala/me/skymc/taboolib/scoreboard/SimpleScoreboard.java deleted file mode 100644 index 45344f5..0000000 --- a/src/main/scala/me/skymc/taboolib/scoreboard/SimpleScoreboard.java +++ /dev/null @@ -1,216 +0,0 @@ -package me.skymc.taboolib.scoreboard; - -import com.google.common.base.Charsets; -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; -import org.bukkit.scoreboard.*; - -import java.lang.reflect.Constructor; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -public class SimpleScoreboard { - - private static Map cache = new HashMap<>(); - - private Scoreboard scoreboard; - private String title; - private Map scores; - private Objective obj; - private List teams; - private List removed; - private Set updated; - - public SimpleScoreboard(String title) { - this.scoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); - this.title = ChatColor.translateAlternateColorCodes('&', title); - this.scores = new ConcurrentHashMap<>(); - this.teams = Collections.synchronizedList(Lists.newArrayList()); - this.removed = Lists.newArrayList(); - this.updated = Collections.synchronizedSet(new HashSet<>()); - } - - public void add(String text, Integer score) { - text = ChatColor.translateAlternateColorCodes('&', text); - if (remove(score, text, false) || !scores.containsValue(score)) { - updated.add(text); - } - scores.put(text, score); - } - - public boolean remove(Integer score, String text) { - return remove(score, text, true); - } - - public boolean remove(Integer score, String n, boolean b) { - String toRemove = get(score, n); - if (toRemove == null) { - return false; - } - scores.remove(toRemove); - if (b) { - removed.add(score); - } - return true; - } - - public String get(int score, String n) { - String str = null; - for (Map.Entry entry : scores.entrySet()) { - if (entry.getValue().equals(score) && !entry.getKey().equals(n)) { - str = entry.getKey(); - } - } - return str; - } - - private Map.Entry createTeam(String text, int pos) { - Team team; - ChatColor color = ChatColor.values()[pos]; - OfflinePlayer result; - if (!cache.containsKey(color.toString())) { - cache.put(color.toString(), getOfflinePlayerSkipLookup(color.toString())); - } - result = cache.get(color.toString()); - try { - team = scoreboard.registerNewTeam("text-" + (teams.size() + 1)); - } catch (IllegalArgumentException e) { - team = scoreboard.getTeam("text-" + (teams.size())); - } - applyText(team, text, result); - - teams.add(team); - return new AbstractMap.SimpleEntry<>(team, result); - } - - private void applyText(Team team, String text, OfflinePlayer result) { - Iterator iterator = Splitter.fixedLength(16).split(text).iterator(); - String prefix = iterator.next(); - team.setPrefix(prefix); - if (!team.hasPlayer(result)) { - team.addPlayer(result); - } - if (text.length() > 16) { - String prefixColor = ChatColor.getLastColors(prefix); - String suffix = iterator.next(); - if (prefix.endsWith(String.valueOf(ChatColor.COLOR_CHAR))) { - prefix = prefix.substring(0, prefix.length() - 1); - team.setPrefix(prefix); - prefixColor = ChatColor.getByChar(suffix.charAt(0)).toString(); - suffix = suffix.substring(1); - } - if (prefixColor == null) { - prefixColor = ""; - } - if (suffix.length() > 16) { - // cut off suffix, done if text is over 30 characters - suffix = suffix.substring(0, (13 - prefixColor.length())); - } - team.setSuffix((prefixColor.equals("") ? ChatColor.RESET : prefixColor) + suffix); - } - } - - public void update() { - if (updated.isEmpty()) { - return; - } - if (obj == null) { - obj = scoreboard.registerNewObjective((title.length() > 16 ? title.substring(0, 15) : title), "dummy"); - obj.setDisplayName(title); - obj.setDisplaySlot(DisplaySlot.SIDEBAR); - } - removed.forEach((remove) -> { - for (String s : scoreboard.getEntries()) { - Score score = obj.getScore(s); - if (score == null) { - continue; - } - if (score.getScore() != remove) { - continue; - } - scoreboard.resetScores(s); - } - }); - removed.clear(); - int index = scores.size(); - for (Map.Entry text : scores.entrySet()) { - Team t = scoreboard.getTeam(ChatColor.values()[text.getValue()].toString()); - Map.Entry team; - if (!updated.contains(text.getKey())) { - continue; - } - if (t != null) { - String color = ChatColor.values()[text.getValue()].toString(); - if (!cache.containsKey(color)) { - cache.put(color, getOfflinePlayerSkipLookup(color)); - } - team = new AbstractMap.SimpleEntry<>(t, cache.get(color)); - applyText(team.getKey(), text.getKey(), team.getValue()); - index -= 1; - continue; - } else { - team = createTeam(text.getKey(), text.getValue()); - } - Integer score = text.getValue() != null ? text.getValue() : index; - obj.getScore(team.getValue()).setScore(score); - index -= 1; - } - updated.clear(); - } - - public void setTitle(String title) { - this.title = ChatColor.translateAlternateColorCodes('&', title); - if (obj != null) { - obj.setDisplayName(this.title); - } - } - - public void reset() { - teams.forEach(Team::unregister); - teams.clear(); - scores.clear(); - } - - public Scoreboard getScoreboard() { - return scoreboard; - } - - public void send(Player... players) { - Arrays.stream(players).forEach(p -> p.setScoreboard(scoreboard)); - } - - private final UUID invalidUserUUID = UUID.nameUUIDFromBytes("InvalidUsername".getBytes(Charsets.UTF_8)); - private Class gameProfileClass; - private Constructor gameProfileConstructor; - private Constructor craftOfflinePlayerConstructor; - - @SuppressWarnings("deprecation") - private OfflinePlayer getOfflinePlayerSkipLookup(String name) { - try { - if (gameProfileConstructor == null) { - try { // 1.7 - gameProfileClass = Class.forName("net.minecraft.util.com.mojang.authlib.GameProfile"); - } catch (ClassNotFoundException e) { // 1.8 - gameProfileClass = Class.forName("com.mojang.authlib.GameProfile"); - } - gameProfileConstructor = gameProfileClass.getDeclaredConstructor(UUID.class, String.class); - gameProfileConstructor.setAccessible(true); - } - if (craftOfflinePlayerConstructor == null) { - Class serverClass = Bukkit.getServer().getClass(); - Class craftOfflinePlayerClass = Class.forName(serverClass.getName().replace("CraftServer", "CraftOfflinePlayer")); - craftOfflinePlayerConstructor = craftOfflinePlayerClass.getDeclaredConstructor(serverClass, gameProfileClass); - craftOfflinePlayerConstructor.setAccessible(true); - } - Object gameProfile = gameProfileConstructor.newInstance(invalidUserUUID, name); - Object craftOfflinePlayer = craftOfflinePlayerConstructor.newInstance(Bukkit.getServer(), gameProfile); - return (OfflinePlayer) craftOfflinePlayer; - } catch (Throwable t) { - return Bukkit.getOfflinePlayer(name); - } - } -} diff --git a/src/main/scala/me/skymc/taboolib/sound/SoundPack.java b/src/main/scala/me/skymc/taboolib/sound/SoundPack.java deleted file mode 100644 index 255914c..0000000 --- a/src/main/scala/me/skymc/taboolib/sound/SoundPack.java +++ /dev/null @@ -1,94 +0,0 @@ -package me.skymc.taboolib.sound; - -import me.skymc.taboolib.TabooLib; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Sound; -import org.bukkit.entity.Player; - -public class SoundPack { - - private Sound sound; - private Float a; - private Float b; - private int delay; - - /** - * ENTITY_VILLAGER_NO-0-0 - */ - public SoundPack() { - this.sound = Sound.valueOf(SoundUtils.getModifiedSound("ENTITY_VILLAGER_NO")); - this.a = 1.0F; - this.b = 1.0F; - } - - public SoundPack(Sound sound, float a, float b) { - this(sound, a, b, 0); - } - - public SoundPack(Sound sound, float a, float b, int delay) { - this.sound = sound; - this.a = a; - this.b = b; - this.delay = delay; - } - - public SoundPack(String s) { - parse(s); - } - - public void play(Player p) { - Bukkit.getScheduler().runTaskLater(TabooLib.instance(), () -> p.playSound(p.getLocation(), this.sound, this.a, this.b), delay); - } - - public void play(Location l) { - Bukkit.getScheduler().runTaskLater(TabooLib.instance(), () -> l.getWorld().playSound(l, this.sound, this.a, this.b), delay); - } - - public void parse(String s) { - try { - String[] split = s.split("-"); - this.sound = Sound.valueOf(SoundUtils.getModifiedSound(split[0])); - this.a = Float.parseFloat(split[1]); - this.b = Float.parseFloat(split[2]); - this.delay = split.length > 3 ? Integer.parseInt(split[3]) : 0; - } catch (Exception var3) { - this.sound = Sound.valueOf(SoundUtils.getModifiedSound("ENTITY_VILLAGER_NO")); - this.a = 1.0F; - this.b = 1.0F; - this.delay = 0; - } - } - - // ********************************* - // - // Getter and Setter - // - // ********************************* - - public Sound getSound() { - return sound; - } - - public Float getA() { - return a; - } - - public Float getB() { - return b; - } - - public int getDelay() { - return delay; - } - - @Override - public String toString() { - return "SoundPack{" + - "sound=" + sound + - ", a=" + a + - ", b=" + b + - ", delay=" + delay + - '}'; - } -} diff --git a/src/main/scala/me/skymc/taboolib/sound/SoundUtils.java b/src/main/scala/me/skymc/taboolib/sound/SoundUtils.java deleted file mode 100644 index 2c51e12..0000000 --- a/src/main/scala/me/skymc/taboolib/sound/SoundUtils.java +++ /dev/null @@ -1,43 +0,0 @@ -package me.skymc.taboolib.sound; - -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.message.MsgUtils; -import org.bukkit.Location; -import org.bukkit.Sound; - -public class SoundUtils { - - public static void sound(Location paramLocation, String paramString, float paramFloat1, float paramFloat2) { - String str = getModifiedSound(paramString); - try { - paramLocation.getWorld().playSound(paramLocation, Sound.valueOf(str), paramFloat1, paramFloat2); - } catch (Exception localException) { - MsgUtils.send("§4Bug with " + paramString + ". No such sound found. Please report it to the plugin creator :)"); - } - } - - public static String getModifiedSound(String str) { - if (TabooLib.getVerint() < 10900) { - str = str.replace("BLOCK_FIRE_EXTINGUISH", "FIZZ"); - str = str.replace("BLOCK_NOTE_HAT", "NOTE_STICKS"); - str = str.replace("ENTITY_SHEEP_DEATH", "SHEEP_IDLE"); - str = str.replace("ENTITY_LLAMA_ANGRY", "HORSE_HIT"); - str = str.replace("BLOCK_BREWING_STAND_BREW", "CREEPER_HISS"); - str = str.replace("ENTITY_SHULKER_TELEPORT", "ENDERMAN_TELEPORT"); - str = str.replace("ENTITY_ZOMBIE_ATTACK_IRON_DOOR", "ZOMBIE_METAL"); - str = str.replace("BLOCK_GRAVEL_BREAK", "DIG_GRAVEL"); - str = str.replace("BLOCK_SNOW_BREAK", "DIG_SNOW"); - str = str.replace("BLOCK_GRAVEL_BREAK", "DIG_GRAVEL"); - str = str.replace("ENTITY_PLAYER_LEVELUP", "LEVEL_UP"); - str = str.replace("ENTITY_SNOWBALL_THROW", "SHOOT_ARROW"); - str = str.replace("PLAYER_ATTACK_CRIT", "ITEM_BREAK"); - str = str.replace("ENDERMEN", "ENDERMAN"); - str = str.replace("ARROW_SHOOT", "SHOOT_ARROW"); - str = str.replace("ENDERMAN_HURT", "ENDERMAN_HIT"); - str = str.replace("BLAZE_HURT", "BLAZE_HIT"); - str = str.replace("_FLAP", "_WINGS"); - str = str.replaceAll("ENTITY_|GENERIC_|BLOCK_|_AMBIENT|_BREAK|UI_BUTTON_|EXPERIENCE_", ""); - } - return str; - } -} diff --git a/src/main/scala/me/skymc/taboolib/update/UpdateTask.java b/src/main/scala/me/skymc/taboolib/update/UpdateTask.java deleted file mode 100644 index be4bba4..0000000 --- a/src/main/scala/me/skymc/taboolib/update/UpdateTask.java +++ /dev/null @@ -1,136 +0,0 @@ -package me.skymc.taboolib.update; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.ilummc.tlib.resources.TLocale; -import me.skymc.taboolib.Main; -import me.skymc.taboolib.TabooLib; -import me.skymc.taboolib.common.schedule.TSchedule; -import me.skymc.taboolib.fileutils.FileUtils; -import me.skymc.taboolib.player.PlayerUtils; -import me.skymc.taboolib.plugin.PluginUtils; -import org.bukkit.Bukkit; - -import java.io.*; - -/** - * @author sky - * @since 2018年2月23日 下午10:39:14 - */ -public class UpdateTask { - - private static double newVersion = 0; - private static double length = -1; - private static int updateLocationUsing; - private static String[][] updateLocation = { - { - "https://api.github.com/repos/Bkm016/TabooLib/releases", - "https://github.com/Bkm016/TabooLib/releases/download/?/TabooLib-?.jar" - }, - { - "https://gitee.com/bkm016/TabooLibCloud/raw/master/release.json", - "https://gitee.com/bkm016/TabooLibCloud/raw/master/core/TabooLib.jar" - } - }; - - @TSchedule(async = true, delay = 100, period = 20 * 60 * 60 * 6) - static void update() { - if (!Main.getInst().getConfig().getBoolean("UPDATE-CHECK", true)) { - return; - } - for (int i = 0; i < updateLocation.length; i++) { - String[] location = updateLocation[i]; - String value = FileUtils.getStringFromURL(location[0], null); - if (value == null) { - continue; - } - JsonElement json = new JsonParser().parse(value); - if (json.isJsonArray()) { - JsonObject releaseData = json.getAsJsonArray().get(0).getAsJsonObject(); - updateLocationUsing = i; - newVersion = releaseData.get("tag_name").getAsDouble(); - // 获取文件长度 - for (JsonElement assetData : releaseData.getAsJsonArray("assets")) { - if (assetData instanceof JsonObject && ((JsonObject) assetData).get("name").getAsString().equals("TabooLib-" + newVersion + ".jar")) { - length = ((JsonObject) assetData).get("size").getAsInt(); - } - } - if (TabooLib.getPluginVersion() >= newVersion) { - TLocale.Logger.info("UPDATETASK.VERSION-LATEST"); - } else { - TLocale.Logger.info("UPDATETASK.VERSION-OUTDATED", String.valueOf(TabooLib.getPluginVersion()), String.valueOf(newVersion)); - // 是否启用启动下载 - if (Main.getInst().getConfig().getBoolean("UPDATE-DOWNLOAD", false)) { - Bukkit.getScheduler().runTask(TabooLib.instance(), () -> updatePlugin(true, false)); - } - } - return; - } - } - TLocale.Logger.error("UPDATETASK.VERSION-FAIL"); - } - - public static boolean isHaveUpdate() { - return newVersion > TabooLib.getPluginVersion(); - } - - public static double getNewVersion() { - return newVersion; - } - - public static int getUpdateLocationUsing() { - return updateLocationUsing; - } - - public static String[][] getUpdateLocation() { - return updateLocation; - } - - public static void updatePlugin(boolean shutdown, boolean force) { - File pluginFile = PluginUtils.getPluginFile(Main.getInst()); - if (pluginFile == null) { - TLocale.Logger.info("COMMANDS.TABOOLIB.UPDATEPLUGIN.FILE-NOT-FOUND"); - return; - } - if (!UpdateTask.isHaveUpdate() && (newVersion == 0 || !force)) { - TLocale.Logger.info("COMMANDS.TABOOLIB.UPDATEPLUGIN.UPDATE-NOT-FOUND"); - return; - } - if (length < 0) { - TLocale.Logger.error("COMMANDS.TABOOLIB.UPDATEPLUGIN.UPDATE-NOT-FOUND-SIZE"); - return; - } - if (PlayerUtils.getOnlinePlayers().size() > 0) { - TLocale.Logger.info("COMMANDS.TABOOLIB.UPDATEPLUGIN.PLAYER-ONLINE"); - return; - } - // 创建临时文件 - File tempFile = new File(Main.getInst().getDataFolder(), "update" + File.separator + "TabooLib-" + newVersion + ".jar"); - FileUtils.createNewFileAndPath(tempFile); - Bukkit.getScheduler().runTaskAsynchronously(TabooLib.instance(), () -> { - FileUtils.download(updateLocation[updateLocationUsing][1].replace("?", String.valueOf(newVersion)), tempFile); - // 判断文件长度是否与标准长度相同 - if (tempFile.length() != length) { - TLocale.Logger.error("COMMANDS.TABOOLIB.UPDATEPLUGIN.UPDATE-FAILED"); - } else { - // 覆盖插件文件 - byte[] buf = new byte[1024]; - int len; - try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(tempFile)); BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(pluginFile))) { - while ((len = inputStream.read(buf)) > 0) { - outputStream.write(buf, 0, len); - } - outputStream.flush(); - } catch (Throwable t) { - t.printStackTrace(); - return; - } - TLocale.Logger.info("COMMANDS.TABOOLIB.UPDATEPLUGIN.UPDATE-SUCCESS"); - if (shutdown) { - Bukkit.shutdown(); - } - } - }); - } -}