├── .gitignore ├── LICENSE ├── NexEngine ├── pom.xml └── src │ └── main │ ├── java │ ├── org │ │ └── jetbrains │ │ │ └── annotations │ │ │ ├── NotNull.java │ │ │ └── Nullable.java │ └── su │ │ └── nexmedia │ │ └── engine │ │ ├── NexEngine.java │ │ ├── NexPlugin.java │ │ ├── Version.java │ │ ├── api │ │ ├── command │ │ │ ├── AbstractCommand.java │ │ │ ├── CommandFlag.java │ │ │ ├── CommandResult.java │ │ │ └── GeneralCommand.java │ │ ├── config │ │ │ ├── JOption.java │ │ │ └── JYML.java │ │ ├── data │ │ │ ├── AbstractDataHandler.java │ │ │ ├── AbstractUser.java │ │ │ ├── AbstractUserDataHandler.java │ │ │ ├── AbstractUserManager.java │ │ │ ├── StorageType.java │ │ │ ├── UserDataHolder.java │ │ │ ├── config │ │ │ │ └── DataConfig.java │ │ │ ├── connection │ │ │ │ ├── AbstractDataConnector.java │ │ │ │ ├── ConnectorMySQL.java │ │ │ │ └── ConnectorSQLite.java │ │ │ ├── serialize │ │ │ │ └── ItemStackSerializer.java │ │ │ ├── sql │ │ │ │ ├── SQLColumn.java │ │ │ │ ├── SQLCondition.java │ │ │ │ ├── SQLExecutor.java │ │ │ │ ├── SQLQueries.java │ │ │ │ ├── SQLValue.java │ │ │ │ ├── column │ │ │ │ │ ├── ColumnFormer.java │ │ │ │ │ └── ColumnType.java │ │ │ │ └── executor │ │ │ │ │ ├── AlterTableExecutor.java │ │ │ │ │ ├── CreateTableExecutor.java │ │ │ │ │ ├── DeleteQueryExecutor.java │ │ │ │ │ ├── InsertQueryExecutor.java │ │ │ │ │ ├── RenameTableExecutor.java │ │ │ │ │ ├── SelectQueryExecutor.java │ │ │ │ │ └── UpdateQueryExecutor.java │ │ │ └── task │ │ │ │ ├── DataSaveTask.java │ │ │ │ └── DataSynchronizationTask.java │ │ ├── editor │ │ │ ├── EditorLocale.java │ │ │ ├── EditorLocales.java │ │ │ ├── InputHandler.java │ │ │ └── InputWrapper.java │ │ ├── lang │ │ │ ├── LangKey.java │ │ │ └── LangMessage.java │ │ ├── manager │ │ │ ├── AbstractConfigHolder.java │ │ │ ├── AbstractListener.java │ │ │ ├── AbstractManager.java │ │ │ └── EventListener.java │ │ ├── menu │ │ │ ├── AutoPaged.java │ │ │ ├── MenuItemType.java │ │ │ ├── click │ │ │ │ ├── ClickHandler.java │ │ │ │ ├── ClickType.java │ │ │ │ └── ItemClick.java │ │ │ ├── impl │ │ │ │ ├── ConfigMenu.java │ │ │ │ ├── EditorMenu.java │ │ │ │ ├── Menu.java │ │ │ │ ├── MenuListener.java │ │ │ │ ├── MenuOptions.java │ │ │ │ ├── MenuRefreshTask.java │ │ │ │ └── MenuViewer.java │ │ │ ├── item │ │ │ │ ├── ItemOptions.java │ │ │ │ └── MenuItem.java │ │ │ └── link │ │ │ │ ├── Linked.java │ │ │ │ └── ViewLink.java │ │ ├── placeholder │ │ │ ├── Placeholder.java │ │ │ └── PlaceholderMap.java │ │ └── server │ │ │ ├── AbstractTask.java │ │ │ └── JPermission.java │ │ ├── command │ │ ├── CommandManager.java │ │ ├── CommandRegister.java │ │ ├── PluginMainCommand.java │ │ └── list │ │ │ ├── CheckPermCommand.java │ │ │ ├── HelpSubCommand.java │ │ │ └── ReloadSubCommand.java │ │ ├── config │ │ ├── ConfigManager.java │ │ ├── EngineConfig.java │ │ └── EnginePerms.java │ │ ├── editor │ │ ├── EditorListener.java │ │ └── EditorManager.java │ │ ├── integration │ │ └── VaultHook.java │ │ ├── lang │ │ ├── EngineLang.java │ │ └── LangManager.java │ │ └── utils │ │ ├── ArrayUtil.java │ │ ├── CollectionsUtil.java │ │ ├── Colorizer.java │ │ ├── Colors.java │ │ ├── Colors2.java │ │ ├── EngineUtils.java │ │ ├── EntityUtil.java │ │ ├── Evaluator.java │ │ ├── FileUtil.java │ │ ├── ItemReplacer.java │ │ ├── ItemUtil.java │ │ ├── LocationUtil.java │ │ ├── NumberUtil.java │ │ ├── PDCUtil.java │ │ ├── Pair.java │ │ ├── Placeholders.java │ │ ├── PlayerRankMap.java │ │ ├── PlayerUtil.java │ │ ├── Reflex.java │ │ ├── ResourceExtractor.java │ │ ├── Scaler.java │ │ ├── StringUtil.java │ │ ├── TimeUtil.java │ │ ├── TriFunction.java │ │ ├── blocktracker │ │ ├── PlayerBlockTracker.java │ │ ├── TrackListener.java │ │ ├── TrackUtil.java │ │ ├── TrackedChunk.java │ │ └── TrackedWorld.java │ │ ├── message │ │ ├── NexComponent.java │ │ ├── NexMessage.java │ │ └── NexParser.java │ │ ├── random │ │ ├── MTRandom.java │ │ └── Rnd.java │ │ ├── regex │ │ ├── MatcherTimeoutException.java │ │ ├── RegexUtil.java │ │ ├── TimedMatcher.java │ │ └── TimeoutCharSequence.java │ │ └── values │ │ ├── UniDouble.java │ │ ├── UniInt.java │ │ ├── UniParticle.java │ │ ├── UniSound.java │ │ └── UniTask.java │ └── resources │ ├── config.yml │ ├── lang │ ├── messages_cn.yml │ └── messages_ru.yml │ └── plugin.yml ├── README.md ├── assets ├── cn.yml ├── cz.yml ├── de.yml ├── en.yml ├── es.yml ├── fr.yml ├── pt_br.yml └── ru.yml └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /pom.xml.versionsBackup 3 | /NexEngine.jar 4 | /NexEngine/target/ 5 | /NexEngine/pom.xml.versionsBackup -------------------------------------------------------------------------------- /NexEngine/src/main/java/org/jetbrains/annotations/NotNull.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2000-2012 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.jetbrains.annotations; 18 | 19 | import java.lang.annotation.*; 20 | 21 | /** 22 | * An element annotated with NotNull claims {@code null} value is 23 | * forbidden to return (for methods), pass to (parameters) and hold 24 | * (local variables and fields). Apart from documentation purposes this 25 | * annotation is intended to be used by static analysis tools to validate 26 | * against probable runtime errors and element contract violations. 27 | * 28 | * @author max 29 | */ 30 | @Documented 31 | @Retention(RetentionPolicy.CLASS) 32 | @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE}) 33 | public @interface NotNull { 34 | 35 | /** 36 | * @return Custom exception message 37 | */ 38 | String value() default ""; 39 | 40 | /** 41 | * @return Custom exception type that should be thrown when not-nullity contract 42 | * is violated. The exception class should have a constructor with one 43 | * String argument (message). 44 | *

45 | * By default, {@link IllegalArgumentException} is thrown on null method 46 | * arguments and {@link IllegalStateException} — on null return 47 | * value. 48 | */ 49 | Class exception() default Exception.class; 50 | } 51 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/org/jetbrains/annotations/Nullable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2000-2014 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | package org.jetbrains.annotations; 18 | 19 | import java.lang.annotation.*; 20 | 21 | /** 22 | * An element annotated with {@link Nullable} claims {@code null} value is 23 | * perfectly valid to return (for methods), pass to (parameters) or 24 | * hold in (local variables and fields). Apart from documentation purposes this 25 | * annotation is intended to be used by static analysis tools to validate 26 | * against probable runtime errors or element contract violations.
27 | * By convention, this annotation applied only when the value should 28 | * always be checked against {@code null} because the developer could 29 | * do nothing to prevent null from happening. Otherwise, too eager 30 | * {@link Nullable} usage could lead to too many false positives from static 31 | * analysis tools.
32 | * For example, {@link java.util.Map#get(Object key)} should not be 33 | * annotated {@link Nullable} because someone may have put not-null value in the 34 | * map by this key and is expecting to find this value there ever since.
35 | * On the other hand, the {@link java.lang.ref.Reference#get()} should be 36 | * annotated {@link Nullable} because it returns {@code null} if object got 37 | * collected which can happen at any time completely unexpectedly. 38 | * 39 | * @author max 40 | */ 41 | @Documented 42 | @Retention(RetentionPolicy.CLASS) 43 | @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE}) 44 | public @interface Nullable { 45 | 46 | String value() default ""; 47 | } 48 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/NexEngine.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.command.GeneralCommand; 5 | import su.nexmedia.engine.api.editor.EditorLocales; 6 | import su.nexmedia.engine.api.menu.impl.MenuListener; 7 | import su.nexmedia.engine.api.menu.impl.MenuRefreshTask; 8 | import su.nexmedia.engine.command.list.CheckPermCommand; 9 | import su.nexmedia.engine.command.list.ReloadSubCommand; 10 | import su.nexmedia.engine.config.EngineConfig; 11 | import su.nexmedia.engine.editor.EditorManager; 12 | import su.nexmedia.engine.integration.VaultHook; 13 | import su.nexmedia.engine.lang.EngineLang; 14 | import su.nexmedia.engine.utils.EngineUtils; 15 | import su.nexmedia.engine.utils.Placeholders; 16 | import su.nexmedia.engine.utils.blocktracker.PlayerBlockTracker; 17 | 18 | import java.util.HashSet; 19 | import java.util.Set; 20 | 21 | public class NexEngine extends NexPlugin { 22 | 23 | private final Set> childrens = new HashSet<>(); 24 | 25 | private EditorManager editorManager; 26 | private MenuListener menuListener; 27 | private MenuRefreshTask menuRefreshTask; 28 | 29 | @Override 30 | @NotNull 31 | protected NexEngine getSelf() { 32 | return this; 33 | } 34 | 35 | @Override 36 | public void enable() { 37 | this.menuListener = new MenuListener(this); 38 | this.menuListener.registerListeners(); 39 | 40 | this.menuRefreshTask = new MenuRefreshTask(this); 41 | this.menuRefreshTask.start(); 42 | 43 | this.editorManager = new EditorManager(this); 44 | this.editorManager.setup(); 45 | } 46 | 47 | @Override 48 | public void disable() { 49 | if (this.editorManager != null) this.editorManager.shutdown(); 50 | if (this.menuListener != null) this.menuListener.unregisterListeners(); 51 | if (this.menuRefreshTask != null) this.menuRefreshTask.stop(); 52 | 53 | if (EngineUtils.hasVault()) { 54 | VaultHook.shutdown(); 55 | } 56 | PlayerBlockTracker.shutdown(); 57 | } 58 | 59 | @Override 60 | public void registerHooks() { 61 | if (EngineUtils.hasVault()) { 62 | VaultHook.setup(); 63 | } 64 | } 65 | 66 | @Override 67 | public void registerCommands(@NotNull GeneralCommand mainCommand) { 68 | mainCommand.addChildren(new ReloadSubCommand<>(this, Placeholders.WILDCARD)); 69 | 70 | if (EngineUtils.hasVault() && VaultHook.hasPermissions()) { 71 | mainCommand.addChildren(new CheckPermCommand(this)); 72 | } 73 | } 74 | 75 | @Override 76 | public void registerPermissions() { 77 | 78 | } 79 | 80 | @Override 81 | public void loadConfig() { 82 | this.getConfig().initializeOptions(EngineConfig.class); 83 | } 84 | 85 | @Override 86 | public void loadLang() { 87 | this.getLangManager().loadMissing(EngineLang.class); 88 | this.getLangManager().loadEditor(EditorLocales.class); 89 | this.getLang().saveChanges(); 90 | } 91 | 92 | void addChildren(@NotNull NexPlugin child) { 93 | this.childrens.add(child); 94 | child.info("Powered by: " + this.getName()); 95 | } 96 | 97 | @NotNull 98 | public Set> getChildrens() { 99 | return this.childrens; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/Version.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.jetbrains.annotations.NotNull; 5 | import su.nexmedia.engine.utils.StringUtil; 6 | 7 | public enum Version { 8 | 9 | // KEEP VERSIONS LIST FROM SMALLER TO GREATER 10 | V1_17_R1("1.17.1", true), 11 | V1_18_R2("1.18.2"), 12 | @Deprecated V1_19_R1("1.19.2", true), 13 | @Deprecated V1_19_R2("1.19.3", true), 14 | V1_19_R3("1.19.4"), 15 | V1_20_R1("1.20.1", true), 16 | V1_20_R2("1.20.2"), 17 | V1_20_R3("1.20.4"), 18 | UNKNOWN("Unknown", true), 19 | // API-Version in plugin.yml won't allow to load this on lower version, so 20 | // assume any other version not listed here is newer one. 21 | ; 22 | 23 | private static Version current; 24 | 25 | private final boolean deprecated; 26 | private final String localized; 27 | 28 | Version(@NotNull String localized) { 29 | this(localized, false); 30 | } 31 | 32 | Version(@NotNull String localized, boolean deprecated) { 33 | this.localized = localized; 34 | this.deprecated = deprecated; 35 | } 36 | 37 | @NotNull 38 | public static String getProtocol() { 39 | String[] split = Bukkit.getServer().getClass().getPackage().getName().split("\\."); 40 | return split[split.length - 1]; 41 | } 42 | 43 | @NotNull 44 | public static Version getCurrent() { 45 | if (current == null) { 46 | current = StringUtil.getEnum(getProtocol(), Version.class).orElse(UNKNOWN); 47 | } 48 | return current; 49 | } 50 | 51 | public boolean isDeprecated() { 52 | return deprecated; 53 | } 54 | 55 | @NotNull 56 | public String getLocalized() { 57 | return localized; 58 | } 59 | 60 | public boolean isLower(@NotNull Version version) { 61 | return this.ordinal() < version.ordinal(); 62 | } 63 | 64 | public boolean isHigher(@NotNull Version version) { 65 | return this.ordinal() > version.ordinal(); 66 | } 67 | 68 | public static boolean isAtLeast(@NotNull Version version) { 69 | return version.isCurrent() || getCurrent().isHigher(version); 70 | } 71 | 72 | public static boolean isAbove(@NotNull Version version) { 73 | return getCurrent().isHigher(version); 74 | } 75 | 76 | public static boolean isBehind(@NotNull Version version) { 77 | return getCurrent().isLower(version); 78 | } 79 | 80 | public boolean isCurrent() { 81 | return this == Version.getCurrent(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/command/CommandFlag.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.command; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.World; 5 | import org.jetbrains.annotations.NotNull; 6 | import su.nexmedia.engine.utils.Colorizer; 7 | import su.nexmedia.engine.utils.StringUtil; 8 | 9 | import java.util.function.Function; 10 | import java.util.regex.Pattern; 11 | 12 | public class CommandFlag { 13 | 14 | private final String name; 15 | private final Pattern pattern; 16 | private final Function parser; 17 | 18 | public CommandFlag(@NotNull String name, @NotNull Function parser) { 19 | this.name = name; 20 | this.pattern = Pattern.compile("-" + name + "(\\s|$)([^-]*)"); 21 | this.parser = parser; 22 | } 23 | 24 | @NotNull 25 | public static CommandFlag worldFlag(@NotNull String name) { 26 | return new CommandFlag<>(name, Bukkit::getWorld); 27 | } 28 | 29 | @NotNull 30 | public static CommandFlag stringFlag(@NotNull String name) { 31 | return new CommandFlag<>(name, Function.identity()); 32 | } 33 | 34 | @NotNull 35 | public static CommandFlag textFlag(@NotNull String name) { 36 | return new CommandFlag<>(name, Colorizer::apply); 37 | } 38 | 39 | @NotNull 40 | public static CommandFlag intFlag(@NotNull String name) { 41 | return new CommandFlag<>(name, str -> StringUtil.getInteger(str, 0, true)); 42 | } 43 | 44 | @NotNull 45 | public static CommandFlag doubleFlag(@NotNull String name) { 46 | return new CommandFlag<>(name, str -> StringUtil.getDouble(str, 0, true)); 47 | } 48 | 49 | @NotNull 50 | public static CommandFlag booleanFlag(@NotNull String name) { 51 | return new CommandFlag<>(name, str -> true); 52 | } 53 | 54 | @NotNull 55 | public String getName() { 56 | return name; 57 | } 58 | 59 | @NotNull 60 | public String getNamePrefixed() { 61 | return "-" + name; 62 | } 63 | 64 | @NotNull 65 | public Pattern getPattern() { 66 | return pattern; 67 | } 68 | 69 | @NotNull 70 | public Function getParser() { 71 | return parser; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/command/CommandResult.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.command; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | import su.nexmedia.engine.utils.StringUtil; 6 | 7 | import java.util.Map; 8 | 9 | public class CommandResult { 10 | 11 | private final String label; 12 | private final Map, String> flags; 13 | 14 | private String[] args; 15 | 16 | public CommandResult(@NotNull String label, String[] args, @NotNull Map, String> flags) { 17 | this.label = label; 18 | this.flags = flags; 19 | this.setArgs(args); 20 | } 21 | 22 | public int length() { 23 | return this.args.length; 24 | } 25 | 26 | public void setArgs(@NotNull String[] args) { 27 | this.args = args; 28 | } 29 | 30 | @NotNull 31 | public String getArg(int index) { 32 | return this.getArgs()[index]; 33 | } 34 | 35 | @NotNull 36 | public String getArg(int index, @NotNull String def) { 37 | if (index >= this.length()) return def; 38 | 39 | return this.getArgs()[index]; 40 | } 41 | 42 | public int getInt(int index, int def) { 43 | return StringUtil.getInteger(this.getArg(index, ""), def, true); 44 | } 45 | 46 | public double getDouble(int index, double def) { 47 | return StringUtil.getDouble(this.getArg(index, ""), def, true); 48 | } 49 | 50 | public boolean hasFlag(@NotNull CommandFlag flag) { 51 | return this.getFlags().containsKey(flag); 52 | } 53 | 54 | @Nullable 55 | public T getFlag(@NotNull CommandFlag flag) { 56 | String value = this.getFlags().get(flag); 57 | if (value == null) return null; 58 | 59 | return flag.getParser().apply(value); 60 | } 61 | 62 | @NotNull 63 | public T getFlag(@NotNull CommandFlag flag, @NotNull T def) { 64 | T value = this.getFlag(flag); 65 | return value == null ? def : value; 66 | } 67 | 68 | @NotNull 69 | public String getLabel() { 70 | return label; 71 | } 72 | 73 | public String[] getArgs() { 74 | return args; 75 | } 76 | 77 | @NotNull 78 | public Map, String> getFlags() { 79 | return flags; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/command/GeneralCommand.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.command; 2 | 3 | import org.bukkit.command.Command; 4 | import org.bukkit.command.CommandExecutor; 5 | import org.bukkit.command.CommandSender; 6 | import org.bukkit.command.TabExecutor; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.permissions.Permission; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | import su.nexmedia.engine.NexPlugin; 12 | import su.nexmedia.engine.utils.StringUtil; 13 | 14 | import java.util.ArrayList; 15 | import java.util.Arrays; 16 | import java.util.Collections; 17 | import java.util.List; 18 | 19 | public abstract class GeneralCommand

> extends AbstractCommand

implements CommandExecutor, TabExecutor { 20 | 21 | private Command fallback; 22 | private AbstractCommand

defaultCommand; 23 | 24 | public GeneralCommand(@NotNull P plugin, @NotNull List aliases) { 25 | this(plugin, aliases.toArray(new String[0])); 26 | } 27 | 28 | public GeneralCommand(@NotNull P plugin, @NotNull String[] aliases) { 29 | this(plugin, aliases, (String) null); 30 | } 31 | 32 | public GeneralCommand(@NotNull P plugin, @NotNull List aliases, @Nullable String permission) { 33 | this(plugin, aliases.toArray(new String[0]), permission); 34 | } 35 | 36 | public GeneralCommand(@NotNull P plugin, @NotNull List aliases, @Nullable Permission permission) { 37 | this(plugin, aliases.toArray(new String[0]), permission); 38 | } 39 | 40 | public GeneralCommand(@NotNull P plugin, @NotNull String[] aliases, @Nullable Permission permission) { 41 | super(plugin, aliases, permission); 42 | } 43 | 44 | public GeneralCommand(@NotNull P plugin, @NotNull String[] aliases, @Nullable String permission) { 45 | super(plugin, aliases, permission); 46 | } 47 | 48 | public void addDefaultCommand(@NotNull AbstractCommand

command) { 49 | this.addChildren(command); 50 | this.defaultCommand = command; 51 | } 52 | 53 | public Command getFallback() { 54 | return fallback; 55 | } 56 | 57 | public void setFallback(@NotNull Command fallback) { 58 | this.fallback = fallback; 59 | } 60 | 61 | @NotNull 62 | public AbstractCommand

findChildren(@NotNull String[] args) { 63 | AbstractCommand

command = this;//.defaultCommand; 64 | int childCount = 0; 65 | while (args.length > childCount) { 66 | AbstractCommand

child = command.getChildren(args[childCount++]); 67 | if (child == null) break; 68 | 69 | command = child; 70 | } 71 | return command; 72 | } 73 | 74 | /*private int countChildren(@NotNull String[] args) { 75 | AbstractCommand

command = this; 76 | int childCount = 0; 77 | while (args.length > childCount) { 78 | AbstractCommand

child = command.getChildren(args[childCount]); 79 | if (child == null) break; 80 | 81 | command = child; 82 | childCount++; 83 | } 84 | return childCount; 85 | }*/ 86 | 87 | @Override 88 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) { 89 | AbstractCommand

command = this.findChildren(args); 90 | if (command instanceof GeneralCommand

generalCommand) { 91 | if (generalCommand.defaultCommand != null) { 92 | command = generalCommand.defaultCommand; 93 | } 94 | } 95 | command.execute(sender, label, args); 96 | return true; 97 | } 98 | 99 | @Override 100 | public List onTabComplete(@NotNull CommandSender sender, @NotNull Command cmd, 101 | @NotNull String label, String[] args) { 102 | 103 | if (!(sender instanceof Player player) || args.length == 0) return Collections.emptyList(); 104 | 105 | AbstractCommand

command = this.findChildren(args); 106 | if (!command.hasPermission(sender)) return Collections.emptyList(); 107 | 108 | List list = new ArrayList<>(); 109 | if (!command.getChildrens().isEmpty()) { 110 | command.getChildrens().stream().filter(child -> child.hasPermission(sender)) 111 | .forEach(child -> list.addAll(Arrays.asList(child.getAliases()))); 112 | } 113 | else { 114 | list.addAll(command.getTab(player, command.equals(this) ? (args.length) : (args.length - 1), args)); 115 | } 116 | return StringUtil.getByPartialMatches(list, args[args.length - 1], 2); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/AbstractUser.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data; 2 | 3 | import org.bukkit.OfflinePlayer; 4 | import org.bukkit.entity.Player; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | import su.nexmedia.engine.NexPlugin; 8 | 9 | import java.util.UUID; 10 | 11 | public abstract class AbstractUser

> { 12 | 13 | protected final P plugin; 14 | protected final UUID uuid; 15 | 16 | protected String name; 17 | protected long dateCreated; 18 | protected long lastOnline; 19 | protected long cachedUntil; 20 | 21 | @Deprecated private boolean isRecent = false; 22 | 23 | public AbstractUser(@NotNull P plugin, @NotNull UUID uuid, @NotNull String name, long dateCreated, long lastOnline) { 24 | this.plugin = plugin; 25 | this.uuid = uuid; 26 | this.name = name; 27 | this.setDateCreated(dateCreated); 28 | this.setLastOnline(lastOnline); 29 | this.setCachedUntil(-1); 30 | } 31 | 32 | public void onLoad() { 33 | 34 | } 35 | 36 | public void onUnload() { 37 | 38 | } 39 | 40 | @SuppressWarnings("unchecked") 41 | @Deprecated 42 | public > void saveData(@NotNull UserDataHolder dataHolder) { 43 | this.plugin.runTaskAsync(task -> dataHolder.getData().saveUser((U) this)); 44 | } 45 | 46 | @Deprecated 47 | public boolean isRecentlyCreated() { 48 | return isRecent; 49 | } 50 | 51 | @Deprecated 52 | public void setRecentlyCreated(boolean recent) { 53 | isRecent = recent; 54 | } 55 | 56 | public boolean isCacheExpired() { 57 | return this.getCachedUntil() > 0 && System.currentTimeMillis() > this.getCachedUntil(); 58 | } 59 | 60 | public long getCachedUntil() { 61 | return cachedUntil; 62 | } 63 | 64 | public void setCachedUntil(long cachedUntil) { 65 | this.cachedUntil = cachedUntil; 66 | } 67 | 68 | @NotNull 69 | public final UUID getId() { 70 | return this.uuid; 71 | } 72 | 73 | @NotNull 74 | public final String getName() { 75 | return this.name; 76 | } 77 | 78 | void setName(String name) { 79 | this.name = name; 80 | } 81 | 82 | public final long getDateCreated() { 83 | return dateCreated; 84 | } 85 | 86 | public final void setDateCreated(long dateCreated) { 87 | this.dateCreated = dateCreated; 88 | } 89 | 90 | public final long getLastOnline() { 91 | return this.lastOnline; 92 | } 93 | 94 | public final void setLastOnline(long lastOnline) { 95 | this.lastOnline = lastOnline; 96 | } 97 | 98 | public final boolean isOnline() { 99 | return this.getPlayer() != null; 100 | } 101 | 102 | @NotNull 103 | public final OfflinePlayer getOfflinePlayer() { 104 | return this.plugin.getServer().getOfflinePlayer(this.getId()); 105 | } 106 | 107 | @Nullable 108 | public final Player getPlayer() { 109 | return this.plugin.getServer().getPlayer(this.getId()); 110 | } 111 | 112 | @Override 113 | public String toString() { 114 | return "AbstractUser [uuid=" + this.uuid + ", name=" + this.name + ", lastOnline=" + this.lastOnline + "]"; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/StorageType.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public enum StorageType { 6 | 7 | MYSQL("MySQL"), SQLITE("SQLite"), 8 | ; 9 | 10 | private final String name; 11 | 12 | StorageType(@NotNull String name) { 13 | this.name = name; 14 | } 15 | 16 | @NotNull 17 | public String getName() { 18 | return this.name; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/UserDataHolder.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.NexPlugin; 5 | 6 | public interface UserDataHolder

, U extends AbstractUser

> { 7 | 8 | boolean setupDataHandlers(); 9 | 10 | @NotNull AbstractUserDataHandler getData(); 11 | 12 | @NotNull AbstractUserManager getUserManager(); 13 | } 14 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/config/DataConfig.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.config; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.config.JOption; 5 | import su.nexmedia.engine.api.config.JYML; 6 | import su.nexmedia.engine.api.data.StorageType; 7 | 8 | import java.util.stream.Stream; 9 | 10 | public class DataConfig { 11 | 12 | public int saveInterval; 13 | public int syncInterval; 14 | public StorageType storageType; 15 | public String tablePrefix; 16 | public boolean purgeEnabled; 17 | public int purgePeriod; 18 | 19 | public String mysqlUser; 20 | public String mysqlPassword; 21 | public String mysqlHost; 22 | public String mysqlBase; 23 | 24 | public String sqliteFilename; 25 | 26 | public DataConfig(@NotNull JYML cfg) { 27 | String path = "Database."; 28 | this.storageType = JOption.create(path + "Type", StorageType.class, StorageType.SQLITE, 29 | "Sets database type.", 30 | "Available values: " + String.join(",", Stream.of(StorageType.values()).map(Enum::name).toList())) 31 | .read(cfg); 32 | this.saveInterval = JOption.create(path + "Auto_Save_Interval", 20, 33 | "Defines how often (in minutes) user data of online players will be saved to the database.", 34 | "Set -1 to disable.") 35 | .read(cfg); 36 | this.syncInterval = JOption.create(path + "Sync_Interval", -1, 37 | "Defines how often (in seconds) plugin data will be fetched and loaded from the remote database.") 38 | .read(cfg); 39 | this.tablePrefix = JOption.create(path + "Table_Prefix", "", 40 | "Table prefix to use when plugin create tables. Do not leave this empty.") 41 | .read(cfg); 42 | 43 | this.mysqlUser = JOption.create(path + "MySQL.Username", "root", 44 | "Database user name.") 45 | .read(cfg); 46 | this.mysqlPassword = JOption.create(path + "MySQL.Password", "root", 47 | "Database user password.") 48 | .read(cfg); 49 | this.mysqlHost = JOption.create(path + "MySQL.Host", "localhost:3306", 50 | "Database host address. Like http://127.0.0.1:3306/") 51 | .read(cfg); 52 | this.mysqlBase = JOption.create(path + "MySQL.Database", "minecraft", 53 | "MySQL database name, where plugin tables will be created.") 54 | .read(cfg); 55 | 56 | this.sqliteFilename = JOption.create(path + "SQLite.FileName", "data.db", 57 | "File name for the database file.", 58 | "Actually it's a path to the file, so you can use directories here.") 59 | .read(cfg); 60 | 61 | path = "Database.Purge."; 62 | this.purgeEnabled = JOption.create(path + "Enabled", false, 63 | "Enables/Disables purge feature.", 64 | "Purge will remove all records from the plugin tables that are 'old' enough.") 65 | .read(cfg); 66 | this.purgePeriod = JOption.create(path + "For_Period", 60, 67 | "Sets maximal 'age' for the database records before they will be purged.", 68 | "This option may have different behavior depends on the plugin.", 69 | "By default it's days of inactivity for the plugin users.") 70 | .read(cfg); 71 | 72 | cfg.saveChanges(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/connection/AbstractDataConnector.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.connection; 2 | 3 | import com.zaxxer.hikari.HikariConfig; 4 | import com.zaxxer.hikari.HikariDataSource; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | import su.nexmedia.engine.NexPlugin; 8 | 9 | import java.sql.Connection; 10 | import java.sql.SQLException; 11 | 12 | public abstract class AbstractDataConnector { 13 | 14 | protected final NexPlugin plugin; 15 | protected final String url; 16 | protected final HikariConfig config; 17 | protected final HikariDataSource dataSource; 18 | 19 | public AbstractDataConnector(@NotNull NexPlugin plugin, @NotNull String url) { 20 | this(plugin, url, null, null); 21 | } 22 | 23 | public AbstractDataConnector(@NotNull NexPlugin plugin, @NotNull String url, 24 | @Nullable String userName, @Nullable String password) { 25 | this.plugin = plugin; 26 | this.url = url; 27 | 28 | this.config = new HikariConfig(); 29 | this.config.setJdbcUrl(url); 30 | if (userName != null) this.config.setUsername(userName); 31 | if (password != null) this.config.setPassword(password); 32 | this.config.addDataSourceProperty("cachePrepStmts", "true"); 33 | this.config.addDataSourceProperty("prepStmtCacheSize", "250"); 34 | this.config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); 35 | // SQLite don't need more than 1 active connection. 36 | if (this instanceof ConnectorSQLite) { 37 | this.config.setMaximumPoolSize(1); 38 | } 39 | this.dataSource = new HikariDataSource(this.config); 40 | } 41 | 42 | public void close() { 43 | this.dataSource.close(); 44 | } 45 | 46 | @NotNull 47 | public final Connection getConnection() throws SQLException { 48 | return this.dataSource.getConnection(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/connection/ConnectorMySQL.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.connection; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.NexPlugin; 5 | import su.nexmedia.engine.api.data.config.DataConfig; 6 | 7 | public class ConnectorMySQL extends AbstractDataConnector { 8 | 9 | public ConnectorMySQL(@NotNull NexPlugin plugin, @NotNull DataConfig config) { 10 | this(plugin, config.mysqlHost, config.mysqlBase, config.mysqlUser, config.mysqlPassword); 11 | } 12 | 13 | public ConnectorMySQL(@NotNull NexPlugin plugin, 14 | @NotNull String host, @NotNull String base, 15 | @NotNull String userName, @NotNull String password) { 16 | super(plugin, "jdbc:mysql://" + host + "/" + base + "?allowPublicKeyRetrieval=true&useSSL=false", userName, password); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/connection/ConnectorSQLite.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.connection; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.NexPlugin; 5 | import su.nexmedia.engine.api.data.config.DataConfig; 6 | 7 | public class ConnectorSQLite extends AbstractDataConnector { 8 | 9 | public ConnectorSQLite(@NotNull NexPlugin plugin, @NotNull DataConfig config) { 10 | this(plugin, plugin.getDataFolder().getAbsolutePath() + "/" + config.sqliteFilename); 11 | } 12 | 13 | public ConnectorSQLite(@NotNull NexPlugin plugin, @NotNull String filePath) { 14 | super(plugin, "jdbc:sqlite:" + filePath); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/serialize/ItemStackSerializer.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.serialize; 2 | 3 | import com.google.gson.*; 4 | import org.bukkit.inventory.ItemStack; 5 | import su.nexmedia.engine.utils.ItemUtil; 6 | 7 | import java.lang.reflect.Type; 8 | 9 | public class ItemStackSerializer implements JsonSerializer, JsonDeserializer { 10 | 11 | @Override 12 | public JsonElement serialize(ItemStack item, Type type, JsonSerializationContext context) { 13 | JsonObject object = new JsonObject(); 14 | object.addProperty("data64", ItemUtil.compress(item)); 15 | return object; 16 | } 17 | 18 | @Override 19 | public ItemStack deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { 20 | JsonObject object = json.getAsJsonObject(); 21 | return ItemUtil.decompress(object.get("data64").getAsString()); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/SQLColumn.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.data.StorageType; 5 | import su.nexmedia.engine.api.data.sql.column.ColumnType; 6 | 7 | public class SQLColumn { 8 | 9 | private final String name; 10 | private final ColumnType type; 11 | private final int length; 12 | 13 | public SQLColumn(@NotNull String name, @NotNull ColumnType type, int length) { 14 | this.name = name.replace(" ", "_"); 15 | this.type = type; 16 | this.length = length; 17 | } 18 | 19 | @NotNull 20 | public static SQLColumn of(@NotNull String name, @NotNull ColumnType type) { 21 | return SQLColumn.of(name, type, -1); 22 | } 23 | 24 | @NotNull 25 | public static SQLColumn of(@NotNull String name, @NotNull ColumnType type, int length) { 26 | return new SQLColumn(name, type, length); 27 | } 28 | 29 | @NotNull 30 | public SQLColumn asLowerCase() { 31 | return of("LOWER(" + this.getName() + ")", this.getType(), this.getLength()); 32 | } 33 | 34 | @NotNull 35 | public String getName() { 36 | return name; 37 | } 38 | 39 | @NotNull 40 | public String getNameEscaped() { 41 | if (this.getName().startsWith("LOWER(")) return this.getName(); 42 | 43 | return this.getName().equalsIgnoreCase("*") ? this.getName() : "`" + this.getName() + "`"; 44 | } 45 | 46 | @NotNull 47 | public ColumnType getType() { 48 | return type; 49 | } 50 | 51 | public int getLength() { 52 | return length; 53 | } 54 | 55 | @NotNull 56 | public String formatType(@NotNull StorageType storageType) { 57 | return this.getType().getFormer().build(storageType, this.getLength()); 58 | } 59 | 60 | @NotNull 61 | public SQLValue toValue(@NotNull Object value) { 62 | return SQLValue.of(this, String.valueOf(value)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/SQLCondition.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class SQLCondition { 6 | 7 | private final SQLValue value; 8 | private final Type type; 9 | 10 | public SQLCondition(@NotNull SQLValue value, @NotNull Type type) { 11 | this.value = value; 12 | this.type = type; 13 | } 14 | 15 | @NotNull 16 | public static SQLCondition of(@NotNull SQLValue value, @NotNull Type type) { 17 | return new SQLCondition(value, type); 18 | } 19 | 20 | @NotNull 21 | public static SQLCondition equal(@NotNull SQLValue value) { 22 | return of(value, Type.EQUAL); 23 | } 24 | 25 | @NotNull 26 | public static SQLCondition not(@NotNull SQLValue value) { 27 | return of(value, Type.NOT_EQUAL); 28 | } 29 | 30 | @NotNull 31 | public static SQLCondition smaller(@NotNull SQLValue value) { 32 | return of(value, Type.SMALLER); 33 | } 34 | 35 | @NotNull 36 | public static SQLCondition greater(@NotNull SQLValue value) { 37 | return of(value, Type.GREATER); 38 | } 39 | 40 | @NotNull 41 | public Type getType() { 42 | return type; 43 | } 44 | 45 | @NotNull 46 | public SQLValue getValue() { 47 | return value; 48 | } 49 | 50 | public enum Type { 51 | GREATER(">"), 52 | SMALLER("<"), 53 | EQUAL("="), 54 | NOT_EQUAL("!="); 55 | 56 | private final String operator; 57 | 58 | Type(@NotNull String operator) { 59 | this.operator = operator; 60 | } 61 | 62 | @NotNull 63 | public String getOperator() { 64 | return operator; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/SQLExecutor.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.data.connection.AbstractDataConnector; 5 | 6 | public abstract class SQLExecutor { 7 | 8 | protected static final String SELECT = "SELECT"; 9 | protected static final String FROM = "FROM"; 10 | protected static final String UPDATE = "UPDATE"; 11 | protected static final String SET = "SET"; 12 | protected static final String WHERE = "WHERE"; 13 | protected static final String INSERT_INTO = "INSERT INTO"; 14 | protected static final String VALUES = "VALUES"; 15 | 16 | protected final String table; 17 | 18 | protected SQLExecutor(@NotNull String table) { 19 | this.table = table; 20 | } 21 | 22 | @NotNull 23 | public String getTable() { 24 | return "`" + this.table + "`"; 25 | } 26 | 27 | @NotNull 28 | public abstract T execute(@NotNull AbstractDataConnector connector); 29 | } 30 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/SQLQueries.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.data.connection.AbstractDataConnector; 5 | 6 | import java.sql.*; 7 | import java.util.*; 8 | import java.util.function.Function; 9 | 10 | public class SQLQueries { 11 | 12 | public static boolean hasTable(@NotNull AbstractDataConnector connector, @NotNull String table) { 13 | try (Connection connection = connector.getConnection()) { 14 | 15 | boolean has; 16 | DatabaseMetaData metaData = connection.getMetaData(); 17 | ResultSet tables = metaData.getTables(null, null, table, null); 18 | has = tables.next(); 19 | tables.close(); 20 | return has; 21 | } 22 | catch (SQLException e) { 23 | e.printStackTrace(); 24 | return false; 25 | } 26 | } 27 | 28 | public static boolean hasColumn(@NotNull AbstractDataConnector connector, @NotNull String table, @NotNull SQLColumn column) { 29 | String sql = "SELECT * FROM " + table; 30 | String columnName = column.getName(); 31 | try (Connection connection = connector.getConnection(); 32 | Statement statement = connection.createStatement()) { 33 | 34 | ResultSet resultSet = statement.executeQuery(sql); 35 | ResultSetMetaData metaData = resultSet.getMetaData(); 36 | int columns = metaData.getColumnCount(); 37 | for (int index = 1; index <= columns; index++) { 38 | if (columnName.equals(metaData.getColumnName(index))) { 39 | return true; 40 | } 41 | } 42 | return false; 43 | } 44 | catch (SQLException e) { 45 | e.printStackTrace(); 46 | return false; 47 | } 48 | } 49 | 50 | public static void executeStatement(@NotNull AbstractDataConnector connector, @NotNull String sql) { 51 | executeStatement(connector, sql, Collections.emptySet()); 52 | } 53 | 54 | public static void executeStatement(@NotNull AbstractDataConnector connector, @NotNull String sql, 55 | @NotNull Collection values1) { 56 | executeStatement(connector, sql, values1, Collections.emptySet()); 57 | } 58 | 59 | public static void executeStatement(@NotNull AbstractDataConnector connector, @NotNull String sql, 60 | @NotNull Collection values1, @NotNull Collection values2) { 61 | 62 | try (Connection connection = connector.getConnection(); 63 | PreparedStatement statement = connection.prepareStatement(sql)) { 64 | 65 | int count = 1; 66 | for (String columnName : values1) { 67 | statement.setString(count++, columnName); 68 | } 69 | for (String columnValue : values2) { 70 | statement.setString(count++, columnValue); 71 | } 72 | 73 | statement.executeUpdate(); 74 | } 75 | catch (SQLException e) { 76 | e.printStackTrace(); 77 | } 78 | } 79 | 80 | @NotNull 81 | public static List<@NotNull T> executeQuery(@NotNull AbstractDataConnector connector, @NotNull String sql, 82 | @NotNull Collection values1, 83 | @NotNull Function dataFunction, 84 | int amount) { 85 | 86 | List list = new ArrayList<>(); 87 | try (Connection connection = connector.getConnection(); 88 | PreparedStatement statement = connection.prepareStatement(sql)) { 89 | 90 | int count = 1; 91 | for (String wValue : values1) { 92 | statement.setString(count++, wValue); 93 | } 94 | 95 | ResultSet resultSet = statement.executeQuery(); 96 | while (resultSet.next() && (amount < 0 || list.size() < amount)) { 97 | list.add(dataFunction.apply(resultSet)); 98 | } 99 | resultSet.close(); 100 | } 101 | catch (SQLException e) { 102 | e.printStackTrace(); 103 | } 104 | list.removeIf(Objects::isNull); 105 | 106 | return list; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/SQLValue.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class SQLValue { 6 | 7 | private final SQLColumn column; 8 | private final String value; 9 | 10 | public SQLValue(@NotNull SQLColumn column, @NotNull String value) { 11 | this.column = column; 12 | this.value = value; 13 | } 14 | 15 | @NotNull 16 | public static SQLValue of(@NotNull SQLColumn column, @NotNull String value) { 17 | return new SQLValue(column, value); 18 | } 19 | 20 | @NotNull 21 | public SQLColumn getColumn() { 22 | return column; 23 | } 24 | 25 | @NotNull 26 | public String getValue() { 27 | return value; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/column/ColumnFormer.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql.column; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.data.StorageType; 5 | 6 | public interface ColumnFormer { 7 | 8 | ColumnFormer STRING = (storageType, length) -> { 9 | if (length < 1 || storageType == StorageType.SQLITE) { 10 | return storageType == StorageType.SQLITE ? "TEXT NOT NULL" : "MEDIUMTEXT NOT NULL"; 11 | } 12 | return "varchar(" + length + ") CHARACTER SET utf8 NOT NULL"; 13 | }; 14 | 15 | ColumnFormer INTEGER = (storageType, length) -> { 16 | if (length < 1 || storageType == StorageType.SQLITE) { 17 | return "INTEGER NOT NULL"; 18 | } 19 | return "int(" + length + ") NOT NULL"; 20 | }; 21 | 22 | ColumnFormer DOUBLE = (storageType, length) -> { 23 | return storageType == StorageType.SQLITE ? "REAL NOT NULL" : "double NOT NULL"; 24 | }; 25 | 26 | ColumnFormer LONG = (storageType, length) -> { 27 | return length < 1 || storageType == StorageType.SQLITE ? "BIGINT NOT NULL" : "bigint(" + length + ") NOT NULL"; 28 | }; 29 | 30 | ColumnFormer BOOLEAN = (storageType, length) -> { 31 | return storageType == StorageType.SQLITE ? "INTEGER NOT NULL" : "tinyint(1) NOT NULL"; 32 | }; 33 | 34 | @NotNull String build(@NotNull StorageType storageType, int length); 35 | } 36 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/column/ColumnType.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql.column; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class ColumnType { 6 | 7 | public static final ColumnType INTEGER = new ColumnType(ColumnFormer.INTEGER); 8 | public static final ColumnType DOUBLE = new ColumnType(ColumnFormer.DOUBLE); 9 | public static final ColumnType LONG = new ColumnType(ColumnFormer.LONG); 10 | public static final ColumnType BOOLEAN = new ColumnType(ColumnFormer.BOOLEAN); 11 | public static final ColumnType STRING = new ColumnType(ColumnFormer.STRING); 12 | 13 | private final ColumnFormer former; 14 | 15 | public ColumnType(@NotNull ColumnFormer former) { 16 | this.former = former; 17 | } 18 | 19 | @NotNull 20 | public ColumnFormer getFormer() { 21 | return former; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/executor/AlterTableExecutor.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql.executor; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.data.StorageType; 5 | import su.nexmedia.engine.api.data.connection.AbstractDataConnector; 6 | import su.nexmedia.engine.api.data.connection.ConnectorSQLite; 7 | import su.nexmedia.engine.api.data.sql.SQLColumn; 8 | import su.nexmedia.engine.api.data.sql.SQLExecutor; 9 | import su.nexmedia.engine.api.data.sql.SQLQueries; 10 | import su.nexmedia.engine.api.data.sql.SQLValue; 11 | import su.nexmedia.engine.api.data.sql.column.ColumnType; 12 | 13 | import java.util.ArrayList; 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | public final class AlterTableExecutor extends SQLExecutor { 18 | 19 | private final StorageType storageType; 20 | private final List columns; 21 | private Type type; 22 | 23 | private AlterTableExecutor(@NotNull String table, @NotNull StorageType storageType) { 24 | super(table); 25 | this.storageType = storageType; 26 | this.columns = new ArrayList<>(); 27 | } 28 | 29 | private enum Type { 30 | ADD_COLUMN, RENAME_COLUMN, DROP_COLUMN 31 | } 32 | 33 | @NotNull 34 | public static AlterTableExecutor builder(@NotNull String table, @NotNull StorageType storageType) { 35 | return new AlterTableExecutor(table, storageType); 36 | } 37 | 38 | @NotNull 39 | public AlterTableExecutor addColumn(@NotNull SQLValue... columns) { 40 | return this.addColumn(Arrays.asList(columns)); 41 | } 42 | 43 | @NotNull 44 | public AlterTableExecutor addColumn(@NotNull List columns) { 45 | return this.columns(columns, Type.ADD_COLUMN); 46 | } 47 | 48 | @NotNull 49 | public AlterTableExecutor renameColumn(@NotNull SQLValue... columns) { 50 | return this.addColumn(Arrays.asList(columns)); 51 | } 52 | 53 | @NotNull 54 | public AlterTableExecutor renameColumn(@NotNull List columns) { 55 | return this.columns(columns, Type.RENAME_COLUMN); 56 | } 57 | 58 | @NotNull 59 | public AlterTableExecutor dropColumn(@NotNull SQLColumn... columns) { 60 | return this.dropColumn(Arrays.asList(columns)); 61 | } 62 | 63 | @NotNull 64 | public AlterTableExecutor dropColumn(@NotNull List columns) { 65 | return this.columns(columns.stream().map(column -> column.toValue("dummy")).toList(), Type.DROP_COLUMN); 66 | } 67 | 68 | private AlterTableExecutor columns(@NotNull List values, @NotNull Type type) { 69 | this.columns.clear(); 70 | this.columns.addAll(values); 71 | this.type = type; 72 | return this; 73 | } 74 | 75 | @Override 76 | @NotNull 77 | public Void execute(@NotNull AbstractDataConnector connector) { 78 | if (this.columns.isEmpty()) return null; 79 | 80 | if (this.type == Type.ADD_COLUMN) { 81 | this.columns.forEach(value -> { 82 | if (SQLQueries.hasColumn(connector, this.getTable(), value.getColumn())) return; 83 | 84 | String sql = "ALTER TABLE " + this.getTable() + " ADD " 85 | + value.getColumn().getName() + " " + value.getColumn().formatType(this.storageType); 86 | 87 | if (connector instanceof ConnectorSQLite || value.getColumn().getType() != ColumnType.STRING) { 88 | sql = sql + " DEFAULT '" + value.getValue() + "'"; 89 | } 90 | 91 | SQLQueries.executeStatement(connector, sql); 92 | }); 93 | } 94 | else if (this.type == Type.RENAME_COLUMN) { 95 | this.columns.forEach(value -> { 96 | if (!SQLQueries.hasColumn(connector, this.getTable(), value.getColumn())) return; 97 | 98 | String sql = "ALTER TABLE " + this.getTable() + " RENAME COLUMN " + value.getColumn().getName() + " TO " + value.getValue(); 99 | SQLQueries.executeStatement(connector, sql); 100 | }); 101 | } 102 | else if (this.type == Type.DROP_COLUMN) { 103 | this.columns.forEach(value -> { 104 | if (!SQLQueries.hasColumn(connector, this.getTable(), value.getColumn())) return; 105 | 106 | String sql = "ALTER TABLE " + this.getTable() + " DROP COLUMN " + value.getColumn().getName(); 107 | SQLQueries.executeStatement(connector, sql); 108 | }); 109 | } 110 | return null; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/executor/CreateTableExecutor.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql.executor; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.data.StorageType; 5 | import su.nexmedia.engine.api.data.connection.AbstractDataConnector; 6 | import su.nexmedia.engine.api.data.sql.SQLColumn; 7 | import su.nexmedia.engine.api.data.sql.SQLExecutor; 8 | import su.nexmedia.engine.api.data.sql.SQLQueries; 9 | import su.nexmedia.engine.api.data.sql.column.ColumnFormer; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.List; 14 | import java.util.stream.Collectors; 15 | 16 | public final class CreateTableExecutor extends SQLExecutor { 17 | 18 | private final StorageType storageType; 19 | private final List columns; 20 | 21 | private CreateTableExecutor(@NotNull String table, @NotNull StorageType storageType) { 22 | super(table); 23 | this.storageType = storageType; 24 | this.columns = new ArrayList<>(); 25 | } 26 | 27 | @NotNull 28 | public static CreateTableExecutor builder(@NotNull String table, @NotNull StorageType storageType) { 29 | return new CreateTableExecutor(table, storageType); 30 | } 31 | 32 | @NotNull 33 | public CreateTableExecutor columns(@NotNull SQLColumn... columns) { 34 | return this.columns(Arrays.asList(columns)); 35 | } 36 | 37 | @NotNull 38 | public CreateTableExecutor columns(@NotNull List columns) { 39 | this.columns.clear(); 40 | this.columns.addAll(columns); 41 | return this; 42 | } 43 | 44 | @Override 45 | @NotNull 46 | public Void execute(@NotNull AbstractDataConnector connector) { 47 | if (this.columns.isEmpty()) return null; 48 | 49 | String id = "`id` " + ColumnFormer.INTEGER.build(this.storageType, 11); 50 | if (this.storageType == StorageType.SQLITE) { 51 | id += " PRIMARY KEY AUTOINCREMENT"; 52 | } 53 | else { 54 | id += " PRIMARY KEY AUTO_INCREMENT"; 55 | } 56 | 57 | String columns = id + "," + this.columns.stream() 58 | .map(column -> column.getNameEscaped() + " " + column.formatType(this.storageType)) 59 | .collect(Collectors.joining(", ")); 60 | 61 | String sql = "CREATE TABLE IF NOT EXISTS " + this.getTable() + "(" + columns + ");"; 62 | 63 | SQLQueries.executeStatement(connector, sql); 64 | return null; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/executor/DeleteQueryExecutor.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql.executor; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.data.connection.AbstractDataConnector; 5 | import su.nexmedia.engine.api.data.sql.SQLCondition; 6 | import su.nexmedia.engine.api.data.sql.SQLExecutor; 7 | import su.nexmedia.engine.api.data.sql.SQLQueries; 8 | import su.nexmedia.engine.api.data.sql.SQLValue; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | 15 | public final class DeleteQueryExecutor extends SQLExecutor { 16 | 17 | private final List wheres; 18 | 19 | private DeleteQueryExecutor(@NotNull String table) { 20 | super(table); 21 | this.wheres = new ArrayList<>(); 22 | } 23 | 24 | @NotNull 25 | public static DeleteQueryExecutor builder(@NotNull String table) { 26 | return new DeleteQueryExecutor(table); 27 | } 28 | 29 | @NotNull 30 | public DeleteQueryExecutor where(@NotNull SQLCondition... wheres) { 31 | return this.where(Arrays.asList(wheres)); 32 | } 33 | 34 | @NotNull 35 | public DeleteQueryExecutor where(@NotNull List wheres) { 36 | this.wheres.clear(); 37 | this.wheres.addAll(wheres); 38 | return this; 39 | } 40 | 41 | @Override 42 | @NotNull 43 | public Void execute(@NotNull AbstractDataConnector connector) { 44 | if (this.wheres.isEmpty()) return null; 45 | 46 | String whereCols = this.wheres.stream() 47 | .map(where -> where.getValue().getColumn().getNameEscaped() + " " + where.getType().getOperator() + " ?") 48 | .collect(Collectors.joining(" AND ")); 49 | String sql = "DELETE FROM " + this.getTable() + (whereCols.isEmpty() ? "" : " WHERE " + whereCols); 50 | 51 | List whereVals = this.wheres.stream().map(SQLCondition::getValue).map(SQLValue::getValue).toList(); 52 | 53 | SQLQueries.executeStatement(connector, sql, whereVals); 54 | return null; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/executor/InsertQueryExecutor.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql.executor; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.data.connection.AbstractDataConnector; 5 | import su.nexmedia.engine.api.data.sql.SQLColumn; 6 | import su.nexmedia.engine.api.data.sql.SQLExecutor; 7 | import su.nexmedia.engine.api.data.sql.SQLQueries; 8 | import su.nexmedia.engine.api.data.sql.SQLValue; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | 15 | public final class InsertQueryExecutor extends SQLExecutor { 16 | 17 | private final List values; 18 | 19 | private InsertQueryExecutor(@NotNull String table) { 20 | super(table); 21 | this.values = new ArrayList<>(); 22 | } 23 | 24 | @NotNull 25 | public static InsertQueryExecutor builder(@NotNull String table) { 26 | return new InsertQueryExecutor(table); 27 | } 28 | 29 | @NotNull 30 | public InsertQueryExecutor values(@NotNull SQLValue... values) { 31 | return this.values(Arrays.asList(values)); 32 | } 33 | 34 | @NotNull 35 | public InsertQueryExecutor values(@NotNull List values) { 36 | this.values.clear(); 37 | this.values.addAll(values); 38 | return this; 39 | } 40 | 41 | @Override 42 | @NotNull 43 | public Void execute(@NotNull AbstractDataConnector connector) { 44 | if (this.values.isEmpty()) return null; 45 | 46 | String columns = this.values.stream().map(SQLValue::getColumn).map(SQLColumn::getNameEscaped).collect(Collectors.joining(",")); 47 | String values = this.values.stream().map(value -> "?").collect(Collectors.joining(",")); 48 | String sql = INSERT_INTO + " " + this.getTable() + "(" + columns + ") " + VALUES + "(" + values + ")"; 49 | List values2 = this.values.stream().map(SQLValue::getValue).toList(); 50 | 51 | SQLQueries.executeStatement(connector, sql, values2); 52 | return null; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/executor/RenameTableExecutor.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql.executor; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.data.StorageType; 5 | import su.nexmedia.engine.api.data.connection.AbstractDataConnector; 6 | import su.nexmedia.engine.api.data.sql.SQLExecutor; 7 | import su.nexmedia.engine.api.data.sql.SQLQueries; 8 | 9 | public final class RenameTableExecutor extends SQLExecutor { 10 | 11 | private final StorageType storageType; 12 | private String renameTo; 13 | 14 | private RenameTableExecutor(@NotNull String table, @NotNull StorageType storageType) { 15 | super(table); 16 | this.storageType = storageType; 17 | } 18 | 19 | @NotNull 20 | public static RenameTableExecutor builder(@NotNull String table, @NotNull StorageType storageType) { 21 | return new RenameTableExecutor(table, storageType); 22 | } 23 | 24 | @NotNull 25 | public RenameTableExecutor renameTo(@NotNull String renameTo) { 26 | this.renameTo = renameTo; 27 | return this; 28 | } 29 | 30 | @Override 31 | @NotNull 32 | public Void execute(@NotNull AbstractDataConnector connector) { 33 | if (this.renameTo == null || this.renameTo.isEmpty()) return null; 34 | if (!SQLQueries.hasTable(connector, this.getTable())) return null; 35 | 36 | StringBuilder sql = new StringBuilder(); 37 | if (this.storageType == StorageType.MYSQL) { 38 | sql.append("RENAME TABLE ").append(this.getTable()).append(" TO ").append(this.renameTo).append(";"); 39 | } 40 | else { 41 | sql.append("ALTER TABLE ").append(this.getTable()).append(" RENAME TO ").append(this.renameTo); 42 | } 43 | SQLQueries.executeStatement(connector, sql.toString()); 44 | return null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/executor/SelectQueryExecutor.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql.executor; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.data.connection.AbstractDataConnector; 5 | import su.nexmedia.engine.api.data.sql.*; 6 | import su.nexmedia.engine.api.data.sql.column.ColumnType; 7 | 8 | import java.sql.ResultSet; 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.Collections; 12 | import java.util.List; 13 | import java.util.function.Function; 14 | import java.util.stream.Collectors; 15 | 16 | public final class SelectQueryExecutor extends SQLExecutor> { 17 | 18 | private final List columns; 19 | private final List wheres; 20 | private final Function dataFunction; 21 | private int amount; 22 | 23 | private SelectQueryExecutor(@NotNull String table, @NotNull Function dataFunction) { 24 | super(table); 25 | this.columns = new ArrayList<>(); 26 | this.wheres = new ArrayList<>(); 27 | this.dataFunction = dataFunction; 28 | this.amount = -1; 29 | } 30 | 31 | @NotNull 32 | public static SelectQueryExecutor builder(@NotNull String table, @NotNull Function dataFunction) { 33 | return new SelectQueryExecutor<>(table, dataFunction); 34 | } 35 | 36 | @NotNull 37 | public SelectQueryExecutor all() { 38 | return this.columns(new SQLColumn("*", ColumnType.STRING, -1)); 39 | } 40 | 41 | @NotNull 42 | public SelectQueryExecutor columns(@NotNull SQLColumn... columns) { 43 | return this.columns(Arrays.asList(columns)); 44 | } 45 | 46 | @NotNull 47 | public SelectQueryExecutor columns(@NotNull List columns) { 48 | if (columns.isEmpty()) return this.all(); 49 | 50 | this.columns.clear(); 51 | this.columns.addAll(columns); 52 | return this; 53 | } 54 | 55 | @NotNull 56 | public SelectQueryExecutor where(@NotNull SQLCondition... wheres) { 57 | return this.where(Arrays.asList(wheres)); 58 | } 59 | 60 | @NotNull 61 | public SelectQueryExecutor where(@NotNull List wheres) { 62 | this.wheres.clear(); 63 | this.wheres.addAll(wheres); 64 | return this; 65 | } 66 | 67 | @NotNull 68 | public SelectQueryExecutor amount(int amount) { 69 | this.amount = amount; 70 | return this; 71 | } 72 | 73 | @Override 74 | @NotNull 75 | public List execute(@NotNull AbstractDataConnector connector) { 76 | if (this.columns.isEmpty()) return Collections.emptyList(); 77 | 78 | String columns = this.columns.stream().map(SQLColumn::getNameEscaped).collect(Collectors.joining(",")); 79 | String wheres = this.wheres.stream().map(where -> where.getValue().getColumn().getNameEscaped() + " " + where.getType().getOperator() + " ?") 80 | .collect(Collectors.joining(" AND ")); 81 | String sql = "SELECT " + columns + " FROM " + this.getTable() + (wheres.isEmpty() ? "" : " WHERE " + wheres); 82 | 83 | //List values2 = this.columns.stream().map(SQLColumn::getName).toList(); 84 | List whers2 = this.wheres.stream().map(SQLCondition::getValue).map(SQLValue::getValue).toList(); 85 | 86 | return SQLQueries.executeQuery(connector, sql, whers2, this.dataFunction, this.amount); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/sql/executor/UpdateQueryExecutor.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.sql.executor; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.data.connection.AbstractDataConnector; 5 | import su.nexmedia.engine.api.data.sql.SQLCondition; 6 | import su.nexmedia.engine.api.data.sql.SQLExecutor; 7 | import su.nexmedia.engine.api.data.sql.SQLQueries; 8 | import su.nexmedia.engine.api.data.sql.SQLValue; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | 15 | public final class UpdateQueryExecutor extends SQLExecutor { 16 | 17 | private final List values; 18 | private final List wheres; 19 | 20 | private UpdateQueryExecutor(@NotNull String table) { 21 | super(table); 22 | this.values = new ArrayList<>(); 23 | this.wheres = new ArrayList<>(); 24 | } 25 | 26 | @NotNull 27 | public static UpdateQueryExecutor builder(@NotNull String table) { 28 | return new UpdateQueryExecutor(table); 29 | } 30 | 31 | @NotNull 32 | public UpdateQueryExecutor values(@NotNull SQLValue... values) { 33 | return this.values(Arrays.asList(values)); 34 | } 35 | 36 | @NotNull 37 | public UpdateQueryExecutor values(@NotNull List values) { 38 | this.values.clear(); 39 | this.values.addAll(values); 40 | return this; 41 | } 42 | 43 | @NotNull 44 | public UpdateQueryExecutor where(@NotNull SQLCondition... wheres) { 45 | return this.where(Arrays.asList(wheres)); 46 | } 47 | 48 | @NotNull 49 | public UpdateQueryExecutor where(@NotNull List wheres) { 50 | this.wheres.clear(); 51 | this.wheres.addAll(wheres); 52 | return this; 53 | } 54 | 55 | @Override 56 | @NotNull 57 | public Void execute(@NotNull AbstractDataConnector connector) { 58 | if (this.values.isEmpty()) return null; 59 | 60 | String values = this.values.stream().map(value -> value.getColumn().getNameEscaped() + " = ?") 61 | .collect(Collectors.joining(",")); 62 | String wheres = this.wheres.stream().map(where -> where.getValue().getColumn().getNameEscaped() + " " + where.getType().getOperator() + " ?") 63 | .collect(Collectors.joining(" AND ")); 64 | String sql = "UPDATE " + this.getTable() + " SET " + values + (wheres.isEmpty() ? "" : " WHERE " + wheres); 65 | 66 | List values2 = this.values.stream().map(SQLValue::getValue).toList(); 67 | List whers2 = this.wheres.stream().map(SQLCondition::getValue).map(SQLValue::getValue).toList(); 68 | 69 | SQLQueries.executeStatement(connector, sql, values2, whers2); 70 | return null; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/task/DataSaveTask.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.task; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.NexPlugin; 5 | import su.nexmedia.engine.api.data.AbstractDataHandler; 6 | import su.nexmedia.engine.api.server.AbstractTask; 7 | 8 | public class DataSaveTask

> extends AbstractTask

{ 9 | 10 | private final AbstractDataHandler

dataHandler; 11 | 12 | public DataSaveTask(@NotNull AbstractDataHandler

dataHandler) { 13 | super(dataHandler.plugin(), dataHandler.getConfig().saveInterval * 60, true); 14 | this.dataHandler = dataHandler; 15 | } 16 | 17 | @Override 18 | public void action() { 19 | this.dataHandler.onSave(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/data/task/DataSynchronizationTask.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.data.task; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.NexPlugin; 5 | import su.nexmedia.engine.api.data.AbstractDataHandler; 6 | import su.nexmedia.engine.api.server.AbstractTask; 7 | 8 | public class DataSynchronizationTask

> extends AbstractTask

{ 9 | 10 | private final AbstractDataHandler

dataHandler; 11 | 12 | public DataSynchronizationTask(@NotNull AbstractDataHandler

dataHandler) { 13 | super(dataHandler.plugin(), dataHandler.getConfig().syncInterval, true); 14 | this.dataHandler = dataHandler; 15 | } 16 | 17 | @Override 18 | public void action() { 19 | this.dataHandler.onSynchronize(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/editor/EditorLocale.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.editor; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.utils.Colorizer; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | public class EditorLocale { 10 | 11 | private final String key; 12 | private final String name; 13 | private final List lore; 14 | 15 | private String localizedName; 16 | private List localizedLore; 17 | 18 | public EditorLocale(@NotNull String key, @NotNull String name, @NotNull List lore) { 19 | this.key = key; 20 | this.name = Colorizer.apply(name); 21 | this.lore = Colorizer.apply(lore); 22 | } 23 | 24 | @NotNull 25 | public static EditorLocale of(@NotNull String key, @NotNull String name, @NotNull String... lore) { 26 | return new EditorLocale(key, name, Arrays.asList(lore)); 27 | } 28 | 29 | @NotNull 30 | public String getKey() { 31 | return key; 32 | } 33 | 34 | @NotNull 35 | public String getName() { 36 | return name; 37 | } 38 | 39 | @NotNull 40 | public List getLore() { 41 | return lore; 42 | } 43 | 44 | @NotNull 45 | public String getLocalizedName() { 46 | return localizedName; 47 | } 48 | 49 | public void setLocalizedName(@NotNull String localizedName) { 50 | this.localizedName = Colorizer.apply(localizedName); 51 | } 52 | 53 | @NotNull 54 | public List getLocalizedLore() { 55 | return localizedLore; 56 | } 57 | 58 | public void setLocalizedLore(@NotNull List localizedLore) { 59 | this.localizedLore = Colorizer.apply(localizedLore); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/editor/EditorLocales.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.editor; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import static su.nexmedia.engine.utils.Colors2.*; 9 | 10 | public class EditorLocales { 11 | 12 | public static final EditorLocale CLOSE = EditorLocale.of("Editor.Generic.Close", RED + "(✕) Exit"); 13 | public static final EditorLocale RETURN = EditorLocale.of("Editor.Generic.Return", GRAY + "(↓) " + WHITE + "Return"); 14 | public static final EditorLocale NEXT_PAGE = EditorLocale.of("Editor.Generic.NextPage", GRAY + "(→) " + WHITE + "Next Page"); 15 | public static final EditorLocale PREVIOUS_PAGE = EditorLocale.of("Editor.Generic.PreviousPage", GRAY + "(←) " + WHITE + "Previous Page"); 16 | 17 | protected static final String LMB = "Left-Click"; 18 | protected static final String RMB = "Right-Click"; 19 | protected static final String DROP_KEY = "[Q] Drop Key"; 20 | protected static final String SWAP_KEY = "[F] Swap Key"; 21 | protected static final String SHIFT_LMB = "Shift-Left"; 22 | protected static final String SHIFT_RMB = "Shift-Right"; 23 | protected static final String DRAG_DROP = "Drag & Drop"; 24 | 25 | @NotNull 26 | protected static Builder builder(@NotNull String key) { 27 | return new Builder(key); 28 | } 29 | 30 | protected static final class Builder { 31 | 32 | private final String key; 33 | private String name; 34 | private final List lore; 35 | 36 | public Builder(@NotNull String key) { 37 | this.key = key; 38 | this.name = ""; 39 | this.lore = new ArrayList<>(); 40 | } 41 | 42 | @NotNull 43 | public EditorLocale build() { 44 | return new EditorLocale(this.key, this.name, this.lore); 45 | } 46 | 47 | @NotNull 48 | public Builder name(@NotNull String name) { 49 | this.name = YELLOW + BOLD + name; 50 | return this; 51 | } 52 | 53 | @NotNull 54 | public Builder text(@NotNull String... text) { 55 | return this.addLore(GRAY, text); 56 | } 57 | 58 | @NotNull 59 | public Builder textRaw(@NotNull String... text) { 60 | return this.addLore("", text); 61 | } 62 | 63 | @NotNull 64 | public Builder currentHeader() { 65 | return this.addLore(YELLOW + BOLD, "Current:"); 66 | } 67 | 68 | @NotNull 69 | public Builder current(@NotNull String type, @NotNull String value) { 70 | return this.addLore(YELLOW + "▪ " + GRAY, type + ": " + YELLOW + value); 71 | } 72 | 73 | @NotNull 74 | @Deprecated 75 | public Builder warningHeader() { 76 | return this.addLore(RED + BOLD, "Warning:"); 77 | } 78 | 79 | @NotNull 80 | @Deprecated 81 | public Builder warning(@NotNull String... info) { 82 | return this.addLore(RED + "▪ " + GRAY, info); 83 | } 84 | 85 | @NotNull 86 | @Deprecated 87 | public Builder noteHeader() { 88 | return this.addLore(ORANGE + BOLD, "Notes:"); 89 | } 90 | 91 | @NotNull 92 | @Deprecated 93 | public Builder notes(@NotNull String... info) { 94 | return this.addLore(ORANGE + "▪ " + GRAY, info); 95 | } 96 | 97 | @NotNull 98 | @Deprecated 99 | public Builder actionsHeader() { 100 | return this.addLore(GREEN + BOLD, "Actions:"); 101 | } 102 | 103 | @NotNull 104 | @Deprecated 105 | public Builder action(@NotNull String click, @NotNull String action) { 106 | return this.addLore(GREEN + "▪ " + GRAY, click + ": " + GREEN + action); 107 | } 108 | 109 | @NotNull 110 | public Builder click(@NotNull String click, @NotNull String action) { 111 | return this.addLore("", GRAY + "(" + WHITE + click + GRAY + " to " + action + GRAY + ")"); 112 | } 113 | 114 | @NotNull 115 | @Deprecated 116 | public Builder breakLine() { 117 | return this.emptyLine(); 118 | } 119 | 120 | @NotNull 121 | public Builder emptyLine() { 122 | return this.addLore("", ""); 123 | } 124 | 125 | @NotNull 126 | private Builder addLore(@NotNull String prefix, @NotNull String... text) { 127 | for (String str : text) { 128 | this.lore.add(prefix + str); 129 | } 130 | return this; 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/editor/InputHandler.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.editor; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public interface InputHandler { 6 | 7 | boolean handle(@NotNull InputWrapper wrapper); 8 | } 9 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/editor/InputWrapper.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.editor; 2 | 3 | import org.bukkit.event.player.AsyncPlayerChatEvent; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | import su.nexmedia.engine.utils.Colorizer; 7 | import su.nexmedia.engine.utils.StringUtil; 8 | import su.nexmedia.engine.utils.values.UniDouble; 9 | import su.nexmedia.engine.utils.values.UniInt; 10 | 11 | public class InputWrapper { 12 | 13 | private final String text; 14 | private final String textRaw; 15 | private final String textColored; 16 | 17 | public InputWrapper(@NotNull AsyncPlayerChatEvent e) { 18 | this(e.getMessage()); 19 | } 20 | 21 | public InputWrapper(@NotNull String text) { 22 | this.text = text; 23 | this.textRaw = Colorizer.restrip(text); 24 | this.textColored = Colorizer.apply(text); 25 | } 26 | 27 | public int asInt() { 28 | return this.asInt(0); 29 | } 30 | 31 | public int asInt(int def) { 32 | return StringUtil.getInteger(this.getTextRaw(), def); 33 | } 34 | 35 | public int asAnyInt(int def) { 36 | return StringUtil.getInteger(this.getTextRaw(), def, true); 37 | } 38 | 39 | public double asDouble() { 40 | return this.asDouble(0D); 41 | } 42 | 43 | public double asDouble(double def) { 44 | return StringUtil.getDouble(this.getTextRaw(), def); 45 | } 46 | 47 | @NotNull 48 | public UniDouble asUniDouble() { 49 | return this.asUniDouble(0, 0); 50 | } 51 | 52 | @NotNull 53 | public UniDouble asUniDouble(double min, double max) { 54 | String[] split = this.getTextRaw().split(" "); 55 | return UniDouble.of(StringUtil.getDouble(split[0], min), StringUtil.getDouble(split.length >= 2 ? split[1] : split[0], max)); 56 | } 57 | 58 | @NotNull 59 | public UniInt asUniInt() { 60 | return this.asUniDouble().asInt(); 61 | } 62 | 63 | public double asAnyDouble(double def) { 64 | return StringUtil.getDouble(this.getTextRaw(), def, true); 65 | } 66 | 67 | @Nullable 68 | public > E asEnum(@NotNull Class clazz) { 69 | return StringUtil.getEnum(this.getTextRaw(), clazz).orElse(null); 70 | } 71 | 72 | @NotNull 73 | public > E asEnum(@NotNull Class clazz, @NotNull E def) { 74 | return StringUtil.getEnum(this.getTextRaw(), clazz).orElse(def); 75 | } 76 | 77 | @NotNull 78 | public String getText() { 79 | return text; 80 | } 81 | 82 | @NotNull 83 | public String getTextRaw() { 84 | return textRaw; 85 | } 86 | 87 | @NotNull 88 | public String getTextColored() { 89 | return textColored; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/lang/LangKey.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.lang; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class LangKey { 6 | 7 | private final String path; 8 | private final String defaultText; 9 | 10 | public LangKey(@NotNull String path, @NotNull String defaultText) { 11 | this.path = path; 12 | this.defaultText = defaultText; 13 | } 14 | 15 | @NotNull 16 | public static LangKey of(@NotNull String path, @NotNull String defaultText) { 17 | return new LangKey(path, defaultText); 18 | } 19 | 20 | @NotNull 21 | public String getPath() { 22 | return path; 23 | } 24 | 25 | @NotNull 26 | public String getDefaultText() { 27 | return defaultText; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/manager/AbstractConfigHolder.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.manager; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.NexPlugin; 5 | import su.nexmedia.engine.api.config.JYML; 6 | import su.nexmedia.engine.utils.StringUtil; 7 | 8 | import java.io.File; 9 | 10 | public abstract class AbstractConfigHolder

> { 11 | 12 | protected final P plugin; 13 | protected final JYML cfg; 14 | private final String id; 15 | 16 | public AbstractConfigHolder(@NotNull P plugin, @NotNull String filePath) { 17 | this(plugin, new JYML(new File(filePath))); 18 | } 19 | 20 | public AbstractConfigHolder(@NotNull P plugin, @NotNull JYML cfg) { 21 | this(plugin, cfg, cfg.getFile().getName().replace(".yml", "")); 22 | } 23 | 24 | public AbstractConfigHolder(@NotNull P plugin, @NotNull String filePath, @NotNull String id) { 25 | this(plugin, new JYML(new File(filePath)), id); 26 | } 27 | 28 | public AbstractConfigHolder(@NotNull P plugin, @NotNull JYML cfg, @NotNull String id) { 29 | this.plugin = plugin; 30 | this.cfg = cfg; 31 | this.id = StringUtil.lowerCaseUnderscore(id); 32 | } 33 | 34 | public abstract boolean load(); 35 | 36 | protected abstract void onSave(); 37 | 38 | public boolean reload() { 39 | return this.getConfig().reload() && this.load(); 40 | } 41 | 42 | public void save() { 43 | this.onSave(); 44 | this.getConfig().save(); 45 | } 46 | 47 | @NotNull 48 | public File getFile() { 49 | return this.getConfig().getFile(); 50 | } 51 | 52 | @NotNull 53 | public P plugin() { 54 | return this.plugin; 55 | } 56 | 57 | @NotNull 58 | public final String getId() { 59 | return this.id; 60 | } 61 | 62 | @NotNull 63 | public final JYML getConfig() { 64 | return this.cfg; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/manager/AbstractListener.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.manager; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.NexPlugin; 5 | 6 | public abstract class AbstractListener

> implements EventListener { 7 | 8 | @NotNull 9 | public final P plugin; 10 | 11 | public AbstractListener(@NotNull P plugin) { 12 | this.plugin = plugin; 13 | } 14 | 15 | @Override 16 | public void registerListeners() { 17 | this.plugin.getPluginManager().registerEvents(this, this.plugin); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/manager/AbstractManager.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.manager; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.NexPlugin; 5 | import su.nexmedia.engine.utils.values.UniTask; 6 | 7 | import java.util.ArrayList; 8 | import java.util.HashSet; 9 | import java.util.List; 10 | import java.util.Set; 11 | 12 | public abstract class AbstractManager

> { 13 | 14 | protected P plugin; 15 | protected final Set listeners; 16 | protected final List tasks; 17 | 18 | public AbstractManager(@NotNull P plugin) { 19 | this.plugin = plugin; 20 | this.listeners = new HashSet<>(); 21 | this.tasks = new ArrayList<>(); 22 | } 23 | 24 | public void setup() { 25 | this.onLoad(); 26 | } 27 | 28 | public void shutdown() { 29 | this.tasks.forEach(UniTask::stop); 30 | this.tasks.clear(); 31 | this.listeners.forEach(EventListener::unregisterListeners); 32 | this.listeners.clear(); 33 | this.onShutdown(); 34 | } 35 | 36 | public void reload() { 37 | this.shutdown(); 38 | this.setup(); 39 | } 40 | 41 | @NotNull 42 | public P plugin() { 43 | return this.plugin; 44 | } 45 | 46 | protected abstract void onLoad(); 47 | 48 | protected abstract void onShutdown(); 49 | 50 | /** 51 | * Adds listener to this manager. Listener will be registered when it's added. 52 | * 53 | * @param listener Listener to add. 54 | */ 55 | protected void addListener(@NotNull EventListener listener) { 56 | if (this.listeners.add(listener)) { 57 | listener.registerListeners(); 58 | } 59 | } 60 | 61 | protected void addTask(@NotNull UniTask.Builder builder) { 62 | this.addTask(builder.build()); 63 | } 64 | 65 | protected void addTask(@NotNull UniTask task) { 66 | this.tasks.add(task); 67 | task.start(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/manager/EventListener.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.manager; 2 | 3 | import org.bukkit.event.HandlerList; 4 | import org.bukkit.event.Listener; 5 | 6 | public interface EventListener extends Listener { 7 | 8 | void registerListeners(); 9 | 10 | default void unregisterListeners() { 11 | HandlerList.unregisterAll(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/menu/AutoPaged.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.menu; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.inventory.ItemStack; 5 | import org.jetbrains.annotations.NotNull; 6 | import su.nexmedia.engine.api.menu.click.ItemClick; 7 | import su.nexmedia.engine.api.menu.impl.MenuViewer; 8 | import su.nexmedia.engine.api.menu.item.ItemOptions; 9 | import su.nexmedia.engine.api.menu.item.MenuItem; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public interface AutoPaged { 15 | 16 | int[] getObjectSlots(); 17 | 18 | @NotNull List getObjects(@NotNull Player player); 19 | 20 | @NotNull ItemStack getObjectStack(@NotNull Player player, @NotNull I object); 21 | 22 | @NotNull ItemClick getObjectClick(@NotNull I object); 23 | 24 | @NotNull 25 | default List getItemsForPage(@NotNull MenuViewer viewer) { 26 | Player player = viewer.getPlayer(); 27 | List items = new ArrayList<>(); 28 | List origin = this.getObjects(player); 29 | 30 | int limit = this.getObjectSlots().length; 31 | int pages = (int) Math.ceil((double) origin.size() / (double) limit); 32 | viewer.setPages(pages); 33 | viewer.finePage(); 34 | 35 | int skip = (viewer.getPage() - 1) * limit; 36 | 37 | List list = new ArrayList<>(origin.stream().skip(skip).limit(limit).toList()); 38 | int count = 0; 39 | for (I object : list) { 40 | ItemStack item = this.getObjectStack(player, object); 41 | ItemOptions options = ItemOptions.personalWeak(player); 42 | MenuItem menuItem = new MenuItem(item, 100, options, this.getObjectSlots()[count++]); 43 | menuItem.setClick(this.getObjectClick(object)); 44 | items.add(menuItem); 45 | } 46 | 47 | return items; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/menu/MenuItemType.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.menu; 2 | 3 | public enum MenuItemType { 4 | NONE, 5 | PAGE_NEXT, 6 | PAGE_PREVIOUS, 7 | CLOSE, 8 | RETURN, 9 | CONFIRMATION_ACCEPT, 10 | CONFIRMATION_DECLINE, 11 | } 12 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/menu/click/ClickHandler.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.menu.click; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | import su.nexmedia.engine.api.menu.impl.Menu; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public class ClickHandler> { 11 | 12 | private final Map, ItemClick> clicks; 13 | 14 | public ClickHandler() { 15 | this.clicks = new HashMap<>(); 16 | } 17 | 18 | @NotNull 19 | public static ItemClick forNextPage(@NotNull Menu menu) { 20 | return ((viewer, event) -> { 21 | if (viewer.getPage() < viewer.getPages()) { 22 | menu.open(viewer.getPlayer(), viewer.getPage() + 1); 23 | } 24 | }); 25 | } 26 | 27 | @NotNull 28 | public static ItemClick forPreviousPage(@NotNull Menu menu) { 29 | return ((viewer, event) -> { 30 | if (viewer.getPage() > 1) { 31 | menu.open(viewer.getPlayer(), viewer.getPage() - 1); 32 | } 33 | }); 34 | } 35 | 36 | @NotNull 37 | public static ItemClick forClose(@NotNull Menu menu) { 38 | return ((viewer, event) -> menu.plugin().runTask(task -> viewer.getPlayer().closeInventory())); 39 | } 40 | 41 | @NotNull 42 | public Map, ItemClick> getClicks() { 43 | return clicks; 44 | } 45 | 46 | @NotNull 47 | public ClickHandler addClick(@NotNull E type, @NotNull ItemClick click) { 48 | this.clicks.put(type, click); 49 | return this; 50 | } 51 | 52 | @Nullable 53 | public ItemClick getClick(@NotNull Enum type) { 54 | return this.clicks.get(type); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/menu/click/ClickType.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.menu.click; 2 | 3 | import org.bukkit.event.inventory.InventoryClickEvent; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public enum ClickType { 7 | 8 | LEFT, RIGHT, SHIFT_LEFT, SHIFT_RIGHT, 9 | DROP_KEY, SWAP_KEY, 10 | NUMBER_1, 11 | NUMBER_2, 12 | NUMBER_3, 13 | NUMBER_4, 14 | NUMBER_5, 15 | NUMBER_6, 16 | NUMBER_7, 17 | NUMBER_8, 18 | NUMBER_9, 19 | ; 20 | 21 | @NotNull 22 | public static ClickType from(@NotNull InventoryClickEvent e) { 23 | if (e.getClick() == org.bukkit.event.inventory.ClickType.DROP) return DROP_KEY; 24 | if (e.getClick() == org.bukkit.event.inventory.ClickType.SWAP_OFFHAND) return SWAP_KEY; 25 | if (e.getHotbarButton() >= 0) { 26 | return switch (e.getHotbarButton()) { 27 | case 0 -> NUMBER_1; 28 | case 1 -> NUMBER_2; 29 | case 2 -> NUMBER_3; 30 | case 3 -> NUMBER_4; 31 | case 4 -> NUMBER_5; 32 | case 5 -> NUMBER_6; 33 | case 6 -> NUMBER_7; 34 | case 7 -> NUMBER_8; 35 | case 8 -> NUMBER_9; 36 | default -> throw new IllegalStateException("Unexpected value: " + e.getHotbarButton()); 37 | }; 38 | } 39 | 40 | if (e.isShiftClick()) { 41 | return e.isLeftClick() ? SHIFT_LEFT : SHIFT_RIGHT; 42 | } 43 | return e.isLeftClick() ? LEFT : RIGHT; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/menu/click/ItemClick.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.menu.click; 2 | 3 | import org.bukkit.event.inventory.InventoryClickEvent; 4 | import org.jetbrains.annotations.NotNull; 5 | import su.nexmedia.engine.api.menu.impl.MenuViewer; 6 | 7 | public interface ItemClick { 8 | 9 | void click(@NotNull MenuViewer viewer, @NotNull InventoryClickEvent event); 10 | } 11 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/menu/impl/MenuListener.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.menu.impl; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.EventHandler; 5 | import org.bukkit.event.EventPriority; 6 | import org.bukkit.event.inventory.InventoryClickEvent; 7 | import org.bukkit.event.inventory.InventoryCloseEvent; 8 | import org.bukkit.event.inventory.InventoryDragEvent; 9 | import org.bukkit.event.player.PlayerQuitEvent; 10 | import org.bukkit.inventory.Inventory; 11 | import org.bukkit.inventory.ItemStack; 12 | import org.jetbrains.annotations.NotNull; 13 | import su.nexmedia.engine.NexEngine; 14 | import su.nexmedia.engine.api.manager.AbstractListener; 15 | 16 | import java.util.Map; 17 | import java.util.UUID; 18 | import java.util.WeakHashMap; 19 | 20 | public class MenuListener extends AbstractListener { 21 | 22 | private static final Map FAST_CLICK = new WeakHashMap<>(); 23 | 24 | public MenuListener(@NotNull NexEngine engine) { 25 | super(engine); 26 | } 27 | 28 | @EventHandler(priority = EventPriority.MONITOR) 29 | public void onQuit(PlayerQuitEvent event) { 30 | Menu.PLAYER_MENUS.remove(event.getPlayer().getUniqueId()); 31 | FAST_CLICK.remove(event.getPlayer().getUniqueId()); 32 | } 33 | 34 | @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) 35 | public void onMenuItemClick(InventoryClickEvent event) { 36 | Player player = (Player) event.getWhoClicked(); 37 | 38 | Menu menu = Menu.getMenu(player); 39 | if (menu == null) return; 40 | 41 | MenuViewer viewer = menu.getViewer(player); 42 | if (viewer == null) return; 43 | 44 | // Fix visual glitch when item goes in player's offhand. 45 | /*if (event.getClick() == ClickType.SWAP_OFFHAND || event.isShiftClick()) { 46 | this.plugin.runTask(task -> player.updateInventory()); 47 | }*/ 48 | 49 | // Prevent clicks spam in our GUIs. 50 | long lastClick = FAST_CLICK.getOrDefault(player.getUniqueId(), 0L); 51 | if (System.currentTimeMillis() - lastClick < 150) { 52 | event.setCancelled(true); 53 | return; 54 | } 55 | 56 | Inventory inventory = event.getInventory(); 57 | ItemStack item = event.getCurrentItem(); 58 | 59 | int slot = event.getRawSlot(); 60 | boolean isPlayerSlot = slot >= inventory.getSize(); 61 | boolean isEmptyItem = item == null || item.getType().isAir(); 62 | 63 | Menu.SlotType slotType; 64 | if (isPlayerSlot) { 65 | slotType = isEmptyItem ? Menu.SlotType.PLAYER_EMPTY : Menu.SlotType.PLAYER; 66 | } 67 | else slotType = isEmptyItem ? Menu.SlotType.MENU_EMPTY : Menu.SlotType.MENU; 68 | 69 | menu.onClick(viewer, item, slotType, slot, event); 70 | FAST_CLICK.put(player.getUniqueId(), System.currentTimeMillis()); 71 | } 72 | 73 | @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) 74 | public void onMenuItemDrag(InventoryDragEvent event) { 75 | Player player = (Player) event.getWhoClicked(); 76 | 77 | Menu menu = Menu.getMenu(player); 78 | if (menu == null) return; 79 | 80 | MenuViewer viewer = menu.getViewer(player); 81 | if (viewer == null) return; 82 | 83 | menu.onDrag(viewer, event); 84 | } 85 | 86 | @EventHandler(priority = EventPriority.NORMAL) 87 | public void onMenuClose(InventoryCloseEvent event) { 88 | Player player = (Player) event.getPlayer(); 89 | 90 | Menu menu = Menu.getMenu(player); 91 | if (menu == null) return; 92 | 93 | MenuViewer viewer = menu.getViewer(player); 94 | if (viewer == null) return; 95 | 96 | menu.onClose(viewer, event); 97 | FAST_CLICK.remove(player.getUniqueId()); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/menu/impl/MenuOptions.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.menu.impl; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.event.inventory.InventoryType; 5 | import org.bukkit.inventory.Inventory; 6 | import org.jetbrains.annotations.NotNull; 7 | import su.nexmedia.engine.utils.Colorizer; 8 | 9 | import java.util.function.UnaryOperator; 10 | 11 | public class MenuOptions { 12 | 13 | private String title; 14 | private int size; 15 | private InventoryType type; 16 | private int autoRefresh; 17 | 18 | private long lastAutoRefresh; 19 | 20 | public MenuOptions(@NotNull String title, int size, @NotNull InventoryType type) { 21 | this(title, size, type, 0); 22 | } 23 | 24 | public MenuOptions(@NotNull String title, int size, @NotNull InventoryType type, int autoRefresh) { 25 | this.setTitle(title); 26 | this.setSize(size); 27 | this.setType(type); 28 | this.setAutoRefresh(autoRefresh); 29 | } 30 | 31 | public MenuOptions(@NotNull MenuOptions options) { 32 | this(options.getTitle(), options.getSize(), options.getType(), options.getAutoRefresh()); 33 | this.lastAutoRefresh = 0L; 34 | } 35 | 36 | @NotNull 37 | public Inventory createInventory() { 38 | String title = this.getTitle(); 39 | if (this.getType() == InventoryType.CHEST) { 40 | return Bukkit.getServer().createInventory(null, this.getSize(), title); 41 | } 42 | else { 43 | return Bukkit.getServer().createInventory(null, this.getType(), title); 44 | } 45 | } 46 | 47 | @NotNull 48 | public String getTitle() { 49 | return title; 50 | } 51 | 52 | public void setTitle(@NotNull String title) { 53 | this.title = Colorizer.apply(title); 54 | } 55 | 56 | public void editTitle(@NotNull UnaryOperator function) { 57 | this.setTitle(function.apply(this.getTitle())); 58 | } 59 | 60 | public int getSize() { 61 | return size; 62 | } 63 | 64 | public void setSize(int size) { 65 | if (size <= 0 || size % 9 != 0 || size > 54) size = 27; 66 | this.size = size; 67 | } 68 | 69 | @NotNull 70 | public InventoryType getType() { 71 | return type; 72 | } 73 | 74 | public void setType(@NotNull InventoryType type) { 75 | this.type = type; 76 | } 77 | 78 | public int getAutoRefresh() { 79 | return autoRefresh; 80 | } 81 | 82 | public void setAutoRefresh(int autoRefresh) { 83 | this.autoRefresh = Math.max(0, autoRefresh); 84 | } 85 | 86 | public long getLastAutoRefresh() { 87 | return lastAutoRefresh; 88 | } 89 | 90 | public void setLastAutoRefresh(long lastAutoRefresh) { 91 | this.lastAutoRefresh = lastAutoRefresh; 92 | } 93 | 94 | public boolean isReadyToRefresh() { 95 | return this.getAutoRefresh() > 0 && System.currentTimeMillis() - this.getLastAutoRefresh() >= this.getAutoRefresh(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/menu/impl/MenuRefreshTask.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.menu.impl; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.NexEngine; 5 | import su.nexmedia.engine.api.server.AbstractTask; 6 | 7 | public class MenuRefreshTask extends AbstractTask { 8 | 9 | public MenuRefreshTask(@NotNull NexEngine plugin) { 10 | super(plugin, 1, false); 11 | } 12 | 13 | @Override 14 | public void action() { 15 | Menu.PLAYER_MENUS.values().forEach(menu -> { 16 | if (menu.getOptions().isReadyToRefresh()) { 17 | menu.update(); 18 | menu.getOptions().setLastAutoRefresh(System.currentTimeMillis()); 19 | } 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/menu/impl/MenuViewer.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.menu.impl; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public class MenuViewer { 7 | 8 | private final Player player; 9 | 10 | private int page; 11 | private int pages; 12 | 13 | public MenuViewer(@NotNull Player player) { 14 | this.player = player; 15 | this.setPage(1); 16 | this.setPages(1); 17 | } 18 | 19 | @NotNull 20 | public Player getPlayer() { 21 | return player; 22 | } 23 | 24 | public int getPage() { 25 | return page; 26 | } 27 | 28 | public void setPage(int page) { 29 | this.page = Math.max(1, page); 30 | } 31 | 32 | public void finePage() { 33 | this.page = Math.max(1, Math.min(this.getPage(), this.getPages())); 34 | } 35 | 36 | public int getPages() { 37 | return pages; 38 | } 39 | 40 | public void setPages(int pages) { 41 | this.pages = Math.max(1, pages); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/menu/item/ItemOptions.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.menu.item; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.inventory.ItemStack; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | import su.nexmedia.engine.api.menu.impl.MenuViewer; 8 | 9 | import java.util.function.BiConsumer; 10 | import java.util.function.Predicate; 11 | 12 | public class ItemOptions { 13 | 14 | private Predicate visibilityPolicy; 15 | private Predicate weakPolicy; 16 | private BiConsumer displayModifier; 17 | 18 | public ItemOptions() { 19 | this(null, null, null); 20 | } 21 | 22 | public ItemOptions(@Nullable Predicate visibilityPolicy, 23 | @Nullable Predicate weakPolicy, 24 | @Nullable BiConsumer displayModifier) { 25 | this.setVisibilityPolicy(visibilityPolicy); 26 | this.setWeakPolicy(weakPolicy); 27 | this.setDisplayModifier(displayModifier); 28 | } 29 | 30 | @NotNull 31 | public static ItemOptions personalWeak(@NotNull Player player) { 32 | Predicate visibility = (viewer -> viewer.getPlayer().getUniqueId().equals(player.getUniqueId())); 33 | Predicate weak = (viewer -> viewer.getPlayer().getUniqueId().equals(player.getUniqueId())); 34 | return new ItemOptions(visibility, weak, null); 35 | } 36 | 37 | @NotNull 38 | public static ItemOptions personalPermanent(@NotNull Player player) { 39 | Predicate visibility = (viewer -> viewer.getPlayer().getUniqueId().equals(player.getUniqueId())); 40 | return new ItemOptions(visibility, null, null); 41 | } 42 | 43 | public boolean canSee(@NotNull MenuViewer viewer) { 44 | Predicate policy = this.getVisibilityPolicy(); 45 | return policy == null || policy.test(viewer); 46 | } 47 | 48 | public boolean canBeDestroyed(@NotNull MenuViewer viewer) { 49 | Predicate policy = this.getWeakPolicy(); 50 | return policy != null && policy.test(viewer); 51 | } 52 | 53 | public void modifyDisplay(@NotNull MenuViewer viewer, @NotNull ItemStack item) { 54 | BiConsumer displayModifier = this.getDisplayModifier(); 55 | if (displayModifier != null) { 56 | displayModifier.accept(viewer, item); 57 | } 58 | } 59 | 60 | @Nullable 61 | public Predicate getVisibilityPolicy() { 62 | return visibilityPolicy; 63 | } 64 | 65 | @NotNull 66 | public ItemOptions setVisibilityPolicy(@Nullable Predicate visibilityPolicy) { 67 | this.visibilityPolicy = visibilityPolicy; 68 | return this; 69 | } 70 | 71 | @Nullable 72 | public Predicate getWeakPolicy() { 73 | return weakPolicy; 74 | } 75 | 76 | @NotNull 77 | public ItemOptions setWeakPolicy(@Nullable Predicate weakPolicy) { 78 | this.weakPolicy = weakPolicy; 79 | return this; 80 | } 81 | 82 | @Nullable 83 | public BiConsumer getDisplayModifier() { 84 | return displayModifier; 85 | } 86 | 87 | @NotNull 88 | public ItemOptions setDisplayModifier(@Nullable BiConsumer displayModifier) { 89 | this.displayModifier = displayModifier; 90 | return this; 91 | } 92 | 93 | @NotNull 94 | public ItemOptions addDisplayModifier(@NotNull BiConsumer displayModifier) { 95 | if (this.displayModifier == null) { 96 | this.displayModifier = displayModifier; 97 | } 98 | else { 99 | this.displayModifier = this.displayModifier.andThen(displayModifier); 100 | } 101 | return this; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/menu/item/MenuItem.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.menu.item; 2 | 3 | import org.bukkit.inventory.ItemStack; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | import su.nexmedia.engine.api.menu.MenuItemType; 7 | import su.nexmedia.engine.api.menu.click.ItemClick; 8 | 9 | public class MenuItem { 10 | 11 | protected Enum type; 12 | protected ItemStack item; 13 | protected int priority; 14 | protected int[] slots; 15 | 16 | protected ItemOptions options; 17 | protected ItemClick click; 18 | 19 | public MenuItem(@NotNull ItemStack item) { 20 | this(MenuItemType.NONE, item); 21 | } 22 | 23 | public MenuItem(@NotNull ItemStack item, int... slots) { 24 | this(MenuItemType.NONE, item, 0, slots); 25 | } 26 | 27 | public MenuItem( @NotNull ItemStack item, int priority, @NotNull ItemOptions options, int... slots) { 28 | this(MenuItemType.NONE, item, priority, options, slots); 29 | } 30 | 31 | 32 | public MenuItem(@NotNull Enum type, @NotNull ItemStack item) { 33 | this(type, item, 0); 34 | } 35 | 36 | public MenuItem(@NotNull Enum type, @NotNull ItemStack item, int priority) { 37 | this(type, item, priority, new int[]{}); 38 | } 39 | 40 | public MenuItem(@NotNull Enum type, @NotNull ItemStack item, int priority, int... slots) { 41 | this(type, item, priority, new ItemOptions(), slots); 42 | } 43 | 44 | public MenuItem(@NotNull Enum type, @NotNull ItemStack item, int priority, @NotNull ItemOptions options, int... slots) { 45 | this.setType(type); 46 | this.setItem(item); 47 | this.setPriority(priority); 48 | this.setSlots(slots); 49 | this.setOptions(options); 50 | } 51 | 52 | @NotNull 53 | public MenuItem copy() { 54 | return new MenuItem(this.getType(), this.getItem(), this.getPriority(), this.getOptions(), this.getSlots()); 55 | } 56 | 57 | @NotNull 58 | public MenuItem resetOptions() { 59 | this.setOptions(new ItemOptions()); 60 | return this; 61 | } 62 | 63 | @NotNull 64 | public Enum getType() { 65 | return type; 66 | } 67 | 68 | @NotNull 69 | public MenuItem setType(@Nullable Enum type) { 70 | this.type = type == null ? MenuItemType.NONE : type; 71 | return this; 72 | } 73 | 74 | @NotNull 75 | public ItemStack getItem() { 76 | return new ItemStack(this.item); 77 | } 78 | 79 | @NotNull 80 | public MenuItem setItem(@NotNull ItemStack item) { 81 | this.item = new ItemStack(item); 82 | return this; 83 | } 84 | 85 | public int getPriority() { 86 | return priority; 87 | } 88 | 89 | @NotNull 90 | public MenuItem setPriority(int priority) { 91 | this.priority = priority; 92 | return this; 93 | } 94 | 95 | public int[] getSlots() { 96 | return slots; 97 | } 98 | 99 | @NotNull 100 | public MenuItem setSlots(int... slots) { 101 | this.slots = slots; 102 | return this; 103 | } 104 | 105 | @NotNull 106 | public ItemOptions getOptions() { 107 | return options; 108 | } 109 | 110 | @NotNull 111 | public MenuItem setOptions(@NotNull ItemOptions options) { 112 | this.options = options; 113 | return this; 114 | } 115 | 116 | @Nullable 117 | public ItemClick getClick() { 118 | return click; 119 | } 120 | 121 | @NotNull 122 | public MenuItem setClick(@Nullable ItemClick click) { 123 | this.click = click; 124 | return this; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/menu/link/Linked.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.menu.link; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public interface Linked { 7 | 8 | @NotNull ViewLink getLink(); 9 | 10 | default boolean open(@NotNull Player player, @NotNull T obj, int page) { 11 | this.getLink().set(player, obj); 12 | 13 | if (!this.open(player, page)) { 14 | this.getLink().clear(player); 15 | return false; 16 | } 17 | 18 | return true; 19 | } 20 | 21 | boolean open(@NotNull Player player, int page); 22 | } 23 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/menu/link/ViewLink.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.menu.link; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.jetbrains.annotations.NotNull; 5 | import su.nexmedia.engine.api.menu.impl.MenuViewer; 6 | 7 | import java.util.Map; 8 | import java.util.WeakHashMap; 9 | 10 | public class ViewLink { 11 | 12 | private final Map map; 13 | 14 | public ViewLink() { 15 | this.map = new WeakHashMap<>(); 16 | } 17 | 18 | public void set(@NotNull MenuViewer viewer, @NotNull T object) { 19 | this.set(viewer.getPlayer(), object); 20 | } 21 | 22 | public void set(@NotNull Player viewer, @NotNull T object) { 23 | this.map.put(viewer, object); 24 | } 25 | 26 | public T get(@NotNull MenuViewer viewer) { 27 | return this.get(viewer.getPlayer()); 28 | } 29 | 30 | public T get(@NotNull Player viewer) { 31 | return this.map.get(viewer); 32 | } 33 | 34 | public void clear(@NotNull MenuViewer viewer) { 35 | this.clear(viewer.getPlayer()); 36 | } 37 | 38 | public void clear(@NotNull Player viewer) { 39 | this.map.remove(viewer); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/placeholder/Placeholder.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.placeholder; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.function.UnaryOperator; 6 | 7 | public interface Placeholder { 8 | 9 | @NotNull PlaceholderMap getPlaceholders(); 10 | 11 | @NotNull 12 | default UnaryOperator replacePlaceholders() { 13 | return this.getPlaceholders().replacer(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/placeholder/PlaceholderMap.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.placeholder; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.utils.Pair; 5 | import su.nexmedia.engine.utils.StringUtil; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.function.Supplier; 10 | import java.util.function.UnaryOperator; 11 | 12 | public class PlaceholderMap { 13 | 14 | private final List>> keys; 15 | 16 | public PlaceholderMap() { 17 | this(new ArrayList<>()); 18 | } 19 | 20 | public PlaceholderMap(@NotNull PlaceholderMap other) { 21 | this(other.getKeys()); 22 | } 23 | 24 | public PlaceholderMap(@NotNull List>> keys) { 25 | this.keys = new ArrayList<>(keys); 26 | } 27 | 28 | @NotNull 29 | public static PlaceholderMap fusion(@NotNull PlaceholderMap... others) { 30 | PlaceholderMap map = new PlaceholderMap(); 31 | for (PlaceholderMap other : others) { 32 | map.add(other); 33 | } 34 | return map; 35 | } 36 | 37 | @NotNull 38 | public static PlaceholderMap fusion(@NotNull Placeholder... others) { 39 | PlaceholderMap map = new PlaceholderMap(); 40 | for (Placeholder other : others) { 41 | map.add(other.getPlaceholders()); 42 | } 43 | return map; 44 | } 45 | 46 | @NotNull 47 | public List>> getKeys() { 48 | return keys; 49 | } 50 | 51 | @NotNull 52 | public PlaceholderMap add(@NotNull PlaceholderMap other) { 53 | this.getKeys().addAll(other.getKeys()); 54 | return this; 55 | } 56 | 57 | @NotNull 58 | public PlaceholderMap add(@NotNull String key, @NotNull String replacer) { 59 | this.add(key, () -> replacer); 60 | return this; 61 | } 62 | 63 | @NotNull 64 | public PlaceholderMap add(@NotNull String key, @NotNull Supplier replacer) { 65 | this.getKeys().add(Pair.of(key, replacer)); 66 | return this; 67 | } 68 | 69 | public void clear() { 70 | this.getKeys().clear(); 71 | } 72 | 73 | @NotNull 74 | public UnaryOperator replacer() { 75 | return str -> StringUtil.replaceEach(str, this.getKeys()); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/server/AbstractTask.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.server; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.NexPlugin; 5 | 6 | public abstract class AbstractTask

> { 7 | 8 | @NotNull protected final P plugin; 9 | 10 | protected int taskId; 11 | protected long interval; 12 | protected boolean async; 13 | 14 | public AbstractTask(@NotNull P plugin, int interval, boolean async) { 15 | this(plugin, interval * 20L, async); 16 | } 17 | 18 | public AbstractTask(@NotNull P plugin, long interval, boolean async) { 19 | this.plugin = plugin; 20 | this.interval = interval; 21 | this.async = async; 22 | this.taskId = -1; 23 | } 24 | 25 | public abstract void action(); 26 | 27 | public final void restart() { 28 | this.stop(); 29 | this.start(); 30 | } 31 | 32 | public boolean start() { 33 | if (this.taskId >= 0) return false; 34 | if (this.interval <= 0L) return false; 35 | 36 | if (this.async) { 37 | this.taskId = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this::action, 1L, interval).getTaskId(); 38 | } 39 | else { 40 | this.taskId = plugin.getServer().getScheduler().runTaskTimer(this.plugin, this::action, 1L, interval).getTaskId(); 41 | } 42 | return true; 43 | } 44 | 45 | public boolean stop() { 46 | if (this.taskId < 0) return false; 47 | 48 | this.plugin.getServer().getScheduler().cancelTask(this.taskId); 49 | this.taskId = -1; 50 | return true; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/api/server/JPermission.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.api.server; 2 | 3 | import org.bukkit.permissions.Permission; 4 | import org.bukkit.permissions.PermissionDefault; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | public class JPermission extends Permission { 9 | 10 | public JPermission(@NotNull String name) { 11 | this(name, null); 12 | } 13 | 14 | public JPermission(@NotNull String name, @Nullable String description) { 15 | this(name, description, PermissionDefault.OP); 16 | } 17 | 18 | public JPermission(@NotNull String name, @Nullable String description, @Nullable PermissionDefault defaultValue) { 19 | super(name, description, defaultValue); 20 | } 21 | 22 | @NotNull 23 | public JPermission description(String... desc) { 24 | this.setDescription(String.join(" ", desc)); 25 | return this; 26 | } 27 | 28 | public void addChildren(@NotNull Permission... childrens) { 29 | for (Permission children : childrens) { 30 | children.addParent(this, true); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/command/CommandManager.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.command; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | import su.nexmedia.engine.NexPlugin; 6 | import su.nexmedia.engine.api.command.GeneralCommand; 7 | import su.nexmedia.engine.api.manager.AbstractManager; 8 | import su.nexmedia.engine.command.list.HelpSubCommand; 9 | import su.nexmedia.engine.utils.ArrayUtil; 10 | import su.nexmedia.engine.utils.values.UniTask; 11 | 12 | import java.util.HashSet; 13 | import java.util.Set; 14 | 15 | public class CommandManager

> extends AbstractManager

{ 16 | 17 | private Set> commands; 18 | private PluginMainCommand

mainCommand; 19 | 20 | public CommandManager(@NotNull P plugin) { 21 | super(plugin); 22 | } 23 | 24 | @Override 25 | public void onLoad() { 26 | this.commands = new HashSet<>(); 27 | if (this.plugin.getConfigManager().commandAliases == null || this.plugin.getConfigManager().commandAliases.length == 0) { 28 | this.plugin.error("Could not register plugin commands!"); 29 | return; 30 | } 31 | 32 | // Create main plugin command and attach help sub-command as a default executor. 33 | this.mainCommand = new PluginMainCommand<>(this.plugin); 34 | this.mainCommand.addDefaultCommand(new HelpSubCommand<>(this.plugin)); 35 | 36 | // Register child plugin sub-commands to the main plugin command. 37 | this.plugin.registerCommands(this.mainCommand); 38 | 39 | // Register main command as a bukkit command. 40 | this.registerCommand(this.mainCommand); 41 | } 42 | 43 | @Override 44 | public void onShutdown() { 45 | for (GeneralCommand

command : new HashSet<>(this.commands)) { 46 | this.unregisterCommand(command); 47 | command.getChildrens().clear(); 48 | } 49 | this.commands.clear(); 50 | } 51 | 52 | @NotNull 53 | public Set> getCommands() { 54 | return this.commands; 55 | } 56 | 57 | @NotNull 58 | public PluginMainCommand

getMainCommand() { 59 | return this.mainCommand; 60 | } 61 | 62 | @Nullable 63 | public GeneralCommand

getCommand(@NotNull String alias) { 64 | return this.getCommands().stream() 65 | .filter(command -> ArrayUtil.contains(command.getAliases(), alias)) 66 | .findFirst().orElse(null); 67 | } 68 | 69 | public void registerCommand(@NotNull GeneralCommand

command) { 70 | if (this.commands.add(command)) { 71 | CommandRegister.register(this.plugin, command); 72 | } 73 | } 74 | 75 | public boolean unregisterCommand(@NotNull String alias) { 76 | GeneralCommand

command = this.getCommand(alias); 77 | if (command != null) { 78 | return this.unregisterCommand(command); 79 | } 80 | return false; 81 | } 82 | 83 | public boolean unregisterCommand(@NotNull GeneralCommand

command) { 84 | if (this.commands.remove(command)) { 85 | return CommandRegister.unregister(command.getAliases()[0]); 86 | } 87 | return false; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/command/CommandRegister.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.command; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.Server; 5 | import org.bukkit.command.*; 6 | import org.bukkit.plugin.Plugin; 7 | import org.jetbrains.annotations.NotNull; 8 | import su.nexmedia.engine.api.command.GeneralCommand; 9 | import su.nexmedia.engine.utils.Reflex; 10 | 11 | import java.lang.reflect.Method; 12 | import java.util.*; 13 | 14 | public class CommandRegister extends Command implements PluginIdentifiableCommand { 15 | 16 | protected final CommandExecutor executor; 17 | protected final Plugin plugin; 18 | protected final TabCompleter tab; 19 | 20 | public CommandRegister(@NotNull Plugin plugin, @NotNull CommandExecutor executor, @NotNull TabCompleter tab, 21 | @NotNull String[] aliases, @NotNull String description, @NotNull String usage) { 22 | super(aliases[0], description, usage, Arrays.asList(aliases)); 23 | this.executor = executor; 24 | this.plugin = plugin; 25 | this.tab = tab; 26 | } 27 | 28 | private static SimpleCommandMap getCommandMap() { 29 | return (SimpleCommandMap) Reflex.getFieldValue(Bukkit.getServer(), "commandMap"); 30 | } 31 | 32 | public static void register(@NotNull Plugin plugin, @NotNull GeneralCommand command) { 33 | CommandRegister register = new CommandRegister(plugin, command, command, command.getAliases(), command.getDescription(), command.getUsage()); 34 | register.setPermission(command.getPermission()); 35 | 36 | if (getCommandMap().register(plugin.getDescription().getName(), register)) { 37 | command.setFallback(register); 38 | } 39 | } 40 | 41 | public static void syncCommands() { 42 | // Fix tab completer when registerd on runtime 43 | Server server = Bukkit.getServer(); 44 | Method method = Reflex.getMethod(server.getClass(), "syncCommands"); 45 | if (method == null) return; 46 | 47 | Reflex.invokeMethod(method, server); 48 | } 49 | 50 | @SuppressWarnings("unchecked") 51 | public static boolean unregister(@NotNull String name) { 52 | SimpleCommandMap map = getCommandMap(); 53 | Command match = map.getCommands().stream() 54 | .filter(command -> command.getLabel().equalsIgnoreCase(name) || command.getAliases().contains(name)) 55 | .findFirst().orElse(null); 56 | if (match == null) return false; 57 | 58 | Map knownCommands = (HashMap) Reflex.getFieldValue(map, "knownCommands"); 59 | if (knownCommands == null) return false; 60 | 61 | if (match.unregister(map)) { 62 | return knownCommands.keySet().removeIf(key -> key.equalsIgnoreCase(match.getName()) || match.getAliases().contains(key)); 63 | } 64 | return false; 65 | } 66 | 67 | @NotNull 68 | public static Set getAliases(@NotNull String name) { 69 | return getAliases(name, false); 70 | } 71 | 72 | @NotNull 73 | public static Set getAliases(@NotNull String name, boolean inclusive) { 74 | Command command = getCommand(name).orElse(null); 75 | if (command == null) return Collections.emptySet(); 76 | 77 | Set aliases = new HashSet<>(command.getAliases()); 78 | if (inclusive) aliases.add(command.getName()); 79 | return aliases; 80 | } 81 | 82 | @NotNull 83 | public static Optional getCommand(@NotNull String name) { 84 | SimpleCommandMap map = getCommandMap(); 85 | return map.getCommands().stream() 86 | .filter(command -> command.getLabel().equalsIgnoreCase(name) || command.getAliases().contains(name)) 87 | .findFirst(); 88 | } 89 | 90 | @Override 91 | @NotNull 92 | public Plugin getPlugin() { 93 | return this.plugin; 94 | } 95 | 96 | @Override 97 | public boolean execute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) { 98 | return this.executor.onCommand(sender, this, label, args); 99 | } 100 | 101 | @Override 102 | @NotNull 103 | public List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) { 104 | if (this.tab != null) { 105 | List list = this.tab.onTabComplete(sender, this, alias, args); 106 | if (list != null) { 107 | return list; 108 | } 109 | } 110 | return Collections.emptyList(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/command/PluginMainCommand.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.command; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.jetbrains.annotations.NotNull; 5 | import su.nexmedia.engine.NexPlugin; 6 | import su.nexmedia.engine.api.command.CommandResult; 7 | import su.nexmedia.engine.api.command.GeneralCommand; 8 | 9 | public class PluginMainCommand

> extends GeneralCommand

{ 10 | 11 | public PluginMainCommand(@NotNull P plugin) { 12 | super(plugin, plugin.getLabels()); 13 | } 14 | 15 | @Override 16 | protected void onExecute(@NotNull CommandSender sender, @NotNull CommandResult result) { 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/command/list/CheckPermCommand.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.command.list; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.bukkit.entity.Player; 5 | import org.jetbrains.annotations.NotNull; 6 | import su.nexmedia.engine.NexEngine; 7 | import su.nexmedia.engine.api.command.AbstractCommand; 8 | import su.nexmedia.engine.api.command.CommandResult; 9 | import su.nexmedia.engine.config.EnginePerms; 10 | import su.nexmedia.engine.integration.VaultHook; 11 | import su.nexmedia.engine.lang.EngineLang; 12 | import su.nexmedia.engine.utils.CollectionsUtil; 13 | import su.nexmedia.engine.utils.Colorizer; 14 | import su.nexmedia.engine.utils.PlayerUtil; 15 | 16 | import java.util.List; 17 | 18 | import static su.nexmedia.engine.utils.Colors2.*; 19 | 20 | public class CheckPermCommand extends AbstractCommand { 21 | 22 | public CheckPermCommand(@NotNull NexEngine plugin) { 23 | super(plugin, new String[]{"checkperm"}, EnginePerms.COMMAND_CHECK_PERM); 24 | this.setDescription(plugin.getMessage(EngineLang.COMMAND_CHECKPERM_DESC)); 25 | this.setUsage(plugin.getMessage(EngineLang.COMMAND_CHECKPERM_USAGE)); 26 | } 27 | 28 | @Override 29 | @NotNull 30 | public List getTab(@NotNull Player player, int arg, @NotNull String[] args) { 31 | if (arg == 1) { 32 | return CollectionsUtil.playerNames(player); 33 | } 34 | return super.getTab(player, arg, args); 35 | } 36 | 37 | @Override 38 | protected void onExecute(@NotNull CommandSender sender, @NotNull CommandResult result) { 39 | if (result.length() < 2) { 40 | this.printUsage(sender); 41 | return; 42 | } 43 | 44 | Player player = PlayerUtil.getPlayer(result.getArg(1)); 45 | if (player == null) { 46 | this.errorPlayer(sender); 47 | return; 48 | } 49 | 50 | sender.sendMessage(LIGHT_YELLOW + BOLD + "Permissions report for " + LIGHT_ORANGE + player.getName() + ":"); 51 | sender.sendMessage(LIGHT_ORANGE + "▪ " + LIGHT_YELLOW + "Primary Group: " + LIGHT_ORANGE + Colorizer.plain(VaultHook.getPermissionGroup(player))); 52 | sender.sendMessage(LIGHT_ORANGE + "▪ " + LIGHT_YELLOW + "All Groups: " + LIGHT_ORANGE + Colorizer.plain(String.join(", ", VaultHook.getPermissionGroups(player)))); 53 | sender.sendMessage(LIGHT_ORANGE + "▪ " + LIGHT_YELLOW + "Prefix: " + LIGHT_ORANGE + VaultHook.getPrefix(player)); 54 | sender.sendMessage(LIGHT_ORANGE + "▪ " + LIGHT_YELLOW + "Suffix: " + LIGHT_ORANGE + VaultHook.getSuffix(player)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/command/list/HelpSubCommand.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.command.list; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.jetbrains.annotations.NotNull; 5 | import su.nexmedia.engine.NexPlugin; 6 | import su.nexmedia.engine.api.command.AbstractCommand; 7 | import su.nexmedia.engine.api.command.CommandResult; 8 | import su.nexmedia.engine.lang.EngineLang; 9 | import su.nexmedia.engine.utils.Placeholders; 10 | 11 | public class HelpSubCommand

> extends AbstractCommand

{ 12 | 13 | public HelpSubCommand(@NotNull P plugin) { 14 | super(plugin, new String[]{"help"}); 15 | this.setDescription(plugin.getMessage(EngineLang.COMMAND_HELP_DESC)); 16 | } 17 | 18 | @Override 19 | protected void onExecute(@NotNull CommandSender sender, @NotNull CommandResult result) { 20 | if (!this.parent.hasPermission(sender)) { 21 | this.errorPermission(sender); 22 | return; 23 | } 24 | 25 | plugin.getMessage(EngineLang.COMMAND_HELP_LIST) 26 | .replace(str -> str.contains(Placeholders.COMMAND_LABEL), (line, list) -> { 27 | this.parent.getChildrens().forEach(children -> { 28 | if (!children.hasPermission(sender)) return; 29 | 30 | list.add(children.replacePlaceholders().apply(line)); 31 | }); 32 | }).send(sender); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/command/list/ReloadSubCommand.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.command.list; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.bukkit.permissions.Permission; 5 | import org.jetbrains.annotations.NotNull; 6 | import su.nexmedia.engine.NexPlugin; 7 | import su.nexmedia.engine.api.command.AbstractCommand; 8 | import su.nexmedia.engine.api.command.CommandResult; 9 | import su.nexmedia.engine.lang.EngineLang; 10 | 11 | public class ReloadSubCommand

> extends AbstractCommand

{ 12 | 13 | public ReloadSubCommand(@NotNull P plugin, @NotNull Permission permission) { 14 | this(plugin, permission.getName()); 15 | } 16 | 17 | public ReloadSubCommand(@NotNull P plugin, @NotNull String permission) { 18 | super(plugin, new String[]{"reload"}, permission); 19 | this.setDescription(plugin.getMessage(EngineLang.COMMAND_RELOAD_DESC)); 20 | } 21 | 22 | @Override 23 | protected void onExecute(@NotNull CommandSender sender, @NotNull CommandResult result) { 24 | plugin.reload(); 25 | plugin.getMessage(EngineLang.COMMAND_RELOAD_DONE).send(sender); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/config/ConfigManager.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.config; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.NexPlugin; 5 | import su.nexmedia.engine.api.config.JOption; 6 | import su.nexmedia.engine.api.config.JYML; 7 | import su.nexmedia.engine.api.manager.AbstractManager; 8 | import su.nexmedia.engine.lang.LangManager; 9 | import su.nexmedia.engine.utils.Colors; 10 | import su.nexmedia.engine.utils.Placeholders; 11 | import su.nexmedia.engine.utils.ResourceExtractor; 12 | 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.util.Locale; 16 | 17 | public class ConfigManager

> extends AbstractManager

{ 18 | 19 | private JYML config; 20 | protected String filePath; 21 | 22 | public String pluginName; 23 | public String pluginPrefix; 24 | public String[] commandAliases; 25 | public String languageCode; 26 | 27 | public ConfigManager(@NotNull P plugin) { 28 | super(plugin); 29 | this.filePath = "config.yml"; 30 | } 31 | 32 | @Override 33 | protected void onLoad() { 34 | this.config = JYML.loadOrExtract(this.plugin, this.filePath); 35 | 36 | this.pluginName = JOption.create("Plugin.Name", plugin.getName(), 37 | "Localized plugin name. It's used in messages and with internal placeholders.") 38 | .read(config); 39 | 40 | // TODO plugin.loadConfig(ConfigDefaults) 41 | 42 | this.pluginPrefix = JOption.create("Plugin.Prefix", 43 | Colors.YELLOW + Placeholders.PLUGIN_NAME + Colors.GRAY + " » ", 44 | "Plugin prefix. Used in messages.", 45 | "You can use " + Placeholders.PLUGIN_NAME_LOCALIZED + " placeholder for a plugin name." 46 | ).read(config).replace(Placeholders.PLUGIN_NAME, this.pluginName); 47 | 48 | this.commandAliases = JOption.create("Plugin.Command_Aliases", plugin.getName().toLowerCase(), 49 | "Command names that will be registered as main plugin commands.", 50 | "Do not leave this empty. Split multiple names with a comma.") 51 | .read(config).split(","); 52 | 53 | this.languageCode = JOption.create("Plugin.Language", Locale.getDefault().getLanguage(), 54 | "Sets the plugin language.", 55 | "It will use language config from the '" + LangManager.DIR_LANG + "' sub-folder for specified language code.", 56 | "By default uses your system's default locale.") 57 | .read(config).toLowerCase(); 58 | 59 | this.config.saveChanges(); 60 | } 61 | 62 | @Override 63 | protected void onShutdown() { 64 | 65 | } 66 | 67 | @NotNull 68 | public JYML getConfig() { 69 | return this.config; 70 | } 71 | 72 | @Deprecated 73 | public void extractResources(@NotNull String folder) { 74 | this.extractResources(folder,plugin.getDataFolder() + folder, false); 75 | } 76 | 77 | @Deprecated 78 | public void extractResources(@NotNull String jarPath, @NotNull String toPath) { 79 | this.extractResources(jarPath, toPath, false); 80 | } 81 | 82 | @Deprecated 83 | public void extractResources(@NotNull String jarPath, @NotNull String toPath, boolean override) { 84 | File destination = new File(toPath); 85 | if (destination.exists() && !override) return; 86 | 87 | if (jarPath.startsWith("/")) { 88 | jarPath = jarPath.substring(1); 89 | } 90 | if (jarPath.endsWith("/")) { 91 | jarPath = jarPath.substring(0, jarPath.length() - 1); 92 | } 93 | 94 | ResourceExtractor extract = ResourceExtractor.create(plugin, jarPath, destination); 95 | try { 96 | extract.extract(override); 97 | } 98 | catch (IOException e) { 99 | e.printStackTrace(); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/config/EngineConfig.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.config; 2 | 3 | import su.nexmedia.engine.api.config.JOption; 4 | 5 | public class EngineConfig { 6 | 7 | public static final JOption USER_DEBUG_ENABLED = JOption.create("UserData.Debug", 8 | false, 9 | "Enables debug messages for user data management.", 10 | "[Default is false]"); 11 | 12 | public static final JOption USER_CACHE_LIFETIME = JOption.create("UserData.Cache.LifeTime", 13 | 300, 14 | "Sets how long (in seconds) user data will be cached for offline users", 15 | "until removed and needs to be loaded from the database again.", 16 | "[Default is 300 (5 minutes)]"); 17 | 18 | public static final JOption USER_CACHE_NAME_AND_UUID = JOption.create("UserData.Cache.Names_And_UUIDs", 19 | true, 20 | "Sets whether or not plugin will cache player names and UUIDs.", 21 | "This will improve database performance when checking if user exists, but will increase memory usage.", 22 | "[Default is true]"); 23 | 24 | public static final JOption TAB_COMPLETER_REGEX_MAX_LENGTH = JOption.create("TabCompleter.Regex_Max_Length", 25 | 32, 26 | "Sets maximal length for input text to use a regex based search (aka smart tab-completer).", 27 | "When player entered text with length that exceeds this value, basic text search will be used instead.", 28 | "[Default is 32]"); 29 | 30 | public static final JOption TAB_COMPLETER_REGEX_TIMEOUT = JOption.create("TabCompleter.Regex_Timeout", 31 | 25, 32 | "Amount of milliseconds for regex matcher timeout in tab completion.", 33 | "If tab-completion takes more than this amount to find matches from a list, it will be interrupted.", 34 | "[Default is 25ms]"); 35 | 36 | public static final JOption RESPECT_PLAYER_DISPLAYNAME = JOption.create("Engine.Respect_Player_DisplayName", 37 | false, 38 | "Sets whether or not 'Player#getDisplayName' can be used to find & get players in addition to regular 'Player#getName'.", 39 | "This is useful if you want to use custom player nicknames in commands.", 40 | "(Works only for NexEngine based plugins.)", 41 | "[Default is false]"); 42 | } 43 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/config/EnginePerms.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.config; 2 | 3 | import su.nexmedia.engine.api.server.JPermission; 4 | 5 | public class EnginePerms { 6 | 7 | public static final JPermission COMMAND_CHECK_PERM = new JPermission("nexengine.command.checkperm"); 8 | } 9 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/editor/EditorListener.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.editor; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.EventHandler; 5 | import org.bukkit.event.EventPriority; 6 | import org.bukkit.event.player.AsyncPlayerChatEvent; 7 | import org.bukkit.event.player.PlayerCommandPreprocessEvent; 8 | import org.bukkit.event.player.PlayerQuitEvent; 9 | import org.jetbrains.annotations.NotNull; 10 | import su.nexmedia.engine.NexEngine; 11 | import su.nexmedia.engine.api.editor.InputHandler; 12 | import su.nexmedia.engine.api.editor.InputWrapper; 13 | import su.nexmedia.engine.api.manager.AbstractListener; 14 | import su.nexmedia.engine.utils.Colorizer; 15 | import su.nexmedia.engine.utils.StringUtil; 16 | 17 | import java.util.HashSet; 18 | 19 | public class EditorListener extends AbstractListener { 20 | 21 | public EditorListener(@NotNull NexEngine plugin) { 22 | super(plugin); 23 | } 24 | 25 | @EventHandler(priority = EventPriority.MONITOR) 26 | public void onQuit(PlayerQuitEvent event) { 27 | EditorManager.endEdit(event.getPlayer()); 28 | } 29 | 30 | @EventHandler(priority = EventPriority.LOWEST) 31 | public void onChatText(AsyncPlayerChatEvent event) { 32 | Player player = event.getPlayer(); 33 | 34 | InputHandler handler = EditorManager.getInputHandler(player); 35 | if (handler == null) return; 36 | 37 | event.getRecipients().clear(); 38 | event.setCancelled(true); 39 | 40 | InputWrapper wrapper = new InputWrapper(event); 41 | 42 | this.plugin.runTask(task -> { 43 | if (wrapper.getTextRaw().equalsIgnoreCase(EditorManager.EXIT) || handler.handle(wrapper)) { 44 | EditorManager.endEdit(player); 45 | } 46 | }); 47 | } 48 | 49 | @EventHandler(priority = EventPriority.LOWEST) 50 | public void onChatCommand(PlayerCommandPreprocessEvent event) { 51 | Player player = event.getPlayer(); 52 | 53 | InputHandler handler = EditorManager.getInputHandler(player); 54 | if (handler == null) return; 55 | 56 | event.setCancelled(true); 57 | 58 | String raw = event.getMessage(); 59 | String text = Colorizer.apply(raw.substring(1)); 60 | if (text.startsWith(EditorManager.VALUES)) { 61 | String[] split = text.split(" "); 62 | int page = split.length >= 2 ? StringUtil.getInteger(split[1], 0) : 0; 63 | boolean auto = split.length >= 3 && Boolean.parseBoolean(split[2]); 64 | EditorManager.displayValues(player, auto, page); 65 | return; 66 | } 67 | 68 | AsyncPlayerChatEvent chatEvent = new AsyncPlayerChatEvent(true, player, text, new HashSet<>()); 69 | InputWrapper wrapper = new InputWrapper(chatEvent); 70 | 71 | this.plugin.runTask(task -> { 72 | if (wrapper.getTextRaw().equalsIgnoreCase(EditorManager.EXIT) || handler.handle(wrapper)) { 73 | EditorManager.endEdit(player); 74 | } 75 | }); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/lang/EngineLang.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.lang; 2 | 3 | import su.nexmedia.engine.api.lang.LangKey; 4 | import su.nexmedia.engine.editor.EditorManager; 5 | import su.nexmedia.engine.utils.Placeholders; 6 | 7 | import static su.nexmedia.engine.utils.Colors.*; 8 | import static su.nexmedia.engine.utils.Placeholders.*; 9 | 10 | public class EngineLang { 11 | 12 | public static final LangKey COMMAND_USAGE = LangKey.of("Command.Usage", 13 | "" + 14 | "\n" + GRAY + 15 | "\n" + RED + "Error: " + GRAY + "Wrong arguments!" + 16 | "\n" + RED + "Usage: " + YELLOW + "/" + COMMAND_LABEL + " " + ORANGE + Placeholders.COMMAND_USAGE + 17 | "\n" + GRAY); 18 | 19 | public static final LangKey COMMAND_HELP_LIST = LangKey.of("Command.Help.List", 20 | "" + 21 | "\n" + GRAY + 22 | "\n" + " " + YELLOW + BOLD + PLUGIN_NAME_LOCALIZED + GRAY + " - " + YELLOW + BOLD + "Commands:" + 23 | "\n" + GRAY + 24 | "\n" + " " + RED + BOLD + "<> " + GRAY + "- Required, " + GREEN + BOLD + "[] " + GRAY + "- Optional." + 25 | "\n" + GRAY + 26 | "\n" + " " + YELLOW + "/" + COMMAND_LABEL + " " + ORANGE + Placeholders.COMMAND_USAGE + " " + GRAY + "- " + COMMAND_DESCRIPTION + 27 | "\n" + GRAY); 28 | 29 | public static final LangKey COMMAND_HELP_DESC = LangKey.of("Command.Help.Desc", "Show help page."); 30 | 31 | public static final LangKey COMMAND_CHECKPERM_DESC = LangKey.of("Command.CheckPerm.Desc", "Print player permission info."); 32 | public static final LangKey COMMAND_CHECKPERM_USAGE = LangKey.of("Command.CheckPerm.Usage", ""); 33 | 34 | public static final LangKey COMMAND_RELOAD_DESC = LangKey.of("Command.Reload.Desc", "Reload the whole plugin."); 35 | public static final LangKey COMMAND_RELOAD_DONE = LangKey.of("Command.Reload.Done", "All data & configuration has been reloaded!"); 36 | 37 | public static final LangKey TIME_DAY = new LangKey("Time.Day", "%s%d."); 38 | public static final LangKey TIME_HOUR = new LangKey("Time.Hour", "%s%h."); 39 | public static final LangKey TIME_MIN = new LangKey("Time.Min", "%s%min."); 40 | public static final LangKey TIME_SEC = new LangKey("Time.Sec", "%s%sec."); 41 | 42 | public static final LangKey OTHER_YES = LangKey.of("Other.Yes", GREEN + "Yes"); 43 | public static final LangKey OTHER_NO = LangKey.of("Other.No", RED + "No"); 44 | public static final LangKey OTHER_ANY = LangKey.of("Other.Any", "Any"); 45 | public static final LangKey OTHER_NONE = LangKey.of("Other.None", "None"); 46 | public static final LangKey OTHER_NEVER = LangKey.of("Other.Never", "Never"); 47 | public static final LangKey OTHER_ONE_TIMED = LangKey.of("Other.OneTimed", "One-Timed"); 48 | public static final LangKey OTHER_UNLIMITED = LangKey.of("Other.Unlimited", "Unlimited"); 49 | public static final LangKey OTHER_INFINITY = LangKey.of("Other.Infinity", "∞"); 50 | 51 | public static final LangKey ERROR_PLAYER_INVALID = LangKey.of("Error.Player.Invalid", RED + "Player not found."); 52 | public static final LangKey ERROR_WORLD_INVALID = LangKey.of("Error.World.Invalid", RED + "World not found."); 53 | public static final LangKey ERROR_NUMBER_INVALID = LangKey.of("Error.Number.Invalid", RED + "%num% is not a valid number."); 54 | public static final LangKey ERROR_PERMISSION_DENY = LangKey.of("Error.Permission.Deny", RED + "You don't have permissions to do that!"); 55 | public static final LangKey ERROR_COMMAND_SELF = LangKey.of("Error.Command.Self", RED + "This command can not be used on yourself."); 56 | public static final LangKey ERROR_COMMAND_SENDER = LangKey.of("Error.Command.Sender", RED + "This command is for players only."); 57 | 58 | public static final LangKey EDITOR_TIP_EXIT = LangKey.of("Editor.Tip.Exit", 59 | "" + 60 | "" + GRAY + "Click here to " + RED + "[Exit Edit Mode]"); 61 | public static final LangKey EDITOR_TITLE_DONE = LangKey.of("Editor.Title.Done", GREEN + BOLD + "Done!"); 62 | public static final LangKey EDITOR_TITLE_EDIT = LangKey.of("Editor.Title.Edit", GREEN + BOLD + "< Edit Mode >"); 63 | public static final LangKey EDITOR_TITLE_ERROR = LangKey.of("Editor.Title.Error", RED + BOLD + "Error!"); 64 | public static final LangKey EDITOR_ERROR_NUMBER_GENERIC = LangKey.of("Editor.Error.Number.Generic", GRAY + "Invalid number!"); 65 | public static final LangKey EDITOR_ERROR_NUMBER_NOT_INT = LangKey.of("Editor.Error.Number.NotInt", GRAY + "Expecting " + RED + "whole" + GRAY + " number!"); 66 | public static final LangKey EDITOR_ERROR_ENUM = LangKey.of("Editor.Error.Enum", GRAY + "Invalid Input!"); 67 | } 68 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/ArrayUtil.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | public class ArrayUtil { 4 | 5 | public static int indexOf(Object[] array, Object objectToFind) { 6 | return indexOf(array, objectToFind, 0); 7 | } 8 | 9 | public static int indexOf(Object[] array, Object objectToFind, int startIndex) { 10 | if (array != null) { 11 | if (startIndex < 0) { 12 | startIndex = 0; 13 | } 14 | 15 | int i; 16 | if (objectToFind == null) { 17 | for (i = startIndex; i < array.length; ++i) { 18 | if (array[i] == null) { 19 | return i; 20 | } 21 | } 22 | } 23 | else if (array.getClass().getComponentType().isInstance(objectToFind)) { 24 | for (i = startIndex; i < array.length; ++i) { 25 | if (objectToFind.equals(array[i])) { 26 | return i; 27 | } 28 | } 29 | } 30 | 31 | } 32 | return -1; 33 | } 34 | 35 | public static boolean contains(Object[] array, Object objectToFind) { 36 | return indexOf(array, objectToFind) != -1; 37 | } 38 | 39 | public static int indexOf(long[] array, long valueToFind) { 40 | return indexOf(array, valueToFind, 0); 41 | } 42 | 43 | public static int indexOf(long[] array, long valueToFind, int startIndex) { 44 | if (array != null) { 45 | if (startIndex < 0) { 46 | startIndex = 0; 47 | } 48 | 49 | for (int i = startIndex; i < array.length; ++i) { 50 | if (valueToFind == array[i]) { 51 | return i; 52 | } 53 | } 54 | 55 | } 56 | return -1; 57 | } 58 | 59 | public static boolean contains(long[] array, long valueToFind) { 60 | return indexOf(array, valueToFind) != -1; 61 | } 62 | 63 | public static int indexOf(int[] array, int valueToFind) { 64 | return indexOf(array, valueToFind, 0); 65 | } 66 | 67 | public static int indexOf(int[] array, int valueToFind, int startIndex) { 68 | if (array != null) { 69 | if (startIndex < 0) { 70 | startIndex = 0; 71 | } 72 | 73 | for (int i = startIndex; i < array.length; ++i) { 74 | if (valueToFind == array[i]) { 75 | return i; 76 | } 77 | } 78 | 79 | } 80 | return -1; 81 | } 82 | 83 | public static int indexOf(char[] array, char valueToFind) { 84 | return indexOf(array, valueToFind, 0); 85 | } 86 | 87 | public static int indexOf(char[] array, char valueToFind, int startIndex) { 88 | if (array != null) { 89 | if (startIndex < 0) { 90 | startIndex = 0; 91 | } 92 | 93 | for (int i = startIndex; i < array.length; ++i) { 94 | if (valueToFind == array[i]) { 95 | return i; 96 | } 97 | } 98 | 99 | } 100 | return -1; 101 | } 102 | 103 | public static boolean contains(int[] array, int valueToFind) { 104 | return indexOf(array, valueToFind) != -1; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/Colors.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | public class Colors { 4 | 5 | public static final String BOLD = "&l"; 6 | public static final String WHITE = "#e8f2f2"; 7 | public static final String GRAY = "#d4d9d8"; 8 | public static final String DARK_GRAY = "#6c6c62"; 9 | public static final String LIME = "#b3ff5d"; 10 | public static final String GREEN = "#aefd5e"; 11 | public static final String YELLOW = "#fdf35e"; 12 | public static final String LIGHT_YELLOW = "#ffeea2"; 13 | public static final String ORANGE = "#fdba5e"; 14 | public static final String RED = "#fd5e5e"; 15 | public static final String BLUE = "#5e9dfd"; 16 | public static final String CYAN = "#5edefd"; 17 | public static final String LIGHT_PURPLE = "#e39fff"; 18 | public static final String PURPLE = "#ce79f0"; 19 | public static final String PINK = "#fd8ddb"; 20 | } 21 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/Colors2.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | public class Colors2 { 4 | 5 | public static final String BOLD = "&l"; 6 | public static final String WHITE = "#e8f2f2"; 7 | public static final String GRAY = "#aaa8a8"; 8 | public static final String GREEN = "#74ea31"; 9 | public static final String YELLOW = "#ead931"; 10 | public static final String ORANGE = "#ea9631"; 11 | public static final String RED = "#ea3131"; 12 | public static final String BLUE = "#3196ea"; 13 | public static final String CYAN = "#31eace"; 14 | public static final String PURPLE = "#bd31ea"; 15 | public static final String PINK = "#ea31b2"; 16 | 17 | public static final String LIGHT_GRAY = "#d4d9d8"; 18 | public static final String DARK_GRAY = "#6c6c62"; 19 | public static final String LIGHT_GREEN = "#aefd5e"; 20 | public static final String LIGHT_YELLOW = "#ffeea2"; 21 | public static final String LIGHT_ORANGE = "#fdba5e"; 22 | public static final String LIGHT_RED = "#fd5e5e"; 23 | public static final String LIGHT_BLUE = "#5e9dfd"; 24 | public static final String LIGHT_CYAN = "#5edefd"; 25 | public static final String LIGHT_PURPLE = "#e39fff"; 26 | public static final String LIGHT_PINK = "#fd8ddb"; 27 | } 28 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/EngineUtils.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | import org.bukkit.plugin.Plugin; 4 | import org.jetbrains.annotations.NotNull; 5 | import su.nexmedia.engine.NexEngine; 6 | 7 | public class EngineUtils { 8 | 9 | public static final NexEngine ENGINE = NexEngine.getPlugin(NexEngine.class); 10 | 11 | public static final String VAULT = "Vault"; 12 | public static final String PLACEHOLDER_API = "PlaceholderAPI"; 13 | public static final String FLOODGATE = "floodgate"; 14 | 15 | public static boolean hasPlugin(@NotNull String pluginName) { 16 | Plugin plugin = ENGINE.getPluginManager().getPlugin(pluginName); 17 | return plugin != null; 18 | } 19 | 20 | public static boolean hasPlaceholderAPI() { 21 | return hasPlugin(PLACEHOLDER_API); 22 | } 23 | 24 | public static boolean hasVault() { 25 | return hasPlugin(VAULT); 26 | } 27 | 28 | public static boolean hasFloodgate() { 29 | return hasPlugin(FLOODGATE); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/EntityUtil.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | import org.bukkit.attribute.Attribute; 4 | import org.bukkit.attribute.AttributeInstance; 5 | import org.bukkit.block.BlockFace; 6 | import org.bukkit.entity.Entity; 7 | import org.bukkit.entity.LivingEntity; 8 | import org.bukkit.inventory.EntityEquipment; 9 | import org.bukkit.inventory.EquipmentSlot; 10 | import org.bukkit.inventory.ItemStack; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | 14 | import java.util.Collections; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | public class EntityUtil { 19 | 20 | @Deprecated 21 | public static boolean isNPC(@NotNull Entity entity) { 22 | return entity.hasMetadata("NPC"); 23 | } 24 | 25 | public static double getAttribute(@NotNull LivingEntity entity, @NotNull Attribute attribute) { 26 | AttributeInstance instance = entity.getAttribute(attribute); 27 | return instance == null ? 0D : instance.getValue(); 28 | } 29 | 30 | public static double getAttributeBase(@NotNull LivingEntity entity, @NotNull Attribute attribute) { 31 | AttributeInstance instance = entity.getAttribute(attribute); 32 | return instance == null ? 0D : instance.getBaseValue(); 33 | } 34 | 35 | @NotNull 36 | public static Map getEquippedItems(@NotNull LivingEntity entity) { 37 | return getEquippedItems(entity, EquipmentSlot.values()); 38 | } 39 | 40 | @NotNull 41 | public static Map getEquippedItems(@NotNull LivingEntity entity, @NotNull EquipmentSlot... slots) { 42 | EntityEquipment equipment = entity.getEquipment(); 43 | if (equipment == null) return Collections.emptyMap(); 44 | 45 | Map map = new HashMap<>(); 46 | for (EquipmentSlot slot : slots) { 47 | map.put(slot, equipment.getItem(slot)); 48 | } 49 | return map; 50 | } 51 | 52 | @NotNull 53 | public static Map getEquippedHands(@NotNull LivingEntity entity) { 54 | return getEquippedItems(entity, EquipmentSlot.HAND, EquipmentSlot.OFF_HAND); 55 | } 56 | 57 | @NotNull 58 | public static Map getEquippedArmor(@NotNull LivingEntity entity) { 59 | return getEquippedItems(entity, EquipmentSlot.FEET, EquipmentSlot.LEGS, EquipmentSlot.CHEST, EquipmentSlot.HEAD); 60 | } 61 | 62 | @Nullable 63 | public static BlockFace getDirection(@NotNull Entity entity) { 64 | float yaw = Math.round(entity.getLocation().getYaw() / 90F); 65 | 66 | if ((yaw == -4.0F) || (yaw == 0.0F) || (yaw == 4.0F)) { 67 | return BlockFace.SOUTH; 68 | } 69 | if ((yaw == -1.0F) || (yaw == 3.0F)) { 70 | return BlockFace.EAST; 71 | } 72 | if ((yaw == -2.0F) || (yaw == 2.0F)) { 73 | return BlockFace.NORTH; 74 | } 75 | if ((yaw == -3.0F) || (yaw == 1.0F)) { 76 | return BlockFace.WEST; 77 | } 78 | return null; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/Evaluator.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | @Deprecated 6 | public class Evaluator { 7 | 8 | public static double evaluate(@NotNull final String str) { 9 | return new Object() { 10 | int pos = -1, ch; 11 | 12 | void nextChar() { 13 | ch = (++pos < str.length()) ? str.charAt(pos) : -1; 14 | } 15 | 16 | boolean eat(int charToEat) { 17 | while (ch == ' ') nextChar(); 18 | if (ch == charToEat) { 19 | nextChar(); 20 | return true; 21 | } 22 | return false; 23 | } 24 | 25 | double parse() { 26 | nextChar(); 27 | double x = parseExpression(); 28 | if (pos < str.length()) throw new RuntimeException("Unexpected: " + (char)ch); 29 | return x; 30 | } 31 | 32 | // Grammar: 33 | // expression = term | expression `+` term | expression `-` term 34 | // term = factor | term `*` factor | term `/` factor 35 | // factor = `+` factor | `-` factor | `(` expression `)` | number 36 | // | functionName `(` expression `)` | functionName factor 37 | // | factor `^` factor 38 | 39 | double parseExpression() { 40 | double x = parseTerm(); 41 | for (;;) { 42 | if (eat('+')) x += parseTerm(); // addition 43 | else if (eat('-')) x -= parseTerm(); // subtraction 44 | else return x; 45 | } 46 | } 47 | 48 | double parseTerm() { 49 | double x = parseFactor(); 50 | for (;;) { 51 | if (eat('*')) x *= parseFactor(); // multiplication 52 | else if (eat('/')) x /= parseFactor(); // division 53 | else return x; 54 | } 55 | } 56 | 57 | double parseFactor() { 58 | if (eat('+')) return +parseFactor(); // unary plus 59 | if (eat('-')) return -parseFactor(); // unary minus 60 | 61 | double x; 62 | int startPos = this.pos; 63 | if (eat('(')) { // parentheses 64 | x = parseExpression(); 65 | if (!eat(')')) throw new RuntimeException("Missing ')'"); 66 | } else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers 67 | while ((ch >= '0' && ch <= '9') || ch == '.') nextChar(); 68 | x = Double.parseDouble(str.substring(startPos, this.pos)); 69 | } else if (ch >= 'a' && ch <= 'z') { // functions 70 | while (ch >= 'a' && ch <= 'z') nextChar(); 71 | String func = str.substring(startPos, this.pos); 72 | if (eat('(')) { 73 | x = parseExpression(); 74 | if (!eat(')')) throw new RuntimeException("Missing ')' after argument to " + func); 75 | } else { 76 | x = parseFactor(); 77 | } 78 | x = switch (func) { 79 | case "sqrt" -> Math.sqrt(x); 80 | case "sin" -> Math.sin(Math.toRadians(x)); 81 | case "cos" -> Math.cos(Math.toRadians(x)); 82 | case "tan" -> Math.tan(Math.toRadians(x)); 83 | default -> throw new RuntimeException("Unknown function: " + func); 84 | }; 85 | } else { 86 | throw new RuntimeException("Unexpected: " + (char)ch); 87 | } 88 | 89 | if (eat('^')) x = Math.pow(x, parseFactor()); // exponentiation 90 | 91 | return x; 92 | } 93 | }.parse(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/FileUtil.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.io.File; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.util.ArrayList; 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.stream.Stream; 13 | 14 | public class FileUtil { 15 | 16 | public static void copy(@NotNull InputStream inputStream, @NotNull File file) { 17 | try { 18 | FileOutputStream outputStream = new FileOutputStream(file); 19 | byte[] array = new byte[1024]; 20 | int read; 21 | while ((read = inputStream.read(array)) > 0) { 22 | outputStream.write(array, 0, read); 23 | } 24 | outputStream.close(); 25 | inputStream.close(); 26 | } 27 | catch (IOException ex) { 28 | ex.printStackTrace(); 29 | } 30 | } 31 | 32 | public static boolean create(@NotNull File file) { 33 | if (file.exists()) return false; 34 | 35 | File parent = file.getParentFile(); 36 | if (parent == null) return false; 37 | 38 | parent.mkdirs(); 39 | try { 40 | return file.createNewFile(); 41 | } 42 | catch (IOException e) { 43 | e.printStackTrace(); 44 | return false; 45 | } 46 | } 47 | 48 | @NotNull 49 | public static List getFiles(@NotNull String path, boolean deep) { 50 | List files = new ArrayList<>(); 51 | 52 | File folder = new File(path); 53 | File[] listOfFiles = folder.listFiles(); 54 | if (listOfFiles == null) return files; 55 | 56 | for (File file : listOfFiles) { 57 | if (file.isFile()) { 58 | files.add(file); 59 | } 60 | else if (file.isDirectory() && deep) { 61 | files.addAll(getFiles(file.getPath(), true)); 62 | } 63 | } 64 | return files; 65 | } 66 | 67 | @NotNull 68 | public static List getFolders(@NotNull String path) { 69 | File folder = new File(path); 70 | File[] listOfFiles = folder.listFiles(); 71 | if (listOfFiles == null) return Collections.emptyList(); 72 | 73 | return Stream.of(listOfFiles).filter(File::isDirectory).toList(); 74 | } 75 | 76 | public static boolean deleteRecursive(@NotNull String path) { 77 | return deleteRecursive(new File(path)); 78 | } 79 | 80 | public static boolean deleteRecursive(@NotNull File dir) { 81 | if (!dir.exists()) return false; 82 | 83 | File[] inside = dir.listFiles(); 84 | if (inside != null) { 85 | for (File file : inside) { 86 | deleteRecursive(file); 87 | } 88 | } 89 | return dir.delete(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/LocationUtil.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.Location; 5 | import org.bukkit.World; 6 | import org.bukkit.util.Vector; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Collection; 12 | import java.util.List; 13 | import java.util.Objects; 14 | 15 | public class LocationUtil { 16 | 17 | @Nullable 18 | public static String serialize(@NotNull Location loc) { 19 | World world = loc.getWorld(); 20 | if (world == null) return null; 21 | 22 | return loc.getX() + "," + loc.getY() + "," + loc.getZ() + "," + loc.getPitch() + "," + loc.getYaw() + "," + world.getName(); 23 | } 24 | 25 | @NotNull 26 | public static List serialize(@NotNull Collection list) { 27 | return new ArrayList<>(list.stream().map(LocationUtil::serialize).filter(Objects::nonNull).toList()); 28 | } 29 | 30 | @Nullable 31 | public static Location deserialize(@NotNull String raw) { 32 | String[] split = raw.split(","); 33 | if (split.length != 6) return null; 34 | 35 | World world = Bukkit.getWorld(split[5]); 36 | if (world == null) { 37 | EngineUtils.ENGINE.error("Invalid/Unloaded world for: '" + raw + "' location!"); 38 | return null; 39 | } 40 | 41 | double x = StringUtil.getDouble(split[0], 0, true); 42 | double y = StringUtil.getDouble(split[1], 0, true); 43 | double z = StringUtil.getDouble(split[2], 0, true); 44 | float pitch = (float) StringUtil.getDouble(split[3], 0, true); 45 | float yaw = (float) StringUtil.getDouble(split[4], 0, true); 46 | 47 | return new Location(world, x, y, z, yaw, pitch); 48 | } 49 | 50 | @NotNull 51 | public static List deserialize(@NotNull Collection list) { 52 | return new ArrayList<>(list.stream().map(LocationUtil::deserialize).filter(Objects::nonNull).toList()); 53 | } 54 | 55 | @NotNull 56 | public static String getWorldName(@NotNull Location location) { 57 | World world = location.getWorld(); 58 | return world == null ? "null" : world.getName(); 59 | } 60 | 61 | @NotNull 62 | public static Location getCenter(@NotNull Location location) { 63 | return getCenter(location, true); 64 | } 65 | 66 | @NotNull 67 | public static Location getCenter(@NotNull Location location, boolean doVertical) { 68 | Location centered = location.clone(); 69 | location.setX(location.getBlockX() + 0.5); 70 | location.setY(location.getBlockY() + (doVertical ? 0.5 : 0)); 71 | location.setZ(location.getBlockZ() + 0.5); 72 | return location; 73 | } 74 | 75 | @NotNull 76 | public static Vector getDirection(@NotNull Location from, @NotNull Location to) { 77 | Location origin = from.clone(); 78 | origin.setDirection(to.toVector().subtract(origin.toVector())); 79 | return origin.getDirection(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/NumberUtil.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.math.BigDecimal; 6 | import java.math.RoundingMode; 7 | import java.text.DecimalFormat; 8 | import java.text.DecimalFormatSymbols; 9 | import java.util.Locale; 10 | import java.util.TreeMap; 11 | 12 | public class NumberUtil { 13 | 14 | private static final DecimalFormat FORMAT_ROUND_HUMAN; 15 | private final static TreeMap ROMAN_MAP = new TreeMap<>(); 16 | 17 | static { 18 | FORMAT_ROUND_HUMAN = new DecimalFormat("#,###.##", new DecimalFormatSymbols(Locale.ENGLISH)); 19 | 20 | ROMAN_MAP.put(1000, "M"); 21 | ROMAN_MAP.put(900, "CM"); 22 | ROMAN_MAP.put(500, "D"); 23 | ROMAN_MAP.put(400, "CD"); 24 | ROMAN_MAP.put(100, "C"); 25 | ROMAN_MAP.put(90, "XC"); 26 | ROMAN_MAP.put(50, "L"); 27 | ROMAN_MAP.put(40, "XL"); 28 | ROMAN_MAP.put(10, "X"); 29 | ROMAN_MAP.put(9, "IX"); 30 | ROMAN_MAP.put(5, "V"); 31 | ROMAN_MAP.put(4, "IV"); 32 | ROMAN_MAP.put(1, "I"); 33 | } 34 | 35 | @NotNull 36 | public static String format(double value) { 37 | return FORMAT_ROUND_HUMAN.format(value); 38 | } 39 | 40 | public static double round(double value) { 41 | return new BigDecimal(value).setScale(2, RoundingMode.HALF_UP).doubleValue(); 42 | } 43 | 44 | @NotNull 45 | public static String toRoman(int number) { 46 | if (number <= 0) return String.valueOf(number); 47 | 48 | int key = ROMAN_MAP.floorKey(number); 49 | if (number == key) { 50 | return ROMAN_MAP.get(number); 51 | } 52 | return ROMAN_MAP.get(key) + toRoman(number - key); 53 | } 54 | 55 | public static int[] splitIntoParts(int whole, int parts) { 56 | int[] arr = new int[parts]; 57 | int remain = whole; 58 | int partsLeft = parts; 59 | for (int i = 0; partsLeft > 0; i++) { 60 | int size = (remain + partsLeft - 1) / partsLeft; // rounded up, aka ceiling 61 | arr[i] = size; 62 | remain -= size; 63 | partsLeft--; 64 | } 65 | return arr; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/Pair.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.Objects; 6 | import java.util.function.Function; 7 | 8 | public class Pair { 9 | 10 | private final F first; 11 | private final S second; 12 | 13 | public Pair(@NotNull F first, @NotNull S second) { 14 | this.first = first; 15 | this.second = second; 16 | } 17 | 18 | @NotNull 19 | public F getFirst() { 20 | return this.first; 21 | } 22 | 23 | @NotNull 24 | public S getSecond() { 25 | return this.second; 26 | } 27 | 28 | @NotNull 29 | public Pair swap() { 30 | return of(this.second, this.first); 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return "Pair{" + "first=" + first + ", second=" + second + '}'; 36 | } 37 | 38 | @Override 39 | public boolean equals(Object obj) { 40 | if (obj instanceof Pair other) { 41 | return Objects.equals(this.first, other.first) && Objects.equals(this.second, other.second); 42 | } 43 | return false; 44 | } 45 | 46 | @NotNull 47 | public Pair mapFirst(@NotNull Function function) { 48 | return of(function.apply(this.first), this.second); 49 | } 50 | 51 | @NotNull 52 | public Pair mapSecond(@NotNull Function function) { 53 | return of(this.first, function.apply(this.second)); 54 | } 55 | 56 | @NotNull 57 | public static Pair of(@NotNull F first, @NotNull S second) { 58 | return new Pair<>(first, second); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/Placeholders.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.command.CommandSender; 5 | import org.bukkit.entity.Player; 6 | import org.jetbrains.annotations.NotNull; 7 | import su.nexmedia.engine.NexPlugin; 8 | import su.nexmedia.engine.api.placeholder.PlaceholderMap; 9 | 10 | import java.util.function.UnaryOperator; 11 | 12 | public class Placeholders { 13 | 14 | public static final String GITHUB_URL = "https://github.com/nulli0n/NexEngine-spigot/"; 15 | public static final String WIKI_MAIN_URL = GITHUB_URL + "wiki/"; 16 | public static final String WIKI_ITEMS_URL = WIKI_MAIN_URL + "Configuration-Tips#item-sections"; 17 | public static final String WIKI_PARTICLE_URL = WIKI_MAIN_URL + "Configuration-Tips#particle-sections"; 18 | public static final String WIKI_MENU_URL = WIKI_MAIN_URL + "Menu-Config"; 19 | public static final String WIKI_LANG_URL = WIKI_MAIN_URL + "Language-Config"; 20 | 21 | public static final String DEFAULT = "default"; 22 | public static final String NONE = "none"; 23 | public static final String WILDCARD = "*"; 24 | 25 | public static final String PLUGIN_NAME = "%plugin_name%"; 26 | public static final String PLUGIN_NAME_LOCALIZED = "%plugin_name_localized%"; 27 | 28 | public static final String PLAYER_NAME = "%player_name%"; 29 | public static final String PLAYER_DISPLAY_NAME = "%player_display_name%"; 30 | 31 | public static final String LOCATION_X = "%location_x%"; 32 | public static final String LOCATION_Y = "%location_y%"; 33 | public static final String LOCATION_Z = "%location_z%"; 34 | public static final String LOCATION_WORLD = "%location_world%"; 35 | 36 | public static final String COMMAND_USAGE = "%command_usage%"; 37 | public static final String COMMAND_DESCRIPTION = "%command_description%"; 38 | public static final String COMMAND_LABEL = "%command_label%"; 39 | 40 | @NotNull 41 | public static UnaryOperator forLocation(@NotNull Location location) { 42 | return new PlaceholderMap() 43 | .add(LOCATION_X, () -> NumberUtil.format(location.getX())) 44 | .add(LOCATION_Y, () -> NumberUtil.format(location.getY())) 45 | .add(LOCATION_Z, () -> NumberUtil.format(location.getZ())) 46 | .add(LOCATION_WORLD, () -> LocationUtil.getWorldName(location)) 47 | .replacer(); 48 | } 49 | 50 | @NotNull 51 | public static UnaryOperator forPlugin(@NotNull NexPlugin plugin) { 52 | return new PlaceholderMap() 53 | .add(PLUGIN_NAME, plugin::getName) 54 | .add(PLUGIN_NAME_LOCALIZED, () -> plugin.getConfigManager().pluginName) 55 | .replacer(); 56 | } 57 | 58 | @NotNull 59 | public static UnaryOperator forPlayer(@NotNull Player player) { 60 | return new PlaceholderMap() 61 | .add(PLAYER_NAME, player::getName) 62 | .add(PLAYER_DISPLAY_NAME, player::getDisplayName) 63 | .replacer(); 64 | } 65 | 66 | @NotNull 67 | public static UnaryOperator forSender(@NotNull CommandSender sender) { 68 | if (sender instanceof Player player) return forPlayer(player); 69 | 70 | return new PlaceholderMap() 71 | .add(PLAYER_NAME, sender::getName) 72 | .add(PLAYER_DISPLAY_NAME, sender::getName) 73 | .replacer(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/PlayerRankMap.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | import su.nexmedia.engine.api.config.JYML; 7 | 8 | import java.util.*; 9 | 10 | public class PlayerRankMap { 11 | 12 | private final Map values; 13 | 14 | private boolean negativeBetter; 15 | private boolean checkAsPermission; 16 | private String permissionPrefix; 17 | 18 | public PlayerRankMap(@NotNull Map values) { 19 | this.values = new HashMap<>(values); 20 | } 21 | 22 | @NotNull 23 | public static PlayerRankMap readInt(@NotNull JYML cfg, @NotNull String path) { 24 | return read(cfg, path, Integer.class); 25 | } 26 | 27 | @NotNull 28 | public static PlayerRankMap readDouble(@NotNull JYML cfg, @NotNull String path) { 29 | return read(cfg, path, Double.class); 30 | } 31 | 32 | @NotNull 33 | public static PlayerRankMap readLong(@NotNull JYML cfg, @NotNull String path) { 34 | return read(cfg, path, Long.class); 35 | } 36 | 37 | @NotNull 38 | public static PlayerRankMap read(@NotNull JYML cfg, @NotNull String path, @NotNull Class clazz) { 39 | Map values = new HashMap<>(); 40 | for (String rank : cfg.getSection(path)) { 41 | T number; 42 | if (clazz == Double.class) { 43 | number = clazz.cast(cfg.getDouble(path + "." + rank)); 44 | } 45 | else number = clazz.cast(cfg.getInt(path + "." + rank)); 46 | 47 | values.put(rank.toLowerCase(), number); 48 | } 49 | return new PlayerRankMap<>(values); 50 | } 51 | 52 | public void write(@NotNull JYML cfg, @NotNull String path) { 53 | this.values.forEach((rank, number) -> { 54 | cfg.set(path + "." + rank, number); 55 | }); 56 | } 57 | 58 | @NotNull 59 | public T getBestValue(@NotNull Player player, @NotNull T def) { 60 | Set groups = PlayerUtil.getPermissionGroups(player); 61 | Optional> opt = this.values.entrySet().stream().filter(entry -> entry.getKey().equalsIgnoreCase(Placeholders.DEFAULT) || groups.contains(entry.getKey())).min((entry1, entry2) -> { 62 | T val1 = entry1.getValue(); 63 | T val2 = entry2.getValue(); 64 | if (this.isNegativeBetter() && val2.doubleValue() < 0) return 1; 65 | if (this.isNegativeBetter() && val1.doubleValue() < 0) return -1; 66 | 67 | return Double.compare(val2.doubleValue(), val1.doubleValue()); 68 | }); 69 | 70 | if (opt.isEmpty() && this.isCheckAsPermission()) { 71 | return this.values.entrySet().stream() 72 | .filter(entry -> player.hasPermission(this.getPermissionPrefix() + entry.getKey())) 73 | .max(Comparator.comparingDouble(e -> e.getValue().doubleValue())).map(Map.Entry::getValue).orElse(def); 74 | } 75 | return opt.map(Map.Entry::getValue).orElse(def); 76 | } 77 | 78 | @NotNull 79 | public T getLowestValue(@NotNull Player player, @NotNull T def) { 80 | Set groups = PlayerUtil.getPermissionGroups(player); 81 | Optional> opt = this.values.entrySet().stream().filter(entry -> entry.getKey().equalsIgnoreCase(Placeholders.DEFAULT) || groups.contains(entry.getKey())).min((entry1, entry2) -> { 82 | T val1 = entry1.getValue(); 83 | T val2 = entry2.getValue(); 84 | if (this.isNegativeBetter() && val2.doubleValue() < 0) return 1; 85 | if (this.isNegativeBetter() && val1.doubleValue() < 0) return -1; 86 | 87 | return Double.compare(val1.doubleValue(), val2.doubleValue()); 88 | }); 89 | 90 | if (opt.isEmpty() && this.isCheckAsPermission()) { 91 | return this.values.entrySet().stream() 92 | .filter(entry -> player.hasPermission(this.getPermissionPrefix() + entry.getKey())) 93 | .min(Comparator.comparingDouble(e -> e.getValue().doubleValue())).map(Map.Entry::getValue).orElse(def); 94 | } 95 | return opt.map(Map.Entry::getValue).orElse(def); 96 | } 97 | 98 | public boolean isNegativeBetter() { 99 | return negativeBetter; 100 | } 101 | 102 | public boolean isCheckAsPermission() { 103 | return checkAsPermission; 104 | } 105 | 106 | @Nullable 107 | public String getPermissionPrefix() { 108 | return permissionPrefix; 109 | } 110 | 111 | @NotNull 112 | public PlayerRankMap setNegativeBetter(boolean negativeBetter) { 113 | this.negativeBetter = negativeBetter; 114 | return this; 115 | } 116 | 117 | @NotNull 118 | public PlayerRankMap setCheckAsPermission(@NotNull String permissionPrefix) { 119 | this.checkAsPermission = true; 120 | this.permissionPrefix = permissionPrefix; 121 | return this; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/ResourceExtractor.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.NexPlugin; 5 | 6 | import java.io.File; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.util.Enumeration; 11 | import java.util.jar.JarEntry; 12 | import java.util.jar.JarFile; 13 | 14 | @Deprecated 15 | public final class ResourceExtractor { 16 | 17 | private final NexPlugin plugin; 18 | private final File destination; 19 | private final String fromPath; 20 | private String regex; 21 | 22 | @NotNull 23 | public static ResourceExtractor create(@NotNull NexPlugin plugin, @NotNull String fromPath, @NotNull File destination) { 24 | return new ResourceExtractor(plugin, fromPath, destination); 25 | } 26 | 27 | private ResourceExtractor(@NotNull NexPlugin plugin, @NotNull String fromPath, @NotNull File destination) { 28 | this.plugin = plugin; 29 | this.destination = destination; 30 | this.fromPath = fromPath; 31 | } 32 | 33 | @NotNull 34 | public ResourceExtractor withRegex(@NotNull String regex) { 35 | this.regex = regex; 36 | return this; 37 | } 38 | 39 | public void extract() throws IOException { 40 | this.extract(false); 41 | } 42 | 43 | public void extract(boolean override) throws IOException { 44 | if (!this.destination.exists()) { 45 | if (!this.destination.mkdirs()) { 46 | return; 47 | } 48 | } 49 | 50 | JarFile jar = new JarFile(this.plugin.getFile()); 51 | Enumeration entries = jar.entries(); 52 | 53 | while (entries.hasMoreElements()) { 54 | JarEntry entry = entries.nextElement(); 55 | String path = entry.getName(); 56 | if (entry.isDirectory() || !path.startsWith(this.fromPath)) continue; 57 | 58 | File file = new File(this.destination, path.replaceFirst(this.fromPath, "")); 59 | String name = file.getName(); 60 | if (this.regex == null || name.matches(this.regex)) { 61 | if (file.exists() && override) { 62 | if (!file.delete()) { 63 | continue; 64 | } 65 | } 66 | 67 | if (!file.exists()) { 68 | FileUtil.create(file); 69 | InputStream inputStream = jar.getInputStream(entry); 70 | FileOutputStream outputStream = new FileOutputStream(file); 71 | 72 | while (inputStream.available() > 0) { 73 | outputStream.write(inputStream.read()); 74 | } 75 | outputStream.close(); 76 | inputStream.close(); 77 | } 78 | } 79 | } 80 | 81 | jar.close(); 82 | } 83 | } -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/Scaler.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.config.JYML; 5 | 6 | import java.util.Map; 7 | import java.util.Set; 8 | import java.util.TreeMap; 9 | 10 | @Deprecated 11 | public class Scaler { 12 | 13 | private final int levelMin; 14 | private final int levelMax; 15 | private final TreeMap values; 16 | 17 | public Scaler(@NotNull JYML cfg, @NotNull String path, @NotNull String levelPlaceholder, int levelMin, int levelMax) { 18 | this.levelMin = levelMin; 19 | this.levelMax = levelMax; 20 | this.values = new TreeMap<>(); 21 | 22 | // Load different values for each object level. 23 | Set lvlKeys = cfg.getSection(path); 24 | if (!lvlKeys.isEmpty()) { 25 | for (String sLvl : lvlKeys) { 26 | int eLvl = StringUtil.getInteger(sLvl, 0); 27 | if (eLvl < this.getLevelMin() || eLvl > this.getLevelMax()) continue; 28 | 29 | String formula = cfg.getString(path + "." + sLvl, "0").replace(levelPlaceholder, sLvl); 30 | values.put(eLvl, Evaluator.evaluate(formula)); 31 | } 32 | return; 33 | } 34 | 35 | // Load the single formula for all object levels. 36 | for (int lvl = this.getLevelMin(); lvl < (this.getLevelMax() + 1); lvl++) { 37 | String sLvl = String.valueOf(lvl); 38 | String exChance = cfg.getString(path, "").replace(levelPlaceholder, sLvl); 39 | if (exChance.isEmpty()) continue; 40 | 41 | values.put(lvl, Evaluator.evaluate(exChance)); 42 | } 43 | } 44 | 45 | public int getLevelMin() { 46 | return this.levelMin; 47 | } 48 | 49 | public int getLevelMax() { 50 | return this.levelMax; 51 | } 52 | 53 | @NotNull 54 | public TreeMap getValues() { 55 | return this.values; 56 | } 57 | 58 | public double getValue(int level) { 59 | Map.Entry en = this.values.floorEntry(level); 60 | return en != null ? en.getValue() : 0D; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/TimeUtil.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.lang.EngineLang; 5 | 6 | import java.time.Instant; 7 | import java.time.LocalDateTime; 8 | import java.time.LocalTime; 9 | import java.util.TimeZone; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | public class TimeUtil { 13 | 14 | @NotNull 15 | public static String formatTime(long time) { 16 | long days = TimeUnit.MILLISECONDS.toDays(time); 17 | long hours = TimeUnit.MILLISECONDS.toHours(time) % 24; 18 | long minutes = TimeUnit.MILLISECONDS.toMinutes(time) % 60; 19 | long seconds = TimeUnit.MILLISECONDS.toSeconds(time) % 60; 20 | 21 | StringBuilder str = new StringBuilder(); 22 | if (days > 0) { 23 | if (str.length() > 0) { 24 | str.append(" "); 25 | } 26 | str.append(EngineUtils.ENGINE.getMessage(EngineLang.TIME_DAY).replace("%s%", days).getLocalized()); 27 | } 28 | if (hours > 0) { 29 | if (str.length() > 0) { 30 | str.append(" "); 31 | } 32 | str.append(EngineUtils.ENGINE.getMessage(EngineLang.TIME_HOUR).replace("%s%", hours).getLocalized()); 33 | } 34 | if (minutes > 0) { 35 | if (str.length() > 0) { 36 | str.append(" "); 37 | } 38 | str.append(EngineUtils.ENGINE.getMessage(EngineLang.TIME_MIN).replace("%s%", minutes).getLocalized()); 39 | } 40 | if (str.length() == 0 || seconds > 0) { 41 | if (str.length() > 0) { 42 | str.append(" "); 43 | } 44 | str.append(EngineUtils.ENGINE.getMessage(EngineLang.TIME_SEC).replace("%s%", seconds).getLocalized()); 45 | } 46 | 47 | return StringUtil.oneSpace(str.toString()); 48 | } 49 | 50 | @NotNull 51 | public static String formatTimeLeft(long max, long min) { 52 | long time = max - min; 53 | return formatTime(time); 54 | } 55 | 56 | @NotNull 57 | public static String formatTimeLeft(long until) { 58 | return formatTime(until - System.currentTimeMillis()); 59 | } 60 | 61 | @NotNull 62 | public static LocalTime getLocalTimeOf(long ms) { 63 | long hours = TimeUnit.MILLISECONDS.toHours(ms) % 24; 64 | long minutes = TimeUnit.MILLISECONDS.toMinutes(ms) % 60; 65 | long seconds = TimeUnit.MILLISECONDS.toSeconds(ms) % 60; 66 | 67 | return LocalTime.of((int) hours, (int) minutes, (int) seconds); 68 | } 69 | 70 | @NotNull 71 | public static LocalDateTime getLocalDateTimeOf(long ms) { 72 | return LocalDateTime.ofInstant(Instant.ofEpochMilli(ms), TimeZone.getDefault().toZoneId()); 73 | } 74 | 75 | public static long toEpochMillis(@NotNull LocalDateTime dateTime) { 76 | Instant instant = dateTime.atZone(TimeZone.getDefault().toZoneId()).toInstant(); 77 | return instant.toEpochMilli(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/TriFunction.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils; 2 | 3 | import java.util.Objects; 4 | import java.util.function.Function; 5 | 6 | public interface TriFunction { 7 | 8 | R apply(T t, U u, V v); 9 | 10 | default TriFunction andThen(Function after) { 11 | Objects.requireNonNull(after); 12 | return (T t, U u, V v) -> after.apply(apply(t, u, v)); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/blocktracker/TrackUtil.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils.blocktracker; 2 | 3 | import org.bukkit.Chunk; 4 | import org.bukkit.block.Block; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | public class TrackUtil { 8 | 9 | public static long getChunkKey(@NotNull Chunk chunk) { 10 | return getChunkKey(chunk.getX(), chunk.getZ()); 11 | } 12 | 13 | public static long getChunkKey(final int chunkX, final int chunkZ) { 14 | return (long) chunkX & 0xFFFFFFFFL | ((long) chunkZ & 0xFFFFFFFFL) << 32; 15 | } 16 | 17 | public static long getChunkKeyOfBlock(@NotNull Block block) { 18 | return getChunkKey(block.getX() >> 4, block.getZ() >> 4); 19 | } 20 | 21 | public static int getRelativeChunkPosition(@NotNull Block block) { 22 | final int relX = (block.getX() % 16 + 16) % 16; 23 | final int relZ = (block.getZ() % 16 + 16) % 16; 24 | final int relY = block.getY(); 25 | return (relY & 0xFFFF) | ((relX & 0xFF) << 16) | ((relZ & 0xFF) << 24); 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/blocktracker/TrackedChunk.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils.blocktracker; 2 | 3 | import it.unimi.dsi.fastutil.ints.IntOpenHashSet; 4 | import it.unimi.dsi.fastutil.ints.IntSet; 5 | import org.bukkit.block.Block; 6 | import org.bukkit.persistence.PersistentDataContainer; 7 | import org.bukkit.persistence.PersistentDataType; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | public class TrackedChunk { 11 | 12 | private final IntSet trackedBlockPositions; 13 | 14 | protected TrackedChunk(@NotNull PersistentDataContainer container) { 15 | final int[] data = container.get(PlayerBlockTracker.TRACKED_DATA_KEY, PersistentDataType.INTEGER_ARRAY); 16 | if (data == null) { 17 | this.trackedBlockPositions = new IntOpenHashSet(); 18 | } 19 | else { 20 | this.trackedBlockPositions = new IntOpenHashSet(data); 21 | } 22 | } 23 | 24 | protected void add(@NotNull Block block) { 25 | this.trackedBlockPositions.add(TrackUtil.getRelativeChunkPosition(block)); 26 | } 27 | 28 | protected void remove(@NotNull Block block) { 29 | this.trackedBlockPositions.remove(TrackUtil.getRelativeChunkPosition(block)); 30 | } 31 | 32 | protected boolean isTracked(@NotNull Block block) { 33 | return this.trackedBlockPositions.contains(TrackUtil.getRelativeChunkPosition(block)); 34 | } 35 | 36 | protected void saveTo(@NotNull PersistentDataContainer container) { 37 | final int[] data = this.trackedBlockPositions.toIntArray(); 38 | container.set(PlayerBlockTracker.TRACKED_DATA_KEY, PersistentDataType.INTEGER_ARRAY, data); 39 | } 40 | 41 | protected boolean isEmpty() { 42 | return this.trackedBlockPositions.isEmpty(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/blocktracker/TrackedWorld.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils.blocktracker; 2 | 3 | import it.unimi.dsi.fastutil.longs.Long2ObjectMap; 4 | import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; 5 | import org.bukkit.Chunk; 6 | import org.bukkit.block.Block; 7 | import org.bukkit.persistence.PersistentDataContainer; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | public class TrackedWorld { 12 | 13 | private final Long2ObjectMap chunkMap; 14 | 15 | protected TrackedWorld() { 16 | this.chunkMap = new Long2ObjectOpenHashMap<>(); 17 | } 18 | 19 | protected boolean isTracked(@NotNull Block block) { 20 | TrackedChunk trackedChunk = this.getChunkOf(block); 21 | return trackedChunk != null && trackedChunk.isTracked(block); 22 | } 23 | 24 | protected void add(@NotNull Block block) { 25 | TrackedChunk trackedChunk = this.getChunkOf(block); 26 | if (trackedChunk == null) return; 27 | 28 | trackedChunk.add(block); 29 | } 30 | 31 | protected void remove(@NotNull Block block) { 32 | TrackedChunk trackedChunk = this.getChunkOf(block); 33 | if (trackedChunk == null) return; 34 | 35 | trackedChunk.remove(block); 36 | } 37 | 38 | protected void initChunk(@NotNull Chunk chunk) { 39 | PersistentDataContainer container = chunk.getPersistentDataContainer(); 40 | TrackedChunk trackedChunk = new TrackedChunk(container); 41 | this.chunkMap.put(TrackUtil.getChunkKey(chunk), trackedChunk); 42 | } 43 | 44 | protected void terminateChunk(@NotNull Chunk chunk) { 45 | TrackedChunk trackedChunk = this.chunkMap.remove(TrackUtil.getChunkKey(chunk)); 46 | if (trackedChunk == null) { 47 | return; 48 | } 49 | PersistentDataContainer container = chunk.getPersistentDataContainer(); 50 | if (trackedChunk.isEmpty()) { 51 | container.remove(PlayerBlockTracker.TRACKED_DATA_KEY); 52 | } 53 | else { 54 | trackedChunk.saveTo(container); 55 | } 56 | } 57 | 58 | @Nullable 59 | private TrackedChunk getChunkOf(@NotNull Block block) { 60 | return this.chunkMap.get(TrackUtil.getChunkKeyOfBlock(block)); 61 | } 62 | } -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/random/MTRandom.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils.random; 2 | 3 | import java.util.Random; 4 | 5 | public class MTRandom extends Random { 6 | 7 | private final static int UPPER_MASK = 0x80000000; 8 | private final static int LOWER_MASK = 0x7fffffff; 9 | 10 | private final static int N = 624; 11 | private final static int M = 397; 12 | private final static int[] MAGIC = {0x0, 0x9908b0df}; 13 | private final static int MAGIC_FACTOR1 = 1812433253; 14 | private final static int MAGIC_FACTOR2 = 1664525; 15 | private final static int MAGIC_FACTOR3 = 1566083941; 16 | private final static int MAGIC_MASK1 = 0x9d2c5680; 17 | private final static int MAGIC_MASK2 = 0xefc60000; 18 | private final static int MAGIC_SEED = 19650218; 19 | private final static long DEFAULT_SEED = 5489L; 20 | 21 | // Internal state 22 | private transient int[] mt; 23 | private transient int mti; 24 | 25 | // Temporary buffer used during setSeed(long) 26 | private transient int[] ibuf; 27 | 28 | public MTRandom() { 29 | 30 | } 31 | 32 | private void setSeed() { 33 | if (mt == null) mt = new int[N]; 34 | 35 | // ---- Begin Mersenne Twister Algorithm ---- 36 | mt[0] = MTRandom.MAGIC_SEED; 37 | for (mti = 1; mti < N; mti++) { 38 | mt[mti] = (MAGIC_FACTOR1 * (mt[mti - 1] ^ (mt[mti - 1] >>> 30)) + mti); 39 | } 40 | // ---- End Mersenne Twister Algorithm ---- 41 | } 42 | 43 | public final synchronized void setSeed(long seed) { 44 | if (ibuf == null) ibuf = new int[2]; 45 | 46 | ibuf[0] = (int) seed; 47 | ibuf[1] = (int) (seed >>> 32); 48 | setSeed(ibuf); 49 | } 50 | 51 | protected final synchronized int next(int bits) { 52 | // ---- Begin Mersenne Twister Algorithm ---- 53 | int y, kk; 54 | if (mti >= N) { 55 | 56 | for (kk = 0; kk < N - M; kk++) { 57 | y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); 58 | mt[kk] = mt[kk + M] ^ (y >>> 1) ^ MAGIC[y & 0x1]; 59 | } 60 | for (; kk < N - 1; kk++) { 61 | y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); 62 | mt[kk] = mt[kk + (M - N)] ^ (y >>> 1) ^ MAGIC[y & 0x1]; 63 | } 64 | y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK); 65 | mt[N - 1] = mt[M - 1] ^ (y >>> 1) ^ MAGIC[y & 0x1]; 66 | 67 | mti = 0; 68 | } 69 | 70 | y = mt[mti++]; 71 | 72 | // Tempering 73 | y ^= (y >>> 11); 74 | y ^= (y << 7) & MAGIC_MASK1; 75 | y ^= (y << 15) & MAGIC_MASK2; 76 | y ^= (y >>> 18); 77 | // ---- End Mersenne Twister Algorithm ---- 78 | return (y >>> (32 - bits)); 79 | } 80 | 81 | // This is a fairly obscure little code section to pack a 82 | // byte[] into an int[] in little endian ordering. 83 | 84 | public final synchronized void setSeed(int[] buf) { 85 | int length = buf.length; 86 | if (length == 0) throw new IllegalArgumentException("Seed buffer may not be empty"); 87 | // ---- Begin Mersenne Twister Algorithm ---- 88 | int i = 1, j = 0, k = (Math.max(N, length)); 89 | setSeed(); 90 | for (; k > 0; k--) { 91 | mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >>> 30)) * MAGIC_FACTOR2)) + buf[j] + j; 92 | i++; 93 | j++; 94 | if (i >= N) { 95 | mt[0] = mt[N - 1]; 96 | i = 1; 97 | } 98 | if (j >= length) j = 0; 99 | } 100 | for (k = N - 1; k > 0; k--) { 101 | mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >>> 30)) * MAGIC_FACTOR3)) - i; 102 | i++; 103 | if (i >= N) { 104 | mt[0] = mt[N - 1]; 105 | i = 1; 106 | } 107 | } 108 | mt[0] = UPPER_MASK; // MSB is 1; assuring non-zero initial array 109 | // ---- End Mersenne Twister Algorithm ---- 110 | } 111 | } -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/random/Rnd.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils.random; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.utils.CollectionsUtil; 5 | import su.nexmedia.engine.utils.Pair; 6 | 7 | import java.util.*; 8 | 9 | public class Rnd { 10 | 11 | public static final MTRandom rnd = new MTRandom(); 12 | 13 | public static float get() { 14 | return Rnd.rnd.nextFloat(); 15 | } 16 | 17 | public static float get(boolean normalize) { 18 | float f = Rnd.get(); 19 | if (normalize) f *= 100f; 20 | return f; 21 | } 22 | 23 | public static int get(int n) { 24 | return Rnd.nextInt(n); 25 | } 26 | 27 | public static int get(int min, int max) { 28 | return min + (int) Math.floor(Rnd.rnd.nextDouble() * (max - min + 1)); 29 | } 30 | 31 | public static double getDouble(double max) { 32 | return getDouble(0, max); 33 | } 34 | 35 | public static double getDouble(double min, double max) { 36 | return min + (max - min) * rnd.nextDouble(); 37 | } 38 | 39 | @NotNull 40 | public static E get(@NotNull E[] list) { 41 | return list[get(list.length)]; 42 | } 43 | 44 | public static int get(int[] list) { 45 | return list[get(list.length)]; 46 | } 47 | 48 | @NotNull 49 | public static E get(@NotNull List list) { 50 | if (list.isEmpty()) throw new NoSuchElementException("Empty list provided!"); 51 | 52 | return list.get(get(list.size())); 53 | } 54 | 55 | @NotNull 56 | public static E get(@NotNull Set list) { 57 | return get(new ArrayList<>(list)); 58 | } 59 | 60 | @NotNull 61 | public static T getByWeight(@NotNull Map itemsMap) { 62 | List> items = CollectionsUtil.sortAscent(itemsMap).entrySet().stream() 63 | .filter(e -> e.getValue() > 0D) 64 | .map(e -> Pair.of(e.getKey(), e.getValue())).toList(); 65 | double totalWeight = items.stream().mapToDouble(Pair::getSecond).sum(); 66 | 67 | int index = 0; 68 | for (double chance = Rnd.nextDouble() * totalWeight; index < items.size() - 1; ++index) { 69 | chance -= items.get(index).getSecond(); 70 | if (chance <= 0D) break; 71 | } 72 | return items.get(index).getFirst(); 73 | } 74 | 75 | public static boolean chance(int chance) { 76 | return chance >= 1 && (chance > 99 || nextInt(99) + 1 <= chance); 77 | } 78 | 79 | public static boolean chance(double chance) { 80 | return nextDouble() <= chance / 100.0; 81 | } 82 | 83 | public static int nextInt(int n) { 84 | return (int) Math.floor(Rnd.rnd.nextDouble() * n); 85 | } 86 | 87 | public static int nextInt() { 88 | return Rnd.rnd.nextInt(); 89 | } 90 | 91 | public static double nextDouble() { 92 | return Rnd.rnd.nextDouble(); 93 | } 94 | 95 | public static double nextGaussian() { 96 | return Rnd.rnd.nextGaussian(); 97 | } 98 | 99 | public static boolean nextBoolean() { 100 | return Rnd.rnd.nextBoolean(); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/regex/MatcherTimeoutException.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils.regex; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class MatcherTimeoutException extends RuntimeException { 6 | 7 | private final String chars; 8 | private final long timeout; 9 | 10 | MatcherTimeoutException(@NotNull CharSequence chars, long timeout) { 11 | this.chars = chars.toString(); 12 | this.timeout = timeout; 13 | } 14 | 15 | @NotNull 16 | public String getString() { 17 | return this.chars; 18 | } 19 | 20 | public long getTimeout() { 21 | return this.timeout; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/regex/RegexUtil.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils.regex; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.utils.EngineUtils; 5 | 6 | import java.util.regex.Matcher; 7 | import java.util.regex.Pattern; 8 | 9 | @Deprecated 10 | public class RegexUtil { 11 | 12 | public static boolean matches(@NotNull Pattern pattern, @NotNull String text) { 13 | Matcher matcher = getMatcher(pattern, text); 14 | return matcher.matches(); 15 | } 16 | 17 | @NotNull 18 | public static Matcher getMatcher(@NotNull String pattern, @NotNull String text) { 19 | return getMatcher(pattern, text, 200); 20 | } 21 | 22 | @NotNull 23 | public static Matcher getMatcher(@NotNull String patternText, @NotNull String text, long timeout) { 24 | Pattern pattern = Pattern.compile(patternText); 25 | return getMatcher(pattern, text, timeout); 26 | } 27 | 28 | @NotNull 29 | public static Matcher getMatcher(@NotNull Pattern pattern, @NotNull String msg) { 30 | return getMatcher(pattern, msg, 200); 31 | } 32 | 33 | public static boolean matcherFind(@NotNull Matcher matcher) { 34 | try { 35 | return matcher.find(); 36 | } 37 | catch (MatcherTimeoutException exception) { 38 | EngineUtils.ENGINE.warn("Matcher " + exception.getTimeout() + "ms timeout error for: '" + matcher.pattern().pattern() + "'"); 39 | return false; 40 | } 41 | } 42 | 43 | @NotNull 44 | public static Matcher getMatcher(@NotNull Pattern pattern, @NotNull String text, long timeout) { 45 | if (timeout <= 0) { 46 | return pattern.matcher(text); 47 | } 48 | return pattern.matcher(new TimeoutCharSequence(text, timeout)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/regex/TimedMatcher.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils.regex; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.utils.EngineUtils; 5 | 6 | import java.util.regex.Matcher; 7 | import java.util.regex.Pattern; 8 | 9 | public class TimedMatcher { 10 | 11 | private final Matcher matcher; 12 | private boolean debug; 13 | 14 | public TimedMatcher(@NotNull Matcher matcher) { 15 | this.matcher = matcher; 16 | } 17 | 18 | @NotNull 19 | public static TimedMatcher create(@NotNull String pattern, @NotNull String str) { 20 | return create(pattern, str, 200); 21 | } 22 | 23 | @NotNull 24 | public static TimedMatcher create(@NotNull Pattern pattern, @NotNull String str) { 25 | return new TimedMatcher(getMatcher(pattern, str, 200)); 26 | } 27 | 28 | @NotNull 29 | public static TimedMatcher create(@NotNull String rawPattern, @NotNull String str, long timeout) { 30 | return create(Pattern.compile(rawPattern), str, timeout); 31 | } 32 | 33 | @NotNull 34 | public static TimedMatcher create(@NotNull Pattern pattern, @NotNull String str, long timeout) { 35 | return new TimedMatcher(getMatcher(pattern, str, timeout)); 36 | } 37 | 38 | @NotNull 39 | private static Matcher getMatcher(@NotNull Pattern pattern, @NotNull String text, long timeout) { 40 | if (timeout <= 0) { 41 | return pattern.matcher(text); 42 | } 43 | return pattern.matcher(new TimeoutCharSequence(text, timeout)); 44 | } 45 | 46 | @NotNull 47 | public Matcher getMatcher() { 48 | return matcher; 49 | } 50 | 51 | public boolean isDebug() { 52 | return debug; 53 | } 54 | 55 | public void setDebug(boolean debug) { 56 | this.debug = debug; 57 | } 58 | 59 | @NotNull 60 | public String replaceAll(@NotNull String with) { 61 | try { 62 | return this.matcher.replaceAll(with); 63 | } 64 | catch (MatcherTimeoutException exception) { 65 | if (this.isDebug()) { 66 | EngineUtils.ENGINE.warn("Matcher " + exception.getTimeout() + "ms timeout error for replaceAll: '" + matcher.pattern().pattern() + "'."); 67 | } 68 | return ""; 69 | } 70 | } 71 | 72 | public boolean matches() { 73 | try { 74 | return this.matcher.matches(); 75 | } 76 | catch (MatcherTimeoutException exception) { 77 | if (this.isDebug()) { 78 | EngineUtils.ENGINE.warn("Matcher " + exception.getTimeout() + "ms timeout error for: '" + matcher.pattern().pattern() + "'."); 79 | } 80 | return false; 81 | } 82 | } 83 | 84 | public boolean find() { 85 | try { 86 | return this.matcher.find(); 87 | } 88 | catch (MatcherTimeoutException exception) { 89 | if (this.isDebug()) { 90 | EngineUtils.ENGINE.warn("Matcher " + exception.getTimeout() + "ms timeout error for: '" + matcher.pattern().pattern() + "'."); 91 | } 92 | return false; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/regex/TimeoutCharSequence.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils.regex; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | public class TimeoutCharSequence implements CharSequence { 6 | 7 | private final CharSequence chars; 8 | private final long timeout; 9 | private final long maxTime; 10 | 11 | public TimeoutCharSequence(@NotNull CharSequence chars, long timeout) { 12 | this.chars = chars; 13 | this.timeout = timeout; 14 | this.maxTime = (System.currentTimeMillis() + timeout); 15 | } 16 | 17 | @Override 18 | public char charAt(int index) { 19 | if (System.currentTimeMillis() > this.maxTime) { 20 | throw new MatcherTimeoutException(this.chars, this.timeout); 21 | } 22 | return this.chars.charAt(index); 23 | } 24 | 25 | @Override 26 | public int length() { 27 | return this.chars.length(); 28 | } 29 | 30 | @Override 31 | public CharSequence subSequence(int start, int end) { 32 | return new TimeoutCharSequence(this.chars.subSequence(start, end), this.timeout); 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return this.chars.toString(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/values/UniDouble.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils.values; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.config.JYML; 5 | import su.nexmedia.engine.utils.random.Rnd; 6 | 7 | public final class UniDouble { 8 | 9 | private final double minInclusive; 10 | private final double maxInclusive; 11 | 12 | private UniDouble(double min, double max) { 13 | this.minInclusive = min; 14 | this.maxInclusive = max; 15 | } 16 | 17 | @NotNull 18 | public static UniDouble of(double min, double max) { 19 | return new UniDouble(min, max); 20 | } 21 | 22 | @NotNull 23 | public static UniDouble read(@NotNull JYML cfg, @NotNull String path) { 24 | double min = cfg.getDouble(path + ".Min"); 25 | double max = cfg.getDouble(path + ".Max"); 26 | return of(min, max); 27 | } 28 | 29 | public void write(@NotNull JYML cfg, @NotNull String path) { 30 | cfg.set(path + ".Min", this.getMinValue()); 31 | cfg.set(path + ".Max", this.getMaxValue()); 32 | } 33 | 34 | @NotNull 35 | public UniInt asInt() { 36 | return UniInt.of((int) this.getMinValue(), (int) this.getMaxValue()); 37 | } 38 | 39 | public double roll() { 40 | return Rnd.getDouble(this.minInclusive, this.maxInclusive); 41 | } 42 | 43 | public double getMinValue() { 44 | return this.minInclusive; 45 | } 46 | 47 | public double getMaxValue() { 48 | return this.maxInclusive; 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return "[" + this.minInclusive + "-" + this.maxInclusive + "]"; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/values/UniInt.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils.values; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.api.config.JYML; 5 | import su.nexmedia.engine.utils.random.Rnd; 6 | 7 | public final class UniInt { 8 | 9 | private final int minInclusive; 10 | private final int maxInclusive; 11 | 12 | private UniInt(int var0, int var1) { 13 | this.minInclusive = var0; 14 | this.maxInclusive = var1; 15 | } 16 | 17 | @NotNull 18 | public static UniInt of(int var0, int var1) { 19 | return new UniInt(var0, var1); 20 | } 21 | 22 | @NotNull 23 | public static UniInt read(@NotNull JYML cfg, @NotNull String path) { 24 | int min = cfg.getInt(path + ".Min"); 25 | int max = cfg.getInt(path + ".Max"); 26 | return of(min, max); 27 | } 28 | 29 | public void write(@NotNull JYML cfg, @NotNull String path) { 30 | cfg.set(path + ".Min", this.getMinValue()); 31 | cfg.set(path + ".Max", this.getMaxValue()); 32 | } 33 | 34 | public int roll() { 35 | return Rnd.get(this.minInclusive, this.maxInclusive); 36 | } 37 | 38 | public int getMinValue() { 39 | return this.minInclusive; 40 | } 41 | 42 | public int getMaxValue() { 43 | return this.maxInclusive; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "[" + this.minInclusive + "-" + this.maxInclusive + "]"; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/values/UniSound.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils.values; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.Sound; 5 | import org.bukkit.World; 6 | import org.bukkit.entity.Player; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | import su.nexmedia.engine.api.config.JOption; 10 | import su.nexmedia.engine.api.config.JYML; 11 | import su.nexmedia.engine.utils.StringUtil; 12 | 13 | public class UniSound { 14 | 15 | private final String soundName; 16 | private final Sound soundType; 17 | private final float volume; 18 | private final float pitch; 19 | 20 | public UniSound(@NotNull String soundName, @Nullable Sound soundType, float volume, float pitch) { 21 | this.soundName = soundName; 22 | this.soundType = soundType; 23 | this.volume = volume; 24 | this.pitch = pitch; 25 | } 26 | 27 | @NotNull 28 | public static UniSound of(@NotNull Sound sound) { 29 | return of(sound, 0.8F); 30 | } 31 | 32 | @NotNull 33 | public static UniSound of(@NotNull Sound sound, float volume) { 34 | return of(sound, volume, 1F); 35 | } 36 | 37 | @NotNull 38 | public static UniSound of(@NotNull Sound sound, float volume, float pitch) { 39 | return new UniSound(sound.name(), sound, volume, pitch); 40 | } 41 | 42 | @NotNull 43 | public static UniSound read(@NotNull JYML cfg, @NotNull String path) { 44 | String soundName = JOption.create(path + ".Name", "null", 45 | "Sound name. You can use Spigot sound names, or ones from your resource pack.", 46 | "Spigot Sounds: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Sound.html").read(cfg); 47 | 48 | float volume = JOption.create(path + ".Volume", 0.8F, 49 | "Sound volume. From 0.0 to 1.0.").read(cfg).floatValue(); 50 | 51 | float pitch = JOption.create(path + ".Pitch", 1D, 52 | "Sound speed. From 0.5 to 2.0").read(cfg).floatValue(); 53 | 54 | Sound soundType = StringUtil.getEnum(soundName, Sound.class).orElse(null); 55 | 56 | return new UniSound(soundName, soundType, volume, pitch); 57 | } 58 | 59 | public void write(@NotNull JYML cfg, @NotNull String path) { 60 | cfg.set(path + ".Name", this.getSoundName()); 61 | cfg.set(path + ".Volume", this.getVolume()); 62 | cfg.set(path + ".Pitch", this.getPitch()); 63 | } 64 | 65 | public boolean isEmpty() { 66 | return this.getVolume() <= 0F || this.getSoundName().isEmpty(); 67 | } 68 | 69 | public void play(@NotNull Player player) { 70 | if (this.isEmpty()) return; 71 | 72 | Location location = player.getLocation(); 73 | if (this.getSoundType() == null) { 74 | player.playSound(location, this.getSoundName(), this.getVolume(), this.getPitch()); 75 | } 76 | else { 77 | player.playSound(location, this.getSoundType(), this.getVolume(), this.getPitch()); 78 | } 79 | } 80 | 81 | public void play(@NotNull Location location) { 82 | if (this.isEmpty()) return; 83 | 84 | World world = location.getWorld(); 85 | if (world == null) return; 86 | 87 | if (this.getSoundType() == null) { 88 | world.playSound(location, this.getSoundName(), this.getVolume(), this.getPitch()); 89 | } 90 | else { 91 | world.playSound(location, this.getSoundType(), this.getVolume(), this.getPitch()); 92 | } 93 | } 94 | 95 | @NotNull 96 | public String getSoundName() { 97 | return soundName; 98 | } 99 | 100 | @Nullable 101 | public Sound getSoundType() { 102 | return soundType; 103 | } 104 | 105 | public float getVolume() { 106 | return volume; 107 | } 108 | 109 | public float getPitch() { 110 | return pitch; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /NexEngine/src/main/java/su/nexmedia/engine/utils/values/UniTask.java: -------------------------------------------------------------------------------- 1 | package su.nexmedia.engine.utils.values; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import su.nexmedia.engine.NexPlugin; 5 | 6 | public class UniTask { 7 | 8 | private final NexPlugin plugin; 9 | private final Runnable runnable; 10 | private final long interval; 11 | private final boolean async; 12 | 13 | private int taskId; 14 | 15 | public UniTask(@NotNull NexPlugin plugin, @NotNull Runnable runnable, long interval, boolean async) { 16 | this.plugin = plugin; 17 | this.runnable = runnable; 18 | this.interval = interval; 19 | this.async = async; 20 | 21 | this.taskId = -1; 22 | } 23 | 24 | @NotNull 25 | public static Builder builder(@NotNull NexPlugin plugin) { 26 | return new Builder(plugin); 27 | } 28 | 29 | public final void restart() { 30 | this.stop(); 31 | this.start(); 32 | } 33 | 34 | public boolean start() { 35 | if (this.taskId >= 0) return false; 36 | if (this.interval <= 0L) return false; 37 | 38 | if (this.async) { 39 | this.taskId = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, runnable, 0L, interval).getTaskId(); 40 | } 41 | else { 42 | this.taskId = plugin.getServer().getScheduler().runTaskTimer(plugin, runnable, 0L, interval).getTaskId(); 43 | } 44 | return true; 45 | } 46 | 47 | public boolean stop() { 48 | if (this.taskId < 0) return false; 49 | 50 | this.plugin.getServer().getScheduler().cancelTask(this.taskId); 51 | this.taskId = -1; 52 | return true; 53 | } 54 | 55 | public static class Builder { 56 | 57 | private final NexPlugin plugin; 58 | 59 | private Runnable runnable; 60 | private long interval; 61 | private boolean async; 62 | 63 | public Builder(@NotNull NexPlugin plugin) { 64 | this.plugin = plugin; 65 | } 66 | 67 | @NotNull 68 | public Builder withRunnable(@NotNull Runnable runnable) { 69 | this.runnable = runnable; 70 | return this; 71 | } 72 | 73 | @NotNull 74 | public Builder withTicks(long interval) { 75 | this.interval = interval; 76 | return this; 77 | } 78 | 79 | @NotNull 80 | public Builder withSeconds(int interval) { 81 | this.interval = interval * 20L; 82 | return this; 83 | } 84 | 85 | @NotNull 86 | public Builder async() { 87 | this.async = true; 88 | return this; 89 | } 90 | 91 | @NotNull 92 | public UniTask build() { 93 | return new UniTask(plugin, runnable, interval, async); 94 | } 95 | 96 | @NotNull 97 | public UniTask buildAndRun() { 98 | UniTask task = this.build(); 99 | task.start(); 100 | return task; 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /NexEngine/src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | Plugin: 2 | Command_Aliases: 'nexengine' -------------------------------------------------------------------------------- /NexEngine/src/main/resources/lang/messages_cn.yml: -------------------------------------------------------------------------------- 1 | Placeholders: 2 | '%green%': '#74ea31' 3 | '%gray%': '#aaa8a8' 4 | '%red%': '#ea3131' 5 | Command: 6 | Usage: 7 | - 8 | - '#aaa8a8' 9 | - '#ea3131错误:#aaa8a8参数错误!' 10 | - '#ea3131用法:#ead931/%command_label% #ea9631%command_usage%' 11 | - '#aaa8a8' 12 | Help: 13 | List: 14 | - 15 | - '#aaa8a8' 16 | - ' #ead931%plugin_name_localized%#aaa8a8 - #ead931命令:' 17 | - '#aaa8a8' 18 | - ' #ea3131<> #aaa8a8- 必需的,#74ea31[] #aaa8a8- 可选的。' 19 | - '#aaa8a8' 20 | - ' #ead931/%command_label% #ea9631%command_usage% #aaa8a8- %command_description%' 21 | - '#aaa8a8' 22 | Desc: 显示帮助页面 23 | About: 24 | Desc: 一些关于插件的信息 25 | Reload: 26 | Desc: 重新加载整个插件 27 | Done: 所有数据和配置已重新加载! 28 | Time: 29 | Day: '%s%天' 30 | Hour: '%s%小时' 31 | Min: '%s%分钟' 32 | Sec: '%s%秒' 33 | Other: 34 | 'Yes': '#74ea31是' 35 | 'No': '#ea3131否' 36 | Any: 任何 37 | None: 无 38 | Never: 从不 39 | OneTimed: 一次性的 40 | Unlimited: 无限的 41 | Infinity: ∞ 42 | Error: 43 | Player: 44 | Invalid: '#ea3131没有找到玩家' 45 | World: 46 | Invalid: '#ea3131没有找到世界' 47 | Number: 48 | Invalid: '#ea3131%num% 这不是一个有效的数字' 49 | Permission: 50 | Deny: '#ea3131你没有权限这么做!' 51 | Command: 52 | Self: '#ea3131此命令不能在自己身上使用' 53 | Sender: '#ea3131此命令仅供玩家使用' 54 | Editor: 55 | Tip: 56 | Exit: '#aaa8a8点击这里 #ea3131[退出编辑模式]' 57 | Title: 58 | Done: '#74ea31完成!' 59 | Edit: '#74ea31< 编辑模式 >' 60 | Error: '#ea3131错误!' 61 | Error: 62 | Number: 63 | Generic: '#aaa8a8无效的数字!' 64 | NotInt: '#aaa8a8期待 #ea3131整数!' 65 | Enum: '#aaa8a8无效的输入!' 66 | Generic: 67 | Close: 68 | Name: '#FF5733(✕) 退出' 69 | Lore: [] 70 | Return: 71 | Name: '#ffee9a(↓) &f返回' 72 | Lore: [] 73 | NextPage: 74 | Name: '#e3fbf9(→) 下一页' 75 | Lore: [] 76 | PreviousPage: 77 | Name: '#e3fbf9(←) 上一页' 78 | Lore: [] 79 | -------------------------------------------------------------------------------- /NexEngine/src/main/resources/lang/messages_ru.yml: -------------------------------------------------------------------------------- 1 | # Здесь вы можете создать свои собственные заполнители, чтобы использовать их в конфигурации языка. 2 | # Key = Placeholder, Value = Replacer. 3 | Placeholders: 4 | '%gray%': '#d4d9d8' 5 | '%red%': '#fd5e5e' 6 | '%green%': '#aefd5e' 7 | Command: 8 | Usage: 9 | - '' 10 | - '#d4d9d8' 11 | - '#fd5e5eError: #d4d9d8Неверные аргументы!' 12 | - '#fd5e5eUsage: #fdf35e/%command_label% #ffeea2%command_usage%' 13 | - '#d4d9d8' 14 | Help: 15 | List: 16 | - '' 17 | - '#d4d9d8' 18 | - '#fdf35e&l%plugin_name_localized%#d4d9d8 - #fdf35e&lКоманды:' 19 | - '#d4d9d8' 20 | - '#fd5e5e&l<> #d4d9d8- Обязательно, #aefd5e&l[] #d4d9d8- Опционально.' 21 | - '#d4d9d8' 22 | - '#ffeea2 #fdf35e/%command_label% #ffeea2%command_usage% #d4d9d8- %command_description%' 23 | - '#d4d9d8' 24 | Desc: 'Отобразить страницу помощи.' 25 | About: 26 | Desc: 'О плагине.' 27 | Reload: 28 | Desc: 'Перезагрузка плагина.' 29 | Done: 'Все данные и настройки перезагружены!' 30 | Time: 31 | Day: '%s%д.' 32 | Hour: '%s%ч.' 33 | Min: '%s%мин.' 34 | Sec: '%s%сек.' 35 | Other: 36 | 'Yes': '#aefd5eДа' 37 | 'No': '#fd5e5eНет' 38 | Any: Любой 39 | None: 'Ничего' 40 | Never: Никогда 41 | OneTimed: Одноразовый 42 | Unlimited: Бесконечный 43 | Infinity: ∞ 44 | Error: 45 | Player: 46 | Invalid: '#fd5e5eИгрок не найден.' 47 | World: 48 | Invalid: '#fd5e5eМир не найден.' 49 | Number: 50 | Invalid: '#fd5e5e%num% недействительное число.' 51 | Permission: 52 | Deny: '#fd5e5eУ вас нет прав на это действие!' 53 | Command: 54 | Self: '#fd5e5eНельзя использовать на себе.' 55 | Sender: '#fd5e5eЭта комманда только для игроков.' 56 | Editor: 57 | Tip: 58 | Exit: '#d4d9d8Click here to #fd5e5e[Exit Edit Mode]' 59 | Title: 60 | Done: '&a&lГотово!' 61 | Edit: '&a&l< Режим редактора >' 62 | Error: '&c&lОшибка!' 63 | Error: 64 | Number: 65 | Generic: '&7Некорректное число!' 66 | NotInt: '&7Число должно быть &cцелым&7!' 67 | Enum: '&7Некорректное значение. Проверьте подсказки в чате.' 68 | Generic: 69 | Close: 70 | Name: '#FF5733(?) &lВыход' 71 | Lore: [] 72 | Return: 73 | Name: '#ffee9a(v) &fНазад' 74 | Lore: [] 75 | NextPage: 76 | Name: '#e3fbf9(>) &lСледующая страница' 77 | Lore: [] 78 | PreviousPage: 79 | Name: '#e3fbf9(<) &lПредыдущая страница' 80 | Lore: [] -------------------------------------------------------------------------------- /NexEngine/src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: NexEngine 2 | main: su.nexmedia.engine.NexEngine 3 | version: '${project.version}' 4 | description: Plugin Engine 5 | author: NightExpress 6 | softdepend: [ Vault] 7 | api-version: 1.17 8 | load: STARTUP 9 | libraries: 10 | - com.zaxxer:HikariCP:5.0.1 11 | - it.unimi.dsi:fastutil:8.5.11 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Outdated, see https://github.com/nulli0n/nightcore-spigot 2 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | su.nexmedia 8 | NexEnginePlugin 9 | pom 10 | 2.2.12 11 | 12 | NexEngine 13 | 14 | 15 | 16 | 16 17 | 16 18 | 19 | 20 | 21 | 22 | spigot-repo 23 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/ 24 | 25 | 26 | jitpack.io 27 | https://jitpack.io 28 | 29 | true 30 | 31 | 32 | 33 | maven 34 | https://repo1.maven.org/maven2/ 35 | 36 | true 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.jetbrains 44 | annotations 45 | 19.0.0 46 | 47 | 48 | 49 | --------------------------------------------------------------------------------