commit today's work

even if this compiles it's unlikely to work properly
this has been my most productive ever well maybe not ever but lately for sure
This commit is contained in:
Minecon724 2024-06-01 19:35:15 +02:00
parent 565fa477dc
commit 90205881f8
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
43 changed files with 940 additions and 9 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target/
/.settings/

View file

@ -14,6 +14,7 @@ differences compared to v0:
- weather levels \
it's not like there's strong rain or there's no rain \
I'm not sure how yet
- sunrise sunset
- snow
- more api providers, multiple api keys
- extensible: api

63
pom.xml
View file

@ -3,4 +3,67 @@
<groupId>eu.m724</groupId>
<artifactId>realweather</artifactId>
<version>0.9-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>724rocks</id>
<url>https://git.724.rocks/api/packages/Minecon724/maven</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.20.6-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>eu.m724</groupId>
<artifactId>wtapi</artifactId>
<version>0.2</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<artifactSet>
<includes>
<include>eu.m724:wtapi</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View file

@ -0,0 +1,18 @@
package eu.m724.realweather;
import java.util.logging.Logger;
public class DebugLogger {
static Logger baseLogger;
static int debugLevel;
public static int getDebugLevel() {
return debugLevel;
}
public static void info(String message, int minDebugLevel, Object... format) {
if (debugLevel >= minDebugLevel)
baseLogger.info(String.format(message, format));
}
}

View file

@ -0,0 +1,124 @@
package eu.m724.realweather;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.logging.Logger;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import com.google.common.base.Charsets;
import eu.m724.realweather.mapper.Mapper;
import eu.m724.realweather.mapper.MapperConfig;
import eu.m724.realweather.object.UserException;
import eu.m724.realweather.thunder.ThunderConfig;
import eu.m724.realweather.thunder.ThunderMaster;
import eu.m724.realweather.time.TimeConfig;
import eu.m724.realweather.time.TimeMaster;
import eu.m724.realweather.weather.WeatherConfig;
import eu.m724.realweather.weather.WeatherMaster;
import eu.m724.wtapi.provider.exception.ProviderException;
public class RealWeatherPlugin extends JavaPlugin {
private Mapper mapper;
private WeatherMaster weatherMaster;
private ThunderMaster thunderMaster;
private TimeMaster timeMaster;
private YamlConfiguration config;
private Logger logger;
private YamlConfiguration mapConfig;
@Override
public void onEnable() {
logger = getLogger();
File dataFolder = getDataFolder();
File modulesFolder = new File(dataFolder, "modules");
modulesFolder.mkdir();
YamlConfiguration configuration,
mapConfiguration, weatherConfiguration,
thunderConfiguration, timeConfiguration;
DebugLogger.info("loading configurations", 1);
try {
configuration = getConfig(new File(dataFolder, "config.yml"));
mapConfiguration = getConfig(new File(dataFolder, "map.yml"));
weatherConfiguration = getConfig(new File(modulesFolder, "weather.yml"));
thunderConfiguration = getConfig(new File(modulesFolder, "thunder.yml"));
timeConfiguration = getConfig(new File(modulesFolder, "time.yml"));
} catch (IOException e) {
logger.severe("Failed to load config!");
e.printStackTrace();
getServer().getPluginManager().disablePlugin(this);
return;
}
DebugLogger.baseLogger = logger;
DebugLogger.debugLevel = configuration.getInt("debug");
if (configuration.getBoolean("enabled")) {
logger.info("plugin disabled by admin");
getServer().getPluginManager().disablePlugin(this);
}
DebugLogger.info("loading mapper", 1);
mapper = new Mapper(
MapperConfig.fromConfiguration(mapConfiguration));
try {
DebugLogger.info("loading weather", 1);
weatherMaster = new WeatherMaster(
WeatherConfig.fromConfiguration(weatherConfiguration), mapper);
weatherMaster.init();
DebugLogger.info("loading thunder", 1);
thunderMaster = new ThunderMaster(
ThunderConfig.fromConfiguration(thunderConfiguration), mapper, this);
thunderMaster.init();
DebugLogger.info("loading time", 1);
timeMaster = new TimeMaster(
TimeConfig.fromConfiguration(timeConfiguration), mapper);
timeMaster.init();
} catch (UserException e) {
logger.severe("There are errors in your config:");
logger.severe(e.getMessage());
getServer().getPluginManager().disablePlugin(this);
} catch (ProviderException e) {
logger.severe("Couldn't initialize provider!");
logger.severe("Possible causes:");
logger.severe("1. Your API key is invalid");
logger.severe("2. The provider or your internet is down");
e.printStackTrace();
getServer().getPluginManager().disablePlugin(this);
}
DebugLogger.info("ended loading", 1);
}
public YamlConfiguration getConfig(File configFile) throws IOException {
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
if (!configFile.exists()) {
final InputStream defConfigStream = getResource("config.yml");
if (defConfigStream == null)
return null;
config = YamlConfiguration.loadConfiguration(new InputStreamReader(defConfigStream, Charsets.UTF_8));
config.save(configFile);
}
return config;
}
}

