[Version 0.7.9.0]

- Added BungeeCord multi-server support (Requires Stargate-Bungee for BungeeCord)
 - Updated Spanish language file
 - Added basic plugin metrics via http://mcstats.org/
This commit is contained in:
Steven Scott 2012-11-24 15:42:57 -08:00
parent fc73e1fbda
commit ac520665e6
8 changed files with 575 additions and 65 deletions

4
README
View File

@ -212,6 +212,10 @@ Client randomly crashes on teleport.
=============
Changes
=============
[Version 0.7.9.0]
- Added BungeeCord multi-server support (Requires Stargate-Bungee for BungeeCord)
- Updated Spanish language file
- Added basic plugin metrics via http://mcstats.org/
[Version 0.7.8.1]
- Resolve issue of language file being overwritten as ANSI instead of UTF8
[Version 0.7.8.0]

View File

@ -0,0 +1,357 @@
/*
* Copyright 2011 Tyler Blair. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package net.TheDgtl.Stargate;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.UUID;
import java.util.logging.Level;
public class MetricsLite {
/**
* The current revision number
*/
private final static int REVISION = 5;
/**
* The base url of the metrics domain
*/
private static final String BASE_URL = "http://mcstats.org";
/**
* The url used to report a server's status
*/
private static final String REPORT_URL = "/report/%s";
/**
* Interval of time to ping (in minutes)
*/
private final static int PING_INTERVAL = 10;
/**
* The plugin this metrics submits for
*/
private final Plugin plugin;
/**
* The plugin configuration file
*/
private final YamlConfiguration configuration;
/**
* The plugin configuration file
*/
private final File configurationFile;
/**
* Unique server id
*/
private final String guid;
/**
* Lock for synchronization
*/
private final Object optOutLock = new Object();
/**
* Id of the scheduled task
*/
private volatile int taskId = -1;
public MetricsLite(Plugin plugin) throws IOException {
if (plugin == null) {
throw new IllegalArgumentException("Plugin cannot be null");
}
this.plugin = plugin;
// load the config
configurationFile = getConfigFile();
configuration = YamlConfiguration.loadConfiguration(configurationFile);
// add some defaults
configuration.addDefault("opt-out", false);
configuration.addDefault("guid", UUID.randomUUID().toString());
// Do we need to create the file?
if (configuration.get("guid", null) == null) {
configuration.options().header("http://mcstats.org").copyDefaults(true);
configuration.save(configurationFile);
}
// Load the guid then
guid = configuration.getString("guid");
}
/**
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send
* the initial data to the metrics backend, and then after that it will post in increments of
* PING_INTERVAL * 1200 ticks.
*
* @return True if statistics measuring is running, otherwise false.
*/
public boolean start() {
synchronized (optOutLock) {
// Did we opt out?
if (isOptOut()) {
return false;
}
// Is metrics already running?
if (taskId >= 0) {
return true;
}
// Begin hitting the server with glorious data
taskId = plugin.getServer().getScheduler().scheduleAsyncRepeatingTask(plugin, new Runnable() {
private boolean firstPost = true;
public void run() {
try {
// This has to be synchronized or it can collide with the disable method.
synchronized (optOutLock) {
// Disable Task, if it is running and the server owner decided to opt-out
if (isOptOut() && taskId > 0) {
plugin.getServer().getScheduler().cancelTask(taskId);
taskId = -1;
}
}
// We use the inverse of firstPost because if it is the first time we are posting,
// it is not a interval ping, so it evaluates to FALSE
// Each time thereafter it will evaluate to TRUE, i.e PING!
postPlugin(!firstPost);
// After the first post we set firstPost to false
// Each post thereafter will be a ping
firstPost = false;
} catch (IOException e) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
}
}
}, 0, PING_INTERVAL * 1200);
return true;
}
}
/**
* Has the server owner denied plugin metrics?
*
* @return true if metrics should be opted out of it
*/
public boolean isOptOut() {
synchronized(optOutLock) {
try {
// Reload the metrics file
configuration.load(getConfigFile());
} catch (IOException ex) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
return true;
} catch (InvalidConfigurationException ex) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
return true;
}
return configuration.getBoolean("opt-out", false);
}
}
/**
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
*
* @throws IOException
*/
public void enable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized (optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if (isOptOut()) {
configuration.set("opt-out", false);
configuration.save(configurationFile);
}
// Enable Task, if it is not running
if (taskId < 0) {
start();
}
}
}
/**
* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
*
* @throws IOException
*/
public void disable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized (optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if (!isOptOut()) {
configuration.set("opt-out", true);
configuration.save(configurationFile);
}
// Disable Task, if it is running
if (taskId > 0) {
this.plugin.getServer().getScheduler().cancelTask(taskId);
taskId = -1;
}
}
}
/**
* Gets the File object of the config file that should be used to store data such as the GUID and opt-out status
*
* @return the File object for the config file
*/
public File getConfigFile() {
// I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use
// is to abuse the plugin object we already have
// plugin.getDataFolder() => base/plugins/PluginA/
// pluginsFolder => base/plugins/
// The base is not necessarily relative to the startup directory.
File pluginsFolder = plugin.getDataFolder().getParentFile();
// return => base/plugins/PluginMetrics/config.yml
return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml");
}
/**
* Generic method that posts a plugin to the metrics website
*/
private void postPlugin(boolean isPing) throws IOException {
// The plugin's description file containg all of the plugin data such as name, version, author, etc
final PluginDescriptionFile description = plugin.getDescription();
// Construct the post data
final StringBuilder data = new StringBuilder();
data.append(encode("guid")).append('=').append(encode(guid));
encodeDataPair(data, "version", description.getVersion());
encodeDataPair(data, "server", Bukkit.getVersion());
encodeDataPair(data, "players", Integer.toString(Bukkit.getServer().getOnlinePlayers().length));
encodeDataPair(data, "revision", String.valueOf(REVISION));
// If we're pinging, append it
if (isPing) {
encodeDataPair(data, "ping", "true");
}
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, encode(plugin.getDescription().getName())));
// Connect to the website
URLConnection connection;
// Mineshafter creates a socks proxy, so we can safely bypass it
// It does not reroute POST requests so we need to go around it
if (isMineshafterPresent()) {
connection = url.openConnection(Proxy.NO_PROXY);
} else {
connection = url.openConnection();
}
connection.setDoOutput(true);
// Write the data
final OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(data.toString());
writer.flush();
// Now read the response
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
final String response = reader.readLine();
// close resources
writer.close();
reader.close();
if (response == null || response.startsWith("ERR")) {
throw new IOException(response); //Throw the exception
}
//if (response.startsWith("OK")) - We should get "OK" followed by an optional description if everything goes right
}
/**
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
*
* @return true if mineshafter is installed on the server
*/
private boolean isMineshafterPresent() {
try {
Class.forName("mineshafter.MineServer");
return true;
} catch (Exception e) {
return false;
}
}
/**
* <p>Encode a key/value data pair to be used in a HTTP post request. This INCLUDES a & so the first
* key/value pair MUST be included manually, e.g:</p>
* <code>
* StringBuffer data = new StringBuffer();
* data.append(encode("guid")).append('=').append(encode(guid));
* encodeDataPair(data, "version", description.getVersion());
* </code>
*
* @param buffer the stringbuilder to append the data pair onto
* @param key the key value
* @param value the value
*/
private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException {
buffer.append('&').append(encode(key)).append('=').append(encode(value));
}
/**
* Encode text as UTF-8
*
* @param text the text to encode
* @return the encoded text, as UTF-8
*/
private static String encode(final String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
}

