use this amazing config library i just found
This commit is contained in:
parent
59804031f5
commit
79cc7e6b7e
9 changed files with 134 additions and 164 deletions
|
@ -37,6 +37,7 @@ dependencies {
|
|||
implementation "com.github.robertlit:SpigotResourcesAPI:2.0"
|
||||
implementation "net.kyori:adventure-platform-bukkit:4.3.0"
|
||||
implementation "com.github.retrooper.packetevents:spigot:2.0.0-SNAPSHOT"
|
||||
implementation "space.arim.dazzleconf:dazzleconf-ext-snakeyaml:1.2.1"
|
||||
}
|
||||
|
||||
group "lol.pyr"
|
||||
|
@ -55,8 +56,12 @@ shadowJar {
|
|||
relocate "org.checkerframework", "lol.pyr.znpcsplus.lib.checkerframework"
|
||||
relocate "javax.annotation", "lol.pyr.znpcsplus.lib.javaxannotation"
|
||||
relocate "com.google", "lol.pyr.znpcsplus.lib.google"
|
||||
|
||||
relocate "com.github.retrooper.packetevents", "lol.pyr.znpcsplus.lib.packetevents.api"
|
||||
relocate "io.github.retrooper.packetevents", "lol.pyr.znpcsplus.lib.packetevents.impl"
|
||||
|
||||
relocate "org.yaml.snakeyaml", "lol.pyr.znpcsplus.lib.snakeyaml"
|
||||
relocate "space.arim.dazzleconf", "lol.pyr.znpcsplus.lib.dazzleconf"
|
||||
minimize()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
package io.github.znetworkw.znpcservers.configuration;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
import io.github.znetworkw.znpcservers.utility.Utils;
|
||||
import lol.pyr.znpcsplus.ZNPCsPlus;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Configuration {
|
||||
private static final Charset CHARSET = StandardCharsets.UTF_8;
|
||||
private final String name;
|
||||
private final Path path;
|
||||
private final Map<ConfigurationValue, Object> configurationValues;
|
||||
public static final Configuration CONFIGURATION = new Configuration("config");
|
||||
public static final Configuration MESSAGES = new Configuration("messages");
|
||||
|
||||
protected Configuration(String name) {
|
||||
this(name, ZNPCsPlus.PLUGIN_FOLDER.toPath().resolve(name + ".json"));
|
||||
}
|
||||
|
||||
private Configuration(String name, Path path) {
|
||||
if (!path.getFileName().toString().endsWith(".json")) throw new IllegalStateException("Invalid configuration format for: " + path.getFileName());
|
||||
this.name = name;
|
||||
this.path = path;
|
||||
this.configurationValues = ConfigurationValue.VALUES_BY_NAME.get(name).stream().collect(Collectors.toMap((c) -> c, ConfigurationValue::getValue));
|
||||
this.onLoad();
|
||||
this.save();
|
||||
}
|
||||
|
||||
protected void onLoad() {
|
||||
try (Reader reader = Files.newBufferedReader(this.path, CHARSET)) {
|
||||
JsonElement data = JsonParser.parseReader(reader);
|
||||
if (data == null) return;
|
||||
for(ConfigurationValue configValue : this.configurationValues.keySet()) {
|
||||
boolean single = this.configurationValues.size() == 1;
|
||||
JsonElement jsonElement = single ? data : (data.isJsonObject() ? data.getAsJsonObject().get(configValue.name()) : null);
|
||||
if (jsonElement == null || jsonElement.isJsonNull()) continue;
|
||||
if (!single && configValue.getPrimitiveType().isEnum()) this.configurationValues.put(configValue, ZNPCsPlus.GSON.fromJson(jsonElement, configValue.getPrimitiveType()));
|
||||
else this.configurationValues.put(configValue, ZNPCsPlus.GSON.fromJson(jsonElement, $Gson$Types.newParameterizedTypeWithOwner(null, configValue.getValue().getClass(), configValue.getPrimitiveType())));
|
||||
}
|
||||
} catch (NoSuchFileException ignored) {
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalStateException("Failed to read configuration: " + this.name);
|
||||
}
|
||||
}
|
||||
|
||||
public void save() {
|
||||
try (Writer writer = Files.newBufferedWriter(this.path, CHARSET)) {
|
||||
ZNPCsPlus.GSON.toJson(this.configurationValues.size() == 1 ? this.configurationValues.values().iterator().next() : this.configurationValues, writer);
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalStateException("Failed to save configuration: " + this.name);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getValue(ConfigurationValue configValue) {
|
||||
return (T)this.configurationValues.get(configValue);
|
||||
}
|
||||
|
||||
public void sendMessage(org.bukkit.command.CommandSender sender, ConfigurationValue configValue, Object... replaces) {
|
||||
sender.sendMessage(Utils.toColor(String.format(this.getValue(configValue), replaces)));
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package io.github.znetworkw.znpcservers.configuration;
|
||||
|
||||
public final class ConfigurationConstants {
|
||||
public static final String SPACE_SYMBOL = Configuration.CONFIGURATION.getValue(ConfigurationValue.REPLACE_SYMBOL);
|
||||
public static final boolean DEBUG_ENABLED = Configuration.CONFIGURATION.getValue(ConfigurationValue.DEBUG_ENABLED);
|
||||
public static final int VIEW_DISTANCE = Configuration.CONFIGURATION.<Integer>getValue(ConfigurationValue.VIEW_DISTANCE);
|
||||
public static final boolean CHECK_FOR_UPDATES = Configuration.CONFIGURATION.getValue(ConfigurationValue.CHECK_FOR_UPDATES);
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package io.github.znetworkw.znpcservers.configuration;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import io.github.znetworkw.znpcservers.utility.GuavaCollectors;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public enum ConfigurationValue {
|
||||
VIEW_DISTANCE("config", 32, Integer.class),
|
||||
REPLACE_SYMBOL("config", "-", String.class),
|
||||
SAVE_NPCS_DELAY_SECONDS("config", 600, Integer.class),
|
||||
MAX_PATH_LOCATIONS("config", 500, Integer.class),
|
||||
DEBUG_ENABLED("config", false, Boolean.class),
|
||||
LINE_SPACING("config", 0.3D, Double.class),
|
||||
ANIMATION_RGB("config", false, Boolean.class),
|
||||
CHECK_FOR_UPDATES("config", true, Boolean.class),
|
||||
NO_PERMISSION("messages", "&cYou do not have permission to execute this command.", String.class),
|
||||
SUCCESS("messages", "&aSuccess!", String.class),
|
||||
INCORRECT_USAGE("messages", "&cThe arguments you specified are invalid. Type &f/znpcs&c for examples.", String.class),
|
||||
COMMAND_NOT_FOUND("messages", "&cThe command you specified does not exist!", String.class),
|
||||
COMMAND_ERROR("messages", "&cAn error occurred when executing this command. See console for more information.", String.class),
|
||||
INVALID_NUMBER("messages", "&cThe ID you have specified is invalid. Please use positive integers only!", String.class),
|
||||
NPC_NOT_FOUND("messages", "&cNo NPCs could be found with this ID!", String.class),
|
||||
TOO_FEW_ARGUMENTS("messages", "&cThis command does not contain enough arguments. Type &f/znpcs&c or view our documentation for a list/examples of existing arguments.", String.class),
|
||||
PATH_START("messages", "&aSuccess! Move to create a path for your NPC. When finished, type &f/znpcs path exit&c to exit path creation.", String.class),
|
||||
EXIT_PATH("messages", "&cYou have exited path creation.", String.class),
|
||||
PATH_FOUND("messages", "&cThere is already a path with this name.", String.class),
|
||||
NPC_FOUND("messages", "&cThere is already an NPC with this ID.", String.class),
|
||||
NO_PATH_FOUND("messages", "&cThe path you have specified does not exist.", String.class),
|
||||
NO_SKIN_FOUND("messages", "&cThe skin username/URL you have specified does not exist or is invalid.", String.class),
|
||||
NO_NPC_FOUND("messages", "&cThe NPC you have specified does not exist.", String.class),
|
||||
NO_ACTION_FOUND("messages", "&cThis action does not exist! Type &f/znpcs&c or view our documentation for a list/examples of existing action types.", String.class),
|
||||
METHOD_NOT_FOUND("messages", "&cThis method does not exist! Type &f/znpcs&c or view our documentation for a list/examples of existing methods.", String.class),
|
||||
INVALID_NAME_LENGTH("messages", "&cThe name you specified either too short or long. Please enter a positive integer of (3 to 16) characters.", String.class),
|
||||
UNSUPPORTED_ENTITY("messages", "&cThis entity type not available in your current server version.", String.class),
|
||||
PATH_SET_INCORRECT_USAGE("messages", "&eUsage: &aset <npc_id> <path_name>", String.class),
|
||||
ACTION_ADD_INCORRECT_USAGE("messages", "&eUsage: &a<SERVER/CMD/MESSAGE/CONSOLE> <actionValue>", String.class),
|
||||
ACTION_DELAY_INCORRECT_USAGE("messages", "&eUsage: &a<action_id> <delay>", String.class),
|
||||
CONVERSATION_SET_INCORRECT_USAGE("messages", "&cUsage: <npc_id> <conversation_name> <RADIUS/CLICK>", String.class),
|
||||
NO_CONVERSATION_FOUND("messages", "&cThe conversation you have specified does not exist!", String.class),
|
||||
CONVERSATION_FOUND("messages", "&cThere is already a conversation with this name.", String.class),
|
||||
INVALID_SIZE("messages", "&cThe position you have specified cannot exceed the limit.", String.class),
|
||||
FETCHING_SKIN("messages", "&aFetching skin for name: &f%s&a. Please wait...", String.class),
|
||||
CANT_GET_SKIN("messages", "&cCould not fetch skin for name: %s.", String.class),
|
||||
GET_SKIN("messages", "&aSkin successfully fetched!", String.class),
|
||||
NOT_SUPPORTED_NPC_TYPE("messages", "&cThis NPC type doesn't exists or is not supported in your current server version.", String.class);
|
||||
|
||||
public static final Map<String, ImmutableSet<ConfigurationValue>> VALUES_BY_NAME;
|
||||
|
||||
static {
|
||||
VALUES_BY_NAME = Arrays.stream(values()).collect(Collectors.groupingBy(ConfigurationValue::getConfigName, GuavaCollectors.toImmutableSet()));
|
||||
}
|
||||
|
||||
private final String configName;
|
||||
private final Object value;
|
||||
private final Class<?> primitiveType;
|
||||
|
||||
ConfigurationValue(String configName, Object value, Class<?> primitiveType) {
|
||||
this.configName = configName;
|
||||
this.value = value;
|
||||
this.primitiveType = primitiveType;
|
||||
}
|
||||
|
||||
public String getConfigName() {
|
||||
return this.configName;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public Class<?> getPrimitiveType() {
|
||||
return this.primitiveType;
|
||||
}
|
||||
}
|
|
@ -6,11 +6,11 @@ import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
|||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
|
||||
import io.github.znetworkw.znpcservers.configuration.ConfigurationConstants;
|
||||
import io.github.znetworkw.znpcservers.listeners.InventoryListener;
|
||||
import io.github.znetworkw.znpcservers.utility.BungeeUtils;
|
||||
import io.github.znetworkw.znpcservers.utility.SchedulerUtils;
|
||||
import io.github.znetworkw.znpcservers.utility.itemstack.ItemStackSerializer;
|
||||
import lol.pyr.znpcsplus.config.Configs;
|
||||
import lol.pyr.znpcsplus.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.entity.PacketLocation;
|
||||
import lol.pyr.znpcsplus.interaction.InteractionPacketListener;
|
||||
|
@ -110,6 +110,9 @@ public class ZNPCsPlus extends JavaPlugin {
|
|||
PLUGIN_FOLDER.mkdirs();
|
||||
PATH_FOLDER.mkdirs();
|
||||
|
||||
log(ChatColor.WHITE + " * Loading configurations...");
|
||||
Configs.init(PLUGIN_FOLDER);
|
||||
|
||||
log(ChatColor.WHITE + " * Registering components...");
|
||||
getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
|
||||
new Metrics(this, PLUGIN_ID);
|
||||
|
@ -122,13 +125,13 @@ public class ZNPCsPlus extends JavaPlugin {
|
|||
new InventoryListener(this);
|
||||
new SkinCacheCleanTask(this);
|
||||
new UserListener(this);
|
||||
if (ConfigurationConstants.CHECK_FOR_UPDATES) new UpdateNotificationListener(this, new UpdateChecker(this));
|
||||
if (Configs.config().checkForUpdates()) new UpdateNotificationListener(this, new UpdateChecker(this));
|
||||
|
||||
enabled = true;
|
||||
log(ChatColor.WHITE + " * Loading complete! (" + (System.currentTimeMillis() - before) + "ms)");
|
||||
log("");
|
||||
|
||||
if (ConfigurationConstants.DEBUG_ENABLED) {
|
||||
if (Configs.config().debugEnabled()) {
|
||||
int wrap = 20;
|
||||
int x = 0;
|
||||
int z = 0;
|
||||
|
|
58
src/main/java/lol/pyr/znpcsplus/config/Configs.java
Normal file
58
src/main/java/lol/pyr/znpcsplus/config/Configs.java
Normal file
|
@ -0,0 +1,58 @@
|
|||
package lol.pyr.znpcsplus.config;
|
||||
|
||||
import lol.pyr.znpcsplus.ZNPCsPlus;
|
||||
import space.arim.dazzleconf.ConfigurationFactory;
|
||||
import space.arim.dazzleconf.ConfigurationOptions;
|
||||
import space.arim.dazzleconf.error.ConfigFormatSyntaxException;
|
||||
import space.arim.dazzleconf.error.InvalidConfigException;
|
||||
import space.arim.dazzleconf.ext.snakeyaml.CommentMode;
|
||||
import space.arim.dazzleconf.ext.snakeyaml.SnakeYamlConfigurationFactory;
|
||||
import space.arim.dazzleconf.ext.snakeyaml.SnakeYamlOptions;
|
||||
import space.arim.dazzleconf.helper.ConfigurationHelper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Configs {
|
||||
private volatile static MainConfig config;
|
||||
private static ConfigurationHelper<MainConfig> configHelper;
|
||||
|
||||
private volatile static MessageConfig messages;
|
||||
private static ConfigurationHelper<MessageConfig> messagesHelper;
|
||||
|
||||
private static <T> ConfigurationHelper<T> createHelper(Class<T> configClass, File file) {
|
||||
SnakeYamlOptions yamlOptions = new SnakeYamlOptions.Builder().commentMode(CommentMode.fullComments()).build();
|
||||
ConfigurationFactory<T> configFactory = SnakeYamlConfigurationFactory.create(configClass, ConfigurationOptions.defaults(), yamlOptions);
|
||||
return new ConfigurationHelper<>(file.getParentFile().toPath(), file.getName(), configFactory);
|
||||
}
|
||||
|
||||
public static void init(File pluginFolder) {
|
||||
configHelper = createHelper(MainConfig.class, new File(pluginFolder, "config.yaml"));
|
||||
messagesHelper = createHelper(MessageConfig.class, new File(pluginFolder, "messages.yaml"));
|
||||
load();
|
||||
}
|
||||
|
||||
public static void load() {
|
||||
try {
|
||||
config = configHelper.reloadConfigData();
|
||||
messages = messagesHelper.reloadConfigData();
|
||||
} catch (IOException e) {
|
||||
ZNPCsPlus.LOGGER.severe("Couldn't open config file!");
|
||||
e.printStackTrace();
|
||||
} catch (ConfigFormatSyntaxException e) {
|
||||
ZNPCsPlus.LOGGER.severe("Invalid config syntax!");
|
||||
e.printStackTrace();
|
||||
} catch (InvalidConfigException e) {
|
||||
ZNPCsPlus.LOGGER.severe("Invalid config value!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static MainConfig config() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public static MessageConfig messages() {
|
||||
return messages;
|
||||
}
|
||||
}
|
24
src/main/java/lol/pyr/znpcsplus/config/MainConfig.java
Normal file
24
src/main/java/lol/pyr/znpcsplus/config/MainConfig.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
package lol.pyr.znpcsplus.config;
|
||||
|
||||
import space.arim.dazzleconf.annote.ConfKey;
|
||||
|
||||
import static space.arim.dazzleconf.annote.ConfDefault.*;
|
||||
|
||||
// TODO: Add comments to the values using @ConfComments()
|
||||
public interface MainConfig {
|
||||
@ConfKey("view-distance")
|
||||
@DefaultInteger(32)
|
||||
int viewDistance();
|
||||
|
||||
@ConfKey("line-spacing")
|
||||
@DefaultDouble(0.3D)
|
||||
double lineSpacing();
|
||||
|
||||
@ConfKey("debug-enabled")
|
||||
@DefaultBoolean(false)
|
||||
boolean debugEnabled();
|
||||
|
||||
@ConfKey("check-for-updates")
|
||||
@DefaultBoolean(true)
|
||||
boolean checkForUpdates();
|
||||
}
|
38
src/main/java/lol/pyr/znpcsplus/config/MessageConfig.java
Normal file
38
src/main/java/lol/pyr/znpcsplus/config/MessageConfig.java
Normal file
|
@ -0,0 +1,38 @@
|
|||
package lol.pyr.znpcsplus.config;
|
||||
|
||||
/**
|
||||
* (OLD CONFIGURATION)
|
||||
* NO_PERMISSION("messages", "&cYou do not have permission to execute this command.", String.class),
|
||||
* SUCCESS("messages", "&aSuccess!", String.class),
|
||||
* INCORRECT_USAGE("messages", "&cThe arguments you specified are invalid. Type &f/znpcs&c for examples.", String.class),
|
||||
* COMMAND_NOT_FOUND("messages", "&cThe command you specified does not exist!", String.class),
|
||||
* COMMAND_ERROR("messages", "&cAn error occurred when executing this command. See console for more information.", String.class),
|
||||
* INVALID_NUMBER("messages", "&cThe ID you have specified is invalid. Please use positive integers only!", String.class),
|
||||
* NPC_NOT_FOUND("messages", "&cNo NPCs could be found with this ID!", String.class),
|
||||
* TOO_FEW_ARGUMENTS("messages", "&cThis command does not contain enough arguments. Type &f/znpcs&c or view our documentation for a list/examples of existing arguments.", String.class),
|
||||
* PATH_START("messages", "&aSuccess! Move to create a path for your NPC. When finished, type &f/znpcs path exit&c to exit path creation.", String.class),
|
||||
* EXIT_PATH("messages", "&cYou have exited path creation.", String.class),
|
||||
* PATH_FOUND("messages", "&cThere is already a path with this name.", String.class),
|
||||
* NPC_FOUND("messages", "&cThere is already an NPC with this ID.", String.class),
|
||||
* NO_PATH_FOUND("messages", "&cThe path you have specified does not exist.", String.class),
|
||||
* NO_SKIN_FOUND("messages", "&cThe skin username/URL you have specified does not exist or is invalid.", String.class),
|
||||
* NO_NPC_FOUND("messages", "&cThe NPC you have specified does not exist.", String.class),
|
||||
* NO_ACTION_FOUND("messages", "&cThis action does not exist! Type &f/znpcs&c or view our documentation for a list/examples of existing action types.", String.class),
|
||||
* METHOD_NOT_FOUND("messages", "&cThis method does not exist! Type &f/znpcs&c or view our documentation for a list/examples of existing methods.", String.class),
|
||||
* INVALID_NAME_LENGTH("messages", "&cThe name you specified either too short or long. Please enter a positive integer of (3 to 16) characters.", String.class),
|
||||
* UNSUPPORTED_ENTITY("messages", "&cThis entity type not available in your current server version.", String.class),
|
||||
* PATH_SET_INCORRECT_USAGE("messages", "&eUsage: &aset <npc_id> <path_name>", String.class),
|
||||
* ACTION_ADD_INCORRECT_USAGE("messages", "&eUsage: &a<SERVER/CMD/MESSAGE/CONSOLE> <actionValue>", String.class),
|
||||
* ACTION_DELAY_INCORRECT_USAGE("messages", "&eUsage: &a<action_id> <delay>", String.class),
|
||||
* CONVERSATION_SET_INCORRECT_USAGE("messages", "&cUsage: <npc_id> <conversation_name> <RADIUS/CLICK>", String.class),
|
||||
* NO_CONVERSATION_FOUND("messages", "&cThe conversation you have specified does not exist!", String.class),
|
||||
* CONVERSATION_FOUND("messages", "&cThere is already a conversation with this name.", String.class),
|
||||
* INVALID_SIZE("messages", "&cThe position you have specified cannot exceed the limit.", String.class),
|
||||
* FETCHING_SKIN("messages", "&aFetching skin for name: &f%s&a. Please wait...", String.class),
|
||||
* CANT_GET_SKIN("messages", "&cCould not fetch skin for name: %s.", String.class),
|
||||
* GET_SKIN("messages", "&aSkin successfully fetched!", String.class),
|
||||
* NOT_SUPPORTED_NPC_TYPE("messages", "&cThis NPC type doesn't exists or is not supported in your current server version.", String.class);
|
||||
*/
|
||||
|
||||
public interface MessageConfig {
|
||||
}
|
|
@ -1,12 +1,13 @@
|
|||
package lol.pyr.znpcsplus.tasks;
|
||||
|
||||
import io.github.znetworkw.znpcservers.configuration.ConfigurationConstants;
|
||||
import lol.pyr.znpcsplus.config.Configs;
|
||||
import lol.pyr.znpcsplus.npc.NPC;
|
||||
import lol.pyr.znpcsplus.npc.NPCRegistry;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.NumberConversions;
|
||||
|
||||
public class NPCVisibilityTask extends BukkitRunnable {
|
||||
public NPCVisibilityTask(Plugin plugin) {
|
||||
|
@ -14,7 +15,7 @@ public class NPCVisibilityTask extends BukkitRunnable {
|
|||
}
|
||||
|
||||
public void run() {
|
||||
int distSq = ConfigurationConstants.VIEW_DISTANCE * ConfigurationConstants.VIEW_DISTANCE;
|
||||
double distSq = NumberConversions.square(Configs.config().viewDistance());
|
||||
for (NPC npc : NPCRegistry.all()) for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
boolean inRange = (player.getWorld() == npc.getWorld() && player.getLocation().distanceSquared(npc.getLocation().toBukkitLocation(npc.getWorld())) <= distSq);
|
||||
if (!inRange && npc.isShown(player)) npc.hide(player);
|
||||
|
|
Loading…
Reference in a new issue