9 Commits

13 changed files with 286 additions and 23 deletions

@ -405,6 +405,23 @@ portalInfoServer=Server: %server%
# Changes # Changes
#### \[Version 0.9.4.2] EpicKnarvik97 fork
- Avoids a NullPointerException if Dynmap is present, but isn't properly loaded.
- Avoids some potential NullPointerExceptions related to Dynmap integration
- Fixes end portals hijacking BungeeCord teleportation
- Fixes a problem where a player might not be properly teleported from an end portal Stargate in the end to the
over-world.
#### \[Version 0.9.4.1] EpicKnarvik97 fork
- Reverts to Spigot API 1.18
- Adds Dynmap integration
#### \[Version 0.9.4.0] EpicKnarvik97 fork
- Updates Stargate to 1.19
#### \[Version 0.9.3.7] EpicKnarvik97 fork #### \[Version 0.9.3.7] EpicKnarvik97 fork
- Adds the Japanese language file provided by spigot user furplag - Adds the Japanese language file provided by spigot user furplag

13
pom.xml

@ -4,7 +4,7 @@
<groupId>net.knarcraft</groupId> <groupId>net.knarcraft</groupId>
<artifactId>Stargate</artifactId> <artifactId>Stargate</artifactId>
<version>0.9.4.0</version> <version>0.9.4.2</version>
<licenses> <licenses>
<license> <license>
@ -28,13 +28,17 @@
<id>vault-repo</id> <id>vault-repo</id>
<url>http://nexus.hc.to/content/repositories/pub_releases</url> <url>http://nexus.hc.to/content/repositories/pub_releases</url>
</repository> </repository>
<repository>
<id>dynmap</id>
<url>https://repo.mikeprimm.com/</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId> <artifactId>spigot-api</artifactId>
<version>1.19-R0.1-SNAPSHOT</version> <version>1.19.2-R0.1-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.milkbowl.vault</groupId> <groupId>net.milkbowl.vault</groupId>
@ -65,6 +69,11 @@
<version>4.13.2</version> <version>4.13.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>us.dynmap</groupId>
<artifactId>dynmap-api</artifactId>
<version>3.1-beta-2</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

@ -3,6 +3,7 @@ package net.knarcraft.stargate.command;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.ConfigOption; import net.knarcraft.stargate.config.ConfigOption;
import net.knarcraft.stargate.config.ConfigTag; import net.knarcraft.stargate.config.ConfigTag;
import net.knarcraft.stargate.config.DynmapManager;
import net.knarcraft.stargate.config.OptionDataType; import net.knarcraft.stargate.config.OptionDataType;
import net.knarcraft.stargate.portal.Portal; import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalRegistry; import net.knarcraft.stargate.portal.PortalRegistry;
@ -377,6 +378,10 @@ public class CommandConfig implements CommandExecutor {
//Load or unload Vault and Economy as necessary //Load or unload Vault and Economy as necessary
Stargate.getStargateConfig().reloadEconomy(); Stargate.getStargateConfig().reloadEconomy();
} }
if (ConfigTag.requiresDynmapReload(configOption)) {
//Regenerate all Dynmap markers
DynmapManager.addAllPortalMarkers();
}
} }
} }