View file

@ -0,0 +1,54 @@
package eu.m724.realweather.mapper;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.World;
import eu.m724.wtapi.object.Coordinates;
public class Mapper {
private MapperConfig config;
private List<World> worlds;
public Mapper(MapperConfig config) {
this.config = config;
}
public Coordinates locationToCoordinates(Location location) {
double latitude = -location.getZ() / config.scaleLatitude;
double longitude = location.getX() / config.scaleLongitude;
return new Coordinates(latitude, longitude);
}
public Location coordinatesToLocation(World world, Coordinates coordinates) {
double x = -coordinates.latitude * config.scaleLatitude;
double z = coordinates.longitude * config.scaleLongitude;
return new Location(world, x, 0, z);
}
public Coordinates getPoint() {
return config.point;
}
public List<World> getWorlds() {
return this.worlds;
}
boolean loadWorld(World world) {
boolean loaded = config.worlds.contains(world.getName()) ^ config.worldBlacklist;
if (loaded)
worlds.add(world);
return loaded;
}
void unloadWorld(World world) {
worlds.remove(world);
}
}

View file

@ -0,0 +1,37 @@
package eu.m724.realweather.mapper;
import java.util.List;
import org.bukkit.configuration.ConfigurationSection;
import eu.m724.wtapi.object.Coordinates;
public class MapperConfig {
public boolean enabled;
public boolean worldBlacklist;
public List<String> worlds;
public int scaleLatitude;
public int scaleLongitude;
public Coordinates point;
public static MapperConfig fromConfiguration(ConfigurationSection configuration) {
MapperConfig mapperConfig = new MapperConfig();
mapperConfig.enabled = configuration.getBoolean("enabled");
mapperConfig.worldBlacklist = configuration.getBoolean("worldBlacklist");
mapperConfig.worlds = configuration.getStringList("worlds");
mapperConfig.scaleLatitude = configuration.getInt("dimensions.latitude");
mapperConfig.scaleLongitude = configuration.getInt("dimensions.longitude");
mapperConfig.point = new Coordinates(
configuration.getDouble("point.latitude"),
configuration.getDouble("point.longitude"));
return mapperConfig;
}
}

View file

@ -0,0 +1,24 @@
package eu.m724.realweather.mapper;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
public class MapperEventHandler implements Listener {
private Mapper mapper;
public MapperEventHandler(Mapper mapper) {
this.mapper = mapper;
}
@EventHandler
public void onWorldLoad(WorldLoadEvent e) {
mapper.loadWorld(e.getWorld());
}
@EventHandler
public void onWorldUnload(WorldUnloadEvent e) {
mapper.unloadWorld(e.getWorld());
}
}

View file

@ -0,0 +1,11 @@
package eu.m724.realweather.object;
public class UserException extends Exception {
private static final long serialVersionUID = 6850666306511891275L;
public UserException(String message) {
super(message);
}
}

View file

@ -0,0 +1,25 @@
package eu.m724.realweather.thunder;
import org.bukkit.configuration.ConfigurationSection;
import eu.m724.realweather.time.TimeConfig;
public class ThunderConfig {
public boolean enabled;
public String provider;
// how often refresh in ms
public int refresh;
public static ThunderConfig fromConfiguration(ConfigurationSection configuration) {
ThunderConfig thunderConfig = new ThunderConfig();
thunderConfig.enabled = configuration.getBoolean("enabled");
thunderConfig.provider = configuration.getString("provider");
thunderConfig.refresh = configuration.getInt("refresh");
return thunderConfig;
}
}

View file

@ -0,0 +1,67 @@
package eu.m724.realweather.thunder;
import java.util.ArrayList;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import eu.m724.realweather.DebugLogger;
import eu.m724.realweather.mapper.Mapper;
import eu.m724.realweather.object.UserException;
import eu.m724.wtapi.provider.WeatherProvider;
import eu.m724.wtapi.provider.exception.ProviderException;
import eu.m724.wtapi.provider.impl.openweathermap.OpenWeatherMapProvider;
import eu.m724.wtapi.thunder.ThunderProvider;
import eu.m724.wtapi.thunder.impl.lightningmaps.LightningMapsProvider;
import eu.m724.wtapi.thunder.impl.lightningmaps.TimedStrike;
public class ThunderMaster {
private ThunderConfig config;
private Mapper mapper;
private ThunderProvider provider;
private Plugin plugin;
private ThunderTask thunderTask;
ArrayList<TimedStrike> strikes = new ArrayList<>();
public ThunderMaster(ThunderConfig config, Mapper mapper, Plugin plugin) {
this.config = config;
this.mapper = mapper;
this.plugin = plugin;
}
/**
* initializes, tests and starts
* @throws UserException config issue
* @throws ProviderException if provider initialization failed
*/
public void init() throws UserException, ProviderException {
if (!config.enabled)
return;
provider = createProvider();
if (provider == null)
throw new UserException("Invalid provider: " + config.provider);
provider.init();
provider.registerStrikeHandler(coords -> {
strikes.add(new TimedStrike(System.currentTimeMillis() + provider.getDelay(), coords));
});
thunderTask = new ThunderTask(this, mapper);
thunderTask.runTaskTimer(plugin, 0, config.refresh);
DebugLogger.info("thunder loaded", 1);
}
private ThunderProvider createProvider() {
switch (config.provider) {
case "lightningmaps":
return new LightningMapsProvider();
}
return null;
}
}

View file

@ -0,0 +1,44 @@
package eu.m724.realweather.thunder;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.scheduler.BukkitRunnable;
import eu.m724.realweather.DebugLogger;
import eu.m724.realweather.mapper.Mapper;
import eu.m724.wtapi.thunder.impl.lightningmaps.TimedStrike;
class ThunderTask extends BukkitRunnable {
private ThunderMaster thunderMaster;
private Mapper mapper;
public ThunderTask(ThunderMaster thunderMaster, Mapper mapper) {
this.thunderMaster = thunderMaster;
this.mapper = mapper;
}
@Override
public void run() {
DebugLogger.info("thundertask running", 3);
while (thunderMaster.strikes.size() > 0) {
TimedStrike strike = thunderMaster.strikes.get(0);
thunderMaster.strikes.remove(0);
DebugLogger.info("strike: %f %f", 2, strike.coordinates.latitude, strike.coordinates.longitude);
mapper.getWorlds().forEach(w -> {
Location location = mapper.coordinatesToLocation(w, strike.coordinates);
DebugLogger.info("in %s that converts to: %d %d %d", 2, w.getName(), location.getBlockX(), location.getBlockY(), location.getBlockZ());
if (w.getChunkAt(location).isLoaded()) {
location.setY(w.getHighestBlockYAt(location));
w.spawnEntity(location, EntityType.LIGHTNING_BOLT);
DebugLogger.info("spawnd lightning in %s on y level %d", 2, w.getName(), location.getBlockY());
}
});
}
}
}

View file

@ -0,0 +1,23 @@
package eu.m724.realweather.time;
import org.bukkit.configuration.ConfigurationSection;
public class TimeConfig {
public boolean enabled;
// state is per player
public boolean dynamic;
// x day cycles in 1 irl day
public double modifier;
public static TimeConfig fromConfiguration(ConfigurationSection configuration) {
TimeConfig timeConfig = new TimeConfig();
timeConfig.enabled = configuration.getBoolean("enabled");
timeConfig.dynamic = configuration.getBoolean("dynamic");
timeConfig.modifier = configuration.getDouble("modifier");
return timeConfig;
}
}

View file

@ -0,0 +1,34 @@
package eu.m724.realweather.time;
import java.util.ArrayList;
import eu.m724.realweather.DebugLogger;
import eu.m724.realweather.mapper.Mapper;
import eu.m724.realweather.object.UserException;
import eu.m724.realweather.thunder.ThunderConfig;
import eu.m724.wtapi.provider.exception.ProviderException;
import eu.m724.wtapi.thunder.ThunderProvider;
import eu.m724.wtapi.thunder.impl.lightningmaps.LightningMapsProvider;
import eu.m724.wtapi.thunder.impl.lightningmaps.TimedStrike;
public class TimeMaster {
private TimeConfig config;
private Mapper mapper;
public TimeMaster(TimeConfig config, Mapper mapper) {
this.config = config;
this.mapper = mapper;
}
/**
* initializes, tests and starts
* @throws UserException config issue
*/
public void init() throws UserException {
if (!config.enabled)
return;
// TODO start task, actually create that task, account for data from weather like sunrise sunset timezone
DebugLogger.info("time loaded", 1);
}
}

View file

@ -0,0 +1,29 @@
package eu.m724.realweather.weather;
import org.bukkit.configuration.ConfigurationSection;
public class WeatherConfig {
public boolean enabled;
public String provider;
public String apiKey;
// state is per player
public boolean dynamic;
// prevent other stuff from changing weather
public boolean lock;
public static WeatherConfig fromConfiguration(ConfigurationSection configuration) {
WeatherConfig weatherConfig = new WeatherConfig();
weatherConfig.enabled = configuration.getBoolean("enabled");
weatherConfig.provider = configuration.getString("provider");
weatherConfig.apiKey = configuration.getString("apiKey");
weatherConfig.dynamic = configuration.getBoolean("dynamic");
weatherConfig.lock = configuration.getBoolean("lock");
return weatherConfig;
}
}

View file

@ -0,0 +1,48 @@
package eu.m724.realweather.weather;
import eu.m724.realweather.DebugLogger;
import eu.m724.realweather.mapper.Mapper;
import eu.m724.realweather.object.UserException;
import eu.m724.wtapi.provider.WeatherProvider;
import eu.m724.wtapi.provider.exception.ProviderException;
import eu.m724.wtapi.provider.impl.openweathermap.OpenWeatherMapProvider;
public class WeatherMaster {
private WeatherConfig config;
private Mapper mapper;
private WeatherProvider provider;
public WeatherMaster(WeatherConfig config, Mapper mapper) {
this.config = config;
this.mapper = mapper;
}
/**
* initializes, tests and starts
* @throws UserException config issue
* @throws ProviderException if provider initialization failed
*/
public void init() throws UserException, ProviderException {
if (!config.enabled)
return;
provider = createProvider();
if (provider == null)
throw new UserException("Invalid provider: " + config.provider);
provider.init();
// TODO start task
DebugLogger.info("weather loaded", 1);
}
private WeatherProvider createProvider() {
switch (config.provider) {
case "openweathermap":
return new OpenWeatherMapProvider(config.apiKey);
}
return null;
}
}

View file

@ -0,0 +1,17 @@
############################
### GENERAL SETTINGS ###
############################
# Master switch
enabled: true
updater:
# notify players about plugin updates
# revelant permission node: realweather.update.notify
notify: true
# 0 - no debug
# 1 - debug loading modules
# 2 - also debug processing conditions
# 3 - also log tasks running, this will spam
debug: 0

View file

@ -0,0 +1,24 @@
############################
### MAP SETTINGS ###
############################
# true if the list below is a blacklist, false otherwise
worldBlacklist: true
worlds:
- disabled_world
- something
dimensions:
# blocks per 1 deg, can't be decimal
# the default (111000) assumes 1 block = 1 meter
latitude: 111000
longitude: 111000
# if you want the globe to cover the whole world use:
# latitude: 333333
# longitude: 166666
# if you use `static` mode
point:
latitude: 0
longitude: 0

View file

@ -0,0 +1,12 @@
############################
### THUNDER SETTINGS ###
############################
enabled: false
# currently only lightningmaps
provider: lightningmaps
# how often should we poll for updates and spawn lightning
# note that this runs synchronously so increase if lag
refresh: 50 # millis

View file

@ -0,0 +1,17 @@
############################
### TIME SETTINGS ###
############################
# warning: this removes sleep
enabled: false
# How this plugin affects your world:
# - static (false): time is the same across the world
# - dynamic (true): static + local time for each player, however it's only cosmetical so it will not match mobs spawning etc
# settings for both are in map.yml
dynamic: true
# x day cycles in 1 irl day cycle
# time will no longer be in sync
# can be decimal
modifier: 1.0

View file

@ -0,0 +1,19 @@
############################
### WEATHER SETTINGS ###
############################
enabled: false
# Currently only OpenWeatherMap
provider: openweathermap
# put your OpenWeatherMap api key
apiKey: REPLACE ME
# How this plugin affects your world:
# - static (false): weather is the same across the world
# - dynamic (true): weather is per player, however it's only cosmetical so it will not match mobs spawning etc
# settings for both are in map.yml
dynamic: true
# prevent the game, players or other plugins from changing the weather
lock: true

View file

@ -0,0 +1,43 @@
name: RealWeather
version: ${project.version}
author: Minecon724
website: https://www.spigotmc.org/resources/101599
api-version: 1.20
load: STARTUP
main: eu.m724.realweather.RealWeatherPlugin
commands:
realweather:
description: AIO RealWeather command
aliases: rw
permission: realweather.command
permission-message: You do not have permission to use this command.
# usage is processed in code
geo:
description: Convert lat,lon to x,y,z and vice versa
permission: realweather.geo
permission-message: You do not have permission to use this command.
# usage is processed in code
permissions:
realweather.command:
description: Allows /realweather (individual nodes are still necessary for subcommands)
realweather.command.status:
description: /realweather status
realweather.command.*:
description: All /realweather commands
children:
realweather.command: true
realweather.command.status: true
realweather.geo:
description: Allows /geo
default: true
realweather.geo.tp:
description: Allows teleportation using /geo
realweather.update.notify:
description: Receive notifications for RealWeather updates

View file

@ -1,5 +1,5 @@
#Generated by Maven Integration for Eclipse
#Sat Jun 01 13:23:15 CEST 2024
#Sat Jun 01 19:33:58 CEST 2024
artifactId=realweather
groupId=eu.m724
m2e.projectLocation=/home/user/eclipse-workspace/realweather

View file

@ -3,4 +3,67 @@
<groupId>eu.m724</groupId>
<artifactId>realweather</artifactId>
<version>0.9-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>724rocks</id>
<url>https://git.724.rocks/api/packages/Minecon724/maven</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.20.6-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>eu.m724</groupId>
<artifactId>wtapi</artifactId>
<version>0.2</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<artifactSet>
<includes>
<include>eu.m724:wtapi</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

17
target/classes/config.yml Normal file
View file

@ -0,0 +1,17 @@
############################
### GENERAL SETTINGS ###
############################
# Master switch
enabled: true
updater:
# notify players about plugin updates
# revelant permission node: realweather.update.notify
notify: true
# 0 - no debug
# 1 - debug loading modules
# 2 - also debug processing conditions
# 3 - also log tasks running, this will spam
debug: 0

Binary file not shown.

Binary file not shown.

24
target/classes/map.yml Normal file
View file

@ -0,0 +1,24 @@
############################
### MAP SETTINGS ###
############################
# true if the list below is a blacklist, false otherwise
worldBlacklist: true
worlds:
- disabled_world
- something
dimensions:
# blocks per 1 deg, can't be decimal
# the default (111000) assumes 1 block = 1 meter
latitude: 111000
longitude: 111000
# if you want the globe to cover the whole world use:
# latitude: 333333
# longitude: 166666
# if you use `static` mode
point:
latitude: 0
longitude: 0

View file

@ -0,0 +1,12 @@
############################
### THUNDER SETTINGS ###
############################
enabled: false
# currently only lightningmaps
provider: lightningmaps
# how often should we poll for updates and spawn lightning
# note that this runs synchronously so increase if lag
refresh: 50 # millis

View file

@ -0,0 +1,17 @@
############################
### TIME SETTINGS ###
############################
# warning: this removes sleep
enabled: false
# How this plugin affects your world:
# - static (false): time is the same across the world
# - dynamic (true): static + local time for each player, however it's only cosmetical so it will not match mobs spawning etc
# settings for both are in map.yml
dynamic: true
# x day cycles in 1 irl day cycle
# time will no longer be in sync
# can be decimal
modifier: 1.0

View file

@ -0,0 +1,19 @@
############################
### WEATHER SETTINGS ###
############################
enabled: false
# Currently only OpenWeatherMap
provider: openweathermap
# put your OpenWeatherMap api key
apiKey: REPLACE ME
# How this plugin affects your world:
# - static (false): weather is the same across the world
# - dynamic (true): weather is per player, however it's only cosmetical so it will not match mobs spawning etc
# settings for both are in map.yml
dynamic: true
# prevent the game, players or other plugins from changing the weather
lock: true

43
target/classes/plugin.yml Normal file
View file

@ -0,0 +1,43 @@
name: RealWeather
version: 0.9-SNAPSHOT
author: Minecon724
website: https://www.spigotmc.org/resources/101599
api-version: 1.20
load: STARTUP
main: eu.m724.realweather.RealWeatherPlugin
commands:
realweather:
description: AIO RealWeather command
aliases: rw
permission: realweather.command
permission-message: You do not have permission to use this command.
# usage is processed in code
geo:
description: Convert lat,lon to x,y,z and vice versa
permission: realweather.geo
permission-message: You do not have permission to use this command.
# usage is processed in code
permissions:
realweather.command:
description: Allows /realweather (individual nodes are still necessary for subcommands)
realweather.command.status:
description: /realweather status
realweather.command.*:
description: All /realweather commands
children:
realweather.command: true
realweather.command.status: true
realweather.geo:
description: Allows /geo
default: true
realweather.geo.tp:
description: Allows teleportation using /geo
realweather.update.notify:
description: Receive notifications for RealWeather updates