View File

@ -63,6 +63,9 @@ public class Portal {
private static final HashMap<String, ArrayList<String>> allPortalsNet = new HashMap<String, ArrayList<String>>();
private static final HashMap<String, HashMap<String, Portal>> lookupNamesNet = new HashMap<String, HashMap<String, Portal>>();
// A list of Bungee gates
private static final HashMap<String, Portal> bungeePortals = new HashMap<String, Portal>();
// Gate location block info
private Blox topLeft;
private int modX;
@ -95,6 +98,7 @@ public class Portal {
private boolean show = false;
private boolean noNetwork = false;
private boolean random = false;
private boolean bungee = false;
// In-use information
private Player player;
@ -107,7 +111,7 @@ public class Portal {
float rotX, Blox id, Blox button,
String dest, String name,
boolean verified, String network, Gate gate, String owner,
boolean hidden, boolean alwaysOn, boolean priv, boolean free, boolean backwards, boolean show, boolean noNetwork, boolean random) {
boolean hidden, boolean alwaysOn, boolean priv, boolean free, boolean backwards, boolean show, boolean noNetwork, boolean random, boolean bungee) {
this.topLeft = topLeft;
this.modX = modX;
this.modZ = modZ;
@ -128,8 +132,9 @@ public class Portal {
this.show = show;
this.noNetwork = noNetwork;
this.random = random;
this.bungee = bungee;
this.world = topLeft.getWorld();
this.fixed = dest.length() > 0 || this.random;
this.fixed = dest.length() > 0 || this.random || this.bungee;
if (this.isAlwaysOn() && !this.isFixed()) {
this.alwaysOn = false;
@ -185,6 +190,10 @@ public class Portal {
return random;
}
public boolean isBungee() {
return bungee;
}
public void setAlwaysOn(boolean alwaysOn) {
this.alwaysOn = alwaysOn;
}
@ -466,8 +475,14 @@ public class Portal {
exit = pEvent.getExit();
}
// The new method to teleport in a move event is set the "to" field.
event.setTo(exit);
// If no event is passed in, assume it's a teleport, and act as such
if (event == null) {
exit.setYaw(this.getRotation());
player.teleport(exit);
} else {
// The new method to teleport in a move event is set the "to" field.
event.setTo(exit);
}
}
public void teleport(final Vehicle vehicle) {
@ -530,8 +545,8 @@ public class Portal {
} else {
Stargate.log.log(Level.WARNING, "[Stargate] Missing destination point in .gate file " + gate.getFilename());
}
if (loc != null) {
if (getWorld().getBlockTypeIdAt(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()) == Material.STEP.getId()) {
loc.setY(loc.getY() + 0.5);
}
@ -691,7 +706,12 @@ public class Portal {
Stargate.setLine(sign, ++done, "(" + network + ")");
}
} else {
if (isFixed()) {
// Awesome new logic for Bungee gates
if (isBungee()) {
Stargate.setLine(sign, ++done, Stargate.getString("bungeeSign"));
Stargate.setLine(sign, ++done, ">" + destination + "<");
Stargate.setLine(sign, ++done, "[" + network + "]");
} else if (isFixed()) {
if (isRandom()) {
Stargate.setLine(sign, ++done, "> " + Stargate.getString("signRandom") + " <");
} else {
@ -768,7 +788,6 @@ public class Portal {
public void unregister(boolean removeAll) {
Stargate.debug("Unregister", "Unregistering gate " + getName());
close(true);
lookupNamesNet.get(getNetwork().toLowerCase()).remove(getName().toLowerCase());
for (Blox block : getFrame()) {
lookupBlocks.remove(block);
@ -790,7 +809,21 @@ public class Portal {
if (removeAll)
allPortals.remove(this);
allPortalsNet.get(getNetwork().toLowerCase()).remove(getName().toLowerCase());
if (bungee) {
bungeePortals.remove(getName().toLowerCase());
} else {
lookupNamesNet.get(getNetwork().toLowerCase()).remove(getName().toLowerCase());
allPortalsNet.get(getNetwork().toLowerCase()).remove(getName().toLowerCase());
for (String originName : allPortalsNet.get(getNetwork().toLowerCase())) {
Portal origin = Portal.getByName(originName, getNetwork());
if (origin == null) continue;
if (!origin.getDestinationName().equalsIgnoreCase(getName())) continue;
if (!origin.isVerified()) continue;
if (origin.isFixed()) origin.drawSign();
if (origin.isAlwaysOn()) origin.close(true);
}
}
if (id.getBlock().getType() == Material.WALL_SIGN && id.getBlock().getState() instanceof Sign) {
Sign sign = (Sign)id.getBlock().getState();
@ -801,15 +834,6 @@ public class Portal {
sign.update();
}
for (String originName : allPortalsNet.get(getNetwork().toLowerCase())) {
Portal origin = Portal.getByName(originName, getNetwork());
if (origin == null) continue;
if (!origin.getDestinationName().equalsIgnoreCase(getName())) continue;
if (!origin.isVerified()) continue;
if (origin.isFixed()) origin.drawSign();
if (origin.isAlwaysOn()) origin.close(true);
}
saveAllGates(getWorld());
}
@ -818,12 +842,26 @@ public class Portal {
}
private void register() {
fixed = destination.length() > 0 || random;
if (!lookupNamesNet.containsKey(getNetwork().toLowerCase())) {
Stargate.debug("register", "Network not in lookupNamesNet, adding");
lookupNamesNet.put(getNetwork().toLowerCase(), new HashMap<String, Portal>());
fixed = destination.length() > 0 || random || bungee;
// Bungee gates are stored in their own list
if (isBungee()) {
bungeePortals.put(getName().toLowerCase(), this);
} else {
// Check if network exists in our network list
if (!lookupNamesNet.containsKey(getNetwork().toLowerCase())) {
Stargate.debug("register", "Network not in lookupNamesNet, adding");
lookupNamesNet.put(getNetwork().toLowerCase(), new HashMap<String, Portal>());
}
lookupNamesNet.get(getNetwork().toLowerCase()).put(getName().toLowerCase(), this);
// Check if this network exists
if (!allPortalsNet.containsKey(getNetwork().toLowerCase())) {
Stargate.debug("register", "Network not in allPortalsNet, adding");
allPortalsNet.put(getNetwork().toLowerCase(), new ArrayList<String>());
}
allPortalsNet.get(getNetwork().toLowerCase()).add(getName().toLowerCase());
}
lookupNamesNet.get(getNetwork().toLowerCase()).put(getName().toLowerCase(), this);
for (Blox block : getFrame()) {
lookupBlocks.put(block, this);
@ -843,12 +881,6 @@ public class Portal {
}
allPortals.add(this);
// Check if this network exists
if (!allPortalsNet.containsKey(getNetwork().toLowerCase())) {
Stargate.debug("register", "Network not in allPortalsNet, adding");
allPortalsNet.put(getNetwork().toLowerCase(), new ArrayList<String>());
}
allPortalsNet.get(getNetwork().toLowerCase()).add(getName().toLowerCase());
}
public static Portal createPortal(SignChangeEvent event, Player player) {
@ -879,6 +911,7 @@ public class Portal {
boolean show = (options.indexOf('s') != -1);
boolean noNetwork = (options.indexOf('n') != -1);
boolean random = (options.indexOf('r') != -1);
boolean bungee = (options.indexOf('u') != -1);
// Check permissions for options.
if (hidden && !Stargate.canOption(player, "hidden")) hidden = false;
@ -890,6 +923,20 @@ public class Portal {
if (noNetwork && !Stargate.canOption(player, "nonetwork")) noNetwork = false;
if (random && !Stargate.canOption(player, "random")) random = false;
// If the player is trying to create a Bungee gate without permissions, drop out here
if (bungee) {
if (!Stargate.enableBungee) {
Stargate.sendMessage(player, Stargate.getString("bungeeDisabled"));
return null;
} else if (!Stargate.hasPerm(player, "stargate.admin.bungee")) {
Stargate.sendMessage(player, Stargate.getString("bungeeDeny"));
return null;
} else if (destName.isEmpty() || network.isEmpty()) {
Stargate.sendMessage(player, Stargate.getString("bungeeEmpty"));
return null;
}
}
// Can not create a non-fixed always-on gate.
if (alwaysOn && destName.length() == 0) {
alwaysOn = false;
@ -906,6 +953,12 @@ public class Portal {
show = false;
}
// Bungee gates are always on and don't support Random
if (bungee) {
alwaysOn = true;
random = false;
}
// Moved the layout check so as to avoid invalid messages when not making a gate
int modX = 0;
int modZ = 0;
@ -966,9 +1019,9 @@ public class Portal {
}
// Debug
Stargate.debug("createPortal", "h = " + hidden + " a = " + alwaysOn + " p = " + priv + " f = " + free + " b = " + backwards + " s = " + show + " n = " + noNetwork + " r = " + random);
Stargate.debug("createPortal", "h = " + hidden + " a = " + alwaysOn + " p = " + priv + " f = " + free + " b = " + backwards + " s = " + show + " n = " + noNetwork + " r = " + random + " u = " + bungee);
if ((network.length() < 1) || (network.length() > 11)) {
if (!bungee && (network.length() < 1 || network.length() > 11)) {
network = Stargate.getDefaultNetwork();
}
@ -976,7 +1029,7 @@ public class Portal {
String denyMsg = "";
// Check if the player can create gates on this network
if (!Stargate.canCreate(player, network)) {
if (!bungee && !Stargate.canCreate(player, network)) {
Stargate.debug("createPortal", "Player doesn't have create permissions on network. Trying personal");
if (Stargate.canCreatePersonal(player)) {
network = player.getName();
@ -1001,7 +1054,7 @@ public class Portal {
}
// Check if the user can create gates to this world.
if (!deny && destName.length() > 0) {
if (!bungee && !deny && destName.length() > 0) {
Portal p = Portal.getByName(destName, network);
if (p != null) {
String world = p.getWorld().getName();
@ -1025,7 +1078,7 @@ public class Portal {
Blox button = null;
Portal portal = null;
portal = new Portal(topleft, modX, modZ, rotX, id, button, destName, name, false, network, gate, player.getName(), hidden, alwaysOn, priv, free, backwards, show, noNetwork, random);
portal = new Portal(topleft, modX, modZ, rotX, id, button, destName, name, false, network, gate, player.getName(), hidden, alwaysOn, priv, free, backwards, show, noNetwork, random, bungee);
int cost = Stargate.getCreateCost(player, gate);
@ -1049,17 +1102,26 @@ public class Portal {
return null;
}
if (getByName(portal.getName(), portal.getNetwork()) != null) {
Stargate.debug("createPortal", "Name Error");
Stargate.sendMessage(player, Stargate.getString("createExists"));
return null;
}
// Check if there are too many gates in this network
ArrayList<String> netList = allPortalsNet.get(portal.getNetwork().toLowerCase());
if (Stargate.maxGates > 0 && netList != null && netList.size() >= Stargate.maxGates) {
Stargate.sendMessage(player, Stargate.getString("createFull"));
return null;
// Don't do network checks for bungee gates
if (portal.isBungee()) {
if (bungeePortals.get(portal.getName().toLowerCase()) != null) {
Stargate.debug("createPortal::Bungee", "Gate Exists");
Stargate.sendMessage(player, Stargate.getString("createExists"));
return null;
}
} else {
if (getByName(portal.getName(), portal.getNetwork()) != null) {
Stargate.debug("createPortal", "Name Error");
Stargate.sendMessage(player, Stargate.getString("createExists"));
return null;
}
// Check if there are too many gates in this network
ArrayList<String> netList = allPortalsNet.get(portal.getNetwork().toLowerCase());
if (Stargate.maxGates > 0 && netList != null && netList.size() >= Stargate.maxGates) {
Stargate.sendMessage(player, Stargate.getString("createFull"));
return null;
}
}
if (cost > 0) {
@ -1086,7 +1148,7 @@ public class Portal {
portal.register();
portal.drawSign();
// Open always on gate
if (portal.isRandom()) {
if (portal.isRandom() || portal.isBungee()) {
portal.open(true);
} else if (portal.isAlwaysOn()) {
Portal dest = Portal.getByName(destName, portal.getNetwork());
@ -1101,14 +1163,17 @@ public class Portal {
}
}
// Open any always on gate pointing at this gate
for (String originName : allPortalsNet.get(portal.getNetwork().toLowerCase())) {
Portal origin = Portal.getByName(originName, portal.getNetwork());
if (origin == null) continue;
if (!origin.getDestinationName().equalsIgnoreCase(portal.getName())) continue;
if (!origin.isVerified()) continue;
if (origin.isFixed()) origin.drawSign();
if (origin.isAlwaysOn()) origin.open(true);
// Don't do network stuff for bungee gates
if (!portal.isBungee()) {
// Open any always on gate pointing at this gate
for (String originName : allPortalsNet.get(portal.getNetwork().toLowerCase())) {
Portal origin = Portal.getByName(originName, portal.getNetwork());
if (origin == null) continue;
if (!origin.getDestinationName().equalsIgnoreCase(portal.getName())) continue;
if (!origin.isVerified()) continue;
if (origin.isFixed()) origin.drawSign();
if (origin.isAlwaysOn()) origin.open(true);
}
}
saveAllGates(portal.getWorld());
@ -1137,6 +1202,10 @@ public class Portal {
public static Portal getByBlock(Block block) {
return lookupBlocks.get(new Blox(block));
}
public static Portal getBungeeGate(String name) {
return bungeePortals.get(name);
}
public static void saveAllGates(World world) {
String loc = Stargate.getSaveLocation() + "/" + world.getName() + ".db";
@ -1190,6 +1259,8 @@ public class Portal {
builder.append(portal.isNoNetwork());
builder.append(':');
builder.append(portal.isRandom());
builder.append(':');
builder.append(portal.isBungee());
bw.append(builder.toString());
bw.newLine();
@ -1260,8 +1331,9 @@ public class Portal {
boolean show = (split.length > 17) ? split[17].equalsIgnoreCase("true") : false;
boolean noNetwork = (split.length > 18) ? split[18].equalsIgnoreCase("true") : false;
boolean random = (split.length > 19) ? split[19].equalsIgnoreCase("true") : false;
boolean bungee = (split.length > 20) ? split[20].equalsIgnoreCase("true") : false;
Portal portal = new Portal(topLeft, modX, modZ, rotX, sign, button, dest, name, false, network, gate, owner, hidden, alwaysOn, priv, free, backwards, show, noNetwork, random);
Portal portal = new Portal(topLeft, modX, modZ, rotX, sign, button, dest, name, false, network, gate, owner, hidden, alwaysOn, priv, free, backwards, show, noNetwork, random, bungee);
portal.register();
portal.close(true);
}
@ -1293,6 +1365,14 @@ public class Portal {
}
if (!portal.isFixed()) continue;
if (portal.isBungee()) {
OpenCount++;
portal.open(true);
portal.drawSign();
continue;
}
Portal dest = portal.getDestination();
if (dest != null) {
if (portal.isAlwaysOn()) {

View File

@ -1,6 +1,7 @@
package net.TheDgtl.Stargate;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
@ -11,6 +12,7 @@ import java.util.logging.Logger;
import net.TheDgtl.Stargate.event.StargateAccessEvent;
import net.TheDgtl.Stargate.event.StargateDestroyEvent;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
@ -98,6 +100,7 @@ public class Stargate extends JavaPlugin {
public static boolean handleVehicles = true;
public static boolean sortLists = false;
public static boolean protectEntrance = false;
public static boolean enableBungee = true;
public static ChatColor signColor;
// Temp workaround for snowmen, don't check gate entrance
@ -145,6 +148,12 @@ public class Stargate extends JavaPlugin {
this.loadConfig();
// Enable the required channels for Bungee support
if (enableBungee) {
Bukkit.getMessenger().registerOutgoingPluginChannel(this, "SGBungee");
Bukkit.getMessenger().registerIncomingPluginChannel(this, "SGBungee", new pmListener());
}
// It is important to load languages here, as they are used during reloadGates()
lang = new LangLoader(langFolder, Stargate.langName);
@ -166,6 +175,19 @@ public class Stargate extends JavaPlugin {
getServer().getScheduler().scheduleSyncRepeatingTask(this, new SGThread(), 0L, 100L);
getServer().getScheduler().scheduleSyncRepeatingTask(this, new BlockPopulatorThread(), 0L, 1L);
// Enable Plugin Metrics
try {
MetricsLite ml = new MetricsLite(this);
if (!ml.isOptOut()) {
ml.start();
log.info("[Stargate] Plugin metrics enabled.");
} else {
log.info("[Stargate] Plugin metrics not enabled.");
}
} catch (IOException ex) {
log.warning("[Stargate] Error enabling plugin metrics: " + ex);
}
}
public void loadConfig() {
@ -186,6 +208,7 @@ public class Stargate extends JavaPlugin {
handleVehicles = newConfig.getBoolean("handleVehicles");
sortLists = newConfig.getBoolean("sortLists");
protectEntrance = newConfig.getBoolean("protectEntrance");
enableBungee = newConfig.getBoolean("enableBungee");
// Sign color
String sc = newConfig.getString("signColor");
try {
@ -567,7 +590,7 @@ public class Stargate extends JavaPlugin {
// Portal is free
if (src.isFree()) return 0;
// Not charging for free destinations
if (!iConomyHandler.chargeFreeDestination && dest.isFree()) return 0;
if (dest != null && !iConomyHandler.chargeFreeDestination && dest.isFree()) return 0;
// Cost is 0 if the player owns this gate and funds go to the owner
if (src.getGate().getToOwner() && src.getOwner().equalsIgnoreCase(player.getName())) return 0;
// Player gets free gate use
@ -637,6 +660,9 @@ public class Stargate extends JavaPlugin {
Portal portal = Portal.getByEntrance(event.getTo());
if (portal == null || !portal.isOpen()) return;
// We don't support vehicles in Bungee portals
if (portal.isBungee()) return;
if (passenger instanceof Player) {
Player player = (Player)passenger;
if (!portal.isOpenFor(player)) {
@ -743,16 +769,17 @@ public class Stargate extends JavaPlugin {
}
Portal destination = portal.getDestination(player);
if (destination == null) return;
if (!portal.isBungee() && destination == null) return;
boolean deny = false;
// Check if player has access to this network
// For Bungee gates this will be the target server name
if (!canAccessNetwork(player, portal.getNetwork())) {
deny = true;
}
// Check if player has access to destination world
if (!canAccessWorld(player, destination.getWorld().getName())) {
if (!portal.isBungee() && !canAccessWorld(player, destination.getWorld().getName())) {
deny = true;
}
@ -786,6 +813,18 @@ public class Stargate extends JavaPlugin {
}
Stargate.sendMessage(player, Stargate.getString("teleportMsg"), false);
if (portal.isBungee()) {
portal.teleport(player, portal, event);
// Teleport player via BungeeCord
String pMsg = portal.getNetwork() + "@#@" + portal.getDestinationName();
player.sendPluginMessage(stargate, "SGBungee", pMsg.getBytes());
// Close portal if required (Should never be)
portal.close(false);
return;
}
destination.teleport(player, portal, event);
portal.close(false);
}

View File

@ -0,0 +1,25 @@
package net.TheDgtl.Stargate;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
public class pmListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
if (!channel.equals("SGBungee")) return;
// Message should be destination gate name.
Portal dest = Portal.getBungeeGate(new String(message));
// Specified an invalid gate. For now we'll just let them connect at their current location
if (dest == null) {
return;
}
// Teleport the player to their destination portal
dest.teleport(player, dest, null);
Stargate.debug("PML", "Recieved message: " + new String(message) + " Player: " + player.getName());
}
}

View File

@ -24,4 +24,9 @@ createConflict=Gate conflicts with existing gate
signRightClick=Right click
signToUse=to use gate
signRandom=Random
signDisconnected=Disconnected
signDisconnected=Disconnected
bungeeDisabled=BungeeCord support is disabled.
bungeeDeny=You do not have permission to create BungeeCord gates.
bungeeEmpty=BungeeCord gates require both a destination and network.
bungeeSign=Teleport to

View File

@ -1,8 +1,8 @@
author=Manuestaire
prefix=[Stargate]
teleportMsg=Teletransportado
destroyMsg=Portal Destruido
invalidMsg=Destino Inválido
destroyMsg=Portal Destruído
invalidMsg=Elige Destino
blockMsg=Destino Bloqueado
destEmpty=La lista de destinos está vacía
denyMsg=Acceso denegado
@ -22,7 +22,7 @@ createFull=Esta red est
createWorldDeny=No tienes permisos para acceder a ese mundo
createConflict=El portal entra en conflicto con un portal ya existente
signRightClick=Right click
signToUse=to use gate
signRandom=Random
signDisconnected=Disconnected
signRightClick=Click derecho
signToUse=para usar
signRandom=Aleatorio
signDisconnected=Desconectado

View File

@ -1,6 +1,6 @@
name: Stargate
main: net.TheDgtl.Stargate.Stargate
version: 0.7.8.1
version: 0.7.9.0
description: Stargate mod for Bukkit
author: Drakia
website: http://www.thedgtl.net