@ -178,7 +178,18 @@ public enum ConfigOption {
/** /**
* The velocity of players exiting a stargate, relative to the entry velocity * The velocity of players exiting a stargate, relative to the entry velocity
*/ */
EXIT_VELOCITY("gates.exitVelocity", "The velocity of players exiting stargates, relative to the entry velocity", 0.1D); EXIT_VELOCITY("gates.exitVelocity", "The velocity of players exiting stargates, relative to the entry velocity", 0.1D),
/**
* Whether to enable showing Stargates in Dynmap
*/
ENABLE_DYNMAP("dynmap.enableDynmap", "Whether to display Stargates in Dynmap's map", true),
/**
* Whether to hide Dynmap icons by default
*/
DYNMAP_ICONS_DEFAULT_HIDDEN("dynmap.dynmapIconsHiddenByDefault",
"Whether to hide Stargate's Dynmap icons by default, requiring the user to enable them.", true);
private final String configNode; private final String configNode;
private final String description; private final String description;

@ -9,7 +9,8 @@ public enum ConfigTag {
COLOR(new ConfigOption[]{ConfigOption.FREE_GATES_COLOR, ConfigOption.MAIN_SIGN_COLOR, COLOR(new ConfigOption[]{ConfigOption.FREE_GATES_COLOR, ConfigOption.MAIN_SIGN_COLOR,
ConfigOption.HIGHLIGHT_SIGN_COLOR, ConfigOption.PER_SIGN_COLORS}), ConfigOption.HIGHLIGHT_SIGN_COLOR, ConfigOption.PER_SIGN_COLORS}),
FOLDER(new ConfigOption[]{ConfigOption.GATE_FOLDER, ConfigOption.PORTAL_FOLDER}); FOLDER(new ConfigOption[]{ConfigOption.GATE_FOLDER, ConfigOption.PORTAL_FOLDER}),
DYNMAP(new ConfigOption[]{ConfigOption.ENABLE_DYNMAP, ConfigOption.DYNMAP_ICONS_DEFAULT_HIDDEN});
private final ConfigOption[] taggedOptions; private final ConfigOption[] taggedOptions;
@ -52,6 +53,16 @@ public enum ConfigTag {
return FOLDER.isTagged(option); return FOLDER.isTagged(option);
} }
/**
* Checks whether a given config option requires a re-load of all Dynmap markers
*
* @param configOption <p>The config option to check</p>
* @return <p>True if changing the config option requires a reload of all dynmap markers</p>
*/
public static boolean requiresDynmapReload(ConfigOption configOption) {
return DYNMAP.isTagged(configOption);
}
/** /**
* Checks whether a given config option requires a portal reload to take effect * Checks whether a given config option requires a portal reload to take effect
* *

@ -0,0 +1,134 @@
package net.knarcraft.stargate.config;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalRegistry;
import org.bukkit.Location;
import org.bukkit.World;
import org.dynmap.DynmapAPI;
import org.dynmap.markers.GenericMarker;
import org.dynmap.markers.Marker;
import org.dynmap.markers.MarkerIcon;
import org.dynmap.markers.MarkerSet;
/**
* A manager for dealing with everything Dynmap
*/
public final class DynmapManager {
private static MarkerSet markerSet;
private static MarkerIcon portalIcon;
private DynmapManager() {
}
/**
* Initializes the dynmap manager
*
* @param dynmapAPI <p>A reference</p>
*/
public static void initialize(DynmapAPI dynmapAPI) {
if (dynmapAPI == null || dynmapAPI.getMarkerAPI() == null) {
markerSet = null;
portalIcon = null;
} else {
markerSet = dynmapAPI.getMarkerAPI().createMarkerSet("stargate", "Stargate", null, false);
if (markerSet != null) {
markerSet.setHideByDefault(Stargate.getStargateConfig().hideDynmapIcons());
}
portalIcon = dynmapAPI.getMarkerAPI().getMarkerIcon("portal");
}
}
/**
* Adds all portal markers for all current portals
*/
public static void addAllPortalMarkers() {
if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) {
//Remove any existing markers if dynmap has been disabled after startup
if (markerSet != null) {
markerSet.getMarkers().forEach(GenericMarker::deleteMarker);
}
return;
}
markerSet.setHideByDefault(Stargate.getStargateConfig().hideDynmapIcons());
//Remove all existing markers for a clean start
markerSet.getMarkers().forEach(GenericMarker::deleteMarker);
for (Portal portal : PortalRegistry.getAllPortals()) {
addPortalMarker(portal);
}
}
/**
* Adds a portal marker for the given portal
*
* @param portal <p>The portal to add a marker for</p>
*/
public static void addPortalMarker(Portal portal) {
if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) {
return;
}
World world = portal.getWorld();
if (portal.getOptions().isHidden() || world == null) {
return;
}
Location location = portal.getBlockAt(portal.getGate().getLayout().getExit());
Marker marker = markerSet.createMarker(getPortalMarkerId(portal), portal.getName(), world.getName(),
location.getX(), location.getY(), location.getZ(), portalIcon, false);
if (marker == null) {
Stargate.logWarning(String.format(
"""
Unable to create marker for portal
Portal marker id: %s
Portal name: %s
Portal world: %s
Portal location: %s,%s,%s""",
getPortalMarkerId(portal), portal.getName(), world.getName(), location.getX(), location.getY(),
location.getZ()));
return;
}
String networkPrompt;
if (portal.getOptions().isBungee()) {
networkPrompt = "Server";
} else {
networkPrompt = "Network";
}
String markerDescription = String.format("<b>Name:</b> %s<br /><b>%s:</b> %s<br /><b>Destination:</b> " +
"%s<br /><b>Owner:</b> %s<br />", portal.getName(), networkPrompt, portal.getNetwork(),
portal.getDestinationName(), portal.getOwner().getName());
marker.setDescription(markerDescription);
marker.setLabel(portal.getName(), true);
if (portalIcon != null) {
marker.setMarkerIcon(portalIcon);
}
}
/**
* Removes the portal marker for the given portal
*
* @param portal <p>The portal to remove the marker for</p>
*/
public static void removePortalMarker(Portal portal) {
if (markerSet == null || Stargate.getStargateConfig().isDynmapDisabled()) {
return;
}
Marker marker = markerSet.findMarker(getPortalMarkerId(portal));
if (marker != null) {
marker.deleteMarker();
}
}
/**
* Gets the id used for the given portal's marker
*
* @param portal <p>The portal to get a marker id for</p>
* @return <p></p>
*/
private static String getPortalMarkerId(Portal portal) {
return portal.getNetwork() + "-:-" + portal.getName();
}
}

@ -15,6 +15,7 @@ import org.bukkit.World;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.messaging.Messenger; import org.bukkit.plugin.messaging.Messenger;
import org.dynmap.DynmapAPI;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -101,6 +102,11 @@ public final class StargateConfig {
//Set up vault economy if vault has been loaded //Set up vault economy if vault has been loaded
setupVaultEconomy(); setupVaultEconomy();
DynmapAPI dynmapAPI = (DynmapAPI) Bukkit.getPluginManager().getPlugin("dynmap");
if (dynmapAPI != null) {
DynmapManager.initialize(dynmapAPI);
DynmapManager.addAllPortalMarkers();
}
} }
/** /**
@ -152,6 +158,24 @@ public final class StargateConfig {
return (boolean) configOptions.get(ConfigOption.PERMISSION_DEBUG); return (boolean) configOptions.get(ConfigOption.PERMISSION_DEBUG);
} }
/**
* Gets whether Dynmap integration is disabled
*
* @return <p>Whether Dynmap integration is disabled</p>
*/
public boolean isDynmapDisabled() {
return !((boolean) configOptions.get(ConfigOption.ENABLE_DYNMAP));
}
/**
* Gets whether Dynmap icons should be hidden by default
*
* @return <p>Whether Dynmap icons should be hidden by default</p>
*/
public boolean hideDynmapIcons() {
return (boolean) configOptions.get(ConfigOption.DYNMAP_ICONS_DEFAULT_HIDDEN);
}
/** /**
* Gets the object containing economy config values * Gets the object containing economy config values
* *
@ -189,6 +213,9 @@ public final class StargateConfig {
startStopBungeeListener(stargateGateConfig.enableBungee()); startStopBungeeListener(stargateGateConfig.enableBungee());
} }
//Reload portal markers
DynmapManager.addAllPortalMarkers();
messageSender.sendErrorMessage(sender, languageLoader.getString("reloaded")); messageSender.sendErrorMessage(sender, languageLoader.getString("reloaded"));
} }

@ -17,6 +17,7 @@ import net.knarcraft.stargate.utility.UpdateChecker;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.data.type.WallSign; import org.bukkit.block.data.type.WallSign;
import org.bukkit.entity.AbstractHorse; import org.bukkit.entity.AbstractHorse;
@ -104,6 +105,11 @@ public class PlayerEventListener implements Listener {
return; return;
} }
Portal entrancePortal = PortalHandler.getByEntrance(toLocation); Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
//Check an additional block away in case the portal is a bungee portal using END_PORTAL
if (entrancePortal == null) {
entrancePortal = PortalHandler.getByAdjacentEntrance(toLocation);
}
Portal destination = entrancePortal.getPortalActivator().getDestination(player); Portal destination = entrancePortal.getPortalActivator().getDestination(player);
Entity playerVehicle = player.getVehicle(); Entity playerVehicle = player.getVehicle();
@ -163,8 +169,13 @@ public class PlayerEventListener implements Listener {
//Check if the player moved from a portal //Check if the player moved from a portal
Portal entrancePortal = PortalHandler.getByEntrance(toLocation); Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
if (entrancePortal == null) { if (entrancePortal == null) {
//Check an additional block away for BungeeCord portals using END_PORTAL as its material
entrancePortal = PortalHandler.getByAdjacentEntrance(toLocation);
if (entrancePortal == null || !entrancePortal.getOptions().isBungee() ||
entrancePortal.getGate().getPortalOpenBlock() != Material.END_PORTAL) {
return false; return false;
} }
}
Portal destination = entrancePortal.getPortalActivator().getDestination(player); Portal destination = entrancePortal.getPortalActivator().getDestination(player);

@ -6,6 +6,7 @@ import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler; import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter; import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import net.knarcraft.stargate.utility.PermissionHelper; import net.knarcraft.stargate.utility.PermissionHelper;
import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
@ -67,14 +68,23 @@ public class PortalEventListener implements Listener {
return; return;
} }
Stargate.debug("PortalEventListener::onEntityPortalEnter",
"Found player " + player + " entering END_PORTAL " + portal);
//Remove any old player teleportations in case weird things happen //Remove any old player teleportations in case weird things happen
playersFromTheEnd.removeIf((teleportation -> teleportation.getPlayer() == player)); playersFromTheEnd.removeIf((teleportation -> teleportation.getPlayer() == player));
//Decide if the anything stops the player from teleporting //Decide if the anything stops the player from teleporting
if (PermissionHelper.playerCannotTeleport(portal, portal.getPortalActivator().getDestination(), player, null)) { if (PermissionHelper.playerCannotTeleport(portal, portal.getPortalActivator().getDestination(), player, null) ||
portal.getOptions().isBungee()) {
//Teleport the player back to the portal they came in, just in case //Teleport the player back to the portal they came in, just in case
playersFromTheEnd.add(new FromTheEndTeleportation(player, portal)); playersFromTheEnd.add(new FromTheEndTeleportation(player, portal));
} Stargate.debug("PortalEventListener::onEntityPortalEnter",
"Sending player back to the entrance");
} else {
playersFromTheEnd.add(new FromTheEndTeleportation(player, portal.getPortalActivator().getDestination())); playersFromTheEnd.add(new FromTheEndTeleportation(player, portal.getPortalActivator().getDestination()));
Stargate.debug("PortalEventListener::onEntityPortalEnter",
"Sending player to destination");
}
} }
} }
@ -95,9 +105,18 @@ public class PortalEventListener implements Listener {
Portal exitPortal = teleportation.getExit(); Portal exitPortal = teleportation.getExit();
//Overwrite respawn location to respawn in front of the portal //Overwrite respawn location to respawn in front of the portal
event.setRespawnLocation(new PlayerTeleporter(exitPortal, respawningPlayer).getExit()); PlayerTeleporter teleporter = new PlayerTeleporter(exitPortal, respawningPlayer);
Location respawnLocation = teleporter.getExit();
event.setRespawnLocation(respawnLocation);
//Try and force the player if for some reason the changing of respawn location isn't properly handled
Bukkit.getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(), () ->
respawningPlayer.teleport(respawnLocation), 1);
//Properly close the portal to prevent it from staying in a locked state until it times out //Properly close the portal to prevent it from staying in a locked state until it times out
exitPortal.getPortalOpener().closePortal(false); exitPortal.getPortalOpener().closePortal(false);
Stargate.debug("PortalEventListener::onRespawn", "Overwriting respawn for " + respawningPlayer +
" to " + respawnLocation.getWorld() + ":" + respawnLocation);
} }
} }

@ -1,6 +1,7 @@
package net.knarcraft.stargate.portal; package net.knarcraft.stargate.portal;
import net.knarcraft.stargate.Stargate; import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.config.DynmapManager;
import net.knarcraft.stargate.container.BlockLocation; import net.knarcraft.stargate.container.BlockLocation;
import net.knarcraft.stargate.utility.PortalFileHelper; import net.knarcraft.stargate.utility.PortalFileHelper;
import org.bukkit.World; import org.bukkit.World;
@ -224,6 +225,7 @@ public class PortalRegistry {
PortalFileHelper.saveAllPortals(portal.getWorld()); PortalFileHelper.saveAllPortals(portal.getWorld());
portal.setRegistered(false); portal.setRegistered(false);
DynmapManager.removePortalMarker(portal);
} }
/** /**
@ -289,6 +291,7 @@ public class PortalRegistry {
allPortals.add(portal); allPortals.add(portal);
portal.setRegistered(true); portal.setRegistered(true);
DynmapManager.addPortalMarker(portal);
} }
} }

@ -169,7 +169,7 @@ public class VehicleTeleporter extends EntityTeleporter {
//Spawn a new vehicle //Spawn a new vehicle
Vehicle newVehicle = vehicleWorld.spawn(exit, teleportingVehicle.getClass()); Vehicle newVehicle = vehicleWorld.spawn(exit, teleportingVehicle.getClass());
if (teleportingVehicle instanceof Boat boat) { if (teleportingVehicle instanceof Boat boat) {
((Boat) newVehicle).setWoodType(boat.getWoodType()); ((Boat) newVehicle).setBoatType(boat.getBoatType());
} }
//Remove the old vehicle //Remove the old vehicle
if (teleportingVehicle.eject()) { if (teleportingVehicle.eject()) {

@ -40,7 +40,8 @@ gates:
destroyedByExplosion: false destroyedByExplosion: false
# verifyPortals - Whether all the non-sign blocks are checked to match the gate layout when a stargate is loaded. # verifyPortals - Whether all the non-sign blocks are checked to match the gate layout when a stargate is loaded.
verifyPortals: false verifyPortals: false
# protectEntrance - Whether to protect gate entrance material (More resource intensive. Only enable if using destroyable open/closed material) # protectEntrance - Whether to protect gate entrance material (More resource intensive. Only enable if using
# destroyable open/closed material)
protectEntrance: false protectEntrance: false
functionality: functionality:
enableBungee: false enableBungee: false
@ -48,18 +49,21 @@ gates:
handleVehicles: true handleVehicles: true
# handleEmptyVehicles - Whether to allow empty vehicles through gates (chest/hopper/tnt/furnace minecarts included) # handleEmptyVehicles - Whether to allow empty vehicles through gates (chest/hopper/tnt/furnace minecarts included)
handleEmptyVehicles: true handleEmptyVehicles: true
# handleCreatureTransportation - Whether to allow players to transport creatures by sending vehicles (minecarts, boats) through gates # handleCreatureTransportation - Whether to allow players to transport creatures by sending vehicles (minecarts,
# boats) through gates
handleCreatureTransportation: true handleCreatureTransportation: true
# handleNonPlayerVehicles - Whether to allow vehicles with a passenger which is not a player through gates. handleCreatureTransportation must be enabled # handleNonPlayerVehicles - Whether to allow vehicles with a passenger which is not a player through gates.
# handleCreatureTransportation must be enabled
handleNonPlayerVehicles: true handleNonPlayerVehicles: true
# handleLeashedCreatures - Whether to allow creatures lead by a player to teleport with the player # handleLeashedCreatures - Whether to allow creatures lead by a player to teleport with the player
handleLeashedCreatures: true handleLeashedCreatures: true
# enableCraftBookRemoveOnEjectFix - Whether to enable a fix that causes loss of NBT data, but allows vehicle teleportation to work when CraftBook's remove minecart/boat on eject setting is enabled # enableCraftBookRemoveOnEjectFix - Whether to enable a fix that causes loss of NBT data, but allows vehicle
# teleportation to work when CraftBook's remove minecart/boat on eject setting is enabled
enableCraftBookRemoveOnEjectFix: false enableCraftBookRemoveOnEjectFix: false
############################# # ######################## #
# stargate economy options # # stargate economy options #
############################ # ######################## #
economy: economy:
# useEconomy - Whether to use an economy plugin # useEconomy - Whether to use an economy plugin
useEconomy: false useEconomy: false
@ -78,14 +82,26 @@ economy:
# freeGatesColor - The color to use for marking free gates # freeGatesColor - The color to use for marking free gates
freeGatesColor: DARK_GREEN freeGatesColor: DARK_GREEN
################# # ############# #
# Debug options # # Debug options #
################# # ############# #
debugging: debugging:
# debug - Debug -- Only enable if you have issues, massive console output # debug - Debug -- Only enable if you have issues, massive console output
debug: false debug: false
# permissionDebug - This will output any and all Permissions checks to console, used for permissions debugging (Requires debug: true) # permissionDebug - This will output any and all Permissions checks to console, used for permissions debugging
# (Requires debug: true)
permissionDebug: false permissionDebug: false
advanced: advanced:
# waitForPlayerAfterTeleportDelay - The amount of ticks to wait before adding a player as passenger of a vehicle. On slow servers, a value of 6 is required to avoid client glitches after teleporting on a vehicle. # waitForPlayerAfterTeleportDelay - The amount of ticks to wait before adding a player as passenger of a vehicle.
# On slow servers, a value of 6 is required to avoid client glitches after teleporting on a vehicle.
waitForPlayerAfterTeleportDelay: 6 waitForPlayerAfterTeleportDelay: 6
# ############## #
# Dynmap options #
# ############## #
dynmap:
# enableDynmap - Whether to display Stargates in Dynmap's map
enableDynmap: true
# dynmapIconsHiddenByDefault - Whether to hide the set of Stargate icons by default, requiring users to
# manually enable them with a checkbox.
dynmapIconsHiddenByDefault: true

@ -1,12 +1,12 @@
name: Stargate name: Stargate
main: net.knarcraft.stargate.Stargate main: net.knarcraft.stargate.Stargate
version: 0.9.4.0 version: 0.9.4.2
description: Stargate mod for Bukkit Revived description: Stargate mod for Bukkit Revived
author: EpicKnarvik97 author: EpicKnarvik97
authors: [ Drakia, PseudoKnight, EpicKnarvik97 ] authors: [ Drakia, PseudoKnight, EpicKnarvik97 ]
website: https://git.knarcraft.net/EpicKnarvik97/Stargate website: https://git.knarcraft.net/EpicKnarvik97/Stargate
api-version: 1.19 api-version: 1.18
softdepend: [ Vault ] softdepend: [ Vault, dynmap ]
commands: commands:
stargate: stargate:
aliases: aliases: