Compare commits
230 Commits
Author | SHA1 | Date | |
---|---|---|---|
e5c1ad1f3a | |||
cab99e11b0 | |||
3c4d10ae3f | |||
aff0082906 | |||
20c3c93c06 | |||
dab9378a67 | |||
62661f65f4 | |||
b8d98c26d4 | |||
8bb9c464d6 | |||
2b5d791581 | |||
2a61480684 | |||
91a0316e6e | |||
b98aec4a20 | |||
89956cf359 | |||
0655d85356 | |||
06cb99de44 | |||
99f8a92857 | |||
01df8db0bf | |||
d754247455 | |||
1f1fef3054 | |||
40f0a99e5a | |||
8fa0cca5ce | |||
a4075363ec | |||
260211b677 | |||
5d41b2114b | |||
50c446f9d9 | |||
56bf51f370 | |||
56ed0495b0 | |||
0237f45046 | |||
5d84e1d78a | |||
f52ba79ae9 | |||
945798916b | |||
f0e5cd45a4 | |||
487cb3ad9e | |||
544384f69b | |||
3fc0e6963a | |||
5c730eb613 | |||
1c906528f2 | |||
eaf7596014 | |||
669767ef89 | |||
822f8fb2b5 | |||
3367d4bb76 | |||
a100ad3fea | |||
2541391d3e | |||
b7998023f5 | |||
deba2e5c2c | |||
7cc8685e26 | |||
50084c40f9 | |||
2196d5b99e | |||
070e7250df | |||
9a0f16e558 | |||
485ca284b0 | |||
4e09b44c7c | |||
593d528bcd | |||
79a43b82e5 | |||
cb2f7443f5 | |||
8eff9ae5e6 | |||
4b42d4914a | |||
2650e31d97 | |||
d2e8c81a5a | |||
635d08b1b3 | |||
1d4b988ca4 | |||
82ed28bba0 | |||
0506cf1b61 | |||
f4ec5e05d6 | |||
8c16ddbed5 | |||
27b1f0641e | |||
ac045fa7db | |||
982d8abf65 | |||
f96e8ed2da | |||
d9ae5456cc | |||
fabe0dda80 | |||
3de785d5ab | |||
59069d1423 | |||
5299efaa86 | |||
e2c91c1feb | |||
d45af537cd | |||
6e658003e0 | |||
382156a719 | |||
44325eeb6a | |||
bf7a10636e | |||
0ab6cb52c0 | |||
f16a7089f4 | |||
4bdc5b6bd9 | |||
5b6e3f81a6 | |||
0709c18e30 | |||
e14007380f | |||
53cd55938b | |||
51afa1527f | |||
72c1b5a239 | |||
b0c350a140 | |||
06757ef9ee | |||
9efc960696 | |||
1bf9914c39 | |||
05123d54bd | |||
2e4d545955 | |||
f8fae1fbf1 | |||
964eb0f898 | |||
38ea543b80 | |||
69a62c921c | |||
b847002617 | |||
6ad7fa4cb9 | |||
2abe10bcde | |||
7a9dbb8046 | |||
3a8943baef | |||
be8de83bcc | |||
ba3304a716 | |||
051a6b8f98 | |||
f87ffc906c | |||
336c3c4bfb | |||
2fec641d9d | |||
0c29788a31 | |||
fff4d8d78b | |||
a68dc4b464 | |||
6d5c4802bc | |||
e7fc1daafe | |||
60c543e52a | |||
76b2aab057 | |||
201f7eaf15 | |||
d86aae87f3 | |||
e4f71f1b71 | |||
7dcf050d96 | |||
8ada84ddb3 | |||
98cee192aa | |||
650a26402a | |||
461202503e | |||
dd7176fa12 | |||
b7c7252fad | |||
24af26324a | |||
f2579c4b12 | |||
1e29db58b9 | |||
d24f35375a | |||
f681db629f | |||
b57f988b62 | |||
f12306426b | |||
8ff30ed03f | |||
d5e6f1145c | |||
8835e69e3c | |||
b191ac1de5 | |||
4851a0b5e2 | |||
e253e95cec | |||
c35378cfe0 | |||
319849fd96 | |||
abd48b646d | |||
f2332badb6 | |||
19018e46b8 | |||
ec4ed1e086 | |||
5c601710e7 | |||
a6fb7dcb62 | |||
6005c2c6d1 | |||
1c3dbbe81d | |||
87735e4935 | |||
93f8f715e5 | |||
b4059dd169 | |||
a86a5de8c3 | |||
7b83b2440c | |||
8ae4ac3fc7 | |||
3ac6270897 | |||
daa3c6f868 | |||
75fbd44af7 | |||
0fe2a5b380 | |||
b1aa53c1a9 | |||
44dfa2a10d | |||
504ef1b52f | |||
da32cf11d1 | |||
ba64572254 | |||
79703e49af | |||
496b5d9779 | |||
378a59586d | |||
2b52759e00 | |||
4acea17ba3 | |||
5f685b2460 | |||
e42da6d6bd | |||
681014a431 | |||
af693bddd2 | |||
151c242e69 | |||
e5fef0b16a | |||
e665a49f03 | |||
279ea9d8f0 | |||
d26196b8aa | |||
fb70b8bc75 | |||
c422cb9ea9 | |||
a475e8d8b1 | |||
1d642bfcf2 | |||
1da0f4eddc | |||
889a9d2cbc | |||
1721750aa1 | |||
2ae4fc9645 | |||
c912624df1 | |||
5b7f5649b1 | |||
df074b9ff5 | |||
42fa6ed8d7 | |||
bd4586e386 | |||
1719e92494 | |||
56410a58f8 | |||
ff8f762ea8 | |||
c41429b6e0 | |||
d472eab21b | |||
095e59c65e | |||
7b9f5a6de5 | |||
e49b94cf9a | |||
a8c0574f3b | |||
f0a7ff8c47 | |||
32410a82ba | |||
b6d18a4217 | |||
68f3bca04f | |||
2bd5bb36cf | |||
5a9d70f827 | |||
a5cf1a7cd3 | |||
af6a2537b8 | |||
cdae2d8f35 | |||
9ace568047 | |||
5a8e8a219e | |||
3521257cb2 | |||
b9cbe9ee4c | |||
e702a0d734 | |||
f97cb32466 | |||
4f5cb84d02 | |||
341a445d16 | |||
df111c2750 | |||
6825266a92 | |||
6d6a7e52b2 | |||
6e1a69881c | |||
9233776b2c | |||
27aa0ed29d | |||
4e3867eae9 | |||
ad2be87404 | |||
a268370f52 | |||
c8d82a8575 | |||
6ff998ac3b |
27
Jenkinsfile
vendored
Normal file
27
Jenkinsfile
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
pipeline {
|
||||
agent any
|
||||
tools {
|
||||
jdk 'JDK16'
|
||||
}
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
echo 'Building...'
|
||||
sh 'mvn clean & mvn validate & mvn compile'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
echo 'Testing...'
|
||||
sh 'mvn test'
|
||||
}
|
||||
}
|
||||
stage('Deploy') {
|
||||
steps {
|
||||
echo 'Deploying...'
|
||||
sh 'mvn verify -Dmaven.test.skip=true'
|
||||
archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
142
pom.xml
142
pom.xml
@ -1,60 +1,84 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.TheDgtl</groupId>
|
||||
<artifactId>Stargate</artifactId>
|
||||
<version>0.8.0.3</version>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>vault-repo</id>
|
||||
<url>http://nexus.hc.to/content/repositories/pub_releases</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.16.2-R0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.milkbowl.vault</groupId>
|
||||
<artifactId>VaultAPI</artifactId>
|
||||
<version>1.7</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>net/TheDgtl/Stargate/resources</targetPath>
|
||||
<directory>src/net/TheDgtl/Stargate/resources</directory>
|
||||
<includes>
|
||||
<include>*.txt</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src</directory>
|
||||
<includes>
|
||||
<include>*.yml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>net.knarcraft</groupId>
|
||||
<artifactId>Stargate</artifactId>
|
||||
<version>0.9.0.5</version>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>GNU Lesser General Public License</name>
|
||||
<url>https://www.gnu.org/licenses/lgpl-3.0.en.html</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>16</maven.compiler.source>
|
||||
<maven.compiler.target>16</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>vault-repo</id>
|
||||
<url>http://nexus.hc.to/content/repositories/pub_releases</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.17.1-R0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.milkbowl.vault</groupId>
|
||||
<artifactId>VaultAPI</artifactId>
|
||||
<version>1.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.8.0-M1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.seeseemelk</groupId>
|
||||
<artifactId>MockBukkit-v1.17</artifactId>
|
||||
<version>1.7.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>19.0.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src/main/java</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<configuration>
|
||||
<source>16</source>
|
||||
<target>16</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -1,54 +0,0 @@
|
||||
# Stargate Configuration File
|
||||
# Main Stargate config
|
||||
#
|
||||
# portal-folder - The folder for storing portals
|
||||
# gate-folder - The folder for storing gate layouts
|
||||
# default-gate-network - The default gate network
|
||||
# destroyexplosion - Whether or not to destroy gates with explosions (Creeper, TNT, etc)
|
||||
# maxgates - The maximum number of gates allowed on a network - 0 for unlimited
|
||||
# lang - The language file to load for messages
|
||||
# destMemory - Whether to remember the cursor location between uses
|
||||
# ignoreEntrance - Ignore the entrance blocks of a gate when checking. Used to work around snowmen
|
||||
# handleVehicles - Whether to allow vehicles through gates
|
||||
# sortLists - Whether to sort network lists alphabetically
|
||||
# protectEntrance - Whether to protect gate entrance material (More resource intensive. Only enable if using destroyable open/closed material)
|
||||
# signColor - The color used for drawing signs (Default: BLACK).
|
||||
# verifyPortals - Whether or not all the non-sign blocks are checked to match the gate layout when a stargate is loaded.
|
||||
############################
|
||||
# Stargate economy options #
|
||||
############################
|
||||
# useeconomy - Whether to use an economy plugin
|
||||
# createcost - The cost to create a gate
|
||||
# destroycost - The cost to destroy a gate
|
||||
# usecost - The cost to use a gate
|
||||
# toowner - Whether the charge for using a gate goes to the gates owner
|
||||
# chargefreedestination - Whether a gate whose destination is a free gate is still charged
|
||||
# freegatesgreen - Whether a free gate in the destination list is drawn green
|
||||
#################
|
||||
# Debug options #
|
||||
#################
|
||||
# debug - Debug -- Only enable if you have issues, massive console output
|
||||
# permdebug - This will output any and all Permissions checks to console, used for permissions debugging (Requires debug: true)
|
||||
portal-folder: plugins/Stargate/portals/
|
||||
gate-folder: plugins/Stargate/gates/
|
||||
default-gate-network: central
|
||||
destroyexplosion: false
|
||||
maxgates: 0
|
||||
lang: en
|
||||
destMemory: false
|
||||
ignoreEntrance: false
|
||||
handleVehicles: true
|
||||
sortLists: false
|
||||
protectEntrance: false
|
||||
signColor: BLACK
|
||||
useeconomy: false
|
||||
createcost: 0
|
||||
destroycost: 0
|
||||
usecost: 0
|
||||
toowner: false
|
||||
chargefreedestination: true
|
||||
freegatesgreen: false
|
||||
debug: false
|
||||
permdebug: false
|
||||
enableBungee: false
|
||||
verifyPortals: false
|
392
src/main/java/net/knarcraft/stargate/Stargate.java
Normal file
392
src/main/java/net/knarcraft/stargate/Stargate.java
Normal file
@ -0,0 +1,392 @@
|
||||
package net.knarcraft.stargate;
|
||||
|
||||
import net.knarcraft.stargate.command.CommandStarGate;
|
||||
import net.knarcraft.stargate.command.StarGateTabCompleter;
|
||||
import net.knarcraft.stargate.config.EconomyConfig;
|
||||
import net.knarcraft.stargate.config.MessageSender;
|
||||
import net.knarcraft.stargate.config.StargateConfig;
|
||||
import net.knarcraft.stargate.config.StargateGateConfig;
|
||||
import net.knarcraft.stargate.container.BlockChangeRequest;
|
||||
import net.knarcraft.stargate.container.ChunkUnloadRequest;
|
||||
import net.knarcraft.stargate.listener.BlockEventListener;
|
||||
import net.knarcraft.stargate.listener.EntityEventListener;
|
||||
import net.knarcraft.stargate.listener.PlayerEventListener;
|
||||
import net.knarcraft.stargate.listener.PluginEventListener;
|
||||
import net.knarcraft.stargate.listener.PortalEventListener;
|
||||
import net.knarcraft.stargate.listener.TeleportEventListener;
|
||||
import net.knarcraft.stargate.listener.VehicleEventListener;
|
||||
import net.knarcraft.stargate.listener.WorldEventListener;
|
||||
import net.knarcraft.stargate.portal.PortalHandler;
|
||||
import net.knarcraft.stargate.portal.PortalRegistry;
|
||||
import net.knarcraft.stargate.thread.BlockChangeThread;
|
||||
import net.knarcraft.stargate.thread.ChunkUnloadThread;
|
||||
import net.knarcraft.stargate.thread.StarGateThread;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.LinkedList;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* The main class of the Stargate plugin
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class Stargate extends JavaPlugin {
|
||||
|
||||
//Used for changing gate open/closed material.
|
||||
private static final Queue<BlockChangeRequest> blockChangeRequestQueue = new LinkedList<>();
|
||||
private static final Queue<ChunkUnloadRequest> chunkUnloadQueue = new PriorityQueue<>();
|
||||
|
||||
private static Logger logger;
|
||||
private static Stargate stargate;
|
||||
|
||||
private static String pluginVersion;
|
||||
|
||||
private static PluginManager pluginManager;
|
||||
private static StargateConfig stargateConfig;
|
||||
|
||||
/**
|
||||
* Empty constructor necessary for Spigot
|
||||
*/
|
||||
public Stargate() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Special constructor used for MockBukkit
|
||||
*
|
||||
* @param loader <p>The plugin loader to be used.</p>
|
||||
* @param descriptionFile <p>The description file to be used.</p>
|
||||
* @param dataFolder <p>The data folder to be used.</p>
|
||||
* @param file <p>The file to be used</p>
|
||||
*/
|
||||
protected Stargate(JavaPluginLoader loader, PluginDescriptionFile descriptionFile, File dataFolder, File file) {
|
||||
super(loader, descriptionFile, dataFolder, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance of this plugin
|
||||
*
|
||||
* @return <p>An instance of this plugin, or null if not instantiated</p>
|
||||
*/
|
||||
public static Stargate getInstance() {
|
||||
return stargate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a block change request to the request queue
|
||||
*
|
||||
* @param request <p>The request to add</p>
|
||||
*/
|
||||
public static void addBlockChangeRequest(BlockChangeRequest request) {
|
||||
if (request != null) {
|
||||
blockChangeRequestQueue.add(request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the queue containing block change requests
|
||||
*
|
||||
* @return <p>A block change request queue</p>
|
||||
*/
|
||||
public static Queue<BlockChangeRequest> getBlockChangeRequestQueue() {
|
||||
return blockChangeRequestQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sender for sending messages to players
|
||||
*
|
||||
* @return <p>The sender for sending messages to players</p>
|
||||
*/
|
||||
public static MessageSender getMessageSender() {
|
||||
return stargateConfig.getMessageSender();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object containing gate configuration values
|
||||
*
|
||||
* @return <p>The object containing gate configuration values</p>
|
||||
*/
|
||||
public static StargateGateConfig getGateConfig() {
|
||||
return stargateConfig.getStargateGateConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version of this plugin
|
||||
*
|
||||
* @return <p>This plugin's version</p>
|
||||
*/
|
||||
public static String getPluginVersion() {
|
||||
return pluginVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the logger used for logging to the console
|
||||
*
|
||||
* @return <p>The logger</p>
|
||||
*/
|
||||
public static Logger getConsoleLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a debug message
|
||||
*
|
||||
* @param route <p>The class name/route where something happened</p>
|
||||
* @param message <p>A message describing what happened</p>
|
||||
*/
|
||||
public static void debug(String route, String message) {
|
||||
if (stargateConfig == null || stargateConfig.isDebuggingEnabled()) {
|
||||
logger.info("[Stargate::" + route + "] " + message);
|
||||
} else {
|
||||
logger.log(Level.FINEST, "[Stargate::" + route + "] " + message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an info message to the console
|
||||
*
|
||||
* @param message <p>The message to log</p>
|
||||
*/
|
||||
public static void logInfo(String message) {
|
||||
logger.info(getBackupString("prefix") + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a severe error message to the console
|
||||
*
|
||||
* @param message <p>The message to log</p>
|
||||
*/
|
||||
public static void logSevere(String message) {
|
||||
log(Level.SEVERE, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a warning message to the console
|
||||
*
|
||||
* @param message <p>The message to log</p>
|
||||
*/
|
||||
public static void logWarning(String message) {
|
||||
log(Level.WARNING, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a message to the console
|
||||
*
|
||||
* @param severity <p>The severity of the event triggering the message</p>
|
||||
* @param message <p>The message to log</p>
|
||||
*/
|
||||
private static void log(Level severity, String message) {
|
||||
logger.log(severity, getBackupString("prefix") + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the folder for saving created portals
|
||||
*
|
||||
* <p>The returned String path is the full path to the folder</p>
|
||||
*
|
||||
* @return <p>The folder for storing the portal database</p>
|
||||
*/
|
||||
public static String getPortalFolder() {
|
||||
return stargateConfig.getPortalFolder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the folder storing gate files
|
||||
*
|
||||
* <p>The returned String path is the full path to the folder</p>
|
||||
*
|
||||
* @return <p>The folder storing gate files</p>
|
||||
*/
|
||||
public static String getGateFolder() {
|
||||
return stargateConfig.getGateFolder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default network for gates where a network is not specified
|
||||
*
|
||||
* @return <p>The default network</p>
|
||||
*/
|
||||
public static String getDefaultNetwork() {
|
||||
return stargateConfig.getStargateGateConfig().getDefaultPortalNetwork();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a translated string given its string key
|
||||
*
|
||||
* <p>The name/key is the string before the equals sign in the language files</p>
|
||||
*
|
||||
* @param name <p>The name/key of the string to get</p>
|
||||
* @return <p>The full translated string</p>
|
||||
*/
|
||||
public static String getString(String name) {
|
||||
return stargateConfig.getLanguageLoader().getString(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a backup string given its string key
|
||||
*
|
||||
* <p>The name/key is the string before the equals sign in the language files</p>
|
||||
*
|
||||
* @param name <p>The name/key of the string to get</p>
|
||||
* @return <p>The full string in the backup language (English)</p>
|
||||
*/
|
||||
public static String getBackupString(String name) {
|
||||
return stargateConfig.getLanguageLoader().getBackupString(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a list of variables in a string in the order they are given
|
||||
*
|
||||
* @param input <p>The input containing the variables</p>
|
||||
* @param search <p>The variables to replace</p>
|
||||
* @param values <p>The replacement values</p>
|
||||
* @return <p>The input string with the search values replaced with the given values</p>
|
||||
*/
|
||||
public static String replaceVars(String input, String[] search, String[] values) {
|
||||
if (search.length != values.length) {
|
||||
throw new IllegalArgumentException("The number of search values and replace values do not match.");
|
||||
}
|
||||
for (int i = 0; i < search.length; i++) {
|
||||
input = replaceVars(input, search[i], values[i]);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a variable in a string
|
||||
*
|
||||
* @param input <p>The input containing the variables</p>
|
||||
* @param search <p>The variable to replace</p>
|
||||
* @param value <p>The replacement value</p>
|
||||
* @return <p>The input string with the search replaced with value</p>
|
||||
*/
|
||||
public static String replaceVars(String input, String search, String value) {
|
||||
return input.replace(search, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this plugin's plugin manager
|
||||
*
|
||||
* @return <p>A plugin manager</p>
|
||||
*/
|
||||
public static PluginManager getPluginManager() {
|
||||
return pluginManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object containing economy config values
|
||||
*
|
||||
* @return <p>The object containing economy config values</p>
|
||||
*/
|
||||
public static EconomyConfig getEconomyConfig() {
|
||||
return stargateConfig.getEconomyConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
PortalHandler.closeAllPortals();
|
||||
PortalRegistry.clearPortals();
|
||||
stargateConfig.clearManagedWorlds();
|
||||
getServer().getScheduler().cancelTasks(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
PluginDescriptionFile pluginDescriptionFile = this.getDescription();
|
||||
pluginManager = getServer().getPluginManager();
|
||||
FileConfiguration newConfig = this.getConfig();
|
||||
logger = Logger.getLogger("Minecraft");
|
||||
Server server = getServer();
|
||||
stargate = this;
|
||||
|
||||
stargateConfig = new StargateConfig(logger);
|
||||
stargateConfig.finishSetup();
|
||||
|
||||
pluginVersion = pluginDescriptionFile.getVersion();
|
||||
|
||||
logger.info(pluginDescriptionFile.getName() + " v." + pluginDescriptionFile.getVersion() + " is enabled.");
|
||||
|
||||
//Register events before loading gates to stop weird things from happening.
|
||||
registerEventListeners();
|
||||
|
||||
//Run necessary threads
|
||||
runThreads();
|
||||
|
||||
this.registerCommands();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts threads using the bukkit scheduler
|
||||
*/
|
||||
private void runThreads() {
|
||||
BukkitScheduler scheduler = getServer().getScheduler();
|
||||
scheduler.runTaskTimer(this, new StarGateThread(), 0L, 100L);
|
||||
scheduler.runTaskTimer(this, new BlockChangeThread(), 0L, 1L);
|
||||
scheduler.runTaskTimer(this, new ChunkUnloadThread(), 0L, 100L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers all event listeners
|
||||
*/
|
||||
private void registerEventListeners() {
|
||||
pluginManager.registerEvents(new PlayerEventListener(), this);
|
||||
pluginManager.registerEvents(new BlockEventListener(), this);
|
||||
|
||||
pluginManager.registerEvents(new VehicleEventListener(), this);
|
||||
pluginManager.registerEvents(new EntityEventListener(), this);
|
||||
pluginManager.registerEvents(new PortalEventListener(), this);
|
||||
pluginManager.registerEvents(new WorldEventListener(), this);
|
||||
pluginManager.registerEvents(new PluginEventListener(this), this);
|
||||
pluginManager.registerEvents(new TeleportEventListener(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a command for this plugin
|
||||
*/
|
||||
private void registerCommands() {
|
||||
PluginCommand stargateCommand = this.getCommand("stargate");
|
||||
if (stargateCommand != null) {
|
||||
stargateCommand.setExecutor(new CommandStarGate());
|
||||
stargateCommand.setTabCompleter(new StarGateTabCompleter());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the chunk unload queue containing chunks to unload
|
||||
*
|
||||
* @return <p>The chunk unload queue</p>
|
||||
*/
|
||||
public static Queue<ChunkUnloadRequest> getChunkUnloadQueue() {
|
||||
return chunkUnloadQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new chunk unload request to the chunk unload queue
|
||||
*
|
||||
* @param request <p>The new chunk unload request to add</p>
|
||||
*/
|
||||
public static void addChunkUnloadRequest(ChunkUnloadRequest request) {
|
||||
chunkUnloadQueue.removeIf((item) -> item.getChunkToUnload().equals(request.getChunkToUnload()));
|
||||
chunkUnloadQueue.add(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the stargate configuration
|
||||
*
|
||||
* @return <p>The stargate configuration</p>
|
||||
*/
|
||||
public static StargateConfig getStargateConfig() {
|
||||
return stargateConfig;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.knarcraft.stargate.command;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* This command represents the plugin's about command
|
||||
*/
|
||||
public class CommandAbout implements CommandExecutor {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
|
||||
@NotNull String[] strings) {
|
||||
|
||||
ChatColor textColor = ChatColor.GOLD;
|
||||
ChatColor highlightColor = ChatColor.GREEN;
|
||||
commandSender.sendMessage(textColor + "Stargate Plugin originally created by " + highlightColor +
|
||||
"Drakia" + textColor + ", and revived by " + highlightColor + "EpicKnarvik97");
|
||||
commandSender.sendMessage(textColor + "Go to " + highlightColor +
|
||||
"https://git.knarcraft.net/EpicKnarvik97/Stargate " + textColor + "for the official repository");
|
||||
String author = Stargate.getStargateConfig().getLanguageLoader().getString("author");
|
||||
if (!author.isEmpty())
|
||||
commandSender.sendMessage(textColor + "Language created by " + highlightColor + author);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package net.knarcraft.stargate.command;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* This command represents the plugin's reload command
|
||||
*/
|
||||
public class CommandReload implements CommandExecutor {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
|
||||
@NotNull String[] args) {
|
||||
if (commandSender instanceof Player player) {
|
||||
if (!player.hasPermission("stargate.admin.reload")) {
|
||||
Stargate.getMessageSender().sendErrorMessage(commandSender, "Permission Denied");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Stargate.getStargateConfig().reload(commandSender);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package net.knarcraft.stargate.command;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* This command represents any command which starts with stargate
|
||||
*
|
||||
* <p>This prefix command should only be used for commands which are certain to collide with others and which relate to
|
||||
* the plugin itself, not commands for functions of the plugin.</p>
|
||||
*/
|
||||
public class CommandStarGate implements CommandExecutor {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
|
||||
@NotNull String[] args) {
|
||||
if (args.length > 0) {
|
||||
if (args[0].equalsIgnoreCase("about")) {
|
||||
return new CommandAbout().onCommand(commandSender, command, s, args);
|
||||
} else if (args[0].equalsIgnoreCase("reload")) {
|
||||
return new CommandReload().onCommand(commandSender, command, s, args);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
commandSender.sendMessage(ChatColor.GOLD + "Stargate version " +
|
||||
ChatColor.GREEN + Stargate.getPluginVersion());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.knarcraft.stargate.command;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This is the tab completer for the /stargate (/sg) command
|
||||
*/
|
||||
public class StarGateTabCompleter implements TabCompleter {
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command,
|
||||
@NotNull String s, @NotNull String[] args) {
|
||||
List<String> commands = new ArrayList<>();
|
||||
commands.add("about");
|
||||
commands.add("reload");
|
||||
|
||||
if (args.length == 1) {
|
||||
return commands;
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
395
src/main/java/net/knarcraft/stargate/config/EconomyConfig.java
Normal file
395
src/main/java/net/knarcraft/stargate/config/EconomyConfig.java
Normal file
@ -0,0 +1,395 @@
|
||||
package net.knarcraft.stargate.config;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.portal.Gate;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import net.knarcraft.stargate.utility.PermissionHelper;
|
||||
import net.milkbowl.vault.economy.Economy;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
import org.bukkit.plugin.ServicesManager;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* The economy config keeps track of economy config values and performs economy actions such as payment for using a gate
|
||||
*/
|
||||
public final class EconomyConfig {
|
||||
|
||||
private boolean economyEnabled = false;
|
||||
private Economy economy = null;
|
||||
private Plugin vault = null;
|
||||
private int useCost = 0;
|
||||
private int createCost = 0;
|
||||
private int destroyCost = 0;
|
||||
private boolean toOwner = false;
|
||||
private boolean chargeFreeDestination = true;
|
||||
private boolean freeGatesGreen = false;
|
||||
|
||||
/**
|
||||
* Instantiates a new economy config
|
||||
*
|
||||
* @param newConfig <p>The file configuration to read values from</p>
|
||||
*/
|
||||
public EconomyConfig(FileConfiguration newConfig) {
|
||||
loadEconomyConfig(newConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cost of using a gate without a specified cost
|
||||
*
|
||||
* @return <p>The gate use cost</p>
|
||||
*/
|
||||
public int getDefaultUseCost() {
|
||||
return useCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether economy is enabled
|
||||
*
|
||||
* @return <p>Whether economy is enabled</p>
|
||||
*/
|
||||
public boolean isEconomyEnabled() {
|
||||
return economyEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the economy object to use for transactions
|
||||
*
|
||||
* @return <p>An economy object, or null if economy is disabled or not initialized</p>
|
||||
*/
|
||||
public Economy getEconomy() {
|
||||
return economy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance of the Vault plugin
|
||||
*
|
||||
* @return <p>An instance of the Vault plugin, or null if Vault is not loaded</p>
|
||||
*/
|
||||
public Plugin getVault() {
|
||||
return vault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables economy support by clearing relevant values
|
||||
*/
|
||||
public void disableEconomy() {
|
||||
this.economy = null;
|
||||
this.vault = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether free portals should be marked with green coloring
|
||||
*
|
||||
* @return <p>Whether free portals should be green</p>
|
||||
*/
|
||||
public boolean drawFreePortalsGreen() {
|
||||
return freeGatesGreen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a gate whose destination is a free gate is still charged
|
||||
*
|
||||
* <p>If teleporting from a free portal, it's free regardless of destination. If chargeFreeDestination is disabled,
|
||||
* it's also free to teleport back to the free portal. If chargeFreeDestination is enabled, it's only free to
|
||||
* teleport back if teleporting from another free portal.</p>
|
||||
*
|
||||
* @return <p>Whether to charge for free destinations</p>
|
||||
*/
|
||||
public boolean chargeFreeDestination() {
|
||||
return chargeFreeDestination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether payments should be sent to the owner of the used portal
|
||||
*
|
||||
* @return <p>Whether to send payments to the portal owner</p>
|
||||
*/
|
||||
public boolean sendPaymentToOwner() {
|
||||
return toOwner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cost of using a gate without a specified cost
|
||||
*
|
||||
* <p>The use cost cannot be negative.</p>
|
||||
*
|
||||
* @param useCost <p>The gate use cost</p>
|
||||
*/
|
||||
public void setDefaultUseCost(int useCost) {
|
||||
if (useCost < 0) {
|
||||
throw new IllegalArgumentException("Using a gate cannot cost a negative amount");
|
||||
}
|
||||
this.useCost = useCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cost of creating a gate without a specified cost
|
||||
*
|
||||
* @return <p>The gate creation cost</p>
|
||||
*/
|
||||
public int getDefaultCreateCost() {
|
||||
return createCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cost of creating a gate without a specified cost
|
||||
*
|
||||
* <p>The gate create cost cannot be negative</p>
|
||||
*
|
||||
* @param createCost <p>The gate creation cost</p>
|
||||
*/
|
||||
public void setDefaultCreateCost(int createCost) {
|
||||
this.createCost = createCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cost of destroying a gate without a specified cost
|
||||
*
|
||||
* @return <p>The gate destruction cost</p>
|
||||
*/
|
||||
public int getDefaultDestroyCost() {
|
||||
return destroyCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cost of destroying a gate without a specified cost
|
||||
*
|
||||
* @param destroyCost <p>The gate destruction cost</p>
|
||||
*/
|
||||
public void setDefaultDestroyCost(int destroyCost) {
|
||||
this.destroyCost = destroyCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Charges the player for an action, if required
|
||||
*
|
||||
* @param player <p>The player to take money from</p>
|
||||
* @param cost <p>The cost of the transaction</p>
|
||||
* @return <p>True if the player was charged successfully</p>
|
||||
*/
|
||||
public boolean chargePlayerIfNecessary(Player player, int cost) {
|
||||
if (skipPayment(cost)) {
|
||||
return true;
|
||||
}
|
||||
//Charge player
|
||||
return chargePlayer(player, cost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given player can afford the given fee
|
||||
*
|
||||
* @param player <p>The player to check</p>
|
||||
* @param cost <p>The fee to pay</p>
|
||||
* @return <p>True if the player can afford to pay the fee</p>
|
||||
*/
|
||||
public boolean canAffordFee(Player player, int cost) {
|
||||
return economy.getBalance(player) > cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Charges the player for an action, if required
|
||||
*
|
||||
* @param player <p>The player to take money from</p>
|
||||
* @param target <p>The target to pay</p>
|
||||
* @param cost <p>The cost of the transaction</p>
|
||||
* @return <p>True if the player was charged successfully</p>
|
||||
*/
|
||||
public boolean chargePlayerIfNecessary(Player player, UUID target, int cost) {
|
||||
if (skipPayment(cost)) {
|
||||
return true;
|
||||
}
|
||||
//Charge player
|
||||
return chargePlayer(player, target, cost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a formatted string for an amount, adding the name of the currency
|
||||
*
|
||||
* @param amount <p>The amount to display</p>
|
||||
* @return <p>A formatted text string describing the amount</p>
|
||||
*/
|
||||
public String format(int amount) {
|
||||
if (economyEnabled) {
|
||||
return economy.format(amount);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up economy by initializing vault and the vault economy provider
|
||||
*
|
||||
* @param pluginManager <p>The plugin manager to get plugins from</p>
|
||||
* @return <p>True if economy was enabled</p>
|
||||
*/
|
||||
public boolean setupEconomy(PluginManager pluginManager) {
|
||||
if (!economyEnabled) {
|
||||
return false;
|
||||
}
|
||||
//Check if vault is loaded
|
||||
Plugin vault = pluginManager.getPlugin("Vault");
|
||||
if (vault != null && vault.isEnabled()) {
|
||||
ServicesManager servicesManager = Stargate.getInstance().getServer().getServicesManager();
|
||||
RegisteredServiceProvider<Economy> economyProvider = servicesManager.getRegistration(Economy.class);
|
||||
if (economyProvider != null) {
|
||||
economy = economyProvider.getProvider();
|
||||
this.vault = vault;
|
||||
return true;
|
||||
} else {
|
||||
Stargate.logInfo(Stargate.getString("ecoLoadError"));
|
||||
}
|
||||
} else {
|
||||
Stargate.logInfo(Stargate.getString("vaultLoadError"));
|
||||
}
|
||||
economyEnabled = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to use economy
|
||||
*
|
||||
* @return <p>True if the user has turned on economy and economy is available</p>
|
||||
*/
|
||||
public boolean useEconomy() {
|
||||
return economyEnabled && economy != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a payment transaction should be skipped
|
||||
*
|
||||
* @param cost <p>The cost of the transaction</p>
|
||||
* @return <p>True if the transaction should be skipped</p>
|
||||
*/
|
||||
private boolean skipPayment(int cost) {
|
||||
return cost == 0 || !useEconomy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the cost of using a gate
|
||||
*
|
||||
* @param player <p>The player trying to use the gate</p>
|
||||
* @param source <p>The source/entry portal</p>
|
||||
* @param destination <p>The destination portal</p>
|
||||
* @return <p>The cost of using the portal</p>
|
||||
*/
|
||||
public int getUseCost(Player player, Portal source, Portal destination) {
|
||||
//No payment required
|
||||
if (!useEconomy() || source.getOptions().isFree()) {
|
||||
return 0;
|
||||
}
|
||||
//Not charging for free destinations
|
||||
if (destination != null && !chargeFreeDestination && destination.getOptions().isFree()) {
|
||||
return 0;
|
||||
}
|
||||
//Cost is 0 if the player owns this gate and funds go to the owner
|
||||
if (source.getGate().getToOwner() && source.isOwner(player)) {
|
||||
return 0;
|
||||
}
|
||||
//Player gets free gate use
|
||||
if (PermissionHelper.hasPermission(player, "stargate.free.use")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return source.getGate().getUseCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cost of creating the given gate
|
||||
*
|
||||
* @param player <p>The player creating the gate</p>
|
||||
* @param gate <p>The gate type used</p>
|
||||
* @return <p>The cost of creating the gate</p>
|
||||
*/
|
||||
public int getCreateCost(Player player, Gate gate) {
|
||||
if (isFree(player, "create")) {
|
||||
return 0;
|
||||
} else {
|
||||
return gate.getCreateCost();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cost of destroying the given gate
|
||||
*
|
||||
* @param player <p>The player creating the gate</p>
|
||||
* @param gate <p>The gate type used</p>
|
||||
* @return <p>The cost of destroying the gate</p>
|
||||
*/
|
||||
public int getDestroyCost(Player player, Gate gate) {
|
||||
if (isFree(player, "destroy")) {
|
||||
return 0;
|
||||
} else {
|
||||
return gate.getDestroyCost();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all config values related to economy
|
||||
*
|
||||
* @param newConfig <p>The configuration containing the values to read</p>
|
||||
*/
|
||||
private void loadEconomyConfig(FileConfiguration newConfig) {
|
||||
economyEnabled = newConfig.getBoolean("economy.useEconomy");
|
||||
setDefaultCreateCost(newConfig.getInt("economy.createCost"));
|
||||
setDefaultDestroyCost(newConfig.getInt("economy.destroyCost"));
|
||||
setDefaultUseCost(newConfig.getInt("economy.useCost"));
|
||||
toOwner = newConfig.getBoolean("economy.toOwner");
|
||||
chargeFreeDestination = newConfig.getBoolean("economy.chargeFreeDestination");
|
||||
freeGatesGreen = newConfig.getBoolean("economy.freeGatesGreen");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a player can do a gate action for free
|
||||
*
|
||||
* @param player <p>The player to check</p>
|
||||
* @param permissionNode <p>The free.permissionNode necessary to allow free gate {action}</p>
|
||||
* @return <p></p>
|
||||
*/
|
||||
private boolean isFree(Player player, String permissionNode) {
|
||||
return !useEconomy() || PermissionHelper.hasPermission(player, "stargate.free." + permissionNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Charges a player
|
||||
*
|
||||
* @param player <p>The player to charge</p>
|
||||
* @param amount <p>The amount to charge</p>
|
||||
* @return <p>True if the payment succeeded, or if no payment was necessary</p>
|
||||
*/
|
||||
private boolean chargePlayer(Player player, double amount) {
|
||||
if (economyEnabled && economy != null) {
|
||||
if (!economy.has(player, amount)) {
|
||||
return false;
|
||||
}
|
||||
economy.withdrawPlayer(player, amount);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Charges a player, giving the charge to a target
|
||||
*
|
||||
* @param player <p>The player to charge</p>
|
||||
* @param target <p>The UUID of the player to pay</p>
|
||||
* @param amount <p>The amount to charge</p>
|
||||
* @return <p>True if the payment succeeded, or if no payment was necessary</p>
|
||||
*/
|
||||
private boolean chargePlayer(Player player, UUID target, double amount) {
|
||||
if (economyEnabled && player.getUniqueId().compareTo(target) != 0 && economy != null) {
|
||||
if (!economy.has(player, amount)) {
|
||||
return false;
|
||||
}
|
||||
//Take money from the user and give to the owner
|
||||
economy.withdrawPlayer(player, amount);
|
||||
economy.depositPlayer(Bukkit.getOfflinePlayer(target), amount);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
255
src/main/java/net/knarcraft/stargate/config/LanguageLoader.java
Normal file
255
src/main/java/net/knarcraft/stargate/config/LanguageLoader.java
Normal file
@ -0,0 +1,255 @@
|
||||
package net.knarcraft.stargate.config;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.utility.FileHelper;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class is responsible for loading all strings which are translated into several languages
|
||||
*/
|
||||
public final class LanguageLoader {
|
||||
|
||||
private final String languageFolder;
|
||||
private final Map<String, String> loadedBackupStrings;
|
||||
private String chosenLanguage;
|
||||
private Map<String, String> loadedStringTranslations;
|
||||
|
||||
/**
|
||||
* Instantiates a new language loader
|
||||
*
|
||||
* <p>This will only load the backup language. Set the chosen language and reload afterwards.</p>
|
||||
*
|
||||
* @param languageFolder <p>The folder containing the language files</p>
|
||||
*/
|
||||
public LanguageLoader(String languageFolder) {
|
||||
this.languageFolder = languageFolder;
|
||||
File testFile = new File(languageFolder, "en.txt");
|
||||
if (!testFile.exists()) {
|
||||
if (testFile.getParentFile().mkdirs()) {
|
||||
Stargate.debug("LanguageLoader", "Created language folder");
|
||||
}
|
||||
}
|
||||
|
||||
//Load english as backup language in case the chosen language is missing newly added text strings
|
||||
InputStream inputStream = FileHelper.getInputStreamForInternalFile("/lang/en.txt");
|
||||
if (inputStream != null) {
|
||||
loadedBackupStrings = load("en", inputStream);
|
||||
} else {
|
||||
loadedBackupStrings = null;
|
||||
Stargate.getConsoleLogger().severe("[stargate] Error loading backup language. " +
|
||||
"There may be missing text in-game");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads languages from the files on disk
|
||||
*/
|
||||
public void reload() {
|
||||
//Extracts/Updates the language as needed
|
||||
updateLanguage(chosenLanguage);
|
||||
loadedStringTranslations = load(chosenLanguage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string to display given its name/key
|
||||
*
|
||||
* @param name <p>The name/key of the string to display</p>
|
||||
* @return <p>The string in the user's preferred language</p>
|
||||
*/
|
||||
public String getString(String name) {
|
||||
String value = null;
|
||||
if (loadedStringTranslations != null) {
|
||||
value = loadedStringTranslations.get(name);
|
||||
}
|
||||
if (value == null) {
|
||||
value = getBackupString(name);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string to display given its name/key
|
||||
*
|
||||
* @param name <p>The name/key of the string to display</p>
|
||||
* @return <p>The string in the backup language (English)</p>
|
||||
*/
|
||||
public String getBackupString(String name) {
|
||||
String value = null;
|
||||
if (loadedBackupStrings != null) {
|
||||
value = loadedBackupStrings.get(name);
|
||||
}
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chosen plugin language
|
||||
*
|
||||
* @param chosenLanguage <p>The new plugin language</p>
|
||||
*/
|
||||
public void setChosenLanguage(String chosenLanguage) {
|
||||
this.chosenLanguage = chosenLanguage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates files in the plugin directory with contents from the compiled .jar
|
||||
*
|
||||
* @param language <p>The language to update</p>
|
||||
*/
|
||||
private void updateLanguage(String language) {
|
||||
Map<String, String> currentLanguageValues = load(language);
|
||||
|
||||
InputStream inputStream = getClass().getResourceAsStream("/lang/" + language + ".txt");
|
||||
if (inputStream == null) {
|
||||
Stargate.logInfo(String.format("The language %s is not available. Falling back to english, You can add a " +
|
||||
"custom language by creating a new text file in the lang directory.", language));
|
||||
Stargate.debug("LanguageLoader::updateLanguage", String.format("Unable to load /lang/%s.txt", language));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
readChangedLanguageStrings(inputStream, language, currentLanguageValues);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads language strings
|
||||
*
|
||||
* @param inputStream <p>The input stream to read from</p>
|
||||
* @param language <p>The selected language</p>
|
||||
* @param currentLanguageValues <p>The current values of the loaded/processed language</p>
|
||||
* @throws IOException <p>if unable to read a language file</p>
|
||||
*/
|
||||
private void readChangedLanguageStrings(InputStream inputStream, String language, Map<String,
|
||||
String> currentLanguageValues) throws IOException {
|
||||
//Get language values
|
||||
BufferedReader bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream);
|
||||
Map<String, String> internalLanguageValues = FileHelper.readKeyValuePairs(bufferedReader);
|
||||
|
||||
//If currentLanguageValues is null; the chosen language has not been used before
|
||||
if (currentLanguageValues == null) {
|
||||
updateLanguageFile(language, internalLanguageValues, null);
|
||||
Stargate.logInfo(String.format("Language (%s) has been loaded", language));
|
||||
return;
|
||||
}
|
||||
|
||||
//If a key is not found in the language file, add the one in the internal file. Must update the external file
|
||||
if (!internalLanguageValues.keySet().equals(currentLanguageValues.keySet())) {
|
||||
Map<String, String> newLanguageValues = new HashMap<>();
|
||||
boolean updateNecessary = false;
|
||||
for (String key : internalLanguageValues.keySet()) {
|
||||
if (currentLanguageValues.get(key) == null) {
|
||||
newLanguageValues.put(key, internalLanguageValues.get(key));
|
||||
//Found at least one value in the internal file not in the external file. Need to update
|
||||
updateNecessary = true;
|
||||
} else {
|
||||
newLanguageValues.put(key, currentLanguageValues.get(key));
|
||||
currentLanguageValues.remove(key);
|
||||
}
|
||||
}
|
||||
//Update the file itself
|
||||
if (updateNecessary) {
|
||||
updateLanguageFile(language, newLanguageValues, currentLanguageValues);
|
||||
Stargate.logInfo(String.format("Your language file (%s.txt) has been updated", language));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the language file for a given language
|
||||
*
|
||||
* @param language <p>The language to update</p>
|
||||
* @param languageStrings <p>The updated language strings</p>
|
||||
* @param customLanguageStrings <p>Any custom language strings not recognized</p>
|
||||
* @throws IOException <p>If unable to write to the language file</p>
|
||||
*/
|
||||
private void updateLanguageFile(String language, Map<String, String> languageStrings,
|
||||
Map<String, String> customLanguageStrings) throws IOException {
|
||||
BufferedWriter bufferedWriter = FileHelper.getBufferedWriterFromString(languageFolder + language + ".txt");
|
||||
|
||||
//Output normal Language data
|
||||
for (String key : languageStrings.keySet()) {
|
||||
bufferedWriter.write(key + "=" + languageStrings.get(key));
|
||||
bufferedWriter.newLine();
|
||||
}
|
||||
bufferedWriter.newLine();
|
||||
//Output any custom language strings the user had
|
||||
if (customLanguageStrings != null) {
|
||||
for (String key : customLanguageStrings.keySet()) {
|
||||
bufferedWriter.write(key + "=" + customLanguageStrings.get(key));
|
||||
bufferedWriter.newLine();
|
||||
}
|
||||
}
|
||||
bufferedWriter.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given language
|
||||
*
|
||||
* @param lang <p>The language to load</p>
|
||||
* @return <p>A mapping between loaded string indexes and the strings to display</p>
|
||||
*/
|
||||
private Map<String, String> load(String lang) {
|
||||
return load(lang, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given language
|
||||
*
|
||||
* @param lang <p>The language to load</p>
|
||||
* @param inputStream <p>An optional input stream to use. Defaults to using a file input stream</p>
|
||||
* @return <p>A mapping between loaded string indexes and the strings to display</p>
|
||||
*/
|
||||
private Map<String, String> load(String lang, InputStream inputStream) {
|
||||
Map<String, String> strings;
|
||||
BufferedReader bufferedReader;
|
||||
try {
|
||||
if (inputStream == null) {
|
||||
bufferedReader = FileHelper.getBufferedReaderFromString(languageFolder + lang + ".txt");
|
||||
} else {
|
||||
bufferedReader = FileHelper.getBufferedReaderFromInputStream(inputStream);
|
||||
}
|
||||
strings = FileHelper.readKeyValuePairs(bufferedReader);
|
||||
} catch (Exception e) {
|
||||
if (Stargate.getStargateConfig().isDebuggingEnabled()) {
|
||||
Stargate.getConsoleLogger().info("[Stargate] Unable to load language " + lang);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints debug output to the console for checking loaded language strings/translations
|
||||
*/
|
||||
public void debug() {
|
||||
if (loadedStringTranslations != null) {
|
||||
Set<String> keys = loadedStringTranslations.keySet();
|
||||
for (String key : keys) {
|
||||
Stargate.debug("LanguageLoader::Debug::loadedStringTranslations", key + " => " +
|
||||
loadedStringTranslations.get(key));
|
||||
}
|
||||
}
|
||||
if (loadedBackupStrings == null) {
|
||||
return;
|
||||
}
|
||||
Set<String> keys = loadedBackupStrings.keySet();
|
||||
for (String key : keys) {
|
||||
Stargate.debug("LanguageLoader::Debug::loadedBackupStrings", key + " => " +
|
||||
loadedBackupStrings.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package net.knarcraft.stargate.config;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
/**
|
||||
* The message sender is responsible sending messages to players with correct coloring and formatting
|
||||
*/
|
||||
public final class MessageSender {
|
||||
|
||||
private final LanguageLoader languageLoader;
|
||||
|
||||
/**
|
||||
* Instantiates a new message sender
|
||||
*
|
||||
* @param languageLoader <p>The language loader to get translated strings from</p>
|
||||
*/
|
||||
public MessageSender(LanguageLoader languageLoader) {
|
||||
this.languageLoader = languageLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an error message to a player
|
||||
*
|
||||
* @param player <p>The player to send the message to</p>
|
||||
* @param message <p>The message to send</p>
|
||||
*/
|
||||
public void sendErrorMessage(CommandSender player, String message) {
|
||||
sendMessage(player, message, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a success message to a player
|
||||
*
|
||||
* @param player <p>The player to send the message to</p>
|
||||
* @param message <p>The message to send</p>
|
||||
*/
|
||||
public void sendSuccessMessage(CommandSender player, String message) {
|
||||
sendMessage(player, message, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to a player
|
||||
*
|
||||
* @param sender <p>The player to send the message to</p>
|
||||
* @param message <p>The message to send</p>
|
||||
* @param error <p>Whether the message sent is an error</p>
|
||||
*/
|
||||
private void sendMessage(CommandSender sender, String message, boolean error) {
|
||||
if (message.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
message = ChatColor.translateAlternateColorCodes('&', message);
|
||||
if (error) {
|
||||
sender.sendMessage(ChatColor.RED + languageLoader.getString("prefix") + ChatColor.WHITE + message);
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.GREEN + languageLoader.getString("prefix") + ChatColor.WHITE + message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
470
src/main/java/net/knarcraft/stargate/config/StargateConfig.java
Normal file
470
src/main/java/net/knarcraft/stargate/config/StargateConfig.java
Normal file
@ -0,0 +1,470 @@
|
||||
package net.knarcraft.stargate.config;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockChangeRequest;
|
||||
import net.knarcraft.stargate.listener.BungeeCordListener;
|
||||
import net.knarcraft.stargate.portal.GateHandler;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import net.knarcraft.stargate.portal.PortalHandler;
|
||||
import net.knarcraft.stargate.portal.PortalRegistry;
|
||||
import net.knarcraft.stargate.thread.BlockChangeThread;
|
||||
import net.knarcraft.stargate.utility.FileHelper;
|
||||
import net.knarcraft.stargate.utility.PortalFileHelper;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.plugin.messaging.Messenger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* The stargate config is responsible for keeping track of all configuration values
|
||||
*/
|
||||
public final class StargateConfig {
|
||||
|
||||
private final Queue<Portal> activePortalsQueue = new ConcurrentLinkedQueue<>();
|
||||
private final Queue<Portal> openPortalsQueue = new ConcurrentLinkedQueue<>();
|
||||
private final HashSet<String> managedWorlds = new HashSet<>();
|
||||
|
||||
private StargateGateConfig stargateGateConfig;
|
||||
private MessageSender messageSender;
|
||||
private final LanguageLoader languageLoader;
|
||||
private EconomyConfig economyConfig;
|
||||
private final Logger logger;
|
||||
|
||||
private final String dataFolderPath;
|
||||
private String gateFolder;
|
||||
private String portalFolder;
|
||||
private String languageName = "en";
|
||||
|
||||
private boolean debuggingEnabled = false;
|
||||
private boolean permissionDebuggingEnabled = false;
|
||||
|
||||
/**
|
||||
* Instantiates a new stargate config
|
||||
*
|
||||
* @param logger <p>The logger to use for logging errors</p>
|
||||
*/
|
||||
public StargateConfig(Logger logger) {
|
||||
this.logger = logger;
|
||||
|
||||
dataFolderPath = Stargate.getInstance().getDataFolder().getPath().replaceAll("\\\\", "/");
|
||||
portalFolder = dataFolderPath + "/portals/";
|
||||
gateFolder = dataFolderPath + "/gates/";
|
||||
languageLoader = new LanguageLoader(dataFolderPath + "/lang/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish the config setup by loading languages, gates and portals, and loading economy if vault is loaded
|
||||
*/
|
||||
public void finishSetup() {
|
||||
this.loadConfig();
|
||||
|
||||
//Enable the required channels for Bungee support
|
||||
if (stargateGateConfig.enableBungee()) {
|
||||
startStopBungeeListener(true);
|
||||
}
|
||||
|
||||
//Set the chosen language and reload the language loader
|
||||
languageLoader.setChosenLanguage(languageName);
|
||||
languageLoader.reload();
|
||||
|
||||
messageSender = new MessageSender(languageLoader);
|
||||
if (debuggingEnabled) {
|
||||
languageLoader.debug();
|
||||
}
|
||||
|
||||
this.createMissingFolders();
|
||||
this.loadGates();
|
||||
this.loadAllPortals();
|
||||
|
||||
//Set up vault economy if vault has been loaded
|
||||
setupVaultEconomy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the queue of open portals
|
||||
*
|
||||
* <p>The open portals queue is used to close open portals after some time has passed</p>
|
||||
*
|
||||
* @return <p>The open portals queue</p>
|
||||
*/
|
||||
public Queue<Portal> getOpenPortalsQueue() {
|
||||
return openPortalsQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the queue of active portals
|
||||
*
|
||||
* <p>The active portals queue is used to de-activate portals after some time has passed</p>
|
||||
*
|
||||
* @return <p>The active portals queue</p>
|
||||
*/
|
||||
public Queue<Portal> getActivePortalsQueue() {
|
||||
return activePortalsQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether debugging is enabled
|
||||
*
|
||||
* @return <p>Whether debugging is enabled</p>
|
||||
*/
|
||||
public boolean isDebuggingEnabled() {
|
||||
return debuggingEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether permission debugging is enabled
|
||||
*
|
||||
* @return <p>Whether permission debugging is enabled</p>
|
||||
*/
|
||||
public boolean isPermissionDebuggingEnabled() {
|
||||
return permissionDebuggingEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object containing economy config values
|
||||
*
|
||||
* @return <p>The object containing economy config values</p>
|
||||
*/
|
||||
public EconomyConfig getEconomyConfig() {
|
||||
return this.economyConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads all portals and files
|
||||
*
|
||||
* @param sender <p>The sender of the reload request</p>
|
||||
*/
|
||||
public void reload(CommandSender sender) {
|
||||
//Unload all saved data
|
||||
unload();
|
||||
|
||||
//Perform all block change requests to prevent mismatch if a gate's open-material changes. Changing the
|
||||
// closed-material still requires a restart.
|
||||
BlockChangeRequest firstElement = Stargate.getBlockChangeRequestQueue().peek();
|
||||
while (firstElement != null) {
|
||||
BlockChangeThread.pollQueue();
|
||||
firstElement = Stargate.getBlockChangeRequestQueue().peek();
|
||||
}
|
||||
|
||||
//Store the old enable bungee state in case it changes
|
||||
boolean oldEnableBungee = stargateGateConfig.enableBungee();
|
||||
|
||||
//Load all data
|
||||
load();
|
||||
|
||||
//Enable or disable the required channels for Bungee support
|
||||
if (oldEnableBungee != stargateGateConfig.enableBungee()) {
|
||||
startStopBungeeListener(stargateGateConfig.enableBungee());
|
||||
}
|
||||
|
||||
messageSender.sendErrorMessage(sender, languageLoader.getString("reloaded"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-loads all loaded data
|
||||
*/
|
||||
private void unload() {
|
||||
//De-activate all currently active portals
|
||||
for (Portal activePortal : activePortalsQueue) {
|
||||
activePortal.getPortalActivator().deactivate();
|
||||
}
|
||||
//Force all portals to close
|
||||
closeAllOpenPortals();
|
||||
PortalHandler.closeAllPortals();
|
||||
|
||||
//Clear queues and lists
|
||||
activePortalsQueue.clear();
|
||||
openPortalsQueue.clear();
|
||||
managedWorlds.clear();
|
||||
|
||||
//Clear all loaded portals
|
||||
PortalRegistry.clearPortals();
|
||||
|
||||
//Clear all loaded gates
|
||||
GateHandler.clearGates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the set of managed worlds
|
||||
*/
|
||||
public void clearManagedWorlds() {
|
||||
managedWorlds.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of the set of managed worlds
|
||||
*
|
||||
* @return <p>The managed worlds</p>
|
||||
*/
|
||||
public Set<String> getManagedWorlds() {
|
||||
return new HashSet<>(managedWorlds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a world to the managed worlds
|
||||
*
|
||||
* @param worldName <p>The name of the world to manage</p>
|
||||
*/
|
||||
public void addManagedWorld(String worldName) {
|
||||
managedWorlds.add(worldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a world from the managed worlds
|
||||
*
|
||||
* @param worldName <p>The name of the world to stop managing</p>
|
||||
*/
|
||||
public void removeManagedWorld(String worldName) {
|
||||
managedWorlds.remove(worldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all necessary data
|
||||
*/
|
||||
private void load() {
|
||||
//Load the config from disk
|
||||
loadConfig();
|
||||
|
||||
//Load all gates
|
||||
loadGates();
|
||||
|
||||
//Load all portals
|
||||
loadAllPortals();
|
||||
|
||||
//Update the language loader in case the loaded language changed
|
||||
languageLoader.setChosenLanguage(languageName);
|
||||
languageLoader.reload();
|
||||
if (debuggingEnabled) {
|
||||
languageLoader.debug();
|
||||
}
|
||||
|
||||
//Load Economy support if enabled/clear if disabled
|
||||
reloadEconomy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the listener for listening to BungeeCord messages
|
||||
*/
|
||||
private void startStopBungeeListener(boolean start) {
|
||||
Messenger messenger = Bukkit.getMessenger();
|
||||
String bungeeChannel = "BungeeCord";
|
||||
|
||||
if (start) {
|
||||
messenger.registerOutgoingPluginChannel(Stargate.getInstance(), bungeeChannel);
|
||||
messenger.registerIncomingPluginChannel(Stargate.getInstance(), bungeeChannel, new BungeeCordListener());
|
||||
} else {
|
||||
messenger.unregisterIncomingPluginChannel(Stargate.getInstance(), bungeeChannel);
|
||||
messenger.unregisterOutgoingPluginChannel(Stargate.getInstance(), bungeeChannel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads economy by enabling or disabling it as necessary
|
||||
*/
|
||||
private void reloadEconomy() {
|
||||
EconomyConfig economyConfig = getEconomyConfig();
|
||||
if (economyConfig.isEconomyEnabled() && economyConfig.getEconomy() == null) {
|
||||
setupVaultEconomy();
|
||||
} else if (!economyConfig.isEconomyEnabled()) {
|
||||
economyConfig.disableEconomy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces all open portals to close
|
||||
*/
|
||||
public void closeAllOpenPortals() {
|
||||
for (Portal openPortal : openPortalsQueue) {
|
||||
openPortal.getPortalOpener().closePortal(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all config values
|
||||
*/
|
||||
public void loadConfig() {
|
||||
Stargate.getInstance().reloadConfig();
|
||||
FileConfiguration newConfig = Stargate.getInstance().getConfig();
|
||||
|
||||
boolean isMigrating = false;
|
||||
if (newConfig.getString("lang") != null ||
|
||||
newConfig.getString("gates.integrity.ignoreEntrance") != null ||
|
||||
newConfig.getString("ignoreEntrance") != null) {
|
||||
migrateConfig(newConfig);
|
||||
isMigrating = true;
|
||||
}
|
||||
|
||||
//Copy missing default values if any values are missing
|
||||
newConfig.options().copyDefaults(true);
|
||||
|
||||
//Get the language name from the config
|
||||
languageName = newConfig.getString("language");
|
||||
|
||||
//Get important folders from the config
|
||||
portalFolder = newConfig.getString("folders.portalFolder");
|
||||
gateFolder = newConfig.getString("folders.gateFolder");
|
||||
|
||||
//Get enabled debug settings from the config
|
||||
debuggingEnabled = newConfig.getBoolean("debugging.debug");
|
||||
permissionDebuggingEnabled = newConfig.getBoolean("debugging.permissionDebug");
|
||||
|
||||
//If users have an outdated config, assume they also need to update their default gates
|
||||
if (isMigrating) {
|
||||
GateHandler.writeDefaultGatesToFolder(gateFolder);
|
||||
}
|
||||
|
||||
//Load all gate config values
|
||||
stargateGateConfig = new StargateGateConfig(newConfig);
|
||||
|
||||
//Load all economy config values
|
||||
economyConfig = new EconomyConfig(newConfig);
|
||||
|
||||
Stargate.getInstance().saveConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object containing configuration values regarding gates
|
||||
*
|
||||
* @return <p>Gets the gate config</p>
|
||||
*/
|
||||
public StargateGateConfig getStargateGateConfig() {
|
||||
return stargateGateConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all available gates
|
||||
*/
|
||||
public void loadGates() {
|
||||
GateHandler.loadGates(gateFolder);
|
||||
Stargate.logInfo(String.format("Loaded %s gate layouts", GateHandler.getGateCount()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes all configuration values from the old name to the new name
|
||||
*
|
||||
* @param newConfig <p>The config to read from and write to</p>
|
||||
*/
|
||||
private void migrateConfig(FileConfiguration newConfig) {
|
||||
//Save the old config just in case something goes wrong
|
||||
try {
|
||||
newConfig.save(dataFolderPath + "/config.yml.old");
|
||||
} catch (IOException e) {
|
||||
Stargate.debug("Stargate::migrateConfig", "Unable to save old backup and do migration");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
//Read all available config migrations
|
||||
Map<String, String> migrationFields;
|
||||
try {
|
||||
migrationFields = FileHelper.readKeyValuePairs(FileHelper.getBufferedReaderFromInputStream(
|
||||
FileHelper.getInputStreamForInternalFile("/config-migrations.txt")));
|
||||
} catch (IOException e) {
|
||||
Stargate.debug("Stargate::migrateConfig", "Unable to load config migration file");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
//Replace old config names with the new ones
|
||||
for (String key : migrationFields.keySet()) {
|
||||
if (newConfig.contains(key)) {
|
||||
String newPath = migrationFields.get(key);
|
||||
Object oldValue = newConfig.get(key);
|
||||
if (!newPath.trim().isEmpty()) {
|
||||
newConfig.set(newPath, oldValue);
|
||||
}
|
||||
newConfig.set(key, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads economy from Vault
|
||||
*/
|
||||
private void setupVaultEconomy() {
|
||||
EconomyConfig economyConfig = getEconomyConfig();
|
||||
if (economyConfig.setupEconomy(Stargate.getPluginManager()) && economyConfig.getEconomy() != null) {
|
||||
String vaultVersion = economyConfig.getVault().getDescription().getVersion();
|
||||
Stargate.logInfo(Stargate.replaceVars(Stargate.getString("vaultLoaded"), "%version%", vaultVersion));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all portals in all un-managed worlds
|
||||
*/
|
||||
public void loadAllPortals() {
|
||||
for (World world : Stargate.getInstance().getServer().getWorlds()) {
|
||||
if (!managedWorlds.contains(world.getName())) {
|
||||
PortalFileHelper.loadAllPortals(world);
|
||||
managedWorlds.add(world.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates missing folders
|
||||
*/
|
||||
private void createMissingFolders() {
|
||||
File newPortalDir = new File(portalFolder);
|
||||
if (!newPortalDir.exists()) {
|
||||
if (!newPortalDir.mkdirs()) {
|
||||
logger.severe("Unable to create portal directory");
|
||||
}
|
||||
}
|
||||
File newFile = new File(portalFolder, Stargate.getInstance().getServer().getWorlds().get(0).getName() +
|
||||
".db");
|
||||
if (!newFile.exists() && !newFile.getParentFile().exists()) {
|
||||
if (!newFile.getParentFile().mkdirs()) {
|
||||
logger.severe("Unable to create portal database folder: " + newFile.getParentFile().getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the folder all portals are stored in
|
||||
*
|
||||
* @return <p>The portal folder</p>
|
||||
*/
|
||||
public String getPortalFolder() {
|
||||
return portalFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the folder storing gate files
|
||||
*
|
||||
* <p>The returned String path is the full path to the folder</p>
|
||||
*
|
||||
* @return <p>The folder storing gate files</p>
|
||||
*/
|
||||
public String getGateFolder() {
|
||||
return gateFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sender for sending messages to players
|
||||
*
|
||||
* @return <p>The sender for sending messages to players</p>
|
||||
*/
|
||||
public MessageSender getMessageSender() {
|
||||
return messageSender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the language loader containing translated strings
|
||||
*
|
||||
* @return <p>The language loader</p>
|
||||
*/
|
||||
public LanguageLoader getLanguageLoader() {
|
||||
return languageLoader;
|
||||
}
|
||||
}
|
@ -0,0 +1,234 @@
|
||||
package net.knarcraft.stargate.config;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.portal.PortalSignDrawer;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
|
||||
/**
|
||||
* The Stargate gate config keeps track of all global config values related to gates
|
||||
*/
|
||||
public final class StargateGateConfig {
|
||||
|
||||
private int maxGatesEachNetwork = 0;
|
||||
private boolean rememberDestination = false;
|
||||
private boolean handleVehicles = true;
|
||||
private boolean handleEmptyVehicles = true;
|
||||
private boolean handleCreatureTransportation = true;
|
||||
private boolean handleNonPlayerVehicles = true;
|
||||
private boolean handleLeashedCreatures = true;
|
||||
private boolean sortNetworkDestinations = false;
|
||||
private boolean protectEntrance = false;
|
||||
private boolean enableBungee = true;
|
||||
private boolean verifyPortals = true;
|
||||
private boolean destroyExplosion = false;
|
||||
private String defaultGateNetwork = "central";
|
||||
private static final int activeTime = 10;
|
||||
private static final int openTime = 10;
|
||||
|
||||
/**
|
||||
* Instantiates a new stargate config
|
||||
*
|
||||
* @param newConfig <p>The file configuration to read values from</p>
|
||||
*/
|
||||
public StargateGateConfig(FileConfiguration newConfig) {
|
||||
loadGateConfig(newConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount of seconds a portal should be open before automatically closing
|
||||
*
|
||||
* @return <p>The open time of a gate</p>
|
||||
*/
|
||||
public int getOpenTime() {
|
||||
return openTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount of seconds a portal should be active before automatically deactivating
|
||||
*
|
||||
* @return <p>The active time of a gate</p>
|
||||
*/
|
||||
public int getActiveTime() {
|
||||
return activeTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of gates allowed on each network
|
||||
*
|
||||
* @return <p>Maximum number of gates for each network</p>
|
||||
*/
|
||||
public int maxGatesEachNetwork() {
|
||||
return maxGatesEachNetwork;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether a portal's lastly used destination should be remembered
|
||||
*
|
||||
* @return <p>Whether a portal's lastly used destination should be remembered</p>
|
||||
*/
|
||||
public boolean rememberDestination() {
|
||||
return rememberDestination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether vehicle teleportation should be handled in addition to player teleportation
|
||||
*
|
||||
* @return <p>Whether vehicle teleportation should be handled</p>
|
||||
*/
|
||||
public boolean handleVehicles() {
|
||||
return handleVehicles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether vehicles with no passengers should be handled
|
||||
*
|
||||
* <p>The handle vehicles option overrides this option if disabled. This option allows empty passenger
|
||||
* minecarts/boats, but also chest/tnt/hopper/furnace minecarts to teleport through stargates.</p>
|
||||
*
|
||||
* @return <p>Whether vehicles without passengers should be handled</p>
|
||||
*/
|
||||
public boolean handleEmptyVehicles() {
|
||||
return handleEmptyVehicles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether vehicles containing creatures should be handled
|
||||
*
|
||||
* <p>The handle vehicles option overrides this option if disabled. This option allows creatures (pigs, pandas,
|
||||
* zombies, etc.) to teleport through stargates if in a vehicle.</p>
|
||||
*
|
||||
* @return <p>Whether vehicles with creatures should be handled</p>
|
||||
*/
|
||||
public boolean handleCreatureTransportation() {
|
||||
return handleCreatureTransportation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether vehicles containing a creature, but not a player should be handled
|
||||
*
|
||||
* <p>The handle vehicles option, and the handle creature transportation option, override this option if disabled.
|
||||
* This option allows creatures (pigs, pandas, zombies, etc.) to teleport through stargates if in a vehicle, even
|
||||
* if no player is in the vehicle.
|
||||
* As it is not possible to check if a creature is allowed through a stargate, they will be able to go through
|
||||
* regardless of whether the initiating player is allowed to enter the stargate. Enabling this is necessary to
|
||||
* teleport creatures using minecarts, but only handleCreatureTransportation is required to teleport creatures
|
||||
* using a boat manned by a player.</p>
|
||||
*
|
||||
* @return <p>Whether non-empty vehicles without a player should be handled</p>
|
||||
*/
|
||||
public boolean handleNonPlayerVehicles() {
|
||||
return handleNonPlayerVehicles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether leashed creatures should be teleported with a teleporting player
|
||||
*
|
||||
* @return <p>Whether leashed creatures should be handled</p>
|
||||
*/
|
||||
public boolean handleLeashedCreatures() {
|
||||
return handleLeashedCreatures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the list of destinations within a network should be sorted
|
||||
*
|
||||
* @return <p>Whether network destinations should be sorted</p>
|
||||
*/
|
||||
public boolean sortNetworkDestinations() {
|
||||
return sortNetworkDestinations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether portal entrances should be protected from block breaking
|
||||
*
|
||||
* @return <p>Whether portal entrances should be protected</p>
|
||||
*/
|
||||
public boolean protectEntrance() {
|
||||
return protectEntrance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether BungeeCord support is enabled
|
||||
*
|
||||
* @return <p>Whether bungee support is enabled</p>
|
||||
*/
|
||||
public boolean enableBungee() {
|
||||
return enableBungee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether all portals' integrity has to be verified on startup and reload
|
||||
*
|
||||
* @return <p>Whether portals need to be verified</p>
|
||||
*/
|
||||
public boolean verifyPortals() {
|
||||
return verifyPortals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether portals should be destroyed by nearby explosions
|
||||
*
|
||||
* @return <p>Whether portals should be destroyed by explosions</p>
|
||||
*/
|
||||
public boolean destroyedByExplosion() {
|
||||
return destroyExplosion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default portal network to use if no other network is given
|
||||
*
|
||||
* @return <p>The default portal network</p>
|
||||
*/
|
||||
public String getDefaultPortalNetwork() {
|
||||
return defaultGateNetwork;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all config values related to gates
|
||||
*
|
||||
* @param newConfig <p>The configuration containing the values to read</p>
|
||||
*/
|
||||
private void loadGateConfig(FileConfiguration newConfig) {
|
||||
String defaultNetwork = newConfig.getString("gates.defaultGateNetwork");
|
||||
defaultGateNetwork = defaultNetwork != null ? defaultNetwork.trim() : null;
|
||||
maxGatesEachNetwork = newConfig.getInt("gates.maxGatesEachNetwork");
|
||||
|
||||
//Functionality
|
||||
handleVehicles = newConfig.getBoolean("gates.functionality.handleVehicles");
|
||||
handleEmptyVehicles = newConfig.getBoolean("gates.functionality.handleEmptyVehicles");
|
||||
handleCreatureTransportation = newConfig.getBoolean("gates.functionality.handleCreatureTransportation");
|
||||
handleNonPlayerVehicles = newConfig.getBoolean("gates.functionality.handleNonPlayerVehicles");
|
||||
handleLeashedCreatures = newConfig.getBoolean("gates.functionality.handleLeashedCreatures");
|
||||
enableBungee = newConfig.getBoolean("gates.functionality.enableBungee");
|
||||
|
||||
//Integrity
|
||||
protectEntrance = newConfig.getBoolean("gates.integrity.protectEntrance");
|
||||
verifyPortals = newConfig.getBoolean("gates.integrity.verifyPortals");
|
||||
destroyExplosion = newConfig.getBoolean("gates.integrity.destroyedByExplosion");
|
||||
|
||||
//Cosmetic
|
||||
sortNetworkDestinations = newConfig.getBoolean("gates.cosmetic.sortNetworkDestinations");
|
||||
rememberDestination = newConfig.getBoolean("gates.cosmetic.rememberDestination");
|
||||
loadSignColor(newConfig.getString("gates.cosmetic.mainSignColor"),
|
||||
newConfig.getString("gates.cosmetic.highlightSignColor"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the correct sign color given a sign color string
|
||||
*
|
||||
* @param mainSignColor <p>A string representing the main sign color</p>
|
||||
*/
|
||||
private void loadSignColor(String mainSignColor, String highlightSignColor) {
|
||||
if (mainSignColor != null) {
|
||||
try {
|
||||
PortalSignDrawer.setColors(ChatColor.valueOf(mainSignColor.toUpperCase()),
|
||||
ChatColor.valueOf(highlightSignColor.toUpperCase()));
|
||||
return;
|
||||
} catch (IllegalArgumentException | NullPointerException ignored) {
|
||||
}
|
||||
}
|
||||
Stargate.logWarning("You have specified an invalid color in your config.yml. Defaulting to BLACK and WHITE");
|
||||
PortalSignDrawer.setColors(ChatColor.BLACK, ChatColor.WHITE);
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package net.knarcraft.stargate.container;
|
||||
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.Material;
|
||||
|
||||
/**
|
||||
* Represents a request for changing a block into another material
|
||||
*/
|
||||
public class BlockChangeRequest {
|
||||
|
||||
private final BlockLocation blockLocation;
|
||||
private final Material newMaterial;
|
||||
private final Axis newAxis;
|
||||
|
||||
/**
|
||||
* Instantiates a new block change request
|
||||
*
|
||||
* @param blockLocation <p>The location of the block to change</p>
|
||||
* @param material <p>The new material to change the block to</p>
|
||||
* @param axis <p>The new axis to orient the block along</p>
|
||||
*/
|
||||
public BlockChangeRequest(BlockLocation blockLocation, Material material, Axis axis) {
|
||||
this.blockLocation = blockLocation;
|
||||
newMaterial = material;
|
||||
newAxis = axis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the block to change
|
||||
*
|
||||
* @return <p>The location of the block</p>
|
||||
*/
|
||||
public BlockLocation getBlockLocation() {
|
||||
return blockLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the material to change the block into
|
||||
*
|
||||
* @return <p>The material to change the block into</p>
|
||||
*/
|
||||
public Material getMaterial() {
|
||||
return newMaterial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the axis to orient the block along
|
||||
*
|
||||
* @return <p>The axis to orient the block along</p>
|
||||
*/
|
||||
public Axis getAxis() {
|
||||
return newAxis;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,227 @@
|
||||
package net.knarcraft.stargate.container;
|
||||
|
||||
import net.knarcraft.stargate.utility.DirectionHelper;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Directional;
|
||||
import org.bukkit.block.data.type.Sign;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
/**
|
||||
* This class represents a block location
|
||||
*
|
||||
* <p>The BlockLocation class is basically a Location with some extra functionality.
|
||||
* Warning: Because of differences in the equals methods between Location and BlockLocation, a BlockLocation which
|
||||
* equals another BlockLocation does not necessarily equal the same BlockLocation if treated as a Location.</p>
|
||||
*/
|
||||
public class BlockLocation extends Location {
|
||||
|
||||
private BlockLocation parent = null;
|
||||
|
||||
/**
|
||||
* Creates a new block location
|
||||
*
|
||||
* @param world <p>The world the block exists in</p>
|
||||
* @param x <p>The x coordinate of the block</p>
|
||||
* @param y <p>The y coordinate of the block</p>
|
||||
* @param z <p>The z coordinate of the block</p>
|
||||
*/
|
||||
public BlockLocation(World world, int x, int y, int z) {
|
||||
super(world, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a block location from a block
|
||||
*
|
||||
* @param block <p>The block to get the location of</p>
|
||||
*/
|
||||
public BlockLocation(Block block) {
|
||||
super(block.getWorld(), block.getX(), block.getY(), block.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a block location from a string
|
||||
*
|
||||
* @param world <p>The world the block exists in</p>
|
||||
* @param string <p>A comma separated list of x, y and z coordinates as integers</p>
|
||||
*/
|
||||
public BlockLocation(World world, String string) {
|
||||
super(world, Integer.parseInt(string.split(",")[0]), Integer.parseInt(string.split(",")[1]),
|
||||
Integer.parseInt(string.split(",")[2]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new block location in a relative position to this block location
|
||||
*
|
||||
* @param x <p>The number of blocks to move in the x-direction</p>
|
||||
* @param y <p>The number of blocks to move in the y-direction</p>
|
||||
* @param z <p>The number of blocks to move in the z-direction</p>
|
||||
* @return <p>A new block location</p>
|
||||
*/
|
||||
public BlockLocation makeRelativeBlockLocation(int x, int y, int z) {
|
||||
return (BlockLocation) this.clone().add(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a location in a relative position to this block location
|
||||
*
|
||||
* @param x <p>The number of blocks to move in the x-direction</p>
|
||||
* @param y <p>The number of blocks to move in the y-direction</p>
|
||||
* @param z <p>The z position relative to this block's position</p>
|
||||
* @param yaw <p>The number of blocks to move in the z-direction</p>
|
||||
* @return <p>A new location</p>
|
||||
*/
|
||||
public Location makeRelativeLocation(double x, double y, double z, float yaw) {
|
||||
Location newLocation = this.clone();
|
||||
newLocation.setYaw(yaw);
|
||||
newLocation.setPitch(0);
|
||||
return newLocation.add(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a location relative to this block location
|
||||
*
|
||||
* @param relativeVector <p>The relative block vector describing the relative location</p>
|
||||
* @param yaw <p>The yaw pointing outwards from a portal (in the relative vector's out direction)</p>
|
||||
* @return <p>A location relative to this location</p>
|
||||
*/
|
||||
public BlockLocation getRelativeLocation(RelativeBlockVector relativeVector, double yaw) {
|
||||
Vector realVector = DirectionHelper.getCoordinateVectorFromRelativeVector(relativeVector.getRight(),
|
||||
relativeVector.getDown(), relativeVector.getOut(), yaw);
|
||||
return makeRelativeBlockLocation(realVector.getBlockX(), realVector.getBlockY(), realVector.getBlockZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a location relative to the current location according to given parameters
|
||||
*
|
||||
* <p>Out goes in the direction of the yaw. Right goes in the direction of (yaw - 90) degrees.
|
||||
* Depth goes downwards following the -y direction.</p>
|
||||
*
|
||||
* @param right <p>The amount of blocks to go right when looking towards a portal</p>
|
||||
* @param down <p>The amount of blocks to go downwards when looking towards a portal</p>
|
||||
* @param out <p>The amount of blocks to go outwards when looking towards a portal</p>
|
||||
* @param portalYaw <p>The yaw when looking out from the portal</p>
|
||||
* @return A new location relative to this block location
|
||||
*/
|
||||
public Location getRelativeLocation(double right, double down, double out, float portalYaw) {
|
||||
Vector realVector = DirectionHelper.getCoordinateVectorFromRelativeVector(right, down, out, portalYaw);
|
||||
return makeRelativeLocation(0.5 + realVector.getBlockX(), realVector.getBlockY(),
|
||||
0.5 + realVector.getBlockZ(), portalYaw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of block at this block location
|
||||
*
|
||||
* @return <p>The block's material type</p>
|
||||
*/
|
||||
public Material getType() {
|
||||
return this.getBlock().getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of block at this location
|
||||
*
|
||||
* @param type <p>The block's new material type</p>
|
||||
*/
|
||||
public void setType(Material type) {
|
||||
this.getBlock().setType(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location representing this block location
|
||||
*
|
||||
* @return <p>The location representing this block location</p>
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return this.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this block location's parent block
|
||||
*
|
||||
* <p>The parent block is the block the item at this block location is attached to. Usually this is the block a
|
||||
* sign or wall sign is attached to.</p>
|
||||
*
|
||||
* @return <p>This block location's parent block</p>
|
||||
*/
|
||||
public Block getParent() {
|
||||
if (parent == null) {
|
||||
findParent();
|
||||
}
|
||||
if (parent == null) {
|
||||
return null;
|
||||
}
|
||||
return parent.getBlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find the parent block location
|
||||
*
|
||||
* <p>If this block location is a sign, the parent is the block location of the block the sign is connected to.</p>
|
||||
*/
|
||||
private void findParent() {
|
||||
int offsetX = 0;
|
||||
int offsetY = 0;
|
||||
int offsetZ = 0;
|
||||
|
||||
BlockData blockData = getBlock().getBlockData();
|
||||
if (blockData instanceof Directional) {
|
||||
//Get the offset of the block "behind" this block
|
||||
BlockFace facing = ((Directional) blockData).getFacing().getOppositeFace();
|
||||
offsetX = facing.getModX();
|
||||
offsetZ = facing.getModZ();
|
||||
} else if (blockData instanceof Sign) {
|
||||
//Get offset the block beneath the sign
|
||||
offsetY = -1;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
parent = this.makeRelativeBlockLocation(offsetX, offsetY, offsetZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.valueOf(this.getBlockX()) + ',' + this.getBlockY() + ',' + this.getBlockZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 18;
|
||||
|
||||
result = result * 27 + this.getBlockX();
|
||||
result = result * 27 + this.getBlockY();
|
||||
result = result * 27 + this.getBlockZ();
|
||||
if (this.getWorld() != null) {
|
||||
result = result * 27 + this.getWorld().getName().hashCode();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
}
|
||||
if (object == null || getClass() != object.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockLocation blockLocation = (BlockLocation) object;
|
||||
|
||||
World thisWorld = this.getWorld();
|
||||
World otherWorld = blockLocation.getWorld();
|
||||
//Check if the worlds of the two locations match
|
||||
boolean worldsEqual = (thisWorld == null && otherWorld == null) || ((thisWorld != null && otherWorld != null)
|
||||
&& thisWorld == otherWorld);
|
||||
|
||||
//As this is a block location, only the block coordinates are compared
|
||||
return blockLocation.getBlockX() == this.getBlockX() && blockLocation.getBlockY() == this.getBlockY() &&
|
||||
blockLocation.getBlockZ() == this.getBlockZ() && worldsEqual;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package net.knarcraft.stargate.container;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a requests for the unloading of a chunk which has been previously loaded by the Stargate plugin
|
||||
*/
|
||||
public class ChunkUnloadRequest implements Comparable<ChunkUnloadRequest> {
|
||||
|
||||
private final Long unloadNanoTime;
|
||||
private final Chunk chunkToUnload;
|
||||
|
||||
/**
|
||||
* Instantiates a new chunk unloading request
|
||||
*
|
||||
* @param chunkToUnload <p>The chunk to request the unloading of</p>
|
||||
* @param timeUntilUnload <p>The time in milliseconds to wait before unloading the chunk</p>
|
||||
*/
|
||||
public ChunkUnloadRequest(Chunk chunkToUnload, Long timeUntilUnload) {
|
||||
this.chunkToUnload = chunkToUnload;
|
||||
long systemNanoTime = System.nanoTime();
|
||||
this.unloadNanoTime = systemNanoTime + (timeUntilUnload * 1000000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the chunk to unload
|
||||
*
|
||||
* @return <p>The chunk to unload</p>
|
||||
*/
|
||||
public Chunk getChunkToUnload() {
|
||||
return this.chunkToUnload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the system nano time denoting at which time the unload request should be executed
|
||||
*
|
||||
* @return <p>The system nano time denoting when the chunk is to be unloaded</p>
|
||||
*/
|
||||
public Long getUnloadNanoTime() {
|
||||
return this.unloadNanoTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" + chunkToUnload + ", " + unloadNanoTime + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull ChunkUnloadRequest otherRequest) {
|
||||
//Prioritize requests based on time until unload
|
||||
return unloadNanoTime.compareTo(otherRequest.unloadNanoTime);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package net.knarcraft.stargate.container;
|
||||
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* This class represents a player teleporting from the end to the over-world using an artificial end portal
|
||||
*
|
||||
* <p>This is necessary because a player entering an end portal in the end is a special case. Instead of being
|
||||
* teleported, the player is respawned. Because of this, the teleportation needs to be saved and later used to hijack
|
||||
* the position of where the player is to respawn.</p>
|
||||
*/
|
||||
public class FromTheEndTeleportation {
|
||||
|
||||
private final Player teleportingPlayer;
|
||||
private final Portal exitPortal;
|
||||
|
||||
/**
|
||||
* Instantiates a new teleportation from the end
|
||||
*
|
||||
* @param teleportingPlayer <p>The teleporting player</p>
|
||||
* @param exitPortal <p>The portal to exit from</p>
|
||||
*/
|
||||
public FromTheEndTeleportation(Player teleportingPlayer, Portal exitPortal) {
|
||||
this.teleportingPlayer = teleportingPlayer;
|
||||
this.exitPortal = exitPortal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the teleporting player
|
||||
*
|
||||
* @return <p>The teleporting player</p>
|
||||
*/
|
||||
public Player getPlayer() {
|
||||
return this.teleportingPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portal to exit from
|
||||
*
|
||||
* @return <p>The portal to exit from</p>
|
||||
*/
|
||||
public Portal getExit() {
|
||||
return this.exitPortal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return teleportingPlayer.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof FromTheEndTeleportation otherTeleportation)) {
|
||||
return false;
|
||||
}
|
||||
return teleportingPlayer.equals(otherTeleportation.teleportingPlayer);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
package net.knarcraft.stargate.container;
|
||||
|
||||
/**
|
||||
* This stores a block location as a vector relative to a position
|
||||
*
|
||||
* <p>A relative block vector stores a vector relative to some origin. The origin in this plugin is usually the
|
||||
* top-left block of a gate (top-left when looking at the side with the sign). The right is therefore the distance
|
||||
* from the top-left corner towards the top-right corner. Down is the distance from the top-left corner towards the
|
||||
* bottom-left corner. Out is the distance outward from the gate.</p>
|
||||
*/
|
||||
public class RelativeBlockVector {
|
||||
|
||||
private final int right;
|
||||
private final int down;
|
||||
private final int out;
|
||||
|
||||
/**
|
||||
* A specifier for one of the relative block vector's three properties
|
||||
*/
|
||||
public enum Property {
|
||||
/**
|
||||
* Specifies the relative block vector's right property
|
||||
*/
|
||||
RIGHT,
|
||||
/**
|
||||
* Specifies the relative block vector's down property
|
||||
*/
|
||||
DOWN,
|
||||
/**
|
||||
* Specifies the relative block vector's out property
|
||||
*/
|
||||
OUT
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new relative block vector
|
||||
*
|
||||
* <p>Relative block vectors start from a top-left corner. A yaw is used to orient a relative block vector in the
|
||||
* "real world".
|
||||
* In terms of a gate layout, the origin is 0,0. Right is towards the end of the line. Down is to the
|
||||
* next line. Out is towards the observer.</p>
|
||||
*
|
||||
* @param right <p>The distance rightward relative to the origin</p>
|
||||
* @param down <p>The distance downward relative to the origin</p>
|
||||
* @param out <p>The distance outward relative to the origin</p>
|
||||
*/
|
||||
public RelativeBlockVector(int right, int down, int out) {
|
||||
this.right = right;
|
||||
this.down = down;
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to one of the properties of this relative block vector
|
||||
*
|
||||
* @param propertyToAddTo <p>The property to add to</p>
|
||||
* @param valueToAdd <p>The value to add to the property (negative to move in the opposite direction)</p>
|
||||
* @return <p>A new relative block vector with the property altered</p>
|
||||
*/
|
||||
public RelativeBlockVector addToVector(Property propertyToAddTo, int valueToAdd) {
|
||||
switch (propertyToAddTo) {
|
||||
case RIGHT:
|
||||
return new RelativeBlockVector(this.right + valueToAdd, this.down, this.out);
|
||||
case DOWN:
|
||||
return new RelativeBlockVector(this.right, this.down + valueToAdd, this.out);
|
||||
case OUT:
|
||||
return new RelativeBlockVector(this.right, this.down, this.out + valueToAdd);
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid relative block vector property given");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a relative block vector which is this inverted (pointing in the opposite direction)
|
||||
*
|
||||
* @return <p>This vector, but inverted</p>
|
||||
*/
|
||||
public RelativeBlockVector invert() {
|
||||
return new RelativeBlockVector(-this.right, -this.down, -this.out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the distance to the right relative to the origin
|
||||
*
|
||||
* @return <p>The distance to the right relative to the origin</p>
|
||||
*/
|
||||
public int getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the distance downward relative to the origin
|
||||
*
|
||||
* @return <p>The distance downward relative to the origin</p>
|
||||
*/
|
||||
public int getDown() {
|
||||
return down;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the distance outward relative to the origin
|
||||
*
|
||||
* @return <p>The distance outward relative to the origin</p>
|
||||
*/
|
||||
public int getOut() {
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("(right = %d, down = %d, out = %d)", right, down, out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) {
|
||||
return true;
|
||||
}
|
||||
if (other == null || this.getClass() != other.getClass()) {
|
||||
return false;
|
||||
}
|
||||
RelativeBlockVector otherVector = (RelativeBlockVector) other;
|
||||
return this.right == otherVector.right && this.down == otherVector.down &&
|
||||
this.out == otherVector.out;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package net.knarcraft.stargate.event;
|
||||
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* This event should be called whenever a player attempts to access a stargate
|
||||
*
|
||||
* <p>This event is triggered whenever a player enters or activates a stargate. This event can be used to override
|
||||
* whether the player should be allowed to access the stargate.</p>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class StargateAccessEvent extends StargatePlayerEvent {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private boolean deny;
|
||||
|
||||
/**
|
||||
* Instantiates a new stargate access event
|
||||
*
|
||||
* @param player <p>The player involved in the event</p>
|
||||
* @param portal <p>The portal involved in the event</p>
|
||||
* @param deny <p>Whether the stargate access should be denied</p>
|
||||
*/
|
||||
public StargateAccessEvent(Player player, Portal portal, boolean deny) {
|
||||
super(portal, player);
|
||||
|
||||
this.deny = deny;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the player should be denied access
|
||||
*
|
||||
* @return <p>Whether the player should be denied access</p>
|
||||
*/
|
||||
public boolean getDeny() {
|
||||
return this.deny;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to deny access to the player
|
||||
*
|
||||
* @param deny <p>Whether to deny access to the player</p>
|
||||
*/
|
||||
public void setDeny(boolean deny) {
|
||||
this.deny = deny;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a handler-list containing all event handlers
|
||||
*
|
||||
* @return <p>A handler-list with all event handlers</p>
|
||||
*/
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package net.knarcraft.stargate.event;
|
||||
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This event should be called whenever a player activates a stargate
|
||||
*
|
||||
* <p>Activation of a stargate happens when a player right-clicks the sign of a stargate.
|
||||
* This event can be used to overwrite the selected destination, and all destinations the player can see.</p>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class StargateActivateEvent extends StargatePlayerEvent {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private List<String> destinations;
|
||||
private String destination;
|
||||
|
||||
/**
|
||||
* Instantiates a new stargate activate event
|
||||
*
|
||||
* @param portal <p>The activated portal</p>
|
||||
* @param player <p>The player activating the portal</p>
|
||||
* @param destinations <p>The destinations available to the player using the portal</p>
|
||||
* @param destination <p>The currently selected destination</p>
|
||||
*/
|
||||
public StargateActivateEvent(Portal portal, Player player, List<String> destinations, String destination) {
|
||||
super(portal, player);
|
||||
|
||||
this.destinations = destinations;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the destinations available for the portal
|
||||
*
|
||||
* @return <p>The destinations available for the portal</p>
|
||||
*/
|
||||
public List<String> getDestinations() {
|
||||
return destinations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the destinations available to the player using the portal
|
||||
*
|
||||
* @param destinations <p>The new list of available destinations</p>
|
||||
*/
|
||||
public void setDestinations(List<String> destinations) {
|
||||
this.destinations = destinations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the selected destination
|
||||
*
|
||||
* @return <p>The selected destination</p>
|
||||
*/
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (changes) the selected destination
|
||||
*
|
||||
* @param destination <p>The new selected destination</p>
|
||||
*/
|
||||
public void setDestination(String destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a handler-list containing all event handlers
|
||||
*
|
||||
* @return <p>A handler-list with all event handlers</p>
|
||||
*/
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package net.knarcraft.stargate.event;
|
||||
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* This event should be called whenever a stargate is closed
|
||||
*
|
||||
* <p>This event can be used to overwrite whether the stargate should be forced to close, even if it's set as
|
||||
* always-on.</p>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class StargateCloseEvent extends StargateEvent {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private boolean force;
|
||||
|
||||
/**
|
||||
* Instantiates a new stargate closing event
|
||||
*
|
||||
* @param portal <p>The portal to close</p>
|
||||
* @param force <p>Whether to force the gate to close, even if set as always-on</p>
|
||||
*/
|
||||
public StargateCloseEvent(Portal portal, boolean force) {
|
||||
super(portal);
|
||||
|
||||
this.force = force;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to force the stargate to close
|
||||
*
|
||||
* @return <p>Whether to force the stargate to close</p>
|
||||
*/
|
||||
public boolean getForce() {
|
||||
return force;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the stargate should be forced to close
|
||||
*
|
||||
* @param force <p>Whether the stargate should be forced to close</p>
|
||||
*/
|
||||
public void setForce(boolean force) {
|
||||
this.force = force;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a handler-list containing all event handlers
|
||||
*
|
||||
* @return <p>A handler-list with all event handlers</p>
|
||||
*/
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
package net.knarcraft.stargate.event;
|
||||
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* This event should be called whenever a stargate is created
|
||||
*
|
||||
* <p>This event can be used to deny or change the cost of a stargate creation.</p>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class StargateCreateEvent extends StargatePlayerEvent {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private final String[] lines;
|
||||
private boolean deny;
|
||||
private String denyReason;
|
||||
private int cost;
|
||||
|
||||
/**
|
||||
* Instantiates a new stargate creation event
|
||||
*
|
||||
* @param player <p>Thg player creating the stargate</p>
|
||||
* @param portal <p>The created portal</p>
|
||||
* @param lines <p>The lines of the sign creating the star gate</p>
|
||||
* @param deny <p>Whether to deny the creation of the new gate</p>
|
||||
* @param denyReason <p>The reason stargate creation was denied</p>
|
||||
* @param cost <p>The cost of creating the new star gate</p>
|
||||
*/
|
||||
public StargateCreateEvent(Player player, Portal portal, String[] lines, boolean deny, String denyReason, int cost) {
|
||||
super(portal, player);
|
||||
this.lines = lines;
|
||||
this.deny = deny;
|
||||
this.denyReason = denyReason;
|
||||
this.cost = cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a given line from the sign creating the star gate
|
||||
*
|
||||
* @param index <p>The line number to get</p>
|
||||
* @return <p>The text on the given line</p>
|
||||
* @throws IndexOutOfBoundsException <p>If given a line index less than zero or above three</p>
|
||||
*/
|
||||
public String getLine(int index) throws IndexOutOfBoundsException {
|
||||
return lines[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the stargate creation should be denied
|
||||
*
|
||||
* @return <p>Whether the stargate creation should be denied</p>
|
||||
*/
|
||||
public boolean getDeny() {
|
||||
return deny;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the stargate creation should be denied
|
||||
*
|
||||
* @param deny <p>Whether the stargate creation should be denied</p>
|
||||
*/
|
||||
public void setDeny(boolean deny) {
|
||||
this.deny = deny;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reason the stargate creation was denied
|
||||
*
|
||||
* @return <p>The reason the stargate creation was denied</p>
|
||||
*/
|
||||
public String getDenyReason() {
|
||||
return denyReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the reason the stargate creation was denied
|
||||
*
|
||||
* @param denyReason <p>The new reason why the stargate creation was denied</p>
|
||||
*/
|
||||
public void setDenyReason(String denyReason) {
|
||||
this.denyReason = denyReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cost of creating the stargate
|
||||
*
|
||||
* @return <p>The cost of creating the stargate</p>
|
||||
*/
|
||||
public int getCost() {
|
||||
return cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cost of creating the stargate
|
||||
*
|
||||
* @param cost <p>The new cost of creating the stargate</p>
|
||||
*/
|
||||
public void setCost(int cost) {
|
||||
this.cost = cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a handler-list containing all event handlers
|
||||
*
|
||||
* @return <p>A handler-list with all event handlers</p>
|
||||
*/
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package net.knarcraft.stargate.event;
|
||||
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* This event should be called whenever a stargate is deactivated
|
||||
*
|
||||
* <p>A deactivation is usually caused by no activity for a set amount of time.
|
||||
* This event can only be used to listen for de-activation events.</p>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class StargateDeactivateEvent extends StargateEvent {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
/**
|
||||
* Instantiates a new stargate deactivation event
|
||||
*
|
||||
* @param portal <p>The portal which was deactivated</p>
|
||||
*/
|
||||
public StargateDeactivateEvent(Portal portal) {
|
||||
super(portal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a handler-list containing all event handlers
|
||||
*
|
||||
* @return <p>A handler-list with all event handlers</p>
|
||||
*/
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
package net.knarcraft.stargate.event;
|
||||
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* This event should be called whenever a stargate is destroyed
|
||||
*
|
||||
* <p>This event can be used to deny or change the cost of a stargate destruction.</p>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class StargateDestroyEvent extends StargatePlayerEvent {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private boolean deny;
|
||||
private String denyReason;
|
||||
private int cost;
|
||||
|
||||
/**
|
||||
* Instantiates a new Stargate Destroy Event
|
||||
*
|
||||
* @param portal <p>The destroyed portal</p>
|
||||
* @param player <p>The player destroying the portal</p>
|
||||
* @param deny <p>Whether the event should be denied (cancelled)</p>
|
||||
* @param denyMsg <p>The message to display if the event is denied</p>
|
||||
* @param cost <p>The cost of destroying the portal</p>
|
||||
*/
|
||||
public StargateDestroyEvent(Portal portal, Player player, boolean deny, String denyMsg, int cost) {
|
||||
super(portal, player);
|
||||
this.deny = deny;
|
||||
this.denyReason = denyMsg;
|
||||
this.cost = cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this event should be denied
|
||||
*
|
||||
* @return <p>Whether this event should be denied</p>
|
||||
*/
|
||||
public boolean getDeny() {
|
||||
return deny;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this event should be denied
|
||||
*
|
||||
* @param deny <p>Whether this event should be denied</p>
|
||||
*/
|
||||
public void setDeny(boolean deny) {
|
||||
this.deny = deny;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reason the event was denied
|
||||
*
|
||||
* @return <p>The reason the event was denied</p>
|
||||
*/
|
||||
public String getDenyReason() {
|
||||
return denyReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the reason the event was denied
|
||||
*
|
||||
* @param denyReason <p>The reason the event was denied</p>
|
||||
*/
|
||||
public void setDenyReason(String denyReason) {
|
||||
this.denyReason = denyReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cost of destroying the portal
|
||||
*
|
||||
* @return <p>The cost of destroying the portal</p>
|
||||
*/
|
||||
public int getCost() {
|
||||
return cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cost of destroying the portal
|
||||
*
|
||||
* @param cost <p>The cost of destroying the portal</p>
|
||||
*/
|
||||
public void setCost(int cost) {
|
||||
this.cost = cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a handler-list containing all event handlers
|
||||
*
|
||||
* @return <p>A handler-list with all event handlers</p>
|
||||
*/
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package net.knarcraft.stargate.event;
|
||||
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* This event should be called whenever a non-player teleports through a stargate
|
||||
*
|
||||
* <p>This event can be used to overwrite the location the entity is teleported to.</p>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class StargateEntityPortalEvent extends StargateEvent {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
final Entity travellingEntity;
|
||||
private final Portal destination;
|
||||
private Location exit;
|
||||
|
||||
/**
|
||||
* Instantiates a new stargate portal event
|
||||
*
|
||||
* @param travellingEntity <p>The entity travelling through this portal</p>
|
||||
* @param portal <p>The portal the entity entered from</p>
|
||||
* @param destination <p>The destination the entity should exit from</p>
|
||||
* @param exit <p>The exit location of the destination portal the entity will be teleported to</p>
|
||||
*/
|
||||
public StargateEntityPortalEvent(Entity travellingEntity, Portal portal, Portal destination, Location exit) {
|
||||
super(portal);
|
||||
|
||||
this.travellingEntity = travellingEntity;
|
||||
this.destination = destination;
|
||||
this.exit = exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the non-player entity teleporting
|
||||
*
|
||||
* @return <p>The non-player teleporting</p>
|
||||
*/
|
||||
public Entity getEntity() {
|
||||
return travellingEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the destination portal
|
||||
*
|
||||
* @return <p>The destination portal</p>
|
||||
*/
|
||||
public Portal getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location of the players exit point
|
||||
*
|
||||
* @return <p>Location of the exit point</p>
|
||||
*/
|
||||
public Location getExit() {
|
||||
return exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the location of the entity's exit point
|
||||
*
|
||||
* @param location <p>The new location of the entity's exit point</p>
|
||||
*/
|
||||
public void setExit(Location location) {
|
||||
this.exit = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a handler-list containing all event handlers
|
||||
*
|
||||
* @return <p>A handler-list with all event handlers</p>
|
||||
*/
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package net.knarcraft.stargate.event;
|
||||
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
|
||||
/**
|
||||
* An abstract event describing any stargate event
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class StargateEvent extends Event implements Cancellable {
|
||||
|
||||
private final Portal portal;
|
||||
private boolean cancelled;
|
||||
|
||||
/**
|
||||
* Instantiates a new stargate event
|
||||
*
|
||||
* @param portal <p>The portal involved in this stargate event</p>
|
||||
*/
|
||||
StargateEvent(Portal portal) {
|
||||
this.portal = portal;
|
||||
this.cancelled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portal involved in this stargate event
|
||||
*
|
||||
* @return <p>The portal involved in this stargate event</p>
|
||||
*/
|
||||
public Portal getPortal() {
|
||||
return portal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancelled) {
|
||||
this.cancelled = cancelled;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package net.knarcraft.stargate.event;
|
||||
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* This event should be called whenever a player opens a stargate
|
||||
*
|
||||
* <p>This event can be used to overwrite whether the stargate should be forced to open, even if it's already open.</p>
|
||||
*/
|
||||
@SuppressWarnings({"unused"})
|
||||
public class StargateOpenEvent extends StargatePlayerEvent {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private boolean force;
|
||||
|
||||
/**
|
||||
* Instantiates a new stargate open event
|
||||
*
|
||||
* @param player <p>The player opening the stargate</p>
|
||||
* @param portal <p>The opened portal</p>
|
||||
* @param force <p>Whether to force the portal open</p>
|
||||
*/
|
||||
public StargateOpenEvent(Player player, Portal portal, boolean force) {
|
||||
super(portal, player);
|
||||
|
||||
this.force = force;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the portal should be forced open
|
||||
*
|
||||
* @return <p>Whether the portal should be forced open</p>
|
||||
*/
|
||||
public boolean getForce() {
|
||||
return force;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the portal should be forced open
|
||||
*
|
||||
* @param force <p>Whether the portal should be forced open</p>
|
||||
*/
|
||||
public void setForce(boolean force) {
|
||||
this.force = force;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a handler-list containing all event handlers
|
||||
*
|
||||
* @return <p>A handler-list with all event handlers</p>
|
||||
*/
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package net.knarcraft.stargate.event;
|
||||
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* An abstract event describing any stargate event where a player is involved
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class StargatePlayerEvent extends StargateEvent {
|
||||
|
||||
private final Player player;
|
||||
|
||||
/**
|
||||
* Instantiates a new stargate player event
|
||||
*
|
||||
* @param portal <p>The portal involved in this stargate event</p>
|
||||
*/
|
||||
StargatePlayerEvent(Portal portal, Player player) {
|
||||
super(portal);
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player creating the star gate
|
||||
*
|
||||
* @return <p>The player creating the star gate</p>
|
||||
*/
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package net.knarcraft.stargate.event;
|
||||
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* This event should be called whenever a player teleports through a stargate
|
||||
*
|
||||
* <p>This event can be used to overwrite the location the player is teleported to.</p>
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class StargatePlayerPortalEvent extends StargatePlayerEvent {
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private final Portal destination;
|
||||
private Location exit;
|
||||
|
||||
/**
|
||||
* Instantiates a new stargate player portal event
|
||||
*
|
||||
* @param player <p>The player teleporting</p>
|
||||
* @param portal <p>The portal the player entered from</p>
|
||||
* @param destination <p>The destination the player should exit from</p>
|
||||
* @param exit <p>The exit location of the destination portal the user will be teleported to</p>
|
||||
*/
|
||||
public StargatePlayerPortalEvent(Player player, Portal portal, Portal destination, Location exit) {
|
||||
super(portal, player);
|
||||
|
||||
this.destination = destination;
|
||||
this.exit = exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the destination portal
|
||||
*
|
||||
* @return <p>The destination portal</p>
|
||||
*/
|
||||
public Portal getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location of the players exit point
|
||||
*
|
||||
* @return <p>Location of the exit point</p>
|
||||
*/
|
||||
public Location getExit() {
|
||||
return exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the location of the player's exit point
|
||||
*
|
||||
* @param location <p>The new location of the player's exit point</p>
|
||||
*/
|
||||
public void setExit(Location location) {
|
||||
this.exit = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a handler-list containing all event handlers
|
||||
*
|
||||
* @return <p>A handler-list with all event handlers</p>
|
||||
*/
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
}
|
25
src/main/java/net/knarcraft/stargate/event/package-info.java
Normal file
25
src/main/java/net/knarcraft/stargate/event/package-info.java
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Events for any plugins wanting to interact with the Stargate plugin
|
||||
*
|
||||
* <p>This package contains several events used for interactions with Stargate. All events can be cancelled. For
|
||||
* several of the events, it is possible to overrule permissions. A general overview of the events' usage:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>The StargateAccessEvent is called whenever a player clicks a stargate's sign, and when a player enters a
|
||||
* Stargate. It can be used to override whether the access should be allowed or denied.</li>
|
||||
* <li>The StargateActivateEvent is called whenever a player activates a stargate (uses the stargate's sign). It
|
||||
* can be used to override which destinations are available to the player.</li>
|
||||
* <li>The StargateCloseEvent is called whenever a stargate is closed. Forcing the stargate closed can be toggled.</li>
|
||||
* <li>The StargateCreateEvent is called whenever a new stargate is created. Its deny value can be overridden, the
|
||||
* cost can be changed</li>
|
||||
* <li>The StargateDeactivateEvent is called whenever a stargate is deactivated.</li>
|
||||
* <li>The StargateDestroyEvent is called whenever a stargate is destroyed. Its deny value can be overridden or the
|
||||
* cost can be changed.</li>
|
||||
* <li>The StargateEntityPortalEvent is called whenever an entity teleports through a stargate. The exit location
|
||||
* can be changed.</li>
|
||||
* <li>The StargateOpenEvent is called whenever a stargate is opened. Forcing the stargate open can be toggled.</li>
|
||||
* <li>The StargatePlayerPortalEvent is called whenever a player teleports through a stargate. The exit location can
|
||||
* be changed.</li>
|
||||
* </ul>
|
||||
*/
|
||||
package net.knarcraft.stargate.event;
|
@ -0,0 +1,252 @@
|
||||
package net.knarcraft.stargate.listener;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.event.StargateDestroyEvent;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import net.knarcraft.stargate.portal.PortalCreator;
|
||||
import net.knarcraft.stargate.portal.PortalHandler;
|
||||
import net.knarcraft.stargate.portal.PortalRegistry;
|
||||
import net.knarcraft.stargate.utility.EconomyHelper;
|
||||
import net.knarcraft.stargate.utility.MaterialHelper;
|
||||
import net.knarcraft.stargate.utility.PermissionHelper;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.type.WallSign;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Snowman;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockFromToEvent;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
import org.bukkit.event.block.BlockPistonEvent;
|
||||
import org.bukkit.event.block.BlockPistonExtendEvent;
|
||||
import org.bukkit.event.block.BlockPistonRetractEvent;
|
||||
import org.bukkit.event.block.EntityBlockFormEvent;
|
||||
import org.bukkit.event.block.SignChangeEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is responsible for listening to relevant block events related to creating and breaking portals
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class BlockEventListener implements Listener {
|
||||
|
||||
/**
|
||||
* Detects snowmen ruining portals
|
||||
*
|
||||
* <p>If entrance protection or portal verification is enabled, the snowman will be prevented from placing snow in
|
||||
* the portal entrance.</p>
|
||||
*
|
||||
* @param event <p>The triggered event</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onBlockFormedByEntity(EntityBlockFormEvent event) {
|
||||
if (event.isCancelled() || (!Stargate.getGateConfig().protectEntrance() &&
|
||||
!Stargate.getGateConfig().verifyPortals())) {
|
||||
return;
|
||||
}
|
||||
//We are only interested in snowman events
|
||||
if (!(event.getEntity() instanceof Snowman)) {
|
||||
return;
|
||||
}
|
||||
//Cancel the event if a snowman is trying to place snow in the portal's entrance
|
||||
if (PortalHandler.getByEntrance(event.getBlock()) != null) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects sign changes to detect if the user is creating a new gate
|
||||
*
|
||||
* @param event <p>The triggered event</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onSignChange(SignChangeEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
Player player = event.getPlayer();
|
||||
Block block = event.getBlock();
|
||||
//Ignore normal signs
|
||||
if (!(block.getBlockData() instanceof WallSign)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Portal portal = new PortalCreator(event, player).createPortal();
|
||||
//Not creating a gate, just placing a sign
|
||||
if (portal == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("createMsg"));
|
||||
Stargate.debug("onSignChange", "Initialized stargate: " + portal.getName());
|
||||
Stargate.getInstance().getServer().getScheduler().scheduleSyncDelayedTask(Stargate.getInstance(),
|
||||
portal::drawSign, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects block breaking to detect if the user is destroying a gate
|
||||
*
|
||||
* @param event <p>The triggered event</p>
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
Block block = event.getBlock();
|
||||
Player player = event.getPlayer();
|
||||
|
||||
//Decide if a portal is broken
|
||||
Portal portal = PortalHandler.getByBlock(block);
|
||||
if (portal == null && Stargate.getGateConfig().protectEntrance()) {
|
||||
portal = PortalHandler.getByEntrance(block);
|
||||
}
|
||||
if (portal == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean deny = false;
|
||||
String denyMessage = "";
|
||||
|
||||
//Decide if the user can destroy the portal
|
||||
if (!PermissionHelper.canDestroyPortal(player, portal)) {
|
||||
denyMessage = Stargate.getString("denyMsg");
|
||||
deny = true;
|
||||
Stargate.logInfo(String.format("%s tried to destroy gate", player.getName()));
|
||||
}
|
||||
|
||||
int cost = Stargate.getEconomyConfig().getDestroyCost(player, portal.getGate());
|
||||
|
||||
//Create and call a StarGateDestroyEvent
|
||||
StargateDestroyEvent destroyEvent = new StargateDestroyEvent(portal, player, deny, denyMessage, cost);
|
||||
Stargate.getInstance().getServer().getPluginManager().callEvent(destroyEvent);
|
||||
if (destroyEvent.isCancelled()) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
//Destroy denied
|
||||
if (destroyEvent.getDeny()) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, destroyEvent.getDenyReason());
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
//Take care of payment transactions
|
||||
if (!handleEconomyPayment(destroyEvent, player, portal, event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PortalRegistry.unregisterPortal(portal, true);
|
||||
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("destroyMsg"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles economy payment for breaking the portal
|
||||
*
|
||||
* @param destroyEvent <p>The destroy event</p>
|
||||
* @param player <p>The player which triggered the event</p>
|
||||
* @param portal <p>The broken portal</p>
|
||||
* @param event <p>The break event</p>
|
||||
* @return <p>True if the payment was successful. False if the event was cancelled</p>
|
||||
*/
|
||||
private boolean handleEconomyPayment(StargateDestroyEvent destroyEvent, Player player, Portal portal,
|
||||
BlockBreakEvent event) {
|
||||
int cost = destroyEvent.getCost();
|
||||
if (cost != 0) {
|
||||
String portalName = portal.getName();
|
||||
//Cannot pay
|
||||
if (!Stargate.getEconomyConfig().chargePlayerIfNecessary(player, cost)) {
|
||||
Stargate.debug("onBlockBreak", "Insufficient Funds");
|
||||
EconomyHelper.sendInsufficientFundsMessage(portalName, player, cost);
|
||||
event.setCancelled(true);
|
||||
return false;
|
||||
}
|
||||
//Tell the player they've paid or deceived money
|
||||
if (cost > 0) {
|
||||
EconomyHelper.sendDeductMessage(portalName, player, cost);
|
||||
} else {
|
||||
EconomyHelper.sendRefundMessage(portalName, player, cost);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents any block physics events which may damage parts of the portal
|
||||
*
|
||||
* @param event <p>The event to check and possibly cancel</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onBlockPhysics(BlockPhysicsEvent event) {
|
||||
Block block = event.getBlock();
|
||||
Portal portal = null;
|
||||
|
||||
if (block.getType() == Material.NETHER_PORTAL) {
|
||||
portal = PortalHandler.getByEntrance(block);
|
||||
} else if (MaterialHelper.isButtonCompatible(block.getType())) {
|
||||
portal = PortalHandler.getByControl(block);
|
||||
}
|
||||
if (portal != null) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels any block move events which may cause a block to enter the opening of a portal
|
||||
*
|
||||
* @param event <p>The event to check and possibly cancel</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onBlockFromTo(BlockFromToEvent event) {
|
||||
Portal portal = PortalHandler.getByEntrance(event.getBlock());
|
||||
|
||||
if (portal != null) {
|
||||
event.setCancelled((event.getBlock().getY() == event.getToBlock().getY()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels any piston extend events if the target block is part of a portal
|
||||
*
|
||||
* @param event <p>The event to check and possibly cancel</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onPistonExtend(BlockPistonExtendEvent event) {
|
||||
cancelPistonEvent(event, event.getBlocks());
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels any piston retract events if the target block is part of a portal
|
||||
*
|
||||
* @param event <p>The event to check and possibly cancel</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onPistonRetract(BlockPistonRetractEvent event) {
|
||||
if (!event.isSticky()) {
|
||||
return;
|
||||
}
|
||||
cancelPistonEvent(event, event.getBlocks());
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a piston event if it would destroy a portal
|
||||
*
|
||||
* @param event <p>The event to cancel</p>
|
||||
* @param blocks <p>The blocks included in the event</p>
|
||||
*/
|
||||
private void cancelPistonEvent(BlockPistonEvent event, List<Block> blocks) {
|
||||
for (Block block : blocks) {
|
||||
Portal portal = PortalHandler.getByBlock(block);
|
||||
if (portal != null) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package net.knarcraft.stargate.listener;
|
||||
|
||||
import net.knarcraft.stargate.utility.BungeeHelper;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* This listener teleports a user if a valid message is received from BungeeCord
|
||||
*
|
||||
* <p>Specifically, if a string starts with SGBungee encoded to be readable by readUTF followed by
|
||||
* [PlayerUUID]delimiter[DestinationPortal] is received on the BungeeCord channel, this listener will teleport the
|
||||
* player to the destination portal.</p>
|
||||
*/
|
||||
public class BungeeCordListener implements PluginMessageListener {
|
||||
|
||||
/**
|
||||
* Receives plugin messages
|
||||
*
|
||||
* @param channel <p>The channel the message was received on</p>
|
||||
* @param unused <p>Unused.</p>
|
||||
* @param message <p>The message received from the plugin</p>
|
||||
*/
|
||||
@Override
|
||||
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player unused, byte[] message) {
|
||||
//Ignore plugin messages if some other plugin message is received
|
||||
if (!channel.equals(BungeeHelper.getBungeeChannel())) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Try to read the plugin message
|
||||
String receivedMessage = BungeeHelper.readPluginMessage(message);
|
||||
if (receivedMessage == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Use the message to initiate teleportation
|
||||
BungeeHelper.handleTeleportMessage(receivedMessage);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package net.knarcraft.stargate.listener;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import net.knarcraft.stargate.portal.PortalHandler;
|
||||
import net.knarcraft.stargate.portal.PortalRegistry;
|
||||
import net.knarcraft.stargate.utility.EntityHelper;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
import org.bukkit.event.entity.EntityPortalEvent;
|
||||
|
||||
/**
|
||||
* This listener listens for any relevant events on portal entities
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class EntityEventListener implements Listener {
|
||||
|
||||
/**
|
||||
* This event handler prevents sending entities to the normal nether instead of the stargate target
|
||||
*
|
||||
* @param event <p>The event to check and possibly cancel</p>
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPortalEvent(EntityPortalEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entity entity = event.getEntity();
|
||||
//Cancel normal portal event is near a stargate
|
||||
if (PortalHandler.getByAdjacentEntrance(event.getFrom(), EntityHelper.getEntityMaxSizeInt(entity)) != null) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method catches any explosion events
|
||||
*
|
||||
* <p>If destroyed by explosions is enabled, any portals destroyed by the explosion will be unregistered. If not,
|
||||
* the explosion will be cancelled.</p>
|
||||
*
|
||||
* @param event <p>The triggered explosion event</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onEntityExplode(EntityExplodeEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
for (Block block : event.blockList()) {
|
||||
Portal portal = PortalHandler.getByBlock(block);
|
||||
if (portal == null) {
|
||||
continue;
|
||||
}
|
||||
if (Stargate.getGateConfig().destroyedByExplosion()) {
|
||||
PortalRegistry.unregisterPortal(portal, true);
|
||||
} else {
|
||||
event.setCancelled(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,314 @@
|
||||
package net.knarcraft.stargate.listener;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.portal.PlayerTeleporter;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import net.knarcraft.stargate.portal.PortalActivator;
|
||||
import net.knarcraft.stargate.portal.PortalHandler;
|
||||
import net.knarcraft.stargate.portal.VehicleTeleporter;
|
||||
import net.knarcraft.stargate.utility.BungeeHelper;
|
||||
import net.knarcraft.stargate.utility.MaterialHelper;
|
||||
import net.knarcraft.stargate.utility.PermissionHelper;
|
||||
import net.knarcraft.stargate.utility.UUIDMigrationHelper;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.type.WallSign;
|
||||
import org.bukkit.entity.AbstractHorse;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
|
||||
/**
|
||||
* This listener listens to any player-related events related to stargates
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class PlayerEventListener implements Listener {
|
||||
|
||||
private static long eventTime;
|
||||
private static PlayerInteractEvent previousEvent;
|
||||
|
||||
/**
|
||||
* This event handler handles detection of any player teleporting through a bungee gate
|
||||
*
|
||||
* @param event <p>The event to check for a teleporting player</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
//Migrate player name to UUID if necessary
|
||||
UUIDMigrationHelper.migrateUUID(event.getPlayer());
|
||||
|
||||
if (!Stargate.getGateConfig().enableBungee()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
//Check if the player is waiting to be teleported to a stargate
|
||||
String destination = BungeeHelper.removeFromQueue(player.getUniqueId());
|
||||
if (destination == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Portal portal = PortalHandler.getBungeePortal(destination);
|
||||
if (portal == null) {
|
||||
Stargate.debug("PlayerJoin", "Error fetching destination portal: " + destination);
|
||||
return;
|
||||
}
|
||||
//Teleport the player to the stargate
|
||||
new PlayerTeleporter(portal, player).teleport(portal, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This event handler detects if a player moves into a portal
|
||||
*
|
||||
* @param event <p>The player move event which was triggered</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
if (event.isCancelled() || event.getTo() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
BlockLocation fromLocation = new BlockLocation(event.getFrom().getBlock());
|
||||
BlockLocation toLocation = new BlockLocation(event.getTo().getBlock());
|
||||
Player player = event.getPlayer();
|
||||
|
||||
//Check whether the event needs to be considered
|
||||
if (!isRelevantMoveEvent(event, player, fromLocation, toLocation)) {
|
||||
return;
|
||||
}
|
||||
Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
|
||||
Portal destination = entrancePortal.getPortalActivator().getDestination(player);
|
||||
|
||||
Entity playerVehicle = player.getVehicle();
|
||||
//If the player is in a vehicle, but vehicle handling is disabled, just ignore the player
|
||||
if (playerVehicle == null || (playerVehicle instanceof LivingEntity &&
|
||||
Stargate.getGateConfig().handleVehicles())) {
|
||||
teleportPlayer(playerVehicle, player, entrancePortal, destination, event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports a player, also teleports the player's vehicle if it's a living entity
|
||||
*
|
||||
* @param playerVehicle <p>The vehicle the player is currently sitting in</p>
|
||||
* @param player <p>The player which moved</p>
|
||||
* @param entrancePortal <p>The entrance the player entered</p>
|
||||
* @param destination <p>The destination of the entrance portal</p>
|
||||
* @param event <p>The move event causing the teleportation to trigger</p>
|
||||
*/
|
||||
private void teleportPlayer(Entity playerVehicle, Player player, Portal entrancePortal, Portal destination,
|
||||
PlayerMoveEvent event) {
|
||||
if (playerVehicle instanceof LivingEntity) {
|
||||
//Make sure any horses are properly tamed
|
||||
if (playerVehicle instanceof AbstractHorse horse && !horse.isTamed()) {
|
||||
horse.setTamed(true);
|
||||
horse.setOwner(player);
|
||||
}
|
||||
//Teleport the player's vehicle
|
||||
new VehicleTeleporter(destination, (Vehicle) playerVehicle).teleport(entrancePortal);
|
||||
} else {
|
||||
//Just teleport the player like normal
|
||||
new PlayerTeleporter(destination, player).teleport(entrancePortal, event);
|
||||
}
|
||||
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
|
||||
entrancePortal.getPortalOpener().closePortal(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a player move event is relevant for this plugin
|
||||
*
|
||||
* @param event <p>The player move event to check</p>
|
||||
* @param player <p>The player which moved</p>
|
||||
* @param fromLocation <p>The location the player is moving from</p>
|
||||
* @param toLocation <p>The location the player is moving to</p>
|
||||
* @return <p>True if the event is relevant</p>
|
||||
*/
|
||||
private boolean isRelevantMoveEvent(PlayerMoveEvent event, Player player, BlockLocation fromLocation,
|
||||
BlockLocation toLocation) {
|
||||
//Check to see if the player moved to another block
|
||||
if (fromLocation.equals(toLocation)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check if the player moved from a portal
|
||||
Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
|
||||
if (entrancePortal == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Portal destination = entrancePortal.getPortalActivator().getDestination(player);
|
||||
|
||||
//Catch always open portals without a valid destination to prevent the user for being teleported and denied
|
||||
if (!entrancePortal.getOptions().isBungee() && destination == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Decide if the anything stops the player from teleport
|
||||
if (PermissionHelper.playerCannotTeleport(entrancePortal, destination, player, event)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Decide if the user should be teleported to another bungee server
|
||||
if (entrancePortal.getOptions().isBungee()) {
|
||||
if (BungeeHelper.bungeeTeleport(player, entrancePortal, event)) {
|
||||
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This event handler detects if a player clicks a button or a sign
|
||||
*
|
||||
* @param event <p>The player interact event which was triggered</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
Block block = event.getClickedBlock();
|
||||
|
||||
if (block == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
handleRightClickBlock(event, player, block);
|
||||
} else if (event.getAction() == Action.LEFT_CLICK_BLOCK && block.getBlockData() instanceof WallSign) {
|
||||
//Handle left click of a wall sign
|
||||
handleSignClick(event, player, block, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method handles left- or right-clicking of a sign
|
||||
*
|
||||
* @param event <p>The event causing the click</p>
|
||||
* @param player <p>The player clicking the sign</p>
|
||||
* @param block <p>The block that was clicked</p>
|
||||
* @param leftClick <p>Whether the player performed a left click as opposed to a right click</p>
|
||||
*/
|
||||
private void handleSignClick(PlayerInteractEvent event, Player player, Block block, boolean leftClick) {
|
||||
Portal portal = PortalHandler.getByBlock(block);
|
||||
if (portal == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.setUseInteractedBlock(Event.Result.DENY);
|
||||
if (leftClick) {
|
||||
//Cancel event in creative mode to prevent breaking the sign
|
||||
if (player.getGameMode().equals(GameMode.CREATIVE)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
} else {
|
||||
//Prevent usage of item in the player's hand (placing block and such)
|
||||
event.setUseItemInHand(Event.Result.DENY);
|
||||
}
|
||||
|
||||
//Check if the user can use the portal
|
||||
if (cannotAccessPortal(player, portal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Cycle portal destination
|
||||
if ((!portal.isOpen()) && (!portal.getOptions().isFixed())) {
|
||||
PortalActivator destinations = portal.getPortalActivator();
|
||||
if (leftClick) {
|
||||
destinations.cycleDestination(player, -1);
|
||||
} else {
|
||||
destinations.cycleDestination(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a player should be denied from accessing (using) a portal
|
||||
*
|
||||
* @param player <p>The player trying to access the portal</p>
|
||||
* @param portal <p>The portal the player is trying to use</p>
|
||||
* @return <p>True if the player should be denied</p>
|
||||
*/
|
||||
private boolean cannotAccessPortal(Player player, Portal portal) {
|
||||
boolean deny = PermissionHelper.cannotAccessNetwork(player, portal.getNetwork());
|
||||
|
||||
if (PermissionHelper.portalAccessDenied(player, portal, deny)) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method handles right-clicking of a sign or button belonging to a stargate
|
||||
*
|
||||
* @param event <p>The event triggering the right-click</p>
|
||||
* @param player <p>The player doing the right-click</p>
|
||||
* @param block <p>The block the player clicked</p>
|
||||
*/
|
||||
private void handleRightClickBlock(PlayerInteractEvent event, Player player, Block block) {
|
||||
if (block.getBlockData() instanceof WallSign) {
|
||||
handleSignClick(event, player, block, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (MaterialHelper.isButtonCompatible(block.getType())) {
|
||||
//Prevent a double click caused by a Spigot bug
|
||||
if (clickIsBug(event, block)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Portal portal = PortalHandler.getByBlock(block);
|
||||
if (portal == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Prevent the held item from being placed
|
||||
event.setUseItemInHand(Event.Result.DENY);
|
||||
event.setUseInteractedBlock(Event.Result.DENY);
|
||||
|
||||
//Check if the user can use the portal
|
||||
if (cannotAccessPortal(player, portal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PermissionHelper.openPortal(player, portal);
|
||||
if (portal.getPortalOpener().isOpenFor(player)) {
|
||||
event.setUseInteractedBlock(Event.Result.ALLOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function decides if a right click of a coral is caused by a Spigot bug
|
||||
*
|
||||
* <p>The Spigot bug currently makes every right click of a coral trigger twice, causing the portal to close
|
||||
* immediately. This fix should detect the bug without breaking wall coral buttons once the bug is fixed.</p>
|
||||
*
|
||||
* @param event <p>The event causing the right click</p>
|
||||
* @param block <p>The block to check</p>
|
||||
* @return <p>True if the click is a bug and should be cancelled</p>
|
||||
*/
|
||||
private boolean clickIsBug(PlayerInteractEvent event, Block block) {
|
||||
if (MaterialHelper.isWallCoral(block.getType())) {
|
||||
if (previousEvent != null &&
|
||||
event.getPlayer() == previousEvent.getPlayer() && eventTime + 15 > System.currentTimeMillis()) {
|
||||
previousEvent = null;
|
||||
eventTime = 0;
|
||||
return true;
|
||||
}
|
||||
previousEvent = event;
|
||||
eventTime = System.currentTimeMillis();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package net.knarcraft.stargate.listener;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.PluginDisableEvent;
|
||||
import org.bukkit.event.server.PluginEnableEvent;
|
||||
|
||||
/**
|
||||
* This listener listens for any plugins being enabled or disabled to catch the loading of vault
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class PluginEventListener implements Listener {
|
||||
|
||||
private final Stargate stargate;
|
||||
|
||||
/**
|
||||
* Instantiates a new plugin event listener
|
||||
*
|
||||
* @param stargate <p>A reference to the stargate plugin to </p>
|
||||
*/
|
||||
public PluginEventListener(Stargate stargate) {
|
||||
this.stargate = stargate;
|
||||
}
|
||||
|
||||
/**
|
||||
* This event listens for and announces that the vault plugin was detected and enabled
|
||||
*
|
||||
* <p>Each time this event is called, the economy handler will try to enable vault</p>
|
||||
*
|
||||
* @param ignored <p>The actual event called. This is currently not used</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onPluginEnable(PluginEnableEvent ignored) {
|
||||
if (Stargate.getEconomyConfig().setupEconomy(stargate.getServer().getPluginManager())) {
|
||||
String vaultVersion = Stargate.getEconomyConfig().getVault().getDescription().getVersion();
|
||||
Stargate.logInfo(Stargate.replaceVars(Stargate.getString("vaultLoaded"), "%version%", vaultVersion));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This event listens for the vault plugin being disabled and notifies the console
|
||||
*
|
||||
* @param event <p>The event caused by disabling a plugin</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onPluginDisable(PluginDisableEvent event) {
|
||||
if (event.getPlugin().equals(Stargate.getEconomyConfig().getVault())) {
|
||||
Stargate.logInfo("Vault plugin lost.");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package net.knarcraft.stargate.listener;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.FromTheEndTeleportation;
|
||||
import net.knarcraft.stargate.portal.PlayerTeleporter;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import net.knarcraft.stargate.portal.PortalHandler;
|
||||
import net.knarcraft.stargate.utility.PermissionHelper;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityPortalEnterEvent;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.bukkit.event.world.PortalCreateEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Listens for and cancels relevant portal events
|
||||
*/
|
||||
public class PortalEventListener implements Listener {
|
||||
|
||||
private static final List<FromTheEndTeleportation> playersFromTheEnd = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Listens for and aborts vanilla portal creation caused by stargate creation
|
||||
*
|
||||
* @param event <p>The triggered event</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onPortalCreation(PortalCreateEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
//Unnecessary nether portal creation is only triggered by nether pairing
|
||||
if (event.getReason() == PortalCreateEvent.CreateReason.NETHER_PAIR) {
|
||||
//If an entity is standing in a Stargate entrance, it can be assumed that the creation is a mistake
|
||||
Entity entity = event.getEntity();
|
||||
if (entity != null && PortalHandler.getByAdjacentEntrance(entity.getLocation()) != null) {
|
||||
Stargate.debug("PortalEventListener::onPortalCreation",
|
||||
"Cancelled nether portal create event");
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen for entities entering an artificial end portal
|
||||
*
|
||||
* @param event <p>The triggered event</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onEntityPortalEnter(EntityPortalEnterEvent event) {
|
||||
Location location = event.getLocation();
|
||||
World world = location.getWorld();
|
||||
Entity entity = event.getEntity();
|
||||
//Hijack normal portal teleportation if teleporting from a stargate
|
||||
if (entity instanceof Player player && location.getBlock().getType() == Material.END_PORTAL && world != null &&
|
||||
world.getEnvironment() == World.Environment.THE_END) {
|
||||
Portal portal = PortalHandler.getByAdjacentEntrance(location);
|
||||
if (portal == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Remove any old player teleportations in case weird things happen
|
||||
playersFromTheEnd.removeIf((teleportation -> teleportation.getPlayer() == player));
|
||||
//Decide if the anything stops the player from teleporting
|
||||
if (PermissionHelper.playerCannotTeleport(portal, portal.getPortalActivator().getDestination(), player, null)) {
|
||||
//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.getPortalActivator().getDestination()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen for the respawn event to catch players teleporting from the end in an artificial end portal
|
||||
*
|
||||
* @param event <p>The triggered event</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onRespawn(PlayerRespawnEvent event) {
|
||||
Player respawningPlayer = event.getPlayer();
|
||||
int playerIndex = playersFromTheEnd.indexOf(new FromTheEndTeleportation(respawningPlayer, null));
|
||||
if (playerIndex == -1) {
|
||||
return;
|
||||
}
|
||||
FromTheEndTeleportation teleportation = playersFromTheEnd.get(playerIndex);
|
||||
playersFromTheEnd.remove(playerIndex);
|
||||
|
||||
Portal exitPortal = teleportation.getExit();
|
||||
//Overwrite respawn location to respawn in front of the portal
|
||||
event.setRespawnLocation(new PlayerTeleporter(exitPortal, respawningPlayer).getExit(respawningPlayer,
|
||||
respawningPlayer.getLocation()));
|
||||
//Properly close the portal to prevent it from staying in a locked state until it times out
|
||||
exitPortal.getPortalOpener().closePortal(false);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package net.knarcraft.stargate.listener;
|
||||
|
||||
import net.knarcraft.stargate.portal.PortalHandler;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
|
||||
/**
|
||||
* This listener listens to teleportation-related events
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class TeleportEventListener implements Listener {
|
||||
|
||||
/**
|
||||
* This event handler handles some special teleportation events
|
||||
*
|
||||
* <p>This event cancels nether portal, end gateway and end portal teleportation if the user teleported from a
|
||||
* stargate entrance. This prevents the user from just teleporting to the nether or the end with portals using
|
||||
* the special teleportation blocks.</p>
|
||||
*
|
||||
* @param event <p>The event to check and possibly cancel</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onPlayerTeleport(PlayerTeleportEvent event) {
|
||||
PlayerTeleportEvent.TeleportCause cause = event.getCause();
|
||||
|
||||
//Block normal portal teleportation if teleporting from a stargate
|
||||
if (!event.isCancelled() && (cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL ||
|
||||
cause == PlayerTeleportEvent.TeleportCause.END_GATEWAY ||
|
||||
cause == PlayerTeleportEvent.TeleportCause.END_PORTAL)
|
||||
&& PortalHandler.getByAdjacentEntrance(event.getFrom()) != null) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
package net.knarcraft.stargate.listener;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import net.knarcraft.stargate.portal.PortalHandler;
|
||||
import net.knarcraft.stargate.portal.VehicleTeleporter;
|
||||
import net.knarcraft.stargate.utility.EconomyHelper;
|
||||
import net.knarcraft.stargate.utility.EntityHelper;
|
||||
import net.knarcraft.stargate.utility.PermissionHelper;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.vehicle.VehicleMoveEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This listener listens for the vehicle move event to teleport vehicles through portals
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class VehicleEventListener implements Listener {
|
||||
|
||||
/**
|
||||
* Check for a vehicle moving through a portal
|
||||
*
|
||||
* @param event <p>The triggered move event</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onVehicleMove(VehicleMoveEvent event) {
|
||||
if (!Stargate.getGateConfig().handleVehicles()) {
|
||||
return;
|
||||
}
|
||||
List<Entity> passengers = event.getVehicle().getPassengers();
|
||||
Vehicle vehicle = event.getVehicle();
|
||||
|
||||
Portal entrancePortal;
|
||||
int entitySize = EntityHelper.getEntityMaxSizeInt(vehicle);
|
||||
if (EntityHelper.getEntityMaxSize(vehicle) > 1) {
|
||||
entrancePortal = PortalHandler.getByAdjacentEntrance(event.getTo(), entitySize - 1);
|
||||
} else {
|
||||
entrancePortal = PortalHandler.getByEntrance(event.getTo());
|
||||
}
|
||||
|
||||
//Return if the portal cannot be teleported through
|
||||
if (entrancePortal == null || !entrancePortal.isOpen() || entrancePortal.getOptions().isBungee()) {
|
||||
return;
|
||||
}
|
||||
|
||||
teleportVehicle(passengers, entrancePortal, vehicle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports a vehicle through a stargate
|
||||
*
|
||||
* @param passengers <p>The passengers inside the vehicle</p>
|
||||
* @param entrancePortal <p>The portal the vehicle is entering</p>
|
||||
* @param vehicle <p>The vehicle passing through</p>
|
||||
*/
|
||||
private static void teleportVehicle(List<Entity> passengers, Portal entrancePortal, Vehicle vehicle) {
|
||||
String route = "VehicleEventListener::teleportVehicle";
|
||||
|
||||
if (!passengers.isEmpty() && passengers.get(0) instanceof Player) {
|
||||
Stargate.debug(route, "Found passenger vehicle");
|
||||
teleportPlayerAndVehicle(entrancePortal, vehicle, passengers);
|
||||
} else {
|
||||
Stargate.debug(route, "Found empty vehicle");
|
||||
Portal destinationPortal = entrancePortal.getPortalActivator().getDestination();
|
||||
if (destinationPortal == null) {
|
||||
Stargate.debug(route, "Unable to find portal destination");
|
||||
return;
|
||||
}
|
||||
Stargate.debug("vehicleTeleport", destinationPortal.getWorld() + " " +
|
||||
destinationPortal.getSignLocation());
|
||||
new VehicleTeleporter(destinationPortal, vehicle).teleport(entrancePortal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports a player and the vehicle the player sits in
|
||||
*
|
||||
* @param entrancePortal <p>The portal the minecart entered</p>
|
||||
* @param vehicle <p>The vehicle to teleport</p>
|
||||
* @param passengers <p>Any entities sitting in the minecart</p>
|
||||
*/
|
||||
private static void teleportPlayerAndVehicle(Portal entrancePortal, Vehicle vehicle, List<Entity> passengers) {
|
||||
Player player = (Player) passengers.get(0);
|
||||
//On the assumption that a non-player cannot sit in the driver's seat and since some portals can only be open
|
||||
// to one player at a time, we only need to check if the portal is open to the driver.
|
||||
if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
|
||||
return;
|
||||
}
|
||||
|
||||
//If no destination exists, the teleportation cannot happen
|
||||
Portal destinationPortal = entrancePortal.getPortalActivator().getDestination(player);
|
||||
if (destinationPortal == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Make sure all player passengers are allowed to, and can afford to, enter the portal
|
||||
for (Entity entity : passengers) {
|
||||
if (entity instanceof Player && !playerCanTeleport((Player) entity, entrancePortal, destinationPortal)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//To prevent the case where the first passenger pays and then the second passenger is denied, this has to be
|
||||
// run after it has been confirmed that all passengers are able to pay
|
||||
int cost = Stargate.getEconomyConfig().getUseCost(player, entrancePortal, destinationPortal);
|
||||
if (cost > 0) {
|
||||
if (!takePlayerPayment(passengers, entrancePortal, cost)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Teleport the vehicle and inform the user if the vehicle was teleported
|
||||
boolean teleported = new VehicleTeleporter(destinationPortal, vehicle).teleport(entrancePortal);
|
||||
if (teleported) {
|
||||
Stargate.getMessageSender().sendSuccessMessage(player, Stargate.getString("teleportMsg"));
|
||||
entrancePortal.getPortalOpener().closePortal(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes payment from all player passengers
|
||||
*
|
||||
* @param passengers <p>All passengers in the teleporting vehicle</p>
|
||||
* @param entrancePortal <p>The portal the vehicle is entering from</p>
|
||||
* @param cost <p>The cost each player has to pay</p>
|
||||
* @return <p>True if all player passengers paid successfully</p>
|
||||
*/
|
||||
private static boolean takePlayerPayment(List<Entity> passengers, Portal entrancePortal, int cost) {
|
||||
for (Entity entity : passengers) {
|
||||
//If the passenger is a player, make it pay
|
||||
if (entity instanceof Player && EconomyHelper.cannotPayTeleportFee(entrancePortal, (Player) entity, cost)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given player is allowed to and can afford to teleport
|
||||
*
|
||||
* @param player <p>The player trying to teleport</p>
|
||||
* @param entrancePortal <p>The portal the player is entering</p>
|
||||
* @param destinationPortal <p>The portal the player is to exit from</p>
|
||||
* @return <p>True if the player is allowed to teleport and is able to pay necessary fees</p>
|
||||
*/
|
||||
private static boolean playerCanTeleport(Player player, Portal entrancePortal, Portal destinationPortal) {
|
||||
//Make sure the user can access the portal
|
||||
if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destinationPortal)) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
|
||||
entrancePortal.getPortalOpener().closePortal(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check if the player is able to afford the teleport fee
|
||||
int cost = Stargate.getEconomyConfig().getUseCost(player, entrancePortal, destinationPortal);
|
||||
boolean canAffordFee = cost <= 0 || Stargate.getEconomyConfig().canAffordFee(player, cost);
|
||||
if (!canAffordFee) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("ecoInFunds"));
|
||||
}
|
||||
return canAffordFee;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package net.knarcraft.stargate.listener;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.config.StargateConfig;
|
||||
import net.knarcraft.stargate.portal.PortalRegistry;
|
||||
import net.knarcraft.stargate.utility.PortalFileHelper;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.WorldLoadEvent;
|
||||
import org.bukkit.event.world.WorldUnloadEvent;
|
||||
|
||||
/**
|
||||
* This listener listens for the loading and unloading of worlds to load and unload stargates
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class WorldEventListener implements Listener {
|
||||
|
||||
/**
|
||||
* This listener listens for the loading of a world and loads all gates from the world if not already loaded
|
||||
*
|
||||
* @param event <p>The triggered world load event</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onWorldLoad(WorldLoadEvent event) {
|
||||
StargateConfig config = Stargate.getStargateConfig();
|
||||
if (!config.getManagedWorlds().contains(event.getWorld().getName()) &&
|
||||
PortalFileHelper.loadAllPortals(event.getWorld())) {
|
||||
config.addManagedWorld(event.getWorld().getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This listener listens for the unloading of a world
|
||||
*
|
||||
* @param event <p>The triggered world unload event</p>
|
||||
*/
|
||||
@EventHandler
|
||||
public void onWorldUnload(WorldUnloadEvent event) {
|
||||
Stargate.debug("onWorldUnload", "Reloading all Stargates");
|
||||
World world = event.getWorld();
|
||||
String worldName = world.getName();
|
||||
StargateConfig config = Stargate.getStargateConfig();
|
||||
if (config.getManagedWorlds().contains(worldName)) {
|
||||
config.removeManagedWorld(worldName);
|
||||
PortalRegistry.clearPortals(world);
|
||||
}
|
||||
}
|
||||
}
|
4
src/main/java/net/knarcraft/stargate/package-info.java
Normal file
4
src/main/java/net/knarcraft/stargate/package-info.java
Normal file
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* The root package of the Stargate plugin. Contains the main Stargate.java file
|
||||
*/
|
||||
package net.knarcraft.stargate;
|
@ -0,0 +1,71 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.event.StargateEntityPortalEvent;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
/**
|
||||
* The portal teleporter takes care of the actual portal teleportation for any entities
|
||||
*/
|
||||
public class EntityTeleporter extends Teleporter {
|
||||
|
||||
private final Entity teleportingEntity;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal teleporter
|
||||
*
|
||||
* @param portal <p>The portal which is the target of the teleportation</p>
|
||||
*/
|
||||
public EntityTeleporter(Portal portal, Entity teleportingEntity) {
|
||||
super(portal);
|
||||
this.teleportingEntity = teleportingEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports an entity to this teleporter's portal
|
||||
*
|
||||
* @param origin <p>The portal the entity is teleporting from</p>
|
||||
* @return <p>True if the entity was teleported. False otherwise</p>
|
||||
*/
|
||||
public boolean teleport(Portal origin) {
|
||||
Location traveller = teleportingEntity.getLocation();
|
||||
Location exit = getExit(teleportingEntity, traveller);
|
||||
|
||||
//Rotate the entity to face out from the portal
|
||||
adjustRotation(exit);
|
||||
|
||||
//Call the StargateEntityPortalEvent to allow plugins to change destination
|
||||
if (!origin.equals(portal)) {
|
||||
exit = triggerEntityPortalEvent(origin, exit);
|
||||
if (exit == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Load chunks to make sure not to teleport to the void
|
||||
loadChunks();
|
||||
|
||||
teleportingEntity.teleport(exit);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the entity portal event to allow plugins to change the exit location
|
||||
*
|
||||
* @param origin <p>The origin portal teleported from</p>
|
||||
* @param exit <p>The exit location to teleport the entity to</p>
|
||||
* @return <p>The location the entity should be teleported to, or null if the event was cancelled</p>
|
||||
*/
|
||||
protected Location triggerEntityPortalEvent(Portal origin, Location exit) {
|
||||
StargateEntityPortalEvent stargateEntityPortalEvent = new StargateEntityPortalEvent(teleportingEntity, origin,
|
||||
portal, exit);
|
||||
Stargate.getInstance().getServer().getPluginManager().callEvent(stargateEntityPortalEvent);
|
||||
//Teleport is cancelled. Teleport the entity back to where it came from just for sanity's sake
|
||||
if (stargateEntityPortalEvent.isCancelled()) {
|
||||
new EntityTeleporter(origin, teleportingEntity).teleport(origin);
|
||||
return null;
|
||||
}
|
||||
return stargateEntityPortalEvent.getExit();
|
||||
}
|
||||
}
|
347
src/main/java/net/knarcraft/stargate/portal/Gate.java
Normal file
347
src/main/java/net/knarcraft/stargate/portal/Gate.java
Normal file
@ -0,0 +1,347 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.container.RelativeBlockVector;
|
||||
import org.bukkit.Material;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A gate describes the physical structure of a stargate
|
||||
*
|
||||
* <p>While the portal class represents a portal in space, the Gate class represents the physical gate/portal entrance.</p>
|
||||
*/
|
||||
public class Gate {
|
||||
|
||||
private final String filename;
|
||||
private final GateLayout layout;
|
||||
private final Map<Character, Material> characterMaterialMap;
|
||||
//Gate materials
|
||||
private final Material portalOpenBlock;
|
||||
private final Material portalClosedBlock;
|
||||
private final Material portalButton;
|
||||
//Economy information
|
||||
private final int useCost;
|
||||
private final int createCost;
|
||||
private final int destroyCost;
|
||||
private final boolean toOwner;
|
||||
|
||||
/**
|
||||
* Instantiates a new gate
|
||||
*
|
||||
* @param filename <p>The name of the gate file, including extension</p>
|
||||
* @param layout <p>The gate layout defined in the gate file</p>
|
||||
* @param characterMaterialMap <p>The material types the different layout characters represent</p>
|
||||
* @param portalOpenBlock <p>The material to set the opening to when the portal is open</p>
|
||||
* @param portalClosedBlock <p>The material to set the opening to when the portal is closed</p>
|
||||
* @param portalButton <p>The material to use for the portal button</p>
|
||||
* @param useCost <p>The cost of using a portal with this gate layout (-1 to disable)</p>
|
||||
* @param createCost <p>The cost of creating a portal with this gate layout (-1 to disable)</p>
|
||||
* @param destroyCost <p>The cost of destroying a portal with this gate layout (-1 to disable)</p>
|
||||
* @param toOwner <p>Whether any payment should go to the owner of the gate, as opposed to just disappearing</p>
|
||||
*/
|
||||
public Gate(String filename, GateLayout layout, Map<Character, Material> characterMaterialMap, Material portalOpenBlock,
|
||||
Material portalClosedBlock, Material portalButton, int useCost, int createCost, int destroyCost,
|
||||
boolean toOwner) {
|
||||
this.filename = filename;
|
||||
this.layout = layout;
|
||||
this.characterMaterialMap = characterMaterialMap;
|
||||
this.portalOpenBlock = portalOpenBlock;
|
||||
this.portalClosedBlock = portalClosedBlock;
|
||||
this.portalButton = portalButton;
|
||||
this.useCost = useCost;
|
||||
this.createCost = createCost;
|
||||
this.destroyCost = destroyCost;
|
||||
this.toOwner = toOwner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this gate's layout
|
||||
*
|
||||
* @return <p>This gate's layout</p>
|
||||
*/
|
||||
public GateLayout getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the material type used for this gate's control blocks
|
||||
*
|
||||
* @return <p>The material type used for control blocks</p>
|
||||
*/
|
||||
public Material getControlBlock() {
|
||||
return characterMaterialMap.get(GateHandler.getControlBlockCharacter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filename of this gate's file
|
||||
*
|
||||
* @return <p>The filename of this gate's file</p>
|
||||
*/
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block type to use for the opening when a portal using this gate is open
|
||||
*
|
||||
* @return <p>The block type to use for the opening when open</p>
|
||||
*/
|
||||
public Material getPortalOpenBlock() {
|
||||
return portalOpenBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block type to use for the opening when a portal using this gate is closed
|
||||
*
|
||||
* @return <p>The block type to use for the opening when closed</p>
|
||||
*/
|
||||
public Material getPortalClosedBlock() {
|
||||
return portalClosedBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the material to use for a portal's button if using this gate type
|
||||
*
|
||||
* @return <p>The material to use for a portal's button if using this gate type</p>
|
||||
*/
|
||||
public Material getPortalButton() {
|
||||
return portalButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cost of using a portal with this gate
|
||||
*
|
||||
* @return <p>The cost of using a portal with this gate</p>
|
||||
*/
|
||||
public int getUseCost() {
|
||||
return useCost < 0 ? Stargate.getEconomyConfig().getDefaultUseCost() : useCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cost of creating a portal with this gate
|
||||
*
|
||||
* @return <p>The cost of creating a portal with this gate</p>
|
||||
*/
|
||||
public Integer getCreateCost() {
|
||||
return createCost < 0 ? Stargate.getEconomyConfig().getDefaultCreateCost() : createCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cost of destroying a portal with this gate
|
||||
*
|
||||
* @return <p>The cost of destroying a portal with this gate</p>
|
||||
*/
|
||||
public Integer getDestroyCost() {
|
||||
return destroyCost < 0 ? Stargate.getEconomyConfig().getDefaultDestroyCost() : destroyCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether portal payments go to this portal's owner
|
||||
*
|
||||
* @return <p>Whether portal payments go to the owner</p>
|
||||
*/
|
||||
public Boolean getToOwner() {
|
||||
return toOwner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a portal's gate matches this gate type
|
||||
*
|
||||
* @param topLeft <p>The top-left block of the portal's gate</p>
|
||||
* @param yaw <p>The yaw when looking directly outwards</p>
|
||||
* @return <p>True if this gate matches the portal</p>
|
||||
*/
|
||||
public boolean matches(BlockLocation topLeft, double yaw) {
|
||||
return matches(topLeft, yaw, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a portal's gate matches this gate type
|
||||
*
|
||||
* <p>If enabling onCreate, opening blocks with materials AIR and WATER will be allowed even if the gate closed
|
||||
* material is a different one. If checking and onCreate is not enabled, any inconsistency with opening blocks
|
||||
* containing AIR or WATER will cause the gate to not match.</p>
|
||||
*
|
||||
* @param topLeft <p>The top-left block of the portal's gate</p>
|
||||
* @param yaw <p>The yaw when looking directly outwards</p>
|
||||
* @param onCreate <p>Whether this is used in the context of creating a new gate</p>
|
||||
* @return <p>True if this gate matches the portal</p>
|
||||
*/
|
||||
public boolean matches(BlockLocation topLeft, double yaw, boolean onCreate) {
|
||||
return verifyGateEntrancesMatch(topLeft, yaw, onCreate) && verifyGateBorderMatches(topLeft, yaw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that all border blocks of a portal matches this gate type
|
||||
*
|
||||
* @param topLeft <p>The top-left block of the portal</p>
|
||||
* @param yaw <p>The yaw when looking directly outwards from the portal</p>
|
||||
* @return <p>True if all border blocks of the gate match the layout</p>
|
||||
*/
|
||||
private boolean verifyGateBorderMatches(BlockLocation topLeft, double yaw) {
|
||||
Map<Character, Material> characterMaterialMap = new HashMap<>(this.characterMaterialMap);
|
||||
for (RelativeBlockVector borderVector : layout.getBorder()) {
|
||||
int rowIndex = borderVector.getRight();
|
||||
int lineIndex = borderVector.getDown();
|
||||
Character key = layout.getLayout()[lineIndex][rowIndex];
|
||||
|
||||
Material materialInLayout = characterMaterialMap.get(key);
|
||||
Material materialAtLocation = topLeft.getRelativeLocation(borderVector, yaw).getType();
|
||||
|
||||
if (materialInLayout == null) {
|
||||
/* This generally should not happen with proper checking, but just in case a material character is not
|
||||
* recognized, but still allowed in previous checks, verify the gate as long as all such instances of
|
||||
* the character correspond to the same material in the physical gate. All subsequent gates will also
|
||||
* need to match the first verified gate. */
|
||||
characterMaterialMap.put(key, materialAtLocation);
|
||||
Stargate.debug("Gate::Matches", String.format("Missing layout material in %s. Using %s from the" +
|
||||
" physical portal.", getFilename(), materialAtLocation));
|
||||
} else if (materialAtLocation != materialInLayout) {
|
||||
Stargate.debug("Gate::Matches", String.format("Block Type Mismatch: %s != %s",
|
||||
materialAtLocation, materialInLayout));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that all entrances of a portal gate matches this gate type
|
||||
*
|
||||
* @param topLeft <p>The top-left block of this portal</p>
|
||||
* @param yaw <p>The yaw when looking directly outwards</p>
|
||||
* @param onCreate <p>Whether this is used in the context of creating a new gate</p>
|
||||
* @return <p>Whether this is used in the context of creating a new gate</p>
|
||||
*/
|
||||
private boolean verifyGateEntrancesMatch(BlockLocation topLeft, double yaw, boolean onCreate) {
|
||||
Stargate.debug("verifyGateEntrancesMatch", String.valueOf(topLeft));
|
||||
for (RelativeBlockVector entranceVector : layout.getEntrances()) {
|
||||
Stargate.debug("verifyGateEntrancesMatch", String.valueOf(entranceVector));
|
||||
Material type = topLeft.getRelativeLocation(entranceVector, yaw).getType();
|
||||
|
||||
//Ignore entrance if it's air or water, and we're creating a new gate
|
||||
if (onCreate && (type == Material.AIR || type == Material.WATER)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type != portalClosedBlock && type != portalOpenBlock) {
|
||||
Stargate.debug("Gate::Matches", "Entrance/Exit Material Mismatch: " + type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this gate to a file
|
||||
*
|
||||
* <p>This method will save the gate to its filename in the given folder.</p>
|
||||
*
|
||||
* @param gateFolder <p>The folder to save the gate file in</p>
|
||||
*/
|
||||
public void save(String gateFolder) {
|
||||
try {
|
||||
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(gateFolder + filename));
|
||||
|
||||
//Save main material names
|
||||
writeConfig(bufferedWriter, "portal-open", portalOpenBlock.name());
|
||||
writeConfig(bufferedWriter, "portal-closed", portalClosedBlock.name());
|
||||
writeConfig(bufferedWriter, "button", portalButton.name());
|
||||
|
||||
//Save the values necessary for economy
|
||||
saveEconomyValues(bufferedWriter);
|
||||
|
||||
//Store material types to use for frame blocks
|
||||
saveFrameBlockTypes(bufferedWriter);
|
||||
|
||||
bufferedWriter.newLine();
|
||||
|
||||
//Save the gate layout
|
||||
layout.saveLayout(bufferedWriter);
|
||||
|
||||
bufferedWriter.close();
|
||||
} catch (IOException ex) {
|
||||
Stargate.logSevere(String.format("Could not save Gate %s - %s", filename, ex.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves current economy related values using a buffered writer
|
||||
*
|
||||
* @param bufferedWriter <p>The buffered writer to write to</p>
|
||||
* @throws IOException <p>If unable to write to the buffered writer</p>
|
||||
*/
|
||||
private void saveEconomyValues(BufferedWriter bufferedWriter) throws IOException {
|
||||
//Write use cost if not disabled
|
||||
if (useCost != -1) {
|
||||
writeConfig(bufferedWriter, "usecost", useCost);
|
||||
}
|
||||
//Write create cost if not disabled
|
||||
if (createCost != -1) {
|
||||
writeConfig(bufferedWriter, "createcost", createCost);
|
||||
}
|
||||
//Write destroy cost if not disabled
|
||||
if (destroyCost != -1) {
|
||||
writeConfig(bufferedWriter, "destroycost", destroyCost);
|
||||
}
|
||||
writeConfig(bufferedWriter, "toowner", toOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the types of blocks used for the gate frame/border using a buffered writer
|
||||
*
|
||||
* @param bufferedWriter <p>The buffered writer to write to</p>
|
||||
* @throws IOException <p>If unable to write to the buffered writer</p>
|
||||
*/
|
||||
private void saveFrameBlockTypes(BufferedWriter bufferedWriter) throws IOException {
|
||||
for (Map.Entry<Character, Material> entry : characterMaterialMap.entrySet()) {
|
||||
Character type = entry.getKey();
|
||||
Material value = entry.getValue();
|
||||
//Skip characters not part of the frame
|
||||
if (type.equals(GateHandler.getAnythingCharacter()) ||
|
||||
type.equals(GateHandler.getEntranceCharacter()) ||
|
||||
type.equals(GateHandler.getExitCharacter())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bufferedWriter.append(type);
|
||||
bufferedWriter.append('=');
|
||||
if (value != null) {
|
||||
bufferedWriter.append(value.toString());
|
||||
}
|
||||
bufferedWriter.newLine();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a formatted string to a buffered writer
|
||||
*
|
||||
* @param bufferedWriter <p>The buffered writer to write the formatted string to</p>
|
||||
* @param key <p>The config key to save</p>
|
||||
* @param value <p>The config value to save</p>
|
||||
* @throws IOException <p>If unable to write to the buffered writer</p>
|
||||
*/
|
||||
private void writeConfig(BufferedWriter bufferedWriter, String key, Object value) throws IOException {
|
||||
//Figure out the correct formatting to use
|
||||
String format = "%s=";
|
||||
if (value instanceof Boolean) {
|
||||
format += "%b";
|
||||
} else if (value instanceof Integer) {
|
||||
format += "%d";
|
||||
} else if (value instanceof String) {
|
||||
format += "%s";
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unrecognized config value type");
|
||||
}
|
||||
|
||||
bufferedWriter.append(String.format(format, key, value));
|
||||
bufferedWriter.newLine();
|
||||
}
|
||||
|
||||
}
|
327
src/main/java/net/knarcraft/stargate/portal/GateHandler.java
Normal file
327
src/main/java/net/knarcraft/stargate/portal/GateHandler.java
Normal file
@ -0,0 +1,327 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.utility.GateReader;
|
||||
import net.knarcraft.stargate.utility.MaterialHelper;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
|
||||
import static net.knarcraft.stargate.utility.GateReader.generateLayoutMatrix;
|
||||
import static net.knarcraft.stargate.utility.GateReader.readGateConfig;
|
||||
import static net.knarcraft.stargate.utility.GateReader.readGateFile;
|
||||
|
||||
/**
|
||||
* The gate handler keeps track of all gates
|
||||
*/
|
||||
public class GateHandler {
|
||||
|
||||
private static final Character ANYTHING = ' ';
|
||||
private static final Character ENTRANCE = '.';
|
||||
private static final Character EXIT = '*';
|
||||
private static final Character CONTROL_BLOCK = '-';
|
||||
|
||||
private static final Material defaultPortalBlockOpen = Material.NETHER_PORTAL;
|
||||
private static final Material defaultPortalBlockClosed = Material.AIR;
|
||||
private static final Material defaultButton = Material.STONE_BUTTON;
|
||||
|
||||
private static final HashMap<String, Gate> gates = new HashMap<>();
|
||||
private static final HashMap<Material, List<Gate>> controlBlocks = new HashMap<>();
|
||||
|
||||
private GateHandler() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character used for blocks that are not part of the gate
|
||||
*
|
||||
* @return <p>The character used for blocks that are not part of the gate</p>
|
||||
*/
|
||||
public static Character getAnythingCharacter() {
|
||||
return ANYTHING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character used for defining the entrance
|
||||
*
|
||||
* @return <p>The character used for defining the entrance</p>
|
||||
*/
|
||||
public static Character getEntranceCharacter() {
|
||||
return ENTRANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character used for defining the exit
|
||||
*
|
||||
* @return <p>The character used for defining the exit</p>
|
||||
*/
|
||||
public static Character getExitCharacter() {
|
||||
return EXIT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the character used for defining control blocks
|
||||
*
|
||||
* @return <p>The character used for defining control blocks</p>
|
||||
*/
|
||||
public static Character getControlBlockCharacter() {
|
||||
return CONTROL_BLOCK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a gate into the list of available gates
|
||||
*
|
||||
* @param gate <p>The gate to register</p>
|
||||
*/
|
||||
private static void registerGate(Gate gate) {
|
||||
gates.put(gate.getFilename(), gate);
|
||||
|
||||
Material blockID = gate.getControlBlock();
|
||||
|
||||
if (!controlBlocks.containsKey(blockID)) {
|
||||
controlBlocks.put(blockID, new ArrayList<>());
|
||||
}
|
||||
|
||||
controlBlocks.get(blockID).add(gate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a gate from a file
|
||||
*
|
||||
* @param file <p>The file containing the gate data</p>
|
||||
* @return <p>The loaded gate, or null if unable to load the gate</p>
|
||||
*/
|
||||
private static Gate loadGate(File file) {
|
||||
try (Scanner scanner = new Scanner(file)) {
|
||||
return loadGate(file.getName(), file.getParent(), scanner);
|
||||
} catch (Exception exception) {
|
||||
Stargate.logSevere(String.format("Could not load Gate %s - %s", file.getName(), exception.getMessage()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a gate from a file
|
||||
*
|
||||
* @param fileName <p>The name of the file containing the gate data</p>
|
||||
* @param parentFolder <p>The parent folder of the gate data file</p>
|
||||
* @param scanner <p>The scanner to use for reading the gate data</p>
|
||||
* @return <p>The loaded gate or null if unable to load the gate</p>
|
||||
*/
|
||||
private static Gate loadGate(String fileName, String parentFolder, Scanner scanner) {
|
||||
List<List<Character>> design = new ArrayList<>();
|
||||
Map<Character, Material> characterMaterialMap = new HashMap<>();
|
||||
Map<String, String> config = new HashMap<>();
|
||||
Set<Material> frameTypes = new HashSet<>();
|
||||
|
||||
//Initialize character to material map
|
||||
characterMaterialMap.put(ENTRANCE, Material.AIR);
|
||||
characterMaterialMap.put(EXIT, Material.AIR);
|
||||
characterMaterialMap.put(ANYTHING, Material.AIR);
|
||||
|
||||
//Read the file into appropriate lists and maps
|
||||
int columns = readGateFile(scanner, characterMaterialMap, fileName, design, frameTypes, config);
|
||||
if (columns < 0) {
|
||||
return null;
|
||||
}
|
||||
Character[][] layout = generateLayoutMatrix(design, columns);
|
||||
|
||||
//Create and validate the new gate
|
||||
Gate gate = createGate(config, fileName, layout, characterMaterialMap);
|
||||
if (gate == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//Update gate file in case the format has changed between versions
|
||||
gate.save(parentFolder + "/");
|
||||
return gate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new gate
|
||||
*
|
||||
* @param config <p>The config map to get configuration values from</p>
|
||||
* @param fileName <p>The name of the saved gate config file</p>
|
||||
* @param layout <p>The layout matrix of the new gate</p>
|
||||
* @param characterMaterialMap <p>A map between layout characters and the material to use</p>
|
||||
* @return <p>A new gate, or null if the config is invalid</p>
|
||||
*/
|
||||
private static Gate createGate(Map<String, String> config, String fileName, Character[][] layout,
|
||||
Map<Character, Material> characterMaterialMap) {
|
||||
//Read relevant material types
|
||||
Material portalOpenBlock = readGateConfig(config, fileName, "portal-open", defaultPortalBlockOpen);
|
||||
Material portalClosedBlock = readGateConfig(config, fileName, "portal-closed", defaultPortalBlockClosed);
|
||||
Material portalButton = readGateConfig(config, fileName, "button", defaultButton);
|
||||
|
||||
//Read economy values
|
||||
int useCost = GateReader.readGateConfig(config, fileName, "usecost");
|
||||
int createCost = GateReader.readGateConfig(config, fileName, "createcost");
|
||||
int destroyCost = GateReader.readGateConfig(config, fileName, "destroycost");
|
||||
boolean toOwner = (config.containsKey("toowner") ? Boolean.parseBoolean(config.get("toowner")) :
|
||||
Stargate.getEconomyConfig().sendPaymentToOwner());
|
||||
|
||||
//Create the new gate
|
||||
Gate gate = new Gate(fileName, new GateLayout(layout), characterMaterialMap, portalOpenBlock, portalClosedBlock,
|
||||
portalButton, useCost, createCost, destroyCost, toOwner);
|
||||
|
||||
if (!validateGate(gate, fileName)) {
|
||||
return null;
|
||||
}
|
||||
return gate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a gate is valid
|
||||
*
|
||||
* @param gate <p>The gate to validate</p>
|
||||
* @param fileName <p>The filename of the loaded gate file</p>
|
||||
* @return <p>True if the gate is valid. False otherwise</p>
|
||||
*/
|
||||
private static boolean validateGate(Gate gate, String fileName) {
|
||||
if (gate.getLayout().getControls().length != 2) {
|
||||
Stargate.logSevere(String.format("Could not load Gate %s - Gates must have exactly 2 control points.",
|
||||
fileName));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!MaterialHelper.isButtonCompatible(gate.getPortalButton())) {
|
||||
Stargate.logSevere(String.format("Could not load Gate %s - Gate button must be a type of button.", fileName));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all gates inside the given folder
|
||||
*
|
||||
* @param gateFolder <p>The folder containing the gates</p>
|
||||
*/
|
||||
public static void loadGates(String gateFolder) {
|
||||
File directory = new File(gateFolder);
|
||||
File[] files;
|
||||
|
||||
if (directory.exists()) {
|
||||
//Get all files with a .gate extension
|
||||
files = directory.listFiles((file) -> file.isFile() && file.getName().endsWith(".gate"));
|
||||
} else {
|
||||
//Set files to empty list to signal that default gates need to be copied
|
||||
files = new File[0];
|
||||
}
|
||||
|
||||
if (files == null || files.length == 0) {
|
||||
//The gates-folder was not found. Assume this is the first run
|
||||
if (directory.mkdir()) {
|
||||
writeDefaultGatesToFolder(gateFolder);
|
||||
}
|
||||
} else {
|
||||
//Load and register the corresponding gate for each file
|
||||
for (File file : files) {
|
||||
Gate gate = loadGate(file);
|
||||
if (gate != null) {
|
||||
registerGate(gate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the default gates to the given folder
|
||||
*
|
||||
* @param gateFolder <p>The folder containing gate config files</p>
|
||||
*/
|
||||
public static void writeDefaultGatesToFolder(String gateFolder) {
|
||||
loadGateFromJar("nethergate.gate", gateFolder);
|
||||
loadGateFromJar("watergate.gate", gateFolder);
|
||||
loadGateFromJar("endgate.gate", gateFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given gate file from within the Jar's resources directory
|
||||
*
|
||||
* @param gateFile <p>The name of the gate file</p>
|
||||
* @param gateFolder <p>The folder containing gates</p>
|
||||
*/
|
||||
private static void loadGateFromJar(String gateFile, String gateFolder) {
|
||||
//Get an input stream for the internal file
|
||||
InputStream gateFileStream = Gate.class.getResourceAsStream("/gates/" + gateFile);
|
||||
if (gateFileStream != null) {
|
||||
Scanner scanner = new Scanner(gateFileStream);
|
||||
//Load and register the gate
|
||||
Gate gate = loadGate(gateFile, gateFolder, scanner);
|
||||
if (gate != null) {
|
||||
registerGate(gate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the gates with the given control block
|
||||
*
|
||||
* <p>The control block is the block type where the sign should be placed. It is used to decide whether a user
|
||||
* is creating a new portal.</p>
|
||||
*
|
||||
* @param block <p>The control block to check</p>
|
||||
* @return <p>A list of gates using the given control block</p>
|
||||
*/
|
||||
public static Gate[] getGatesByControlBlock(Block block) {
|
||||
return getGatesByControlBlock(block.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the gates with the given control block
|
||||
*
|
||||
* <p>The control block is the block type where the sign should be placed. It is used to decide whether a user
|
||||
* is creating a new portal.</p>
|
||||
*
|
||||
* @param type <p>The type of the control block to check</p>
|
||||
* @return <p>A list of gates using the given material for control block</p>
|
||||
*/
|
||||
public static Gate[] getGatesByControlBlock(Material type) {
|
||||
Gate[] result = new Gate[0];
|
||||
List<Gate> lookup = controlBlocks.get(type);
|
||||
|
||||
if (lookup != null) {
|
||||
result = lookup.toArray(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a portal given its filename
|
||||
*
|
||||
* @param fileName <p>The filename of the gate to get</p>
|
||||
* @return <p>The gate with the given filename</p>
|
||||
*/
|
||||
public static Gate getGateByName(String fileName) {
|
||||
return gates.get(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of loaded gate configurations
|
||||
*
|
||||
* @return <p>The number of loaded gate configurations</p>
|
||||
*/
|
||||
public static int getGateCount() {
|
||||
return gates.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all loaded gates and control blocks
|
||||
*/
|
||||
public static void clearGates() {
|
||||
gates.clear();
|
||||
controlBlocks.clear();
|
||||
}
|
||||
|
||||
}
|
209
src/main/java/net/knarcraft/stargate/portal/GateLayout.java
Normal file
209
src/main/java/net/knarcraft/stargate/portal/GateLayout.java
Normal file
@ -0,0 +1,209 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.container.RelativeBlockVector;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The gate layout describes where every part of the gate should be
|
||||
*
|
||||
* <p>The gate layout parses a layout described by a Character matrix and stores the different parts of the gate as
|
||||
* relative block vectors. All relative vectors has an origin in the top-left block when looking at the gate's front
|
||||
* (the side with the sign). The origin of the relative vectors can also be seen as 0,0 in the character matrix.</p>
|
||||
*/
|
||||
public class GateLayout {
|
||||
|
||||
private final Character[][] layout;
|
||||
private final List<RelativeBlockVector> exits = new ArrayList<>();
|
||||
private RelativeBlockVector[] entrances = new RelativeBlockVector[0];
|
||||
private RelativeBlockVector[] border = new RelativeBlockVector[0];
|
||||
private RelativeBlockVector[] controls = new RelativeBlockVector[0];
|
||||
private RelativeBlockVector exitBlock = null;
|
||||
|
||||
/**
|
||||
* Instantiates a new gate layout
|
||||
*
|
||||
* @param layout <p>A character matrix describing the layout</p>
|
||||
*/
|
||||
public GateLayout(Character[][] layout) {
|
||||
this.layout = layout;
|
||||
readLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character array describing this layout
|
||||
*
|
||||
* @return <p>The character array describing this layout</p>
|
||||
*/
|
||||
public Character[][] getLayout() {
|
||||
return this.layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the locations of all entrances for this gate
|
||||
*
|
||||
* <p>Entrances contain both the portal entrance blocks and the portal exit blocks.</p>
|
||||
*
|
||||
* @return <p>The locations of entrances for this gate</p>
|
||||
*/
|
||||
public RelativeBlockVector[] getEntrances() {
|
||||
return entrances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the locations of border blocks for the gate described by this layout
|
||||
*
|
||||
* <p>A border block is basically any block of the frame. In terms of the nether gate, the border blocks are every
|
||||
* block of the gate that's not air when the gate is closed. The sign and button are not border blocks.</p>
|
||||
*
|
||||
* @return <p>The locations of border blocks for this gate</p>
|
||||
*/
|
||||
public RelativeBlockVector[] getBorder() {
|
||||
return border;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exit block defined in the layout
|
||||
*
|
||||
* @return <p>The exit block defined in the layout</p>
|
||||
*/
|
||||
public RelativeBlockVector getExit() {
|
||||
return exitBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all possible exit locations defined in the layout
|
||||
*
|
||||
* <p>This returns all blocks usable as exits. This basically means it returns the lowest block in each opening of
|
||||
* the gate layout.</p>
|
||||
*
|
||||
* @return <p>All possible exits</p>
|
||||
*/
|
||||
public List<RelativeBlockVector> getExits() {
|
||||
return exits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the locations of the control blocks for this gate
|
||||
*
|
||||
* <p>The control blocks are the blocks where a sign can be placed to create a portal. The control block without a
|
||||
* sign will be used for the button if necessary. There will always be exactly two control blocks.</p>
|
||||
*
|
||||
* @return <p>The locations of the control blocks for this gate</p>
|
||||
*/
|
||||
public RelativeBlockVector[] getControls() {
|
||||
return controls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the gate layout using a buffered writer
|
||||
*
|
||||
* @param bufferedWriter <p>The buffered writer to write to</p>
|
||||
* @throws IOException <p>If unable to write to the buffered writer</p>
|
||||
*/
|
||||
public void saveLayout(BufferedWriter bufferedWriter) throws IOException {
|
||||
for (Character[] line : this.layout) {
|
||||
for (Character character : line) {
|
||||
bufferedWriter.append(character);
|
||||
}
|
||||
bufferedWriter.newLine();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the layout and stores key information
|
||||
*
|
||||
* <p>This methods reads the layout and stores exits, entrances, border blocks and control blocks.</p>
|
||||
*/
|
||||
private void readLayout() {
|
||||
List<RelativeBlockVector> entranceList = new ArrayList<>();
|
||||
List<RelativeBlockVector> borderList = new ArrayList<>();
|
||||
List<RelativeBlockVector> controlList = new ArrayList<>();
|
||||
|
||||
readLayout(controlList, entranceList, borderList);
|
||||
|
||||
this.entrances = entranceList.toArray(this.entrances);
|
||||
this.border = borderList.toArray(this.border);
|
||||
this.controls = controlList.toArray(this.controls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the given layout matrix, filling in the given lists of relative block vectors
|
||||
*
|
||||
* @param controlList <p>The list of control blocks to save to</p>
|
||||
* @param entranceList <p>The list of entrances to save to</p>
|
||||
* @param borderList <p>The list of border blocks to save to</p>
|
||||
*/
|
||||
private void readLayout(List<RelativeBlockVector> controlList, List<RelativeBlockVector> entranceList,
|
||||
List<RelativeBlockVector> borderList) {
|
||||
//Store the lowest opening for each column
|
||||
int[] exitDepths = new int[layout[0].length];
|
||||
|
||||
//A row is the same as one line in the gate file
|
||||
int lineCount = layout.length;
|
||||
for (int rowIndex = 0; rowIndex < lineCount; rowIndex++) {
|
||||
Character[] row = layout[rowIndex];
|
||||
int rowSize = row.length;
|
||||
for (int columnIndex = 0; columnIndex < rowSize; columnIndex++) {
|
||||
Character key = row[columnIndex];
|
||||
parseLayoutCharacter(key, columnIndex, rowIndex, exitDepths, controlList, entranceList, borderList);
|
||||
}
|
||||
}
|
||||
|
||||
//Generate all possible exits
|
||||
for (int x = 0; x < exitDepths.length; x++) {
|
||||
//Ignore invalid exits
|
||||
if (exitDepths[x] > 0) {
|
||||
this.exits.add(new RelativeBlockVector(x, exitDepths[x], 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses one character of the layout
|
||||
*
|
||||
* @param key <p>The read character</p>
|
||||
* @param columnIndex <p>The column containing the read character</p>
|
||||
* @param rowIndex <p>The row containing the read character</p>
|
||||
* @param exitDepths <p>The list of exit depths to save to</p>
|
||||
* @param controlList <p>The list of control blocks to save to</p>
|
||||
* @param entranceList <p>The list of entrances to save to</p>
|
||||
* @param borderList <p>The list of border blocks to save to</p>
|
||||
*/
|
||||
private void parseLayoutCharacter(Character key, int columnIndex, int rowIndex, int[] exitDepths,
|
||||
List<RelativeBlockVector> controlList, List<RelativeBlockVector> entranceList,
|
||||
List<RelativeBlockVector> borderList) {
|
||||
//Add control blocks to the control block list
|
||||
if (key.equals(GateHandler.getControlBlockCharacter())) {
|
||||
controlList.add(new RelativeBlockVector(columnIndex, rowIndex, 0));
|
||||
}
|
||||
|
||||
if (isOpening(key)) {
|
||||
//Register entrance
|
||||
entranceList.add(new RelativeBlockVector(columnIndex, rowIndex, 0));
|
||||
//Overwrite the lowest exit location for this column/x-coordinate
|
||||
exitDepths[columnIndex] = rowIndex;
|
||||
//Register exit if found
|
||||
if (key.equals(GateHandler.getExitCharacter())) {
|
||||
this.exitBlock = new RelativeBlockVector(columnIndex, rowIndex, 0);
|
||||
}
|
||||
} else if (!key.equals(GateHandler.getAnythingCharacter())) {
|
||||
//Register border block
|
||||
borderList.add(new RelativeBlockVector(columnIndex, rowIndex, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given character represents a gate opening
|
||||
*
|
||||
* @param character <p>The character to check</p>
|
||||
* @return <p>True if the character represents an opening</p>
|
||||
*/
|
||||
private boolean isOpening(Character character) {
|
||||
return character.equals(GateHandler.getEntranceCharacter()) || character.equals(GateHandler.getExitCharacter());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.event.StargatePlayerPortalEvent;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
|
||||
/**
|
||||
* The portal teleporter takes care of the actual portal teleportation for any players
|
||||
*/
|
||||
public class PlayerTeleporter extends Teleporter {
|
||||
|
||||
private final Player player;
|
||||
|
||||
/**
|
||||
* Instantiates a new player teleporter
|
||||
*
|
||||
* @param portal <p>The portal which is the target of the teleportation</p>
|
||||
* @param player <p>The teleporting player</p>
|
||||
*/
|
||||
public PlayerTeleporter(Portal portal, Player player) {
|
||||
super(portal);
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports a player to this teleporter's portal
|
||||
*
|
||||
* @param origin <p>The portal the player teleports from</p>
|
||||
* @param event <p>The player move event triggering the event</p>
|
||||
*/
|
||||
public void teleport(Portal origin, PlayerMoveEvent event) {
|
||||
Location traveller = player.getLocation();
|
||||
Location exit = getExit(player, traveller);
|
||||
|
||||
//Rotate the player to face out from the portal
|
||||
adjustRotation(exit);
|
||||
|
||||
//Call the StargatePlayerPortalEvent to allow plugins to change destination
|
||||
if (!origin.equals(portal)) {
|
||||
exit = triggerPlayerPortalEvent(origin, exit, event);
|
||||
if (exit == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Load chunks to make sure not to teleport to the void
|
||||
loadChunks();
|
||||
|
||||
//Teleport any creatures leashed by the player in a 15-block range
|
||||
teleportLeashedCreatures(player, origin);
|
||||
|
||||
//If no event is passed in, assume it's a teleport, and act as such
|
||||
if (event == null) {
|
||||
player.teleport(exit);
|
||||
} else {
|
||||
//The new method to teleport in a move event is set the "to" field.
|
||||
event.setTo(exit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the player portal event to allow plugins to change the exit location
|
||||
*
|
||||
* @param origin <p>The origin portal teleported from</p>
|
||||
* @param exit <p>The exit location to teleport the player to</p>
|
||||
* @param event <p>The player move event which triggered the teleportation</p>
|
||||
* @return <p>The location the player should be teleported to, or null if the event was cancelled</p>
|
||||
*/
|
||||
private Location triggerPlayerPortalEvent(Portal origin, Location exit, PlayerMoveEvent event) {
|
||||
StargatePlayerPortalEvent stargatePlayerPortalEvent = new StargatePlayerPortalEvent(player, origin, portal, exit);
|
||||
Stargate.getInstance().getServer().getPluginManager().callEvent(stargatePlayerPortalEvent);
|
||||
//Teleport is cancelled. Teleport the player back to where it came from
|
||||
if (stargatePlayerPortalEvent.isCancelled()) {
|
||||
new PlayerTeleporter(origin, player).teleport(origin, event);
|
||||
return null;
|
||||
}
|
||||
return stargatePlayerPortalEvent.getExit();
|
||||
}
|
||||
|
||||
}
|
289
src/main/java/net/knarcraft/stargate/portal/Portal.java
Normal file
289
src/main/java/net/knarcraft/stargate/portal/Portal.java
Normal file
@ -0,0 +1,289 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.container.RelativeBlockVector;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class represents a portal in space which points to one or several portals
|
||||
*/
|
||||
public class Portal {
|
||||
|
||||
private final String name;
|
||||
private final String network;
|
||||
private final PortalOwner portalOwner;
|
||||
|
||||
private final PortalOptions options;
|
||||
private final PortalOpener portalOpener;
|
||||
private final PortalLocation location;
|
||||
private final PortalSignDrawer signDrawer;
|
||||
private final PortalStructure structure;
|
||||
private final PortalActivator portalActivator;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal
|
||||
*
|
||||
* @param portalLocation <p>Object containing locations of all relevant blocks</p>
|
||||
* @param button <p>The location of the portal's open button</p>
|
||||
* @param destination <p>The destination defined on the sign's destination line. "" for non-fixed gates</p>
|
||||
* @param name <p>The name of the portal defined on the sign's first line</p>
|
||||
* @param network <p>The network the portal belongs to, defined on the sign's third</p>
|
||||
* @param gate <p>The gate type to use for this portal</p>
|
||||
* @param portalOwner <p>The portal's owner</p>
|
||||
* @param options <p>A map containing all possible portal options, with true for the ones enabled</p>
|
||||
*/
|
||||
public Portal(PortalLocation portalLocation, BlockLocation button, String destination, String name, String network,
|
||||
Gate gate, PortalOwner portalOwner, Map<PortalOption, Boolean> options) {
|
||||
this.location = portalLocation;
|
||||
this.network = network;
|
||||
this.name = name;
|
||||
this.portalOwner = portalOwner;
|
||||
this.options = new PortalOptions(options, destination.length() > 0);
|
||||
this.signDrawer = new PortalSignDrawer(this);
|
||||
this.portalOpener = new PortalOpener(this, destination);
|
||||
this.structure = new PortalStructure(this, gate, button);
|
||||
this.portalActivator = portalOpener.getPortalActivator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location data for this portal
|
||||
*
|
||||
* @return <p>This portal's location data</p>
|
||||
*/
|
||||
public PortalLocation getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the structure of this portal
|
||||
*
|
||||
* <p>The structure contains information about the portal's gate, button and real locations of frames and
|
||||
* entrances. The structure is also responsible for verifying built StarGates to make sure they match the gate.</p>
|
||||
*
|
||||
* @return <p>This portal's structure</p>
|
||||
*/
|
||||
public PortalStructure getStructure() {
|
||||
return this.structure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this portal's activator
|
||||
*
|
||||
* <p>The activator is responsible for activating/de-activating the portal and contains information about
|
||||
* available destinations and which player activated the portal.</p>
|
||||
*
|
||||
* @return <p>This portal's activator</p>
|
||||
*/
|
||||
public PortalActivator getPortalActivator() {
|
||||
return this.portalActivator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-draws the sign on this portal
|
||||
*/
|
||||
public void drawSign() {
|
||||
this.signDrawer.drawSign();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portal options for this portal
|
||||
*
|
||||
* @return <p>This portal's portal options</p>
|
||||
*/
|
||||
public PortalOptions getOptions() {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal is currently open
|
||||
*
|
||||
* @return <p>Whether this portal is open</p>
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
return portalOpener.isOpen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player currently using this portal
|
||||
*
|
||||
* @return <p>The player currently using this portal</p>
|
||||
*/
|
||||
public Player getActivePlayer() {
|
||||
return portalActivator.getActivePlayer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the network this portal belongs to
|
||||
*
|
||||
* @return <p>The network this portal belongs to</p>
|
||||
*/
|
||||
public String getNetwork() {
|
||||
return network;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time this portal was triggered (activated/opened)
|
||||
*
|
||||
* <p>The time is given in the equivalent of a Unix timestamp. It's used to decide when a portal times out and
|
||||
* automatically closes/deactivates.</p>
|
||||
*
|
||||
* @return <p>The time this portal was triggered (activated/opened)</p>
|
||||
*/
|
||||
public long getTriggeredTime() {
|
||||
return portalOpener.getTriggeredTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this portal
|
||||
*
|
||||
* @return <p>The name of this portal</p>
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portal opener used by this portal
|
||||
*
|
||||
* <p>The portal opener is responsible for opening and closing this portal.</p>
|
||||
*
|
||||
* @return <p>This portal's portal opener</p>
|
||||
*/
|
||||
public PortalOpener getPortalOpener() {
|
||||
return portalOpener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this portal's destination portal
|
||||
*
|
||||
* @return <p>The name of this portal's destination portal</p>
|
||||
*/
|
||||
public String getDestinationName() {
|
||||
return portalOpener.getPortalActivator().getDestinationName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the gate type used by this portal
|
||||
*
|
||||
* @return <p>The gate type used by this portal</p>
|
||||
*/
|
||||
public Gate getGate() {
|
||||
return structure.getGate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this portal's owner
|
||||
*
|
||||
* <p>The owner is the player which created the portal.</p>
|
||||
*
|
||||
* @return <p>This portal's owner</p>
|
||||
*/
|
||||
public PortalOwner getOwner() {
|
||||
return portalOwner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given player is the owner of this portal
|
||||
*
|
||||
* @param player <p>The player to check</p>
|
||||
* @return <p>True if the player is the owner of this portal</p>
|
||||
*/
|
||||
public boolean isOwner(Player player) {
|
||||
if (this.portalOwner.getUUID() != null) {
|
||||
return player.getUniqueId().compareTo(this.portalOwner.getUUID()) == 0;
|
||||
} else {
|
||||
return player.getName().equalsIgnoreCase(this.portalOwner.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world this portal belongs to
|
||||
*
|
||||
* @return <p>The world this portal belongs to</p>
|
||||
*/
|
||||
public World getWorld() {
|
||||
return location.getWorld();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of this portal's sign
|
||||
*
|
||||
* @return <p>The location of this portal's sign</p>
|
||||
*/
|
||||
public BlockLocation getSignLocation() {
|
||||
return this.location.getSignLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rotation (yaw) of this portal
|
||||
*
|
||||
* <p>The yaw is used to calculate all kinds of directions. See DirectionHelper to see how the yaw is used to
|
||||
* calculate to/from other direction types.</p>
|
||||
*
|
||||
* @return <p>The rotation (yaw) of this portal</p>
|
||||
*/
|
||||
public float getYaw() {
|
||||
return this.location.getYaw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the top-left block of the portal
|
||||
*
|
||||
* @return <p>The location of the top-left portal block</p>
|
||||
*/
|
||||
public BlockLocation getTopLeft() {
|
||||
return this.location.getTopLeft();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block at the given location relative to this portal's top-left block
|
||||
*
|
||||
* @param vector <p>The relative block vector explaining the position of the block</p>
|
||||
* @return <p>The block at the given relative position</p>
|
||||
*/
|
||||
public BlockLocation getBlockAt(RelativeBlockVector vector) {
|
||||
return getTopLeft().getRelativeLocation(vector, getYaw());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Portal [id=%s, network=%s name=%s, type=%s]", getSignLocation(), network, name,
|
||||
structure.getGate().getFilename());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((network == null) ? 0 : network.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
}
|
||||
if (object == null || getClass() != object.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Portal other = (Portal) object;
|
||||
if (name == null) {
|
||||
if (other.name != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!name.equalsIgnoreCase(other.name)) {
|
||||
return false;
|
||||
}
|
||||
//If none of the portals have a name, check if the network is the same
|
||||
if (network == null) {
|
||||
return other.network == null;
|
||||
} else {
|
||||
return network.equalsIgnoreCase(other.network);
|
||||
}
|
||||
}
|
||||
}
|
286
src/main/java/net/knarcraft/stargate/portal/PortalActivator.java
Normal file
286
src/main/java/net/knarcraft/stargate/portal/PortalActivator.java
Normal file
@ -0,0 +1,286 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.event.StargateActivateEvent;
|
||||
import net.knarcraft.stargate.event.StargateDeactivateEvent;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* The portal activator activates/de-activates portals and keeps track of a portal's destinations
|
||||
*
|
||||
* <p>The portal activator is responsible for activating/de-activating the portal and contains information about
|
||||
* available destinations and which player activated the portal.</p>
|
||||
*/
|
||||
public class PortalActivator {
|
||||
|
||||
private final Portal portal;
|
||||
private final PortalOpener opener;
|
||||
|
||||
private List<String> destinations = new ArrayList<>();
|
||||
private String destination;
|
||||
private String lastDestination = "";
|
||||
private Player activePlayer;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal destinations object
|
||||
*
|
||||
* @param portal <p>The portal which this this object stores destinations for</p>
|
||||
* @param portalOpener <p>The portal opener to trigger when the activation causes the portal to open</p>
|
||||
* @param destination <p>The fixed destination specified on the portal's sign</p>
|
||||
*/
|
||||
public PortalActivator(Portal portal, PortalOpener portalOpener, String destination) {
|
||||
this.portal = portal;
|
||||
this.opener = portalOpener;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player which this activator's portal is currently activated for
|
||||
*
|
||||
* @return <p>The player this activator's portal is currently activated for</p>
|
||||
*/
|
||||
public Player getActivePlayer() {
|
||||
return activePlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the available portal destinations
|
||||
*
|
||||
* @return <p>The available portal destinations</p>
|
||||
*/
|
||||
public List<String> getDestinations() {
|
||||
return new ArrayList<>(this.destinations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portal destination given a player
|
||||
*
|
||||
* @param player <p>Used for random gates to determine which destinations are available</p>
|
||||
* @return <p>The destination portal the player should teleport to</p>
|
||||
*/
|
||||
public Portal getDestination(Player player) {
|
||||
String portalNetwork = portal.getNetwork();
|
||||
if (portal.getOptions().isRandom()) {
|
||||
//Find possible destinations
|
||||
List<String> destinations = PortalHandler.getDestinations(portal, player, portalNetwork);
|
||||
if (destinations.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
//Get one random destination
|
||||
String destination = destinations.get((new Random()).nextInt(destinations.size()));
|
||||
return PortalHandler.getByName(destination, portalNetwork);
|
||||
} else {
|
||||
//Just return the normal fixed destination
|
||||
return PortalHandler.getByName(destination, portalNetwork);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portal's destination
|
||||
*
|
||||
* <p>For random portals, getDestination must be given a player to decide which destinations are valid. Without a
|
||||
* player, or with a null player, behavior is only defined for a non-random gate.</p>
|
||||
*
|
||||
* @return <p>The portal destination</p>
|
||||
*/
|
||||
public Portal getDestination() {
|
||||
return getDestination(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the destination of this portal activator's portal
|
||||
*
|
||||
* @param destination <p>The new destination of this portal activator's portal</p>
|
||||
*/
|
||||
public void setDestination(Portal destination) {
|
||||
setDestination(destination.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the destination of this portal activator's portal
|
||||
*
|
||||
* @param destination <p>The new destination of this portal activator's portal</p>
|
||||
*/
|
||||
public void setDestination(String destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the selected destination
|
||||
*
|
||||
* @return <p>The name of the selected destination</p>
|
||||
*/
|
||||
public String getDestinationName() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates this activator's portal for the given player
|
||||
*
|
||||
* @param player <p>The player to activate the portal for</p>
|
||||
* @return <p>True if the portal was activated</p>
|
||||
*/
|
||||
boolean activate(Player player) {
|
||||
//Clear previous destination data
|
||||
this.destination = "";
|
||||
this.destinations.clear();
|
||||
|
||||
//Adds the active gate to the active queue to allow it to be remotely deactivated
|
||||
Stargate.getStargateConfig().getActivePortalsQueue().add(portal);
|
||||
|
||||
//Set the given player as the active player
|
||||
activePlayer = player;
|
||||
|
||||
String network = portal.getNetwork();
|
||||
destinations = PortalHandler.getDestinations(portal, player, network);
|
||||
|
||||
//Sort destinations if enabled
|
||||
if (Stargate.getGateConfig().sortNetworkDestinations()) {
|
||||
Collections.sort(destinations);
|
||||
}
|
||||
|
||||
//Select last used destination if remember destination is enabled
|
||||
if (Stargate.getGateConfig().rememberDestination() && !lastDestination.isEmpty() &&
|
||||
destinations.contains(lastDestination)) {
|
||||
destination = lastDestination;
|
||||
}
|
||||
|
||||
//Trigger an activation event to allow the cancellation to be cancelled
|
||||
return triggerStargateActivationEvent(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a stargate activation event to allow other plugins to cancel the activation
|
||||
*
|
||||
* <p>The event may also end up changing destinations.</p>
|
||||
*
|
||||
* @param player <p>The player trying to activate this activator's portal</p>
|
||||
* @return <p>True if the portal was activated. False otherwise</p>
|
||||
*/
|
||||
private boolean triggerStargateActivationEvent(Player player) {
|
||||
StargateActivateEvent event = new StargateActivateEvent(portal, player, destinations, destination);
|
||||
Stargate.getInstance().getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
Stargate.getStargateConfig().getActivePortalsQueue().remove(portal);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Update destinations in case they changed, and update the sign
|
||||
destination = event.getDestination();
|
||||
destinations = event.getDestinations();
|
||||
portal.drawSign();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates this portal
|
||||
*/
|
||||
public void deactivate() {
|
||||
//Trigger a stargate deactivate event to allow other plugins to cancel the event
|
||||
StargateDeactivateEvent event = new StargateDeactivateEvent(portal);
|
||||
Stargate.getInstance().getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Un-mark the portal as activated
|
||||
Stargate.getStargateConfig().getActivePortalsQueue().remove(portal);
|
||||
|
||||
//Fixed portals are active by definition, but should never be de-activated
|
||||
if (portal.getOptions().isFixed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Clear destinations and the active player before re-drawing the sign to show that it's deactivated
|
||||
destinations.clear();
|
||||
destination = "";
|
||||
activePlayer = null;
|
||||
portal.drawSign();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal activator's portal is active
|
||||
*
|
||||
* @return <p>Whether this portal activator's portal is active</p>
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return portal.getOptions().isFixed() || (destinations.size() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles destination for a non-fixed gate by one forwards step
|
||||
*
|
||||
* @param player <p>The player to cycle the gate for</p>
|
||||
*/
|
||||
public void cycleDestination(Player player) {
|
||||
cycleDestination(player, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles destination for a non-fixed gate
|
||||
*
|
||||
* @param player <p>The player cycling destinations</p>
|
||||
* @param direction <p>The direction of the cycle (+1 for next, -1 for previous)</p>
|
||||
*/
|
||||
public void cycleDestination(Player player, int direction) {
|
||||
//Only allow going exactly one step in either direction
|
||||
if (direction != 1 && direction != -1) {
|
||||
throw new IllegalArgumentException("The destination direction must be 1 or -1.");
|
||||
}
|
||||
|
||||
boolean activate = false;
|
||||
if (!isActive() || getActivePlayer() != player) {
|
||||
//If not active or not active for the given player, and the activation is denied, just abort
|
||||
if (!activate(player)) {
|
||||
return;
|
||||
}
|
||||
activate = true;
|
||||
|
||||
Stargate.debug("cycleDestination", "Network Size: " +
|
||||
PortalHandler.getNetwork(portal.getNetwork()).size());
|
||||
Stargate.debug("cycleDestination", "Player has access to: " + destinations.size());
|
||||
}
|
||||
|
||||
//If no destinations are available, just tell the player and quit
|
||||
if (destinations.size() == 0) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("destEmpty"));
|
||||
return;
|
||||
}
|
||||
|
||||
//Cycle if destination remembering is disabled, if the portal was already active, or it has no last destination
|
||||
if (!Stargate.getGateConfig().rememberDestination() || !activate || lastDestination.isEmpty()) {
|
||||
cycleDestination(direction);
|
||||
}
|
||||
|
||||
//Update the activated time to allow it to be deactivated after a timeout, and re-draw the sign to show the
|
||||
// selected destination
|
||||
opener.setTriggeredTime(System.currentTimeMillis() / 1000);
|
||||
portal.drawSign();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual destination cycling with no input checks
|
||||
*
|
||||
* @param direction <p>The direction of the cycle (+1 for next, -1 for previous)</p>
|
||||
*/
|
||||
private void cycleDestination(int direction) {
|
||||
int index = destinations.indexOf(destination);
|
||||
index += direction;
|
||||
|
||||
//Wrap around if the last destination has been reached
|
||||
if (index >= destinations.size()) {
|
||||
index = 0;
|
||||
} else if (index < 0) {
|
||||
index = destinations.size() - 1;
|
||||
}
|
||||
//Store selected destination
|
||||
destination = destinations.get(index);
|
||||
lastDestination = destination;
|
||||
}
|
||||
|
||||
}
|
336
src/main/java/net/knarcraft/stargate/portal/PortalCreator.java
Normal file
336
src/main/java/net/knarcraft/stargate/portal/PortalCreator.java
Normal file
@ -0,0 +1,336 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.container.RelativeBlockVector;
|
||||
import net.knarcraft.stargate.event.StargateCreateEvent;
|
||||
import net.knarcraft.stargate.utility.DirectionHelper;
|
||||
import net.knarcraft.stargate.utility.EconomyHelper;
|
||||
import net.knarcraft.stargate.utility.PermissionHelper;
|
||||
import net.knarcraft.stargate.utility.PortalFileHelper;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.Directional;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.SignChangeEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The portal creator can create and validate a new portal
|
||||
*/
|
||||
public class PortalCreator {
|
||||
|
||||
private Portal portal;
|
||||
private final SignChangeEvent event;
|
||||
private final Player player;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal creator
|
||||
*
|
||||
* @param event <p>The sign change event which initialized the creation</p>
|
||||
* @param player <p>The player creating the portal</p>
|
||||
*/
|
||||
public PortalCreator(SignChangeEvent event, Player player) {
|
||||
this.event = event;
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new portal
|
||||
*
|
||||
* @return <p>The created portal</p>
|
||||
*/
|
||||
public Portal createPortal() {
|
||||
BlockLocation signLocation = new BlockLocation(event.getBlock());
|
||||
Block idParent = signLocation.getParent();
|
||||
|
||||
//Return early if the sign is not placed on a block, or the block is not a control block
|
||||
if (idParent == null || GateHandler.getGatesByControlBlock(idParent).length == 0) {
|
||||
Stargate.debug("createPortal", "Control block not registered");
|
||||
return null;
|
||||
}
|
||||
|
||||
//The control block is already part of another portal
|
||||
if (PortalHandler.getByBlock(idParent) != null) {
|
||||
Stargate.debug("createPortal", "idParent belongs to existing stargate");
|
||||
return null;
|
||||
}
|
||||
|
||||
//Get necessary information from the gate's sign
|
||||
String portalName = PortalHandler.filterName(event.getLine(0));
|
||||
String destinationName = PortalHandler.filterName(event.getLine(1));
|
||||
String network = PortalHandler.filterName(event.getLine(2));
|
||||
String options = PortalHandler.filterName(event.getLine(3)).toLowerCase();
|
||||
|
||||
//Get portal options available to the player creating the portal
|
||||
Map<PortalOption, Boolean> portalOptions = PortalHandler.getPortalOptions(player, destinationName, options);
|
||||
|
||||
//Get the yaw
|
||||
float yaw = DirectionHelper.getYawFromLocationDifference(idParent.getLocation(), signLocation.getLocation());
|
||||
|
||||
//Get the direction the button should be facing
|
||||
BlockFace buttonFacing = DirectionHelper.getBlockFaceFromYaw(yaw);
|
||||
|
||||
PortalLocation portalLocation = new PortalLocation();
|
||||
portalLocation.setButtonFacing(buttonFacing).setYaw(yaw).setSignLocation(signLocation);
|
||||
|
||||
Stargate.debug("createPortal", "Finished getting all portal info");
|
||||
|
||||
//Try and find a gate matching the new portal
|
||||
Gate gate = PortalHandler.findMatchingGate(portalLocation, player);
|
||||
if ((gate == null) || (portalLocation.getButtonVector() == null)) {
|
||||
Stargate.debug("createPortal", "Could not find matching gate layout");
|
||||
return null;
|
||||
}
|
||||
|
||||
//If the portal is a bungee portal and invalid, abort here
|
||||
if (!PortalHandler.isValidBungeePortal(portalOptions, player, destinationName, network)) {
|
||||
Stargate.debug("createPortal", "Portal is an invalid bungee portal");
|
||||
return null;
|
||||
}
|
||||
|
||||
//Debug
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (PortalOption option : portalOptions.keySet()) {
|
||||
builder.append(option.getCharacterRepresentation()).append(" = ").append(portalOptions.get(option)).append(" ");
|
||||
}
|
||||
Stargate.debug("createPortal", builder.toString());
|
||||
|
||||
//Use default network if a proper alternative is not set
|
||||
if (!portalOptions.get(PortalOption.BUNGEE) && (network.length() < 1 || network.length() > 11)) {
|
||||
network = Stargate.getDefaultNetwork();
|
||||
}
|
||||
|
||||
boolean deny = false;
|
||||
String denyMessage = "";
|
||||
|
||||
//Check if the player can create portals on this network. If not, create a personal portal
|
||||
if (!portalOptions.get(PortalOption.BUNGEE) && !PermissionHelper.canCreateNetworkGate(player, network)) {
|
||||
Stargate.debug("createPortal", "Player doesn't have create permissions on network. Trying personal");
|
||||
if (PermissionHelper.canCreatePersonalPortal(player)) {
|
||||
network = player.getName();
|
||||
if (network.length() > 11) {
|
||||
network = network.substring(0, 11);
|
||||
}
|
||||
Stargate.debug("createPortal", "Creating personal portal");
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createPersonal"));
|
||||
} else {
|
||||
Stargate.debug("createPortal", "Player does not have access to network");
|
||||
deny = true;
|
||||
denyMessage = Stargate.getString("createNetDeny");
|
||||
}
|
||||
}
|
||||
|
||||
//Check if the player can create this gate layout
|
||||
String gateName = gate.getFilename();
|
||||
gateName = gateName.substring(0, gateName.indexOf('.'));
|
||||
if (!deny && !PermissionHelper.canCreatePortal(player, gateName)) {
|
||||
Stargate.debug("createPortal", "Player does not have access to gate layout");
|
||||
deny = true;
|
||||
denyMessage = Stargate.getString("createGateDeny");
|
||||
}
|
||||
|
||||
//Check if the user can create portals to this world.
|
||||
if (!portalOptions.get(PortalOption.BUNGEE) && !deny && destinationName.length() > 0) {
|
||||
Portal portal = PortalHandler.getByName(destinationName, network);
|
||||
if (portal != null) {
|
||||
String world = portal.getWorld().getName();
|
||||
if (PermissionHelper.cannotAccessWorld(player, world)) {
|
||||
Stargate.debug("canCreateNetworkGate", "Player does not have access to destination world");
|
||||
deny = true;
|
||||
denyMessage = Stargate.getString("createWorldDeny");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Check if a conflict exists
|
||||
if (conflictsWithExistingPortal(gate, portalLocation.getTopLeft(), yaw, player)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PortalOwner owner = new PortalOwner(player);
|
||||
this.portal = new Portal(portalLocation, null, destinationName, portalName, network, gate, owner,
|
||||
portalOptions);
|
||||
return validatePortal(denyMessage, event.getLines(), deny);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the newly created portal assigned to this portal validator
|
||||
*
|
||||
* @param denyMessage <p>The deny message to displayed if the creation has already been denied</p>
|
||||
* @param lines <p>The lines on the sign causing the portal to be created</p>
|
||||
* @param deny <p>Whether the portal creation has already been denied</p>
|
||||
* @return <p>The portal or null if its creation was denied</p>
|
||||
*/
|
||||
public Portal validatePortal(String denyMessage, String[] lines, boolean deny) {
|
||||
PortalLocation portalLocation = portal.getLocation();
|
||||
Gate gate = portal.getStructure().getGate();
|
||||
PortalOptions portalOptions = portal.getOptions();
|
||||
String portalName = portal.getName();
|
||||
String destinationName = portal.getDestinationName();
|
||||
|
||||
int createCost = Stargate.getEconomyConfig().getCreateCost(player, gate);
|
||||
|
||||
//Call StargateCreateEvent to let other plugins cancel or overwrite denial
|
||||
StargateCreateEvent stargateCreateEvent = new StargateCreateEvent(player, portal, lines, deny,
|
||||
denyMessage, createCost);
|
||||
Stargate.getInstance().getServer().getPluginManager().callEvent(stargateCreateEvent);
|
||||
if (stargateCreateEvent.isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//Tell the user why it was denied from creating the portal
|
||||
if (stargateCreateEvent.getDeny()) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, stargateCreateEvent.getDenyReason());
|
||||
return null;
|
||||
}
|
||||
|
||||
createCost = stargateCreateEvent.getCost();
|
||||
|
||||
//Check if the new portal is valid
|
||||
if (!checkIfNewPortalIsValid(createCost, portalName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//Add button if the portal is not always on
|
||||
if (!portalOptions.isAlwaysOn() && !portalOptions.isBungee()) {
|
||||
generatePortalButton(portalLocation.getTopLeft(), portalLocation.getButtonVector(),
|
||||
portalLocation.getButtonFacing());
|
||||
}
|
||||
|
||||
//Register the new portal
|
||||
PortalHandler.registerPortal(portal);
|
||||
updateNewPortalOpenState(destinationName);
|
||||
|
||||
//Update portals pointing at this one if it's not a bungee portal
|
||||
if (!portal.getOptions().isBungee()) {
|
||||
PortalHandler.updatePortalsPointingAtNewPortal(portal);
|
||||
}
|
||||
|
||||
PortalFileHelper.saveAllPortals(portal.getWorld());
|
||||
|
||||
return portal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the newly created, but unregistered portal is valid
|
||||
*
|
||||
* @param cost <p>The cost of creating the portal</p>
|
||||
* @param portalName <p>The name of the newly created portal</p>
|
||||
* @return <p>True if the portal is completely valid</p>
|
||||
*/
|
||||
private boolean checkIfNewPortalIsValid(int cost, String portalName) {
|
||||
//Check if the portal name can fit on the sign with padding (>name<)
|
||||
if (portal.getName().length() < 1 || portal.getName().length() > 11) {
|
||||
Stargate.debug("createPortal", "Name length error");
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createNameLength"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (portal.getOptions().isBungee()) {
|
||||
//Check if the bungee portal's name has been duplicated
|
||||
if (PortalHandler.getBungeePortals().get(portal.getName().toLowerCase()) != null) {
|
||||
Stargate.debug("createPortal::Bungee", "Gate name duplicate");
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createExists"));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
//Check if the portal name has been duplicated on the network
|
||||
if (PortalHandler.getByName(portal.getName(), portal.getNetwork()) != null) {
|
||||
Stargate.debug("createPortal", "Gate name duplicate");
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createExists"));
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check if the number of portals in the network has been surpassed
|
||||
List<String> networkList = PortalHandler.getAllPortalNetworks().get(portal.getNetwork().toLowerCase());
|
||||
int maxGates = Stargate.getGateConfig().maxGatesEachNetwork();
|
||||
if (maxGates > 0 && networkList != null && networkList.size() >= maxGates) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createFull"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (cost > 0) {
|
||||
//Deduct the required fee from the player
|
||||
if (!Stargate.getEconomyConfig().chargePlayerIfNecessary(player, cost)) {
|
||||
EconomyHelper.sendInsufficientFundsMessage(portalName, player, cost);
|
||||
Stargate.debug("createPortal", "Insufficient Funds");
|
||||
return false;
|
||||
} else {
|
||||
EconomyHelper.sendDeductMessage(portalName, player, cost);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a button for a portal
|
||||
*
|
||||
* @param topLeft <p>The top-left block of the portal</p>
|
||||
* @param buttonVector <p>A relative vector pointing at the button</p>
|
||||
* @param buttonFacing <p>The direction the button should be facing</p>
|
||||
*/
|
||||
private void generatePortalButton(BlockLocation topLeft, RelativeBlockVector buttonVector,
|
||||
BlockFace buttonFacing) {
|
||||
//Go one block outwards to find the button's location rather than the control block's location
|
||||
BlockLocation button = topLeft.getRelativeLocation(buttonVector.addToVector(
|
||||
RelativeBlockVector.Property.OUT, 1), portal.getYaw());
|
||||
|
||||
Directional buttonData = (Directional) Bukkit.createBlockData(portal.getGate().getPortalButton());
|
||||
buttonData.setFacing(buttonFacing);
|
||||
button.getBlock().setBlockData(buttonData);
|
||||
portal.getStructure().setButton(button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the open state of the newly created portal
|
||||
*
|
||||
* @param destinationName <p>The name of the destination portal. Only used if set as always on</p>
|
||||
*/
|
||||
private void updateNewPortalOpenState(String destinationName) {
|
||||
portal.drawSign();
|
||||
if (portal.getOptions().isRandom() || portal.getOptions().isBungee()) {
|
||||
//Open the implicitly always on portal
|
||||
portal.getPortalOpener().openPortal(true);
|
||||
} else if (portal.getOptions().isAlwaysOn()) {
|
||||
//For a normal always-on portal, open both the portal and the destination
|
||||
Portal destinationPortal = PortalHandler.getByName(destinationName, portal.getNetwork());
|
||||
if (destinationPortal != null) {
|
||||
portal.getPortalOpener().openPortal(true);
|
||||
destinationPortal.drawSign();
|
||||
}
|
||||
} else {
|
||||
//Update the block type for the portal's opening to the closed block as the closed block can be anything,
|
||||
// not just air or water
|
||||
for (BlockLocation entrance : portal.getStructure().getEntrances()) {
|
||||
entrance.setType(portal.getGate().getPortalClosedBlock());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the new portal conflicts with an existing portal
|
||||
*
|
||||
* @param gate <p>The gate type of the new portal</p>
|
||||
* @param topLeft <p>The top-left block of the new portal</p>
|
||||
* @param yaw <p>The yaw when looking directly outwards from the portal</p>
|
||||
* @param player <p>The player creating the new portal</p>
|
||||
* @return <p>True if a conflict was found. False otherwise</p>
|
||||
*/
|
||||
private static boolean conflictsWithExistingPortal(Gate gate, BlockLocation topLeft, double yaw, Player player) {
|
||||
for (RelativeBlockVector borderVector : gate.getLayout().getBorder()) {
|
||||
BlockLocation borderBlockLocation = topLeft.getRelativeLocation(borderVector, yaw);
|
||||
if (PortalHandler.getByBlock(borderBlockLocation.getBlock()) != null) {
|
||||
Stargate.debug("createPortal", "Gate conflicts with existing gate");
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("createConflict"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
444
src/main/java/net/knarcraft/stargate/portal/PortalHandler.java
Normal file
444
src/main/java/net/knarcraft/stargate/portal/PortalHandler.java
Normal file
@ -0,0 +1,444 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.container.RelativeBlockVector;
|
||||
import net.knarcraft.stargate.utility.PermissionHelper;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Keeps track of all loaded portals, and handles portal creation
|
||||
*/
|
||||
public class PortalHandler {
|
||||
|
||||
private PortalHandler() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of all portal networks
|
||||
*
|
||||
* @return <p>A copy of all portal networks</p>
|
||||
*/
|
||||
public static Map<String, List<String>> getAllPortalNetworks() {
|
||||
return PortalRegistry.getAllPortalNetworks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of all bungee portals
|
||||
*
|
||||
* @return <p>A copy of all bungee portals</p>
|
||||
*/
|
||||
public static Map<String, Portal> getBungeePortals() {
|
||||
return PortalRegistry.getBungeePortals();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets names of all portals within a network
|
||||
*
|
||||
* @param network <p>The network to get portals from</p>
|
||||
* @return <p>A list of portal names</p>
|
||||
*/
|
||||
public static List<String> getNetwork(String network) {
|
||||
return PortalRegistry.getNetwork(network);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all destinations in the network viewable by the given player
|
||||
*
|
||||
* @param entrancePortal <p>The portal the user is entering from</p>
|
||||
* @param player <p>The player who wants to see destinations</p>
|
||||
* @param network <p>The network to get destinations from</p>
|
||||
* @return <p>All destinations the player can go to</p>
|
||||
*/
|
||||
public static List<String> getDestinations(Portal entrancePortal, Player player, String network) {
|
||||
List<String> destinations = new ArrayList<>();
|
||||
for (String destination : PortalRegistry.getAllPortalNetworks().get(network.toLowerCase())) {
|
||||
Portal portal = getByName(destination, network);
|
||||
if (portal == null) {
|
||||
continue;
|
||||
}
|
||||
//Check if destination is a random portal
|
||||
if (portal.getOptions().isRandom()) {
|
||||
continue;
|
||||
}
|
||||
//Check if destination is always open (Don't show if so)
|
||||
if (portal.getOptions().isAlwaysOn() && !portal.getOptions().isShown()) {
|
||||
continue;
|
||||
}
|
||||
//Check if destination is this portal
|
||||
if (destination.equalsIgnoreCase(entrancePortal.getName())) {
|
||||
continue;
|
||||
}
|
||||
//Check if destination is a fixed portal not pointing to this portal
|
||||
if (portal.getOptions().isFixed() && !portal.getDestinationName().equalsIgnoreCase(entrancePortal.getName())) {
|
||||
continue;
|
||||
}
|
||||
//Allow random use by non-players (Minecarts)
|
||||
if (player == null) {
|
||||
destinations.add(portal.getName());
|
||||
continue;
|
||||
}
|
||||
//Check if this player can access the destination world
|
||||
if (PermissionHelper.cannotAccessWorld(player, portal.getWorld().getName())) {
|
||||
continue;
|
||||
}
|
||||
//The portal is visible to the player
|
||||
if (PermissionHelper.canSeePortal(player, portal)) {
|
||||
destinations.add(portal.getName());
|
||||
}
|
||||
}
|
||||
return destinations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a portal
|
||||
*
|
||||
* @param portal <p>The portal to register</p>
|
||||
*/
|
||||
public static void registerPortal(Portal portal) {
|
||||
PortalRegistry.registerPortal(portal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the new portal is a valid bungee portal
|
||||
*
|
||||
* @param portalOptions <p>The enabled portal options</p>
|
||||
* @param player <p>The player trying to create the new portal</p>
|
||||
* @param destinationName <p>The name of the portal's destination</p>
|
||||
* @param network <p>The name of the portal's network</p>
|
||||
* @return <p>False if the portal is an invalid bungee portal. True otherwise</p>
|
||||
*/
|
||||
static boolean isValidBungeePortal(Map<PortalOption, Boolean> portalOptions, Player player,
|
||||
String destinationName, String network) {
|
||||
if (portalOptions.get(PortalOption.BUNGEE)) {
|
||||
if (!PermissionHelper.hasPermission(player, "stargate.admin.bungee")) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeDeny"));
|
||||
return false;
|
||||
} else if (!Stargate.getGateConfig().enableBungee()) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeDisabled"));
|
||||
return false;
|
||||
} else if (destinationName.isEmpty() || network.isEmpty()) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeEmpty"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find a gate matching the portal the user is trying to create
|
||||
*
|
||||
* @param portalLocation <p>The location data for the new portal</p>
|
||||
* @param player <p>The player trying to create the new portal</p>
|
||||
* @return <p>The matching gate type, or null if no such gate could be found</p>
|
||||
*/
|
||||
static Gate findMatchingGate(PortalLocation portalLocation, Player player) {
|
||||
Block signParent = portalLocation.getSignLocation().getParent();
|
||||
BlockLocation parent = new BlockLocation(player.getWorld(), signParent.getX(), signParent.getY(),
|
||||
signParent.getZ());
|
||||
|
||||
//Get all gates with the used type of control blocks
|
||||
Gate[] possibleGates = GateHandler.getGatesByControlBlock(signParent);
|
||||
double yaw = portalLocation.getYaw();
|
||||
Gate gate = null;
|
||||
|
||||
for (Gate possibleGate : possibleGates) {
|
||||
//Get gate controls
|
||||
RelativeBlockVector[] vectors = possibleGate.getLayout().getControls();
|
||||
|
||||
portalLocation.setButtonVector(null);
|
||||
for (RelativeBlockVector controlVector : vectors) {
|
||||
//Assuming the top-left location is pointing to the gate's top-left location, check if it's a match
|
||||
BlockLocation possibleTopLocation = parent.getRelativeLocation(controlVector.invert(), yaw);
|
||||
if (possibleGate.matches(possibleTopLocation, portalLocation.getYaw(), true)) {
|
||||
gate = possibleGate;
|
||||
portalLocation.setTopLeft(possibleTopLocation);
|
||||
} else {
|
||||
portalLocation.setButtonVector(controlVector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the sign and open state of portals pointing at the newly created portal
|
||||
*
|
||||
* @param portal <p>The newly created portal</p>
|
||||
*/
|
||||
static void updatePortalsPointingAtNewPortal(Portal portal) {
|
||||
for (String originName : PortalRegistry.getAllPortalNetworks().get(portal.getNetwork().toLowerCase())) {
|
||||
Portal origin = getByName(originName, portal.getNetwork());
|
||||
if (origin == null ||
|
||||
!origin.getDestinationName().equalsIgnoreCase(portal.getName()) ||
|
||||
!origin.getStructure().isVerified()) {
|
||||
continue;
|
||||
}
|
||||
//Update sign of fixed gates pointing at this gate
|
||||
if (origin.getOptions().isFixed()) {
|
||||
origin.drawSign();
|
||||
}
|
||||
//Open any always on portal pointing at this portal
|
||||
if (origin.getOptions().isAlwaysOn()) {
|
||||
origin.getPortalOpener().openPortal(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all portal options to be applied to a new portal
|
||||
*
|
||||
* @param player <p>The player creating the portal</p>
|
||||
* @param destinationName <p>The destination of the portal</p>
|
||||
* @param options <p>The string on the option line of the sign</p>
|
||||
* @return <p>A map containing all portal options and their values</p>
|
||||
*/
|
||||
static Map<PortalOption, Boolean> getPortalOptions(Player player, String destinationName, String options) {
|
||||
Map<PortalOption, Boolean> portalOptions = new HashMap<>();
|
||||
for (PortalOption option : PortalOption.values()) {
|
||||
portalOptions.put(option, options.indexOf(option.getCharacterRepresentation()) != -1 &&
|
||||
PermissionHelper.canUseOption(player, option));
|
||||
}
|
||||
|
||||
//Can not create a non-fixed always-on portal
|
||||
if (portalOptions.get(PortalOption.ALWAYS_ON) && destinationName.length() == 0) {
|
||||
portalOptions.put(PortalOption.ALWAYS_ON, false);
|
||||
}
|
||||
|
||||
//Show isn't useful if always on is false
|
||||
if (portalOptions.get(PortalOption.SHOW) && !portalOptions.get(PortalOption.ALWAYS_ON)) {
|
||||
portalOptions.put(PortalOption.SHOW, false);
|
||||
}
|
||||
|
||||
//Random portals are always on and can't be shown
|
||||
if (portalOptions.get(PortalOption.RANDOM)) {
|
||||
portalOptions.put(PortalOption.ALWAYS_ON, true);
|
||||
portalOptions.put(PortalOption.SHOW, false);
|
||||
}
|
||||
|
||||
//Bungee portals are always on and don't support Random
|
||||
if (portalOptions.get(PortalOption.BUNGEE)) {
|
||||
portalOptions.put(PortalOption.ALWAYS_ON, true);
|
||||
portalOptions.put(PortalOption.RANDOM, false);
|
||||
}
|
||||
return portalOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a portal given its name
|
||||
*
|
||||
* @param name <p>The name of the portal</p>
|
||||
* @param network <p>The network the portal is connected to</p>
|
||||
* @return <p>The portal with the given name or null</p>
|
||||
*/
|
||||
public static Portal getByName(String name, String network) {
|
||||
Map<String, Map<String, Portal>> lookupMap = PortalRegistry.getPortalLookupByNetwork();
|
||||
if (!lookupMap.containsKey(network.toLowerCase())) {
|
||||
return null;
|
||||
}
|
||||
return lookupMap.get(network.toLowerCase()).get(name.toLowerCase());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a portal given its entrance
|
||||
*
|
||||
* @param location <p>The location of the portal's entrance</p>
|
||||
* @return <p>The portal at the given location</p>
|
||||
*/
|
||||
public static Portal getByEntrance(Location location) {
|
||||
return PortalRegistry.getLookupEntrances().get(new BlockLocation(location.getWorld(), location.getBlockX(),
|
||||
location.getBlockY(), location.getBlockZ()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a portal given its entrance
|
||||
*
|
||||
* @param block <p>The block at the portal's entrance</p>
|
||||
* @return <p>The portal at the given block's location</p>
|
||||
*/
|
||||
public static Portal getByEntrance(Block block) {
|
||||
return PortalRegistry.getLookupEntrances().get(new BlockLocation(block));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a portal given a location adjacent to its entrance
|
||||
*
|
||||
* @param location <p>A location adjacent to the portal's entrance</p>
|
||||
* @return <p>The portal adjacent to the given location</p>
|
||||
*/
|
||||
public static Portal getByAdjacentEntrance(Location location) {
|
||||
return getByAdjacentEntrance(location, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a portal given a location adjacent to its entrance
|
||||
*
|
||||
* @param location <p>A location adjacent to the portal's entrance</p>
|
||||
* @param range <p>The range to scan for portals</p>
|
||||
* @return <p>The portal adjacent to the given location</p>
|
||||
*/
|
||||
public static Portal getByAdjacentEntrance(Location location, int range) {
|
||||
List<BlockLocation> adjacentPositions = new ArrayList<>();
|
||||
BlockLocation centerLocation = new BlockLocation(location.getBlock());
|
||||
adjacentPositions.add(centerLocation);
|
||||
|
||||
for (int index = 1; index <= range; index++) {
|
||||
adjacentPositions.add(centerLocation.makeRelativeBlockLocation(index, 0, 0));
|
||||
adjacentPositions.add(centerLocation.makeRelativeBlockLocation(-index, 0, 0));
|
||||
adjacentPositions.add(centerLocation.makeRelativeBlockLocation(0, 0, index));
|
||||
adjacentPositions.add(centerLocation.makeRelativeBlockLocation(0, 0, -index));
|
||||
if (index < range) {
|
||||
adjacentPositions.add(centerLocation.makeRelativeBlockLocation(index, 0, index));
|
||||
adjacentPositions.add(centerLocation.makeRelativeBlockLocation(-index, 0, -index));
|
||||
adjacentPositions.add(centerLocation.makeRelativeBlockLocation(index, 0, -index));
|
||||
adjacentPositions.add(centerLocation.makeRelativeBlockLocation(-index, 0, index));
|
||||
}
|
||||
}
|
||||
|
||||
for (BlockLocation adjacentPosition : adjacentPositions) {
|
||||
Portal portal = PortalRegistry.getLookupEntrances().get(adjacentPosition);
|
||||
if (portal != null) {
|
||||
return portal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a portal given its control block (the block type used for the sign and button)
|
||||
*
|
||||
* @param block <p>The portal's control block</p>
|
||||
* @return <p>The portal with the given control block</p>
|
||||
*/
|
||||
public static Portal getByControl(Block block) {
|
||||
return PortalRegistry.getLookupControls().get(new BlockLocation(block));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a portal given a block
|
||||
*
|
||||
* @param block <p>One of the loaded lookup blocks</p>
|
||||
* @return <p>The portal corresponding to the block</p>
|
||||
*/
|
||||
public static Portal getByBlock(Block block) {
|
||||
return PortalRegistry.getLookupBlocks().get(new BlockLocation(block));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a bungee portal given its name
|
||||
*
|
||||
* @param name <p>The name of the bungee portal to get</p>
|
||||
* @return <p>A bungee portal</p>
|
||||
*/
|
||||
public static Portal getBungeePortal(String name) {
|
||||
return PortalRegistry.getBungeePortals().get(name.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all portal options stored in the portal data
|
||||
*
|
||||
* @param portalData <p>The string list containing all information about a portal</p>
|
||||
* @return <p>A map between portal options and booleans</p>
|
||||
*/
|
||||
public static Map<PortalOption, Boolean> getPortalOptions(String[] portalData) {
|
||||
Map<PortalOption, Boolean> portalOptions = new HashMap<>();
|
||||
for (PortalOption option : PortalOption.values()) {
|
||||
int saveIndex = option.getSaveIndex();
|
||||
portalOptions.put(option, portalData.length > saveIndex && Boolean.parseBoolean(portalData[saveIndex]));
|
||||
}
|
||||
return portalOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens all always-on portals
|
||||
*
|
||||
* @return <p>The number of always open portals enabled</p>
|
||||
*/
|
||||
public static int openAlwaysOpenPortals() {
|
||||
int alwaysOpenCount = 0;
|
||||
|
||||
for (Portal portal : PortalRegistry.getAllPortals()) {
|
||||
//Open the gate if it's set as always open or if it's a bungee gate
|
||||
if (portal.getOptions().isFixed() && (Stargate.getGateConfig().enableBungee() &&
|
||||
portal.getOptions().isBungee() || portal.getPortalActivator().getDestination() != null &&
|
||||
portal.getOptions().isAlwaysOn())) {
|
||||
portal.getPortalOpener().openPortal(true);
|
||||
alwaysOpenCount++;
|
||||
}
|
||||
}
|
||||
return alwaysOpenCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to verify all portals and un-registers non-verifiable portals
|
||||
*/
|
||||
public static void verifyAllPortals() {
|
||||
List<Portal> invalidPortals = new ArrayList<>();
|
||||
for (Portal portal : PortalRegistry.getAllPortals()) {
|
||||
//Try and verify the portal. Invalidate it if it cannot be validated
|
||||
PortalStructure structure = portal.getStructure();
|
||||
if (!structure.wasVerified() && (!structure.isVerified() || !structure.checkIntegrity())) {
|
||||
invalidPortals.add(portal);
|
||||
}
|
||||
}
|
||||
|
||||
//Un-register any invalid portals found
|
||||
for (Portal portal : invalidPortals) {
|
||||
unregisterInvalidPortal(portal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-registers a portal which has failed its integrity tests
|
||||
*
|
||||
* @param portal <p>The portal of the star portal</p>
|
||||
*/
|
||||
private static void unregisterInvalidPortal(Portal portal) {
|
||||
//Show debug information
|
||||
for (RelativeBlockVector control : portal.getGate().getLayout().getControls()) {
|
||||
Block block = portal.getBlockAt(control).getBlock();
|
||||
//Log control blocks not matching the gate layout
|
||||
if (!block.getType().equals(portal.getGate().getControlBlock())) {
|
||||
Stargate.debug("PortalHandler::destroyInvalidPortal", "Control Block Type == " +
|
||||
block.getType().name());
|
||||
}
|
||||
}
|
||||
PortalRegistry.unregisterPortal(portal, false);
|
||||
Stargate.logInfo(String.format("Destroying stargate at %s", portal));
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all portals
|
||||
*/
|
||||
public static void closeAllPortals() {
|
||||
Stargate.logInfo("Closing all stargates.");
|
||||
for (Portal portal : PortalRegistry.getAllPortals()) {
|
||||
if (portal != null) {
|
||||
portal.getPortalOpener().closePortal(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the special characters |, : and # from a portal name
|
||||
*
|
||||
* @param input <p>The name to filter</p>
|
||||
* @return <p>The filtered name</p>
|
||||
*/
|
||||
public static String filterName(String input) {
|
||||
if (input == null) {
|
||||
return "";
|
||||
}
|
||||
return input.replaceAll("[|:#]", "").trim();
|
||||
}
|
||||
}
|
145
src/main/java/net/knarcraft/stargate/portal/PortalLocation.java
Normal file
145
src/main/java/net/knarcraft/stargate/portal/PortalLocation.java
Normal file
@ -0,0 +1,145 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.container.RelativeBlockVector;
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.BlockFace;
|
||||
|
||||
/**
|
||||
* Keeps track of location related data for a portal
|
||||
*/
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public class PortalLocation {
|
||||
|
||||
private BlockLocation topLeft;
|
||||
private float yaw;
|
||||
private BlockLocation signLocation;
|
||||
private RelativeBlockVector buttonVector;
|
||||
private BlockFace buttonFacing;
|
||||
|
||||
/**
|
||||
* Gets the top-left block of the portal
|
||||
*
|
||||
* @return <p>The top-left block of the portal</p>
|
||||
*/
|
||||
public BlockLocation getTopLeft() {
|
||||
return topLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the yaw for looking outwards from the portal
|
||||
*
|
||||
* @return <p>The portal's yaw</p>
|
||||
*/
|
||||
public float getYaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the portal's sign
|
||||
*
|
||||
* @return <p>The location of the portal's sign</p>
|
||||
*/
|
||||
public BlockLocation getSignLocation() {
|
||||
return signLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* The relative block vector pointing to the portal's button
|
||||
*
|
||||
* @return <p>The relative location of the portal's button</p>
|
||||
*/
|
||||
public RelativeBlockVector getButtonVector() {
|
||||
return buttonVector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block face determining the button's direction
|
||||
*
|
||||
* @return <p>The button's block face</p>
|
||||
*/
|
||||
public BlockFace getButtonFacing() {
|
||||
return buttonFacing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rotation axis, which is the axis along which the gate is placed
|
||||
* <p>The portal's rotation axis is the cross axis of the button's axis</p>
|
||||
*
|
||||
* @return <p>The portal's rotation axis</p>
|
||||
*/
|
||||
public Axis getRotationAxis() {
|
||||
return getYaw() == 0.0F || getYaw() == 180.0F ? Axis.X : Axis.Z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world this portal resides in
|
||||
*
|
||||
* @return <p>The world this portal resides in</p>
|
||||
*/
|
||||
public World getWorld() {
|
||||
return topLeft.getWorld();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the portal's top-left location
|
||||
*
|
||||
* <p>Assuming the portal is a square, the top-left block is the top-left block when looking at the portal at the
|
||||
* side with the portal's sign.</p>
|
||||
*
|
||||
* @param topLeft <p>The new top-left block of the portal's square structure</p>
|
||||
* @return <p>The portal location Object</p>
|
||||
*/
|
||||
public PortalLocation setTopLeft(BlockLocation topLeft) {
|
||||
this.topLeft = topLeft;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the portal's yaw
|
||||
*
|
||||
* <p>The portal's yaw is the yaw a player would get when looking directly out from the portal</p>
|
||||
*
|
||||
* @param yaw <p>The portal's new yaw</p>
|
||||
* @return <p>The portal location Object</p>
|
||||
*/
|
||||
public PortalLocation setYaw(float yaw) {
|
||||
this.yaw = yaw;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location of the portal's sign
|
||||
*
|
||||
* @param signLocation <p>The new sign location</p>
|
||||
* @return <p>The portal location Object</p>
|
||||
*/
|
||||
public PortalLocation setSignLocation(BlockLocation signLocation) {
|
||||
this.signLocation = signLocation;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the relative location of the portal's button
|
||||
*
|
||||
* @param buttonVector <p>The new relative button location</p>
|
||||
* @return <p>The portal location Object</p>
|
||||
*/
|
||||
public PortalLocation setButtonVector(RelativeBlockVector buttonVector) {
|
||||
this.buttonVector = buttonVector;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the block face for the direction the portal button is facing
|
||||
*
|
||||
* @param buttonFacing <p>The new block face of the portal's button</p>
|
||||
* @return <p>The portal location Object</p>
|
||||
*/
|
||||
public PortalLocation setButtonFacing(BlockFace buttonFacing) {
|
||||
this.buttonFacing = buttonFacing;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
231
src/main/java/net/knarcraft/stargate/portal/PortalOpener.java
Normal file
231
src/main/java/net/knarcraft/stargate/portal/PortalOpener.java
Normal file
@ -0,0 +1,231 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockChangeRequest;
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.event.StargateCloseEvent;
|
||||
import net.knarcraft.stargate.event.StargateOpenEvent;
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.Orientable;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* The portal opener is responsible for opening and closing a portal
|
||||
*/
|
||||
public class PortalOpener {
|
||||
|
||||
private boolean isOpen = false;
|
||||
private final Portal portal;
|
||||
private long triggeredTime;
|
||||
private Player player;
|
||||
private final PortalActivator portalActivator;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal opener
|
||||
*
|
||||
* @param portal <p>The portal this portal opener should open</p>
|
||||
* @param destination <p>The fixed destination defined on the portal's sign</p>
|
||||
*/
|
||||
public PortalOpener(Portal portal, String destination) {
|
||||
this.portal = portal;
|
||||
this.portalActivator = new PortalActivator(portal, this, destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal opener's portal is currently open
|
||||
*
|
||||
* @return <p>Whether this portal opener's portal is open</p>
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
return isOpen || portal.getOptions().isAlwaysOn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time when this portal was triggered (activated/opened)
|
||||
*
|
||||
* @param triggeredTime <p>Unix timestamp when portal was triggered</p>
|
||||
*/
|
||||
public void setTriggeredTime(long triggeredTime) {
|
||||
this.triggeredTime = triggeredTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the portal activator belonging to this portal opener
|
||||
*
|
||||
* @return <p>The portal activator belonging to this portal opener</p>
|
||||
*/
|
||||
public PortalActivator getPortalActivator() {
|
||||
return this.portalActivator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open this portal opener's portal
|
||||
*
|
||||
* @param force <p>Whether to force the portal open, even if it's already open for some player</p>
|
||||
*/
|
||||
public void openPortal(boolean force) {
|
||||
openPortal(null, force);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open this portal opener's portal
|
||||
*
|
||||
* @param openFor <p>The player to open the portal for</p>
|
||||
* @param force <p>Whether to force the portal open, even if it's already open for some player</p>
|
||||
*/
|
||||
public void openPortal(Player openFor, boolean force) {
|
||||
//Call the StargateOpenEvent to allow the opening to be cancelled
|
||||
StargateOpenEvent event = new StargateOpenEvent(openFor, portal, force);
|
||||
Stargate.getInstance().getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled() || (isOpen() && !event.getForce())) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Get the material to change the opening to
|
||||
Material openType = portal.getGate().getPortalOpenBlock();
|
||||
//Adjust orientation if applicable
|
||||
Axis axis = (openType.createBlockData() instanceof Orientable) ? portal.getLocation().getRotationAxis() : null;
|
||||
|
||||
//Change the entrance blocks to the correct type
|
||||
for (BlockLocation inside : portal.getStructure().getEntrances()) {
|
||||
Stargate.addBlockChangeRequest(new BlockChangeRequest(inside, openType, axis));
|
||||
}
|
||||
|
||||
//Update the portal state to make is actually open
|
||||
updatePortalOpenState(openFor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this portal opener's portal to be recognized as open and opens its destination portal
|
||||
*
|
||||
* @param openFor <p>The player to open this portal opener's portal for</p>
|
||||
*/
|
||||
private void updatePortalOpenState(Player openFor) {
|
||||
//Update the open state of this portal
|
||||
isOpen = true;
|
||||
triggeredTime = System.currentTimeMillis() / 1000;
|
||||
|
||||
//Change state from active to open
|
||||
Stargate.getStargateConfig().getOpenPortalsQueue().add(portal);
|
||||
Stargate.getStargateConfig().getActivePortalsQueue().remove(portal);
|
||||
|
||||
PortalOptions options = portal.getOptions();
|
||||
|
||||
//If this portal is always open, opening the destination is not necessary
|
||||
if (options.isAlwaysOn()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Update the player the portal is open for
|
||||
this.player = openFor;
|
||||
|
||||
Portal destination = portal.getPortalActivator().getDestination();
|
||||
if (destination == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean thisIsDestination = destination.getDestinationName().equalsIgnoreCase(portal.getName());
|
||||
//Only open destination if it's not-fixed or points at this portal, and is not already open
|
||||
if (!options.isRandom() && (!destination.getOptions().isFixed() || thisIsDestination) && !destination.isOpen()) {
|
||||
//Open the destination portal
|
||||
destination.getPortalOpener().openPortal(openFor, false);
|
||||
//Set the destination portal to this opener's portal
|
||||
destination.getPortalActivator().setDestination(portal);
|
||||
|
||||
//Update the destination's sign if it's verified
|
||||
if (destination.getStructure().isVerified()) {
|
||||
destination.drawSign();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this portal opener's portal
|
||||
*
|
||||
* @param force <p>Whether to force the portal closed, even if it's set as always on</p>
|
||||
*/
|
||||
public void closePortal(boolean force) {
|
||||
//No need to close a portal which is already closed
|
||||
if (!isOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Call the StargateCloseEvent to allow other plugins to cancel the closing, or change whether to force it closed
|
||||
StargateCloseEvent event = new StargateCloseEvent(portal, force);
|
||||
Stargate.getInstance().getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Only close an always-open portal if forced to
|
||||
if (portal.getOptions().isAlwaysOn() && !event.getForce()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Close the portal by requesting the opening blocks to change
|
||||
Material closedType = portal.getGate().getPortalClosedBlock();
|
||||
for (BlockLocation entrance : portal.getStructure().getEntrances()) {
|
||||
Stargate.addBlockChangeRequest(new BlockChangeRequest(entrance, closedType, null));
|
||||
}
|
||||
|
||||
//Update the portal state to make it actually closed
|
||||
updatePortalClosedState();
|
||||
|
||||
//Finally, deactivate the portal
|
||||
portalActivator.deactivate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this portal to be recognized as closed and closes its destination portal
|
||||
*/
|
||||
private void updatePortalClosedState() {
|
||||
//Unset the stored player and set the portal to closed
|
||||
player = null;
|
||||
isOpen = false;
|
||||
|
||||
//Un-mark the portal as active and open
|
||||
Stargate.getStargateConfig().getOpenPortalsQueue().remove(portal);
|
||||
Stargate.getStargateConfig().getActivePortalsQueue().remove(portal);
|
||||
|
||||
//Close the destination portal if not always open
|
||||
if (!portal.getOptions().isAlwaysOn()) {
|
||||
Portal destination = portal.getPortalActivator().getDestination();
|
||||
|
||||
if (destination != null && destination.isOpen()) {
|
||||
//De-activate and close the destination portal
|
||||
destination.getPortalActivator().deactivate();
|
||||
destination.getPortalOpener().closePortal(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal opener's portal is open for the given player
|
||||
*
|
||||
* @param player <p>The player to check portal state for</p>
|
||||
* @return <p>True if this portal opener's portal is open to the given player</p>
|
||||
*/
|
||||
public boolean isOpenFor(Player player) {
|
||||
//If closed, it's closed for everyone
|
||||
if (!isOpen) {
|
||||
return false;
|
||||
}
|
||||
//If always on, or player is null which only happens with an always on portal, allow the player to pass
|
||||
if (portal.getOptions().isAlwaysOn() || this.player == null) {
|
||||
return true;
|
||||
}
|
||||
//If the player is the player which the portal opened for, allow it to pass
|
||||
return player != null && player.getName().equalsIgnoreCase(this.player.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time this portal opener's portal was triggered (activated/opened)
|
||||
*
|
||||
* @return <p>The time this portal opener's portal was triggered</p>
|
||||
*/
|
||||
public long getTriggeredTime() {
|
||||
return triggeredTime;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
/**
|
||||
* Each enum value represents one option a portal can have/use
|
||||
*/
|
||||
public enum PortalOption {
|
||||
|
||||
/**
|
||||
* This option allows a portal to be hidden from others
|
||||
*/
|
||||
HIDDEN('h', "stargate.option.hidden", 11),
|
||||
|
||||
/**
|
||||
* This option allows a portal that's always on and does not need to be activated or opened each time
|
||||
*/
|
||||
ALWAYS_ON('a', "stargate.option.alwayson", 12),
|
||||
|
||||
/**
|
||||
* This option allows a portal that's private to the stargate's owner
|
||||
*/
|
||||
PRIVATE('p', "stargate.option.private", 13),
|
||||
|
||||
/**
|
||||
* This option allows a portal that's free even if stargates usually are not
|
||||
*/
|
||||
FREE('f', "stargate.option.free", 15),
|
||||
|
||||
/**
|
||||
* This option allows a portal where players exit through the back of the portal
|
||||
*/
|
||||
BACKWARDS('b', "stargate.option.backwards", 16),
|
||||
|
||||
/**
|
||||
* This option shows the gate in the network list even if it's always on
|
||||
*/
|
||||
SHOW('s', "stargate.option.show", 17),
|
||||
|
||||
/**
|
||||
* This option hides the network name on the sign
|
||||
*/
|
||||
NO_NETWORK('n', "stargate.option.nonetwork", 18),
|
||||
|
||||
/**
|
||||
* This option allows a portal where players teleport to a random exit portal in the network
|
||||
*/
|
||||
RANDOM('r', "stargate.option.random", 19),
|
||||
|
||||
/**
|
||||
* This option allows a portal to teleport to another server connected through BungeeCord
|
||||
*/
|
||||
BUNGEE('u', "stargate.admin.bungee", 20);
|
||||
|
||||
private final char characterRepresentation;
|
||||
private final String permissionString;
|
||||
private final int saveIndex;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal options
|
||||
*
|
||||
* @param characterRepresentation <p>The character representation used on the sign to allow this option</p>
|
||||
* @param permissionString <p>The permission necessary to use this option</p>
|
||||
*/
|
||||
PortalOption(final char characterRepresentation, String permissionString, int saveIndex) {
|
||||
this.characterRepresentation = characterRepresentation;
|
||||
this.permissionString = permissionString;
|
||||
this.saveIndex = saveIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the character representation used to enable this setting on the sign
|
||||
*
|
||||
* @return <p>The character representation of this option</p>
|
||||
*/
|
||||
public char getCharacterRepresentation() {
|
||||
return this.characterRepresentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the permission necessary to use this option
|
||||
*
|
||||
* @return <p>The permission necessary for this option</p>
|
||||
*/
|
||||
public String getPermissionString() {
|
||||
return this.permissionString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the save file this option is stored at
|
||||
*
|
||||
* @return <p>This option's save index</p>
|
||||
*/
|
||||
public int getSaveIndex() {
|
||||
return this.saveIndex;
|
||||
}
|
||||
|
||||
}
|
168
src/main/java/net/knarcraft/stargate/portal/PortalOptions.java
Normal file
168
src/main/java/net/knarcraft/stargate/portal/PortalOptions.java
Normal file
@ -0,0 +1,168 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Keeps track of all options for one portal
|
||||
*/
|
||||
public class PortalOptions {
|
||||
|
||||
private final Map<PortalOption, Boolean> options;
|
||||
private boolean isFixed;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal options object
|
||||
*
|
||||
* @param options <p>All options to keep track of</p>
|
||||
* @param hasDestination <p>Whether the portal has a fixed destination</p>
|
||||
*/
|
||||
public PortalOptions(Map<PortalOption, Boolean> options, boolean hasDestination) {
|
||||
this.options = options;
|
||||
|
||||
isFixed = hasDestination || this.isRandom() || this.isBungee();
|
||||
|
||||
if (this.isAlwaysOn() && !isFixed) {
|
||||
this.options.put(PortalOption.ALWAYS_ON, false);
|
||||
Stargate.debug("Portal", "Can not create a non-fixed always-on gate. Setting AlwaysOn = false");
|
||||
}
|
||||
|
||||
if (this.isRandom() && !this.isAlwaysOn()) {
|
||||
this.options.put(PortalOption.ALWAYS_ON, true);
|
||||
Stargate.debug("Portal", "Gate marked as random, set to always-on");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal is fixed
|
||||
*
|
||||
* <p>A fixed portal is a portal for which the player cannot choose destination. A portal with a set destination, a
|
||||
* random portal and bungee portals are fixed. While the player has no choice regarding destinations, a fixed gate
|
||||
* may still need to be activated if not set to always on.</p>
|
||||
*
|
||||
* @return <p>Whether this portal is fixed</p>
|
||||
*/
|
||||
public boolean isFixed() {
|
||||
return this.isFixed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this portal is fixed
|
||||
*
|
||||
* @param fixed <p>Whether this gate should be fixed</p>
|
||||
*/
|
||||
public void setFixed(boolean fixed) {
|
||||
this.isFixed = fixed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal is always on
|
||||
*
|
||||
* <p>An always on portal is always open for everyone, and always uses the open-block. It never needs to be
|
||||
* activated or opened manually.</p>
|
||||
*
|
||||
* @return <p>Whether this portal is always on</p>
|
||||
*/
|
||||
public boolean isAlwaysOn() {
|
||||
return this.options.get(PortalOption.ALWAYS_ON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal is hidden
|
||||
*
|
||||
* <p>A hidden portal will be hidden on a network for everyone but admins and the portal owner. In other words,
|
||||
* when selecting a destination using a portal's sign, hidden gates will only be available in the list for the
|
||||
* owner and players with the appropriate permission.</p>
|
||||
*
|
||||
* @return <p>Whether this portal is hidden</p>
|
||||
*/
|
||||
public boolean isHidden() {
|
||||
return this.options.get(PortalOption.HIDDEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal is private
|
||||
*
|
||||
* <p>A private portal can only be opened by the owner and players with the appropriate permission. A private gate
|
||||
* is not hidden unless the hidden option is also enabled.</p>
|
||||
*
|
||||
* @return <p>Whether this portal is private</p>
|
||||
*/
|
||||
public boolean isPrivate() {
|
||||
return this.options.get(PortalOption.PRIVATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal is free
|
||||
*
|
||||
* <p>A free portal is exempt from any fees which would normally occur from using the portal. It does nothing if
|
||||
* economy is disabled.</p>
|
||||
*
|
||||
* @return <p>Whether this portal is free</p>
|
||||
*/
|
||||
public boolean isFree() {
|
||||
return this.options.get(PortalOption.FREE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal is backwards
|
||||
*
|
||||
* <p>A backwards portal is one where players exit through the back. It's important to note that the exit is
|
||||
* mirrored, not rotated, when exiting backwards.</p>
|
||||
*
|
||||
* @return <p>Whether this portal is backwards</p>
|
||||
*/
|
||||
public boolean isBackwards() {
|
||||
return this.options.get(PortalOption.BACKWARDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal is shown on the network even if it's always on
|
||||
*
|
||||
* <p>Normally, always-on portals are not selectable on a network, but enabling this option allows the portal to be
|
||||
* shown.</p>
|
||||
*
|
||||
* @return <p>Whether portal gate is shown</p>
|
||||
*/
|
||||
public boolean isShown() {
|
||||
return this.options.get(PortalOption.SHOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal shows no network
|
||||
*
|
||||
* <p>Enabling the no network option allows the portal's network to be hidden for whatever reason. If allowing
|
||||
* normal players to create portals, this can be used to prevent random users from connecting gates to
|
||||
* "protected networks".</p>
|
||||
*
|
||||
* @return <p>Whether this portal shows no network/p>
|
||||
*/
|
||||
public boolean isNoNetwork() {
|
||||
return this.options.get(PortalOption.NO_NETWORK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal goes to a random location on the network
|
||||
*
|
||||
* <p>A random portal is always on and will teleport to a random destination within the same network.</p>
|
||||
*
|
||||
* @return <p>Whether this portal goes to a random location</p>
|
||||
*/
|
||||
public boolean isRandom() {
|
||||
return this.options.get(PortalOption.RANDOM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this portal is a bungee portal
|
||||
*
|
||||
* <p>A bungee portal is able to teleport to a portal on another server. It works differently from other portals as
|
||||
* it does not have a network, but instead the network line specifies the same of the server it connects to.</p>
|
||||
*
|
||||
* @return <p>Whether this portal is a bungee portal</p>
|
||||
*/
|
||||
public boolean isBungee() {
|
||||
return this.options.get(PortalOption.BUNGEE);
|
||||
}
|
||||
|
||||
}
|
118
src/main/java/net/knarcraft/stargate/portal/PortalOwner.java
Normal file
118
src/main/java/net/knarcraft/stargate/portal/PortalOwner.java
Normal file
@ -0,0 +1,118 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* The portal owner represents the owner of a portal
|
||||
*/
|
||||
public class PortalOwner {
|
||||
|
||||
private UUID ownerUUID;
|
||||
private String ownerName;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal owner
|
||||
*
|
||||
* @param ownerIdentifier <p>A UUID, or a username for legacy support</p>
|
||||
*/
|
||||
public PortalOwner(String ownerIdentifier) {
|
||||
parseIdentifier(ownerIdentifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new portal owner
|
||||
*
|
||||
* @param player <p>The player which is the owner of the portal</p>
|
||||
*/
|
||||
public PortalOwner(Player player) {
|
||||
this.ownerUUID = player.getUniqueId();
|
||||
this.ownerName = player.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the UUID of this owner
|
||||
*
|
||||
* @return <p>The UUID of this owner, or null if a UUID is not available</p>
|
||||
*/
|
||||
public UUID getUUID() {
|
||||
return ownerUUID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unique id for a portal owner without one
|
||||
*
|
||||
* <p>This method is only meant to be used to set the unique id for an owner without one. If the owner already has
|
||||
* an unique id, an exception will be thrown.</p>
|
||||
*
|
||||
* @param uniqueId <p>The new unique id for the portal owner</p>
|
||||
*/
|
||||
public void setUUID(UUID uniqueId) {
|
||||
if (ownerUUID == null) {
|
||||
ownerUUID = uniqueId;
|
||||
} else {
|
||||
throw new IllegalArgumentException("An existing UUID cannot be overwritten.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this owner
|
||||
*
|
||||
* @return <p>The name of this owner</p>
|
||||
*/
|
||||
public String getName() {
|
||||
return ownerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the one identifier used for saving the owner
|
||||
*
|
||||
* <p>If the UUID is available, a string representation of the UUID will be returned. If not, the owner's name will
|
||||
* be returned.</p>
|
||||
*
|
||||
* @return <p>The owner's identifier</p>
|
||||
*/
|
||||
public String getIdentifier() {
|
||||
if (ownerUUID != null) {
|
||||
return ownerUUID.toString();
|
||||
} else {
|
||||
return ownerName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the identifier of a portal's owner
|
||||
*
|
||||
* <p>The identifier should be a valid UUID, but can be a username of max 16 characters for legacy support. Strings
|
||||
* longer than 16 characters not parse-able as a UUID will silently fail by setting the owner name to the
|
||||
* identifier.</p>
|
||||
*
|
||||
* @param ownerIdentifier <p>The identifier for a portal's owner</p>
|
||||
*/
|
||||
private void parseIdentifier(String ownerIdentifier) {
|
||||
UUID ownerUUID = null;
|
||||
String ownerName;
|
||||
if (ownerIdentifier.length() > 16) {
|
||||
//If more than 16 characters, the string cannot be a username, so it's probably a UUID
|
||||
try {
|
||||
ownerUUID = UUID.fromString(ownerIdentifier);
|
||||
OfflinePlayer offlineOwner = Bukkit.getServer().getOfflinePlayer(ownerUUID);
|
||||
ownerName = offlineOwner.getName();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
//Invalid as UUID and username, so just keep it as owner name and hope the server owner fixes it
|
||||
ownerName = ownerIdentifier;
|
||||
Stargate.debug("loadAllPortals", "Invalid stargate owner string: " + ownerIdentifier);
|
||||
}
|
||||
} else {
|
||||
//Old username from the pre-UUID times. Just keep it as the owner name
|
||||
ownerName = ownerIdentifier;
|
||||
}
|
||||
this.ownerName = ownerName;
|
||||
this.ownerUUID = ownerUUID;
|
||||
}
|
||||
|
||||
}
|
297
src/main/java/net/knarcraft/stargate/portal/PortalRegistry.java
Normal file
297
src/main/java/net/knarcraft/stargate/portal/PortalRegistry.java
Normal file
@ -0,0 +1,297 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.utility.PortalFileHelper;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.data.type.WallSign;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The portal registry keeps track of all registered portals and all their lookup blocks
|
||||
*/
|
||||
public class PortalRegistry {
|
||||
|
||||
private static final Map<BlockLocation, Portal> lookupBlocks = new HashMap<>();
|
||||
private static final Map<BlockLocation, Portal> lookupEntrances = new HashMap<>();
|
||||
private static final Map<BlockLocation, Portal> lookupControls = new HashMap<>();
|
||||
|
||||
private static final Map<String, Map<String, Portal>> portalLookupByNetwork = new HashMap<>();
|
||||
private static final Map<String, List<String>> allPortalNetworks = new HashMap<>();
|
||||
private static final Map<String, Portal> bungeePortals = new HashMap<>();
|
||||
|
||||
private static final List<Portal> allPortals = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Clears all portals and all data held by the portal registry
|
||||
*/
|
||||
public static void clearPortals() {
|
||||
lookupBlocks.clear();
|
||||
portalLookupByNetwork.clear();
|
||||
lookupEntrances.clear();
|
||||
lookupControls.clear();
|
||||
allPortals.clear();
|
||||
allPortalNetworks.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all portals loaded in a given world
|
||||
*
|
||||
* @param world <p>The world containing the portals to clear</p>
|
||||
*/
|
||||
public static void clearPortals(World world) {
|
||||
//Storing the portals to clear is necessary to avoid a concurrent modification exception
|
||||
List<Portal> portalsToRemove = new ArrayList<>();
|
||||
allPortals.forEach((portal) -> {
|
||||
if (portal.getWorld().equals(world)) {
|
||||
portalsToRemove.add(portal);
|
||||
}
|
||||
});
|
||||
|
||||
clearPortals(portalsToRemove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears a given list of portals from all relevant variables
|
||||
*
|
||||
* @param portalsToRemove <p>A list of portals to remove</p>
|
||||
*/
|
||||
private static void clearPortals(List<Portal> portalsToRemove) {
|
||||
//Store the names of the portals to remove as some maps require the name, not the object
|
||||
List<String> portalNames = new ArrayList<>();
|
||||
portalsToRemove.forEach((portal) -> portalNames.add(portal.getName()));
|
||||
|
||||
//Clear all the lookup locations for the portals
|
||||
lookupBlocks.keySet().removeIf((key) -> portalsToRemove.contains(lookupBlocks.get(key)));
|
||||
lookupEntrances.keySet().removeIf((key) -> portalsToRemove.contains(lookupEntrances.get(key)));
|
||||
lookupControls.keySet().removeIf((key) -> portalsToRemove.contains(lookupControls.get(key)));
|
||||
|
||||
//Remove the portals from all networks, and then remove any empty networks. This is done for both network maps
|
||||
portalLookupByNetwork.keySet().forEach((network) -> portalLookupByNetwork.get(network).keySet().removeIf((key) ->
|
||||
portalsToRemove.contains(portalLookupByNetwork.get(network).get(key))));
|
||||
portalLookupByNetwork.keySet().removeIf((key) -> portalLookupByNetwork.get(key).isEmpty());
|
||||
allPortalNetworks.keySet().forEach((network) -> allPortalNetworks.get(network).removeIf(portalNames::contains));
|
||||
allPortalNetworks.keySet().removeIf((network) -> allPortalNetworks.get(network).isEmpty());
|
||||
|
||||
//Finally, remove the portals from the portal list
|
||||
allPortals.removeIf(portalsToRemove::contains);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of the list of all portals
|
||||
*
|
||||
* @return <p>A copy of the list of all portals</p>
|
||||
*/
|
||||
public static List<Portal> getAllPortals() {
|
||||
return new ArrayList<>(allPortals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of the lookup map for finding a portal by its frame
|
||||
*
|
||||
* @return <p>A copy of the frame block lookup map</p>
|
||||
*/
|
||||
public static Map<BlockLocation, Portal> getLookupBlocks() {
|
||||
return new HashMap<>(lookupBlocks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of the lookup map for finding a portal by its control block
|
||||
*
|
||||
* @return <p>A copy of the control block lookup map</p>
|
||||
*/
|
||||
public static Map<BlockLocation, Portal> getLookupControls() {
|
||||
return new HashMap<>(lookupControls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of the lookup map for finding all portals in a network
|
||||
*
|
||||
* @return <p>A copy of the network portal lookup map</p>
|
||||
*/
|
||||
public static Map<String, Map<String, Portal>> getPortalLookupByNetwork() {
|
||||
return new HashMap<>(portalLookupByNetwork);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of all portal entrances available for lookup
|
||||
*
|
||||
* @return <p>A copy of all entrances to portal mappings</p>
|
||||
*/
|
||||
public static Map<BlockLocation, Portal> getLookupEntrances() {
|
||||
return new HashMap<>(lookupEntrances);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of all portal networks
|
||||
*
|
||||
* @return <p>A copy of all portal networks</p>
|
||||
*/
|
||||
public static Map<String, List<String>> getAllPortalNetworks() {
|
||||
return new HashMap<>(allPortalNetworks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of all bungee portals
|
||||
*
|
||||
* @return <p>A copy of all bungee portals</p>
|
||||
*/
|
||||
public static Map<String, Portal> getBungeePortals() {
|
||||
return new HashMap<>(bungeePortals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets names of all portals within a network
|
||||
*
|
||||
* @param network <p>The network to get portals from</p>
|
||||
* @return <p>A list of portal names</p>
|
||||
*/
|
||||
public static List<String> getNetwork(String network) {
|
||||
return allPortalNetworks.get(network.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-registers the given portal
|
||||
*
|
||||
* @param portal <p>The portal to un-register</p>
|
||||
* @param removeAll <p>Whether to remove the portal from the list of all portals</p>
|
||||
*/
|
||||
public static void unregisterPortal(Portal portal, boolean removeAll) {
|
||||
Stargate.debug("Unregister", "Unregistering gate " + portal.getName());
|
||||
portal.getPortalOpener().closePortal(true);
|
||||
|
||||
String portalName = portal.getName().toLowerCase();
|
||||
String networkName = portal.getNetwork().toLowerCase();
|
||||
|
||||
//Remove portal from lookup blocks
|
||||
for (BlockLocation block : portal.getStructure().getFrame()) {
|
||||
lookupBlocks.remove(block);
|
||||
}
|
||||
|
||||
//Remove registered info about the lookup controls and blocks
|
||||
lookupBlocks.remove(portal.getSignLocation());
|
||||
lookupControls.remove(portal.getSignLocation());
|
||||
|
||||
BlockLocation button = portal.getStructure().getButton();
|
||||
if (button != null) {
|
||||
lookupBlocks.remove(button);
|
||||
lookupControls.remove(button);
|
||||
}
|
||||
|
||||
//Remove entrances
|
||||
for (BlockLocation entrance : portal.getStructure().getEntrances()) {
|
||||
lookupEntrances.remove(entrance);
|
||||
}
|
||||
|
||||
//Remove the portal from the list of all portals
|
||||
if (removeAll) {
|
||||
allPortals.remove(portal);
|
||||
}
|
||||
|
||||
if (portal.getOptions().isBungee()) {
|
||||
//Remove the bungee listing
|
||||
bungeePortals.remove(portalName);
|
||||
} else {
|
||||
//Remove from network lists
|
||||
portalLookupByNetwork.get(networkName).remove(portalName);
|
||||
allPortalNetworks.get(networkName).remove(portalName);
|
||||
|
||||
//Update all portals in the same network with this portal as its destination
|
||||
for (String originName : allPortalNetworks.get(networkName)) {
|
||||
Portal origin = PortalHandler.getByName(originName, portal.getNetwork());
|
||||
if (origin == null || !origin.getDestinationName().equalsIgnoreCase(portalName) ||
|
||||
!origin.getStructure().isVerified()) {
|
||||
continue;
|
||||
}
|
||||
//Update the portal's sign
|
||||
if (origin.getOptions().isFixed()) {
|
||||
origin.drawSign();
|
||||
}
|
||||
//Close portal without destination
|
||||
if (origin.getOptions().isAlwaysOn()) {
|
||||
origin.getPortalOpener().closePortal(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Clear sign data
|
||||
if (portal.getSignLocation().getBlock().getBlockData() instanceof WallSign) {
|
||||
Sign sign = (Sign) portal.getSignLocation().getBlock().getState();
|
||||
sign.setLine(0, portal.getName());
|
||||
sign.setLine(1, "");
|
||||
sign.setLine(2, "");
|
||||
sign.setLine(3, "");
|
||||
sign.update();
|
||||
}
|
||||
|
||||
PortalFileHelper.saveAllPortals(portal.getWorld());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a portal
|
||||
*
|
||||
* @param portal <p>The portal to register</p>
|
||||
*/
|
||||
static void registerPortal(Portal portal) {
|
||||
portal.getOptions().setFixed(portal.getDestinationName().length() > 0 || portal.getOptions().isRandom() ||
|
||||
portal.getOptions().isBungee());
|
||||
|
||||
String portalName = portal.getName().toLowerCase();
|
||||
String networkName = portal.getNetwork().toLowerCase();
|
||||
|
||||
//Bungee portals are stored in their own list
|
||||
if (portal.getOptions().isBungee()) {
|
||||
bungeePortals.put(portalName, portal);
|
||||
} else {
|
||||
//Check if network exists in the lookup list. If not, register the new network
|
||||
if (!portalLookupByNetwork.containsKey(networkName)) {
|
||||
Stargate.debug("register", "Network " + portal.getNetwork() +
|
||||
" not in lookupNamesNet, adding");
|
||||
portalLookupByNetwork.put(networkName, new HashMap<>());
|
||||
}
|
||||
//Check if this network exists in the network list. If not, register the network
|
||||
if (!allPortalNetworks.containsKey(networkName)) {
|
||||
Stargate.debug("register", "Network " + portal.getNetwork() +
|
||||
" not in allPortalsNet, adding");
|
||||
allPortalNetworks.put(networkName, new ArrayList<>());
|
||||
}
|
||||
|
||||
//Register the portal
|
||||
portalLookupByNetwork.get(networkName).put(portalName, portal);
|
||||
|
||||
if (!allPortalNetworks.get(networkName).contains(portalName)) {
|
||||
allPortalNetworks.get(networkName).add(portalName);
|
||||
} else {
|
||||
Stargate.logSevere(String.format("Portal %s on network %s was registered twice. Check your portal " +
|
||||
"database for duplicates.", portal.getName(), portal.getNetwork()));
|
||||
}
|
||||
}
|
||||
|
||||
//Register all frame blocks to the lookup list
|
||||
for (BlockLocation block : portal.getStructure().getFrame()) {
|
||||
lookupBlocks.put(block, portal);
|
||||
}
|
||||
//Register the sign and button to the lookup lists
|
||||
lookupBlocks.put(portal.getSignLocation(), portal);
|
||||
lookupControls.put(portal.getSignLocation(), portal);
|
||||
|
||||
BlockLocation button = portal.getStructure().getButton();
|
||||
if (button != null) {
|
||||
lookupBlocks.put(button, portal);
|
||||
lookupControls.put(button, portal);
|
||||
}
|
||||
|
||||
//Register entrances to the lookup list
|
||||
for (BlockLocation entrance : portal.getStructure().getEntrances()) {
|
||||
lookupEntrances.put(entrance, portal);
|
||||
}
|
||||
|
||||
allPortals.add(portal);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,240 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.utility.PermissionHelper;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
|
||||
/**
|
||||
* The portal sign drawer draws the sing of a given portal
|
||||
*/
|
||||
public class PortalSignDrawer {
|
||||
|
||||
private final Portal portal;
|
||||
private final static ChatColor errorColor = ChatColor.DARK_RED;
|
||||
private final static ChatColor freeColor = ChatColor.DARK_GREEN;
|
||||
private static ChatColor mainColor;
|
||||
private static ChatColor highlightColor;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal sign drawer
|
||||
*
|
||||
* @param portal <p>The portal whose sign this portal sign drawer is responsible for drawing</p>
|
||||
*/
|
||||
public PortalSignDrawer(Portal portal) {
|
||||
this.portal = portal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the main sign color
|
||||
*
|
||||
* <p>The main sign color is used for most text on the sign, while the highlighting color is used for the markings
|
||||
* around portal names and network names ('>','<','-',')','(')</p>
|
||||
*
|
||||
* @param newMainColor <p>The new main sign color</p>
|
||||
* @param newHighlightColor <p>The new highlight color</p>
|
||||
*/
|
||||
public static void setColors(ChatColor newMainColor, ChatColor newHighlightColor) {
|
||||
mainColor = newMainColor;
|
||||
highlightColor = newHighlightColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the sign of the portal this sign drawer is responsible for
|
||||
*/
|
||||
public void drawSign() {
|
||||
Block signBlock = portal.getSignLocation().getBlock();
|
||||
BlockState state = signBlock.getState();
|
||||
if (!(state instanceof Sign sign)) {
|
||||
Stargate.logWarning("Sign block is not a Sign object");
|
||||
Stargate.debug("Portal::drawSign", String.format("Block: %s @ %s", signBlock.getType(),
|
||||
signBlock.getLocation()));
|
||||
return;
|
||||
}
|
||||
|
||||
drawSign(sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the sign of the portal this sign drawer is responsible for
|
||||
*
|
||||
* @param sign <p>The sign re-draw</p>
|
||||
*/
|
||||
private void drawSign(Sign sign) {
|
||||
//Clear sign
|
||||
for (int index = 0; index <= 3; index++) {
|
||||
sign.setLine(index, "");
|
||||
}
|
||||
setLine(sign, 0, highlightColor + "-" + mainColor +
|
||||
portal.getName() + highlightColor + "-");
|
||||
|
||||
if (!portal.getPortalActivator().isActive()) {
|
||||
//Default sign text
|
||||
drawInactiveSign(sign);
|
||||
} else {
|
||||
if (portal.getOptions().isBungee()) {
|
||||
//Bungee sign
|
||||
drawBungeeSign(sign);
|
||||
} else if (portal.getOptions().isFixed()) {
|
||||
//Sign pointing at one other portal
|
||||
drawFixedSign(sign);
|
||||
} else {
|
||||
//Networking stuff
|
||||
drawNetworkSign(sign);
|
||||
}
|
||||
}
|
||||
|
||||
sign.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a sign with choose-able network locations
|
||||
*
|
||||
* @param sign <p>The sign to re-draw</p>
|
||||
*/
|
||||
private void drawNetworkSign(Sign sign) {
|
||||
PortalActivator destinations = portal.getPortalActivator();
|
||||
int maxIndex = destinations.getDestinations().size() - 1;
|
||||
int signLineIndex = 0;
|
||||
int destinationIndex = destinations.getDestinations().indexOf(portal.getDestinationName());
|
||||
boolean freeGatesGreen = Stargate.getEconomyConfig().useEconomy() &&
|
||||
Stargate.getEconomyConfig().drawFreePortalsGreen();
|
||||
|
||||
//Last, and not only entry. Draw the entry two back
|
||||
if ((destinationIndex == maxIndex) && (maxIndex > 1)) {
|
||||
drawNetworkSignLine(freeGatesGreen, sign, ++signLineIndex, destinationIndex - 2);
|
||||
}
|
||||
//Not first entry. Draw the previous entry
|
||||
if (destinationIndex > 0) {
|
||||
drawNetworkSignLine(freeGatesGreen, sign, ++signLineIndex, destinationIndex - 1);
|
||||
}
|
||||
//Draw the chosen entry (line 2 or 3)
|
||||
drawNetworkSignChosenLine(freeGatesGreen, sign, ++signLineIndex);
|
||||
//Has another entry and space on the sign
|
||||
if ((maxIndex >= destinationIndex + 1)) {
|
||||
drawNetworkSignLine(freeGatesGreen, sign, ++signLineIndex, destinationIndex + 1);
|
||||
}
|
||||
//Has another entry and space on the sign
|
||||
if ((maxIndex >= destinationIndex + 2) && (++signLineIndex <= 3)) {
|
||||
drawNetworkSignLine(freeGatesGreen, sign, signLineIndex, destinationIndex + 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the chosen destination on one sign line
|
||||
*
|
||||
* @param freeGatesGreen <p>Whether to display free gates in a green color</p>
|
||||
* @param sign <p>The sign to draw on</p>
|
||||
* @param signLineIndex <p>The line to draw on</p>
|
||||
*/
|
||||
private void drawNetworkSignChosenLine(boolean freeGatesGreen, Sign sign, int signLineIndex) {
|
||||
if (freeGatesGreen) {
|
||||
Portal destination = PortalHandler.getByName(portal.getDestinationName(), portal.getNetwork());
|
||||
boolean green = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination);
|
||||
ChatColor nameColor = (green ? freeColor : highlightColor);
|
||||
setLine(sign, signLineIndex, nameColor + ">" + (green ? freeColor : mainColor) +
|
||||
portal.getDestinationName() + nameColor + "<");
|
||||
} else {
|
||||
setLine(sign, signLineIndex, highlightColor + ">" + mainColor + portal.getDestinationName() +
|
||||
highlightColor + "<");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a line on a sign, adding the chosen sign color
|
||||
*
|
||||
* @param sign <p>The sign to update</p>
|
||||
* @param index <p>The index of the sign line to change</p>
|
||||
* @param text <p>The new text on the sign</p>
|
||||
*/
|
||||
public void setLine(Sign sign, int index, String text) {
|
||||
sign.setLine(index, mainColor + text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws one network destination on one sign line
|
||||
*
|
||||
* @param freeGatesGreen <p>Whether to display free gates in a green color</p>
|
||||
* @param sign <p>The sign to draw on</p>
|
||||
* @param signLineIndex <p>The line to draw on</p>
|
||||
* @param destinationIndex <p>The index of the destination to draw</p>
|
||||
*/
|
||||
private void drawNetworkSignLine(boolean freeGatesGreen, Sign sign, int signLineIndex, int destinationIndex) {
|
||||
PortalActivator destinations = portal.getPortalActivator();
|
||||
String destinationName = destinations.getDestinations().get(destinationIndex);
|
||||
if (freeGatesGreen) {
|
||||
Portal destination = PortalHandler.getByName(destinationName, portal.getNetwork());
|
||||
boolean green = PermissionHelper.isFree(portal.getActivePlayer(), portal, destination);
|
||||
setLine(sign, signLineIndex, (green ? freeColor : mainColor) + destinationName);
|
||||
} else {
|
||||
setLine(sign, signLineIndex, mainColor + destinationName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a bungee sign
|
||||
*
|
||||
* @param sign <p>The sign to re-draw</p>
|
||||
*/
|
||||
private void drawBungeeSign(Sign sign) {
|
||||
setLine(sign, 1, Stargate.getString("bungeeSign"));
|
||||
setLine(sign, 2, highlightColor + ">" + mainColor + portal.getDestinationName() + highlightColor + "<");
|
||||
setLine(sign, 3, highlightColor + "[" + mainColor + portal.getNetwork() + highlightColor + "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an inactive sign
|
||||
*
|
||||
* @param sign <p>The sign to re-draw</p>
|
||||
*/
|
||||
private void drawInactiveSign(Sign sign) {
|
||||
setLine(sign, 1, Stargate.getString("signRightClick"));
|
||||
setLine(sign, 2, Stargate.getString("signToUse"));
|
||||
if (!portal.getOptions().isNoNetwork()) {
|
||||
setLine(sign, 3, highlightColor + "(" + mainColor + portal.getNetwork() + highlightColor + ")");
|
||||
} else {
|
||||
setLine(sign, 3, "");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a sign pointing to a fixed location
|
||||
*
|
||||
* @param sign <p>The sign to re-draw</p>
|
||||
*/
|
||||
private void drawFixedSign(Sign sign) {
|
||||
String destinationName = portal.getOptions().isRandom() ? Stargate.getString("signRandom") :
|
||||
portal.getDestinationName();
|
||||
setLine(sign, 1, highlightColor + ">" + mainColor + destinationName + highlightColor + "<");
|
||||
|
||||
if (portal.getOptions().isNoNetwork()) {
|
||||
setLine(sign, 2, "");
|
||||
} else {
|
||||
setLine(sign, 2, highlightColor + "(" + mainColor + portal.getNetwork() + highlightColor + ")");
|
||||
}
|
||||
Portal destination = PortalHandler.getByName(portal.getDestinationName(), portal.getNetwork());
|
||||
if (destination == null && !portal.getOptions().isRandom()) {
|
||||
setLine(sign, 3, errorColor + Stargate.getString("signDisconnected"));
|
||||
} else {
|
||||
setLine(sign, 3, "");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a portal with an invalid gate by changing its sign and writing to the console
|
||||
*
|
||||
* @param portalLocation <p>The location of the portal with an invalid gate</p>
|
||||
* @param gateName <p>The name of the invalid gate type</p>
|
||||
* @param lineIndex <p>The index of the line the invalid portal was found at</p>
|
||||
*/
|
||||
public static void markPortalWithInvalidGate(PortalLocation portalLocation, String gateName, int lineIndex) {
|
||||
Sign sign = (Sign) portalLocation.getSignLocation().getBlock().getState();
|
||||
sign.setLine(3, errorColor + Stargate.getString("signInvalidGate"));
|
||||
sign.update();
|
||||
|
||||
Stargate.logInfo(String.format("Gate layout on line %d does not exist [%s]", lineIndex, gateName));
|
||||
}
|
||||
|
||||
}
|
148
src/main/java/net/knarcraft/stargate/portal/PortalStructure.java
Normal file
148
src/main/java/net/knarcraft/stargate/portal/PortalStructure.java
Normal file
@ -0,0 +1,148 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.container.RelativeBlockVector;
|
||||
|
||||
/**
|
||||
* The portal structure is responsible for the physical properties of a portal
|
||||
*
|
||||
* <p>The portal structure knows which gate type is used, where the real locations of buttons, frames and entrances are
|
||||
* and whether the portal is verified.</p>
|
||||
*/
|
||||
public class PortalStructure {
|
||||
|
||||
private final Portal portal;
|
||||
private final Gate gate;
|
||||
private BlockLocation button;
|
||||
private BlockLocation[] frame;
|
||||
private BlockLocation[] entrances;
|
||||
private boolean verified;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal structure
|
||||
*
|
||||
* @param portal <p>The portal whose structure to store</p>
|
||||
* @param gate <p>The gate type used by this portal structure</p>
|
||||
* @param button <p>The real location of the portal's button</p>
|
||||
*/
|
||||
public PortalStructure(Portal portal, Gate gate, BlockLocation button) {
|
||||
this.portal = portal;
|
||||
this.gate = gate;
|
||||
this.verified = false;
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the gate used by this portal structure
|
||||
*
|
||||
* @return <p>The gate used by this portal structure</p>
|
||||
*/
|
||||
public Gate getGate() {
|
||||
return gate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of this portal's button
|
||||
*
|
||||
* @return <p>The location of this portal's button</p>
|
||||
*/
|
||||
public BlockLocation getButton() {
|
||||
return button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location of this portal's button
|
||||
*
|
||||
* @param button <p>The location of this portal's button</p>
|
||||
*/
|
||||
public void setButton(BlockLocation button) {
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that all control blocks in this portal follows its gate template
|
||||
*
|
||||
* @return <p>True if all control blocks were verified</p>
|
||||
*/
|
||||
public boolean isVerified() {
|
||||
boolean verified = true;
|
||||
if (!Stargate.getGateConfig().verifyPortals()) {
|
||||
return true;
|
||||
}
|
||||
for (RelativeBlockVector control : gate.getLayout().getControls()) {
|
||||
verified = verified && portal.getBlockAt(control).getBlock().getType().equals(gate.getControlBlock());
|
||||
}
|
||||
this.verified = verified;
|
||||
return verified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result of the last portal verification
|
||||
*
|
||||
* @return <p>True if this portal was verified</p>
|
||||
*/
|
||||
public boolean wasVerified() {
|
||||
if (!Stargate.getGateConfig().verifyPortals()) {
|
||||
return true;
|
||||
}
|
||||
return verified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all blocks in a gate matches the gate template
|
||||
*
|
||||
* @return <p>True if all blocks match the gate template</p>
|
||||
*/
|
||||
public boolean checkIntegrity() {
|
||||
if (Stargate.getGateConfig().verifyPortals()) {
|
||||
return gate.matches(portal.getTopLeft(), portal.getYaw());
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of block locations from a list of relative block vectors
|
||||
*
|
||||
* <p>The block locations will be calculated by using this portal's top-left block as the origin for the relative
|
||||
* vectors..</p>
|
||||
*
|
||||
* @param vectors <p>The relative block vectors to convert</p>
|
||||
* @return <p>A list of block locations</p>
|
||||
*/
|
||||
private BlockLocation[] relativeBlockVectorsToBlockLocations(RelativeBlockVector[] vectors) {
|
||||
BlockLocation[] locations = new BlockLocation[vectors.length];
|
||||
for (int i = 0; i < vectors.length; i++) {
|
||||
locations[i] = portal.getBlockAt(vectors[i]);
|
||||
}
|
||||
return locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the locations of this portal's entrances
|
||||
*
|
||||
* @return <p>The locations of this portal's entrances</p>
|
||||
*/
|
||||
public BlockLocation[] getEntrances() {
|
||||
if (entrances == null) {
|
||||
//Get the locations of the entrances once, and only if necessary as it's an expensive operation
|
||||
entrances = relativeBlockVectorsToBlockLocations(gate.getLayout().getEntrances());
|
||||
}
|
||||
return entrances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the locations of this portal's frame
|
||||
*
|
||||
* @return <p>The locations of this portal's frame</p>
|
||||
*/
|
||||
public BlockLocation[] getFrame() {
|
||||
if (frame == null) {
|
||||
//Get the locations of the frame blocks once, and only if necessary as it's an expensive operation
|
||||
frame = relativeBlockVectorsToBlockLocations(gate.getLayout().getBorder());
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
}
|
295
src/main/java/net/knarcraft/stargate/portal/Teleporter.java
Normal file
295
src/main/java/net/knarcraft/stargate/portal/Teleporter.java
Normal file
@ -0,0 +1,295 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.container.ChunkUnloadRequest;
|
||||
import net.knarcraft.stargate.container.RelativeBlockVector;
|
||||
import net.knarcraft.stargate.utility.DirectionHelper;
|
||||
import net.knarcraft.stargate.utility.EntityHelper;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.Bisected;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Slab;
|
||||
import org.bukkit.entity.AbstractHorse;
|
||||
import org.bukkit.entity.Creature;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The portal teleporter takes care of common teleportation logic
|
||||
*/
|
||||
public abstract class Teleporter {
|
||||
|
||||
/**
|
||||
* The portal the entity is teleporting to
|
||||
*/
|
||||
protected final Portal portal;
|
||||
/**
|
||||
* The scheduler to use for delaying tasks
|
||||
*/
|
||||
protected final BukkitScheduler scheduler;
|
||||
|
||||
/**
|
||||
* Instantiates a new portal teleporter
|
||||
*
|
||||
* @param portal <p>The portal which is the target of the teleportation</p>
|
||||
*/
|
||||
public Teleporter(Portal portal) {
|
||||
this.portal = portal;
|
||||
this.scheduler = Stargate.getInstance().getServer().getScheduler();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adjusts the rotation of the exit to make the teleporting entity face directly out from the portal
|
||||
*
|
||||
* @param exit <p>The location the entity will exit from</p>
|
||||
*/
|
||||
protected void adjustRotation(Location exit) {
|
||||
int adjust = 0;
|
||||
if (portal.getOptions().isBackwards()) {
|
||||
adjust = 180;
|
||||
}
|
||||
float newYaw = (portal.getYaw() + adjust) % 360;
|
||||
Stargate.debug("Portal::adjustRotation", "Setting exit yaw to " + newYaw);
|
||||
exit.setYaw(newYaw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exit location for a given entity and current location
|
||||
*
|
||||
* @param entity <p>The entity to teleport (used to determine distance from portal to avoid suffocation)</p>
|
||||
* @param traveller <p>The location of the entity travelling</p>
|
||||
* @return <p>The location the entity should be teleported to.</p>
|
||||
*/
|
||||
public Location getExit(Entity entity, Location traveller) {
|
||||
Location exitLocation = null;
|
||||
RelativeBlockVector relativeExit = portal.getGate().getLayout().getExit();
|
||||
if (relativeExit != null) {
|
||||
BlockLocation exit = portal.getBlockAt(relativeExit);
|
||||
|
||||
//Move one block out to prevent exiting inside the portal
|
||||
float portalYaw = portal.getYaw();
|
||||
if (portal.getOptions().isBackwards()) {
|
||||
portalYaw += 180;
|
||||
}
|
||||
exitLocation = exit.getRelativeLocation(0D, 0D, 1, portalYaw);
|
||||
|
||||
if (entity != null) {
|
||||
double entitySize = EntityHelper.getEntityMaxSize(entity);
|
||||
//Prevent exit suffocation for players riding horses or similar
|
||||
if (entitySize > 1) {
|
||||
exitLocation = preventExitSuffocation(relativeExit, exitLocation, entity);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Stargate.logWarning(String.format("Missing destination point in .gate file %s",
|
||||
portal.getGate().getFilename()));
|
||||
}
|
||||
|
||||
//Adjust pitch and height
|
||||
return adjustExitLocation(traveller, exitLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the positioning of the portal exit to prevent the given entity from suffocating
|
||||
*
|
||||
* @param relativeExit <p>The relative exit defined as the portal's exit</p>
|
||||
* @param exitLocation <p>The currently calculated portal exit</p>
|
||||
* @param entity <p>The travelling entity</p>
|
||||
* @return <p>A location which won't suffocate the entity inside the portal</p>
|
||||
*/
|
||||
private Location preventExitSuffocation(RelativeBlockVector relativeExit, Location exitLocation, Entity entity) {
|
||||
//Go left to find start of opening
|
||||
RelativeBlockVector openingLeft = getPortalExitEdge(relativeExit, -1);
|
||||
|
||||
//Go right to find the end of the opening
|
||||
RelativeBlockVector openingRight = getPortalExitEdge(relativeExit, 1);
|
||||
|
||||
//Get the width to check if the entity fits
|
||||
int openingWidth = openingRight.getRight() - openingLeft.getRight() + 1;
|
||||
int existingOffset = relativeExit.getRight() - openingLeft.getRight();
|
||||
double newOffset = (openingWidth - existingOffset) / 2D;
|
||||
|
||||
//Remove the half offset for better centering
|
||||
if (openingWidth > 1) {
|
||||
newOffset -= 0.5;
|
||||
}
|
||||
exitLocation = DirectionHelper.moveLocation(exitLocation, newOffset, 0, 0, portal.getYaw());
|
||||
|
||||
//Move large entities further from the portal
|
||||
return moveExitLocationOutwards(exitLocation, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the exit location out from the portal to prevent the entity from entering a teleportation loop
|
||||
*
|
||||
* @param exitLocation <p>The current exit location to adjust</p>
|
||||
* @param entity <p>The entity to adjust the exit location for</p>
|
||||
* @return <p>The adjusted exit location</p>
|
||||
*/
|
||||
private Location moveExitLocationOutwards(Location exitLocation, Entity entity) {
|
||||
double entitySize = EntityHelper.getEntityMaxSize(entity);
|
||||
int entityBoxSize = EntityHelper.getEntityMaxSizeInt(entity);
|
||||
if (entitySize > 1) {
|
||||
double entityOffset;
|
||||
if (portal.getOptions().isAlwaysOn()) {
|
||||
entityOffset = entityBoxSize / 2D;
|
||||
} else {
|
||||
entityOffset = (entitySize / 2D) - 1;
|
||||
}
|
||||
//If a horse has a player riding it, the player will spawn inside the roof of a standard portal unless it's
|
||||
// moved one block out.
|
||||
if (entity instanceof AbstractHorse) {
|
||||
entityOffset += 1;
|
||||
}
|
||||
exitLocation = DirectionHelper.moveLocation(exitLocation, 0, 0, entityOffset, portal.getYaw());
|
||||
}
|
||||
return exitLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one of the edges of a portal's opening/exit
|
||||
*
|
||||
* @param relativeExit <p>The known exit to start from</p>
|
||||
* @param direction <p>The direction to move (+1 for right, -1 for left)</p>
|
||||
* @return <p>The right or left edge of the opening</p>
|
||||
*/
|
||||
private RelativeBlockVector getPortalExitEdge(RelativeBlockVector relativeExit, int direction) {
|
||||
RelativeBlockVector openingEdge = relativeExit;
|
||||
|
||||
do {
|
||||
RelativeBlockVector possibleOpening = new RelativeBlockVector(openingEdge.getRight() + direction,
|
||||
openingEdge.getDown(), openingEdge.getOut());
|
||||
if (portal.getGate().getLayout().getExits().contains(possibleOpening)) {
|
||||
openingEdge = possibleOpening;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
return openingEdge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts an exit location by setting pitch and adjusting height
|
||||
*
|
||||
* <p>If the exit location is a slab or water, the exit location will be changed to arrive one block above. The
|
||||
* slab check is necessary to prevent the player from clipping through the slab and spawning beneath it. The water
|
||||
* check is necessary when teleporting boats to prevent it from becoming a submarine.</p>
|
||||
*
|
||||
* @param traveller <p>The location of the travelling entity</p>
|
||||
* @param exitLocation <p>The exit location generated</p>
|
||||
* @return <p>The location the travelling entity should be teleported to</p>
|
||||
*/
|
||||
private Location adjustExitLocation(Location traveller, Location exitLocation) {
|
||||
if (exitLocation != null) {
|
||||
BlockData blockData = portal.getWorld().getBlockAt(exitLocation).getBlockData();
|
||||
if ((blockData instanceof Bisected && ((Bisected) blockData).getHalf() == Bisected.Half.BOTTOM) ||
|
||||
(blockData instanceof Slab) && ((Slab) blockData).getType() == Slab.Type.BOTTOM) {
|
||||
//Prevent traveller from spawning inside a slab
|
||||
Stargate.debug("adjustExitLocation", "Added a block to get above a slab");
|
||||
exitLocation.add(0, 1, 0);
|
||||
} else if (blockData.getMaterial() == Material.WATER) {
|
||||
//If there's water outside, go one up to allow for boat teleportation
|
||||
Stargate.debug("adjustExitLocation", "Added a block to get above a block of water");
|
||||
exitLocation.add(0, 1, 0);
|
||||
}
|
||||
|
||||
exitLocation.setPitch(traveller.getPitch());
|
||||
return exitLocation;
|
||||
} else {
|
||||
Stargate.logWarning("Unable to generate exit location");
|
||||
return traveller;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the chunks outside the portal's entrance
|
||||
*/
|
||||
protected void loadChunks() {
|
||||
for (Chunk chunk : getChunksToLoad()) {
|
||||
chunk.addPluginChunkTicket(Stargate.getInstance());
|
||||
//Allow the chunk to unload after 3 seconds
|
||||
Stargate.addChunkUnloadRequest(new ChunkUnloadRequest(chunk, 3000L));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all relevant chunks near this teleporter's portal's entrance which need to be loaded before teleportation
|
||||
*
|
||||
* @return <p>A list of chunks to load</p>
|
||||
*/
|
||||
private List<Chunk> getChunksToLoad() {
|
||||
List<Chunk> chunksToLoad = new ArrayList<>();
|
||||
for (RelativeBlockVector vector : portal.getGate().getLayout().getEntrances()) {
|
||||
BlockLocation entranceLocation = portal.getBlockAt(vector);
|
||||
Chunk chunk = entranceLocation.getChunk();
|
||||
//Make sure not to load chunks twice
|
||||
if (!chunksToLoad.contains(chunk)) {
|
||||
chunksToLoad.add(chunk);
|
||||
}
|
||||
|
||||
//Get the chunk in front of the gate entrance
|
||||
int blockOffset = portal.getOptions().isBackwards() ? -5 : 5;
|
||||
Location fiveBlocksForward = DirectionHelper.moveLocation(entranceLocation, 0, 0, blockOffset,
|
||||
portal.getYaw());
|
||||
//Load the chunk five blocks forward to make sure the teleported entity will never spawn in unloaded chunks
|
||||
Chunk forwardChunk = fiveBlocksForward.getChunk();
|
||||
if (!chunksToLoad.contains(forwardChunk)) {
|
||||
chunksToLoad.add(forwardChunk);
|
||||
}
|
||||
}
|
||||
return chunksToLoad;
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports any creatures leashed by the player
|
||||
*
|
||||
* @param player <p>The player which is teleported</p>
|
||||
* @param origin <p>The portal the player is teleporting from</p>
|
||||
*/
|
||||
protected void teleportLeashedCreatures(Player player, Portal origin) {
|
||||
//If this feature is disabled, just return
|
||||
if (!Stargate.getGateConfig().handleLeashedCreatures()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Find any nearby leashed entities to teleport with the player
|
||||
List<Creature> nearbyEntities = getLeashedCreatures(player);
|
||||
//Teleport all creatures leashed by the player to the portal the player is to exit from
|
||||
for (Creature creature : nearbyEntities) {
|
||||
creature.setLeashHolder(null);
|
||||
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> {
|
||||
new EntityTeleporter(portal, creature).teleport(origin);
|
||||
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> creature.setLeashHolder(player), 3);
|
||||
}, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all creatures leashed by a player within the given range
|
||||
*
|
||||
* @param player <p>The player to check</p>
|
||||
* @return <p>A list of all creatures the player is holding in a leash (lead)</p>
|
||||
*/
|
||||
protected List<Creature> getLeashedCreatures(Player player) {
|
||||
List<Creature> leashedCreatures = new ArrayList<>();
|
||||
//Find any nearby leashed entities to teleport with the player
|
||||
List<Entity> nearbyEntities = player.getNearbyEntities(15, 15, 15);
|
||||
//Teleport all creatures leashed by the player to the portal the player is to exit from
|
||||
for (Entity entity : nearbyEntities) {
|
||||
if (entity instanceof Creature creature && creature.isLeashed() && creature.getLeashHolder() == player) {
|
||||
leashedCreatures.add(creature);
|
||||
}
|
||||
}
|
||||
return leashedCreatures;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,239 @@
|
||||
package net.knarcraft.stargate.portal;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.config.StargateGateConfig;
|
||||
import net.knarcraft.stargate.utility.DirectionHelper;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The portal teleporter takes care of the actual portal teleportation for any vehicles
|
||||
*/
|
||||
public class VehicleTeleporter extends EntityTeleporter {
|
||||
|
||||
private final Vehicle teleportingVehicle;
|
||||
|
||||
/**
|
||||
* Instantiates a new vehicle teleporter
|
||||
*
|
||||
* @param portal <p>The portal which is the target of the teleportation</p>
|
||||
* @param teleportingVehicle <p>The teleporting vehicle</p>
|
||||
*/
|
||||
public VehicleTeleporter(Portal portal, Vehicle teleportingVehicle) {
|
||||
super(portal, teleportingVehicle);
|
||||
this.teleportingVehicle = teleportingVehicle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports a vehicle to this teleporter's portal
|
||||
*
|
||||
* <p>It is assumed that if a vehicle contains any players, their permissions have already been validated before
|
||||
* calling this method.</p>
|
||||
*
|
||||
* @param origin <p>The portal the vehicle is teleporting from</p>
|
||||
* @return <p>True if the vehicle was teleported. False otherwise</p>
|
||||
*/
|
||||
@Override
|
||||
public boolean teleport(Portal origin) {
|
||||
Location traveller = teleportingVehicle.getLocation();
|
||||
Location exit = getExit(teleportingVehicle, traveller);
|
||||
|
||||
double velocity = teleportingVehicle.getVelocity().length();
|
||||
|
||||
//Stop and teleport
|
||||
teleportingVehicle.setVelocity(new Vector());
|
||||
|
||||
//Get new velocity
|
||||
Vector newVelocityDirection = DirectionHelper.getDirectionVectorFromYaw(portal.getYaw());
|
||||
Vector newVelocity = newVelocityDirection.multiply(velocity);
|
||||
|
||||
//Make sure the vehicle points out from the portal
|
||||
adjustRotation(exit);
|
||||
|
||||
//Call the StargateEntityPortalEvent to allow plugins to change destination
|
||||
if (!origin.equals(portal)) {
|
||||
exit = triggerEntityPortalEvent(origin, exit);
|
||||
if (exit == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Teleport the vehicle
|
||||
return teleportVehicle(exit, newVelocity, origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports a vehicle with any passengers to the given location
|
||||
*
|
||||
* @param exit <p>The location the vehicle should be teleported to</p>
|
||||
* @param newVelocity <p>The velocity to give the vehicle right after teleportation</p>
|
||||
* @param origin <p>The portal the vehicle teleported from</p>
|
||||
* @return <p>True if the vehicle was teleported. False otherwise</p>
|
||||
*/
|
||||
private boolean teleportVehicle(Location exit, Vector newVelocity, Portal origin) {
|
||||
//Load chunks to make sure not to teleport to the void
|
||||
loadChunks();
|
||||
|
||||
List<Entity> passengers = teleportingVehicle.getPassengers();
|
||||
if (!passengers.isEmpty()) {
|
||||
//Check if the passengers are allowed according to current config settings
|
||||
if (!vehiclePassengersAllowed(passengers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(teleportingVehicle instanceof LivingEntity)) {
|
||||
//Teleport a normal vehicle with passengers (minecart or boat)
|
||||
putPassengersInNewVehicle(passengers, exit, newVelocity, origin);
|
||||
} else {
|
||||
//Teleport a living vehicle with passengers (pig, horse, donkey, strider)
|
||||
teleportLivingVehicle(exit, passengers, origin);
|
||||
}
|
||||
} else {
|
||||
//Check if teleportation of empty vehicles is enabled
|
||||
if (!Stargate.getGateConfig().handleEmptyVehicles()) {
|
||||
return false;
|
||||
}
|
||||
//Teleport an empty vehicle
|
||||
teleportingVehicle.teleport(exit);
|
||||
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(),
|
||||
() -> teleportingVehicle.setVelocity(newVelocity), 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether current config values allow the teleportation of the given passengers
|
||||
*
|
||||
* @param passengers <p>The passengers to teleport</p>
|
||||
* @return <p>True if the passengers are allowed to teleport</p>
|
||||
*/
|
||||
private boolean vehiclePassengersAllowed(List<Entity> passengers) {
|
||||
StargateGateConfig config = Stargate.getGateConfig();
|
||||
//Don't teleport if the vehicle contains a creature and creature transportation is disabled
|
||||
if (containsNonPlayer(passengers) && !config.handleCreatureTransportation()) {
|
||||
return false;
|
||||
}
|
||||
//Don't teleport if the player does not contain a player and non-player vehicles is disabled
|
||||
return containsPlayer(passengers) || config.handleNonPlayerVehicles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a list of entities contains any non-players
|
||||
*
|
||||
* @param entities <p>The list of entities to check</p>
|
||||
* @return <p>True if at least one entity is not a player</p>
|
||||
*/
|
||||
private boolean containsNonPlayer(List<Entity> entities) {
|
||||
for (Entity entity : entities) {
|
||||
if (!(entity instanceof Player)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a list of entities contains at least one player
|
||||
*
|
||||
* @param entities <p>The list of entities to check</p>
|
||||
* @return <p>True if at least one player is present among the passengers</p>
|
||||
*/
|
||||
private boolean containsPlayer(List<Entity> entities) {
|
||||
for (Entity entity : entities) {
|
||||
if (entity instanceof Player) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleport a vehicle which is not a minecart or a boat
|
||||
*
|
||||
* @param exit <p>The location the vehicle will exit</p>
|
||||
* @param passengers <p>The passengers of the vehicle</p>
|
||||
* @param origin <p>The portal the vehicle teleported from</p>
|
||||
*/
|
||||
private void teleportLivingVehicle(Location exit, List<Entity> passengers, Portal origin) {
|
||||
teleportingVehicle.eject();
|
||||
teleportingVehicle.teleport(exit);
|
||||
handleVehiclePassengers(passengers, teleportingVehicle, 2, origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new vehicle equal to the player's previous vehicle and puts any passengers inside
|
||||
*
|
||||
* <p>While it is possible to teleport boats and minecarts using the same methods as "teleportLivingVehicle", this
|
||||
* method works better with CraftBook with minecart options enabled. Using normal teleportation, CraftBook destroys
|
||||
* the minecart once the player is ejected, causing the minecart to disappear and the player to teleport without it.</p>
|
||||
*
|
||||
* @param passengers <p>A list of all passengers in the vehicle</p>
|
||||
* @param exit <p>The exit location to spawn the new vehicle on</p>
|
||||
* @param newVelocity <p>The new velocity of the new vehicle</p>
|
||||
* @param origin <p>The portal the vehicle teleported from</p>
|
||||
*/
|
||||
private void putPassengersInNewVehicle(List<Entity> passengers, Location exit,
|
||||
Vector newVelocity, Portal origin) {
|
||||
World vehicleWorld = exit.getWorld();
|
||||
if (vehicleWorld == null) {
|
||||
Stargate.logWarning("Unable to get the world to teleport the vehicle to");
|
||||
return;
|
||||
}
|
||||
//Spawn a new vehicle
|
||||
Vehicle newVehicle = vehicleWorld.spawn(exit, teleportingVehicle.getClass());
|
||||
//Remove the old vehicle
|
||||
teleportingVehicle.eject();
|
||||
teleportingVehicle.remove();
|
||||
//Set rotation, add passengers and restore velocity
|
||||
newVehicle.setRotation(exit.getYaw(), exit.getPitch());
|
||||
handleVehiclePassengers(passengers, newVehicle, 1, origin);
|
||||
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> newVehicle.setVelocity(newVelocity), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejects, teleports and adds all passengers to the target vehicle
|
||||
*
|
||||
* @param passengers <p>The passengers to handle</p>
|
||||
* @param vehicle <p>The vehicle the passengers should be put into</p>
|
||||
* @param delay <p>The amount of milliseconds to wait before adding the vehicle passengers</p>
|
||||
* @param origin <p>The portal the vehicle teleported from</p>
|
||||
*/
|
||||
private void handleVehiclePassengers(List<Entity> passengers, Vehicle vehicle, long delay, Portal origin) {
|
||||
for (Entity passenger : passengers) {
|
||||
passenger.eject();
|
||||
scheduler.scheduleSyncDelayedTask(Stargate.getInstance(), () -> {
|
||||
if (passenger instanceof Player player) {
|
||||
//Teleport any creatures leashed by the player in a 15-block range
|
||||
teleportLeashedCreatures(player, origin);
|
||||
}
|
||||
teleportAndAddPassenger(vehicle, passenger);
|
||||
}, delay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports and adds a passenger to a vehicle
|
||||
*
|
||||
* <p>Teleportation of living vehicles is really buggy if you wait between the teleportation and passenger adding,
|
||||
* but there needs to be a delay between teleporting the vehicle and teleporting and adding the passenger.</p>
|
||||
*
|
||||
* @param targetVehicle <p>The vehicle to add the passenger to</p>
|
||||
* @param passenger <p>The passenger to teleport and add</p>
|
||||
*/
|
||||
private void teleportAndAddPassenger(Vehicle targetVehicle, Entity passenger) {
|
||||
if (!passenger.teleport(targetVehicle.getLocation())) {
|
||||
Stargate.debug("handleVehiclePassengers", "Failed to teleport passenger");
|
||||
}
|
||||
if (!targetVehicle.addPassenger(passenger)) {
|
||||
Stargate.debug("handleVehiclePassengers", "Failed to add passenger");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package net.knarcraft.stargate.thread;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockChangeRequest;
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.EndGateway;
|
||||
import org.bukkit.block.data.Orientable;
|
||||
|
||||
/**
|
||||
* This thread changes gate blocks to display a gate as open or closed
|
||||
*
|
||||
* <p>This thread fetches some entries from blockPopulateQueue each time it's called.</p>
|
||||
*/
|
||||
public class BlockChangeThread implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long sTime = System.nanoTime();
|
||||
//Repeat for at most 0.025 seconds
|
||||
while (System.nanoTime() - sTime < 25000000) {
|
||||
pollQueue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls the block change request queue for any waiting requests
|
||||
*/
|
||||
public static void pollQueue() {
|
||||
//Abort if there's no work to be done
|
||||
BlockChangeRequest blockChangeRequest = Stargate.getBlockChangeRequestQueue().poll();
|
||||
if (blockChangeRequest == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Change the material of the pulled block
|
||||
Block block = blockChangeRequest.getBlockLocation().getBlock();
|
||||
block.setType(blockChangeRequest.getMaterial(), false);
|
||||
|
||||
if (blockChangeRequest.getMaterial() == Material.END_GATEWAY &&
|
||||
block.getWorld().getEnvironment() == World.Environment.THE_END) {
|
||||
//Force a specific location to prevent exit gateway generation
|
||||
fixEndGatewayGate(block);
|
||||
} else if (blockChangeRequest.getAxis() != null) {
|
||||
//If orientation is relevant, adjust the block's orientation
|
||||
orientBlock(block, blockChangeRequest.getAxis());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents end gateway portal from behaving strangely
|
||||
*
|
||||
* @param block <p>The block to fix</p>
|
||||
*/
|
||||
private static void fixEndGatewayGate(Block block) {
|
||||
EndGateway gateway = (EndGateway) block.getState();
|
||||
gateway.setExitLocation(block.getLocation());
|
||||
gateway.setExactTeleport(true);
|
||||
gateway.update(false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the orientation axis of the placed block
|
||||
*
|
||||
* @param block <p>The block to orient</p>
|
||||
* @param axis <p>The axis to use for orienting the block</p>
|
||||
*/
|
||||
private static void orientBlock(Block block, Axis axis) {
|
||||
Orientable orientable = (Orientable) block.getBlockData();
|
||||
orientable.setAxis(axis);
|
||||
block.setBlockData(orientable);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package net.knarcraft.stargate.thread;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.ChunkUnloadRequest;
|
||||
import org.bukkit.Chunk;
|
||||
|
||||
import java.util.Queue;
|
||||
|
||||
/**
|
||||
* Unloads chunks which should no longer be forced to stay loaded
|
||||
*/
|
||||
public class ChunkUnloadThread implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long systemNanoTime = System.nanoTime();
|
||||
Queue<ChunkUnloadRequest> unloadQueue = Stargate.getChunkUnloadQueue();
|
||||
|
||||
//Peek at the first element to check if the chunk should be unloaded
|
||||
ChunkUnloadRequest firstElement = unloadQueue.peek();
|
||||
//Repeat until all un-loadable chunks have been processed
|
||||
while (firstElement != null && firstElement.getUnloadNanoTime() < systemNanoTime) {
|
||||
unloadQueue.remove();
|
||||
Chunk chunkToUnload = firstElement.getChunkToUnload();
|
||||
//Allow the chunk to be unloaded
|
||||
chunkToUnload.removePluginChunkTicket(Stargate.getInstance());
|
||||
firstElement = unloadQueue.peek();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package net.knarcraft.stargate.thread;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
/**
|
||||
* This class contains the function used to close servers which should no longer be open/active
|
||||
*/
|
||||
public class StarGateThread implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long time = System.currentTimeMillis() / 1000;
|
||||
closeOpenPortals(time);
|
||||
deactivateActivePortals(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes portals which are open and have timed out
|
||||
*
|
||||
* @param time <p>The current time</p>
|
||||
*/
|
||||
private void closeOpenPortals(long time) {
|
||||
List<Portal> closedPortals = new ArrayList<>();
|
||||
Queue<Portal> openPortalsQueue = Stargate.getStargateConfig().getOpenPortalsQueue();
|
||||
|
||||
for (Portal portal : openPortalsQueue) {
|
||||
//Skip always open and non-open gates
|
||||
if (portal.getOptions().isAlwaysOn() || portal.getOptions().isRandom() || portal.getOptions().isBungee() ||
|
||||
!portal.isOpen()) {
|
||||
continue;
|
||||
}
|
||||
if (time > portal.getTriggeredTime() + Stargate.getGateConfig().getOpenTime()) {
|
||||
portal.getPortalOpener().closePortal(false);
|
||||
closedPortals.add(portal);
|
||||
}
|
||||
}
|
||||
openPortalsQueue.removeAll(closedPortals);
|
||||
}
|
||||
|
||||
/**
|
||||
* De-activates portals which are active and have timed out
|
||||
*
|
||||
* @param time <p>The current time</p>
|
||||
*/
|
||||
private void deactivateActivePortals(long time) {
|
||||
List<Portal> deactivatedPortals = new ArrayList<>();
|
||||
Queue<Portal> activePortalsQueue = Stargate.getStargateConfig().getActivePortalsQueue();
|
||||
|
||||
for (Portal portal : activePortalsQueue) {
|
||||
//Skip portals which aren't active
|
||||
if (!portal.getPortalActivator().isActive()) {
|
||||
continue;
|
||||
}
|
||||
if (time > portal.getTriggeredTime() + Stargate.getGateConfig().getActiveTime()) {
|
||||
portal.getPortalActivator().deactivate();
|
||||
deactivatedPortals.add(portal);
|
||||
}
|
||||
}
|
||||
activePortalsQueue.removeAll(deactivatedPortals);
|
||||
}
|
||||
|
||||
}
|
208
src/main/java/net/knarcraft/stargate/utility/BungeeHelper.java
Normal file
208
src/main/java/net/knarcraft/stargate/utility/BungeeHelper.java
Normal file
@ -0,0 +1,208 @@
|
||||
package net.knarcraft.stargate.utility;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.portal.PlayerTeleporter;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import net.knarcraft.stargate.portal.PortalHandler;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This class contains helpful functions to help with sending and receiving BungeeCord plugin messages
|
||||
*/
|
||||
public final class BungeeHelper {
|
||||
|
||||
private final static String bungeeSubChannel = "SGBungee";
|
||||
private final static String bungeeChannel = "BungeeCord";
|
||||
private final static String teleportMessageDelimiter = "#@#";
|
||||
private final static Map<UUID, String> bungeeQueue = new HashMap<>();
|
||||
|
||||
private BungeeHelper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin message channel use for BungeeCord messages
|
||||
*
|
||||
* @return <p>The bungee plugin channel</p>
|
||||
*/
|
||||
public static String getBungeeChannel() {
|
||||
return bungeeChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a player from the queue of players teleporting through BungeeCord
|
||||
*
|
||||
* <p>Whenever a BungeeCord teleportation message is received and the player is not currently connected to this
|
||||
* server, it'll be added to this queue. Once the player joins this server, the player should be removed from the
|
||||
* queue and teleported to the destination.</p>
|
||||
*
|
||||
* @param playerUUID <p>The UUID of the player to remove</p>
|
||||
* @return <p>The name of the destination portal the player should be teleported to</p>
|
||||
*/
|
||||
public static String removeFromQueue(UUID playerUUID) {
|
||||
return bungeeQueue.remove(playerUUID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a plugin message to BungeeCord allowing the target server to catch it
|
||||
*
|
||||
* @param player <p>The teleporting player</p>
|
||||
* @param entrancePortal <p>The portal the player is teleporting from</p>
|
||||
* @return <p>True if the message was successfully sent</p>
|
||||
*/
|
||||
public static boolean sendTeleportationMessage(Player player, Portal entrancePortal) {
|
||||
try {
|
||||
//Build the teleportation message, format is <player identifier>delimiter<destination>
|
||||
String message = player.getUniqueId() + teleportMessageDelimiter + entrancePortal.getDestinationName();
|
||||
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
|
||||
|
||||
//Build the message data and send it over the SGBungee BungeeCord channel
|
||||
dataOutputStream.writeUTF("Forward");
|
||||
//Send the message to the server defined in the entrance portal's network line
|
||||
dataOutputStream.writeUTF(entrancePortal.getNetwork());
|
||||
//Specify the sub-channel/tag to make it recognizable on arrival
|
||||
dataOutputStream.writeUTF(bungeeSubChannel);
|
||||
//Write the length of the message
|
||||
dataOutputStream.writeShort(message.length());
|
||||
//Write the actual message
|
||||
dataOutputStream.writeBytes(message);
|
||||
//Send the plugin message
|
||||
player.sendPluginMessage(Stargate.getInstance(), bungeeChannel, byteArrayOutputStream.toByteArray());
|
||||
} catch (IOException ex) {
|
||||
Stargate.logSevere("Error sending BungeeCord teleport packet");
|
||||
ex.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the bungee message necessary to make a player connect to another server
|
||||
*
|
||||
* @param player <p>The player to teleport</p>
|
||||
* @param entrancePortal <p>The bungee portal the player is teleporting from</p>
|
||||
* @return <p>True if the plugin message was sent successfully</p>
|
||||
*/
|
||||
public static boolean changeServer(Player player, Portal entrancePortal) {
|
||||
try {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
|
||||
|
||||
//Send a connect-message to connect the player to the server defined in the entrance portal's network line
|
||||
dataOutputStream.writeUTF("Connect");
|
||||
dataOutputStream.writeUTF(entrancePortal.getNetwork());
|
||||
|
||||
//Send the plugin message
|
||||
player.sendPluginMessage(Stargate.getInstance(), bungeeChannel, byteArrayOutputStream.toByteArray());
|
||||
} catch (IOException ex) {
|
||||
Stargate.logSevere("Error sending BungeeCord connect packet");
|
||||
ex.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a plugin message byte array to a string if it's sent from another stargate plugin
|
||||
*
|
||||
* @param message <p>The byte array to read</p>
|
||||
* @return <p>The message contained in the byte array, or null on failure</p>
|
||||
*/
|
||||
public static String readPluginMessage(byte[] message) {
|
||||
byte[] data;
|
||||
try {
|
||||
DataInputStream dataInputStream = new DataInputStream(new ByteArrayInputStream(message));
|
||||
String subChannel = dataInputStream.readUTF();
|
||||
//Only listen for the SGBungee channel
|
||||
if (!subChannel.equals(bungeeSubChannel)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//Get the length of the contained message
|
||||
short dataLength = dataInputStream.readShort();
|
||||
//Prepare a byte array for the sent message
|
||||
data = new byte[dataLength];
|
||||
//Read the message to the prepared array
|
||||
dataInputStream.readFully(data);
|
||||
} catch (IOException ex) {
|
||||
Stargate.logSevere("Error receiving BungeeCord message");
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return new String(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the receival of a teleport message
|
||||
*
|
||||
* @param receivedMessage <p>The received teleport message</p>
|
||||
*/
|
||||
public static void handleTeleportMessage(String receivedMessage) {
|
||||
//Get the player id and destination from the message
|
||||
String[] messageParts = receivedMessage.split(teleportMessageDelimiter);
|
||||
UUID playerUUID = UUID.fromString(messageParts[0]);
|
||||
String destination = messageParts[1];
|
||||
|
||||
//Check if the player is online, if so, teleport, otherwise, queue
|
||||
Player player = Stargate.getInstance().getServer().getPlayer(playerUUID);
|
||||
if (player == null) {
|
||||
bungeeQueue.put(playerUUID, destination);
|
||||
} else {
|
||||
Portal destinationPortal = PortalHandler.getBungeePortal(destination);
|
||||
//If teleporting to an invalid portal, let the server decide where the player arrives
|
||||
if (destinationPortal == null) {
|
||||
Stargate.logInfo(String.format("Bungee portal %s does not exist", destination));
|
||||
return;
|
||||
}
|
||||
new PlayerTeleporter(destinationPortal, player).teleport(destinationPortal, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports a player to a bungee gate
|
||||
*
|
||||
* @param player <p>The player to teleport</p>
|
||||
* @param entrancePortal <p>The gate the player is entering from</p>
|
||||
* @param event <p>The event causing the teleportation</p>
|
||||
* @return <p>True if the teleportation was successful</p>
|
||||
*/
|
||||
public static boolean bungeeTeleport(Player player, Portal entrancePortal, PlayerMoveEvent event) {
|
||||
//Check if bungee is actually enabled
|
||||
if (!Stargate.getGateConfig().enableBungee()) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeDisabled"));
|
||||
entrancePortal.getPortalOpener().closePortal(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Teleport the player back to this gate, for sanity's sake
|
||||
new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event);
|
||||
|
||||
//Send the SGBungee packet first, it will be queued by BC if required
|
||||
if (!BungeeHelper.sendTeleportationMessage(player, entrancePortal)) {
|
||||
Stargate.debug("bungeeTeleport", "Unable to send teleportation message");
|
||||
return false;
|
||||
}
|
||||
|
||||
//Send the connect-message to make the player change server
|
||||
if (!BungeeHelper.changeServer(player, entrancePortal)) {
|
||||
Stargate.debug("bungeeTeleport", "Unable to change server");
|
||||
return false;
|
||||
}
|
||||
|
||||
Stargate.debug("bungeeTeleport", "Teleported player to another server");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
package net.knarcraft.stargate.utility;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
/**
|
||||
* This class helps with direction-related calculations
|
||||
*/
|
||||
public final class DirectionHelper {
|
||||
|
||||
private DirectionHelper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a yaw by comparing two locations
|
||||
*
|
||||
* <p>The yaw here is the direction an observer a the first location has to look to face the second location.
|
||||
* The yaw is only meant to be calculated for locations where both have either the same x value or the same z value.
|
||||
* Equal locations, or locations with equal x and equal z will throw an exception.</p>
|
||||
*
|
||||
* @param location1 <p>The first location, which works as the origin</p>
|
||||
* @param location2 <p>The second location, which the yaw will point towards</p>
|
||||
* @return <p>The yaw pointing from the first location to the second location</p>
|
||||
*/
|
||||
public static float getYawFromLocationDifference(Location location1, Location location2) {
|
||||
Location difference = location1.clone().subtract(location2.clone());
|
||||
if (difference.getX() > 0) {
|
||||
return 90;
|
||||
} else if (difference.getX() < 0) {
|
||||
return 270;
|
||||
} else if (difference.getZ() > 0) {
|
||||
return 180;
|
||||
} else if (difference.getZ() < 0) {
|
||||
return 0;
|
||||
}
|
||||
throw new IllegalArgumentException("Locations given are equal or at the same x and y axis");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a block face given a yaw value
|
||||
*
|
||||
* <p>The supplied yaw must be a value such that (yaw mod 90) = 0. If not, an exception is thrown.</p>
|
||||
*
|
||||
* @param yaw <p>The yaw value to convert</p>
|
||||
* @return <p>The block face the yaw corresponds to</p>
|
||||
*/
|
||||
public static BlockFace getBlockFaceFromYaw(double yaw) {
|
||||
//Make sure the yaw is between 0 and 360
|
||||
yaw = normalizeYaw(yaw);
|
||||
|
||||
if (yaw == 0) {
|
||||
return BlockFace.SOUTH;
|
||||
} else if (yaw == 90) {
|
||||
return BlockFace.WEST;
|
||||
} else if (yaw == 180) {
|
||||
return BlockFace.NORTH;
|
||||
} else if (yaw == 270) {
|
||||
return BlockFace.EAST;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid yaw given. Yaw must be divisible by 90.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a direction vector given a yaw
|
||||
*
|
||||
* @param yaw <p>The yaw to convert to a direction vector</p>
|
||||
* @return <p>The direction vector pointing in the same direction as the yaw</p>
|
||||
*/
|
||||
public static Vector getDirectionVectorFromYaw(double yaw) {
|
||||
//Make sure the yaw is between 0 and 360
|
||||
yaw = normalizeYaw(yaw);
|
||||
|
||||
if (yaw == 0) {
|
||||
return new Vector(0, 0, 1);
|
||||
} else if (yaw == 90) {
|
||||
return new Vector(-1, 0, 0);
|
||||
} else if (yaw == 180) {
|
||||
return new Vector(0, 0, -1);
|
||||
} else if (yaw == 270) {
|
||||
return new Vector(1, 0, 0);
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("Invalid yaw %f given", yaw));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a location by the given amounts
|
||||
*
|
||||
* <p>The right, down and out work the same as for the relative block vector. Looking a the front of a portal,
|
||||
* right goes rightwards, down goes downwards and out goes towards the observer.</p>
|
||||
*
|
||||
* @param location <p>The location to start at</p>
|
||||
* @param right <p>The amount to go right</p>
|
||||
* @param down <p>The amount to go downward</p>
|
||||
* @param out <p>The amount to go outward</p>
|
||||
* @param yaw <p>The yaw when looking directly outwards from a portal</p>
|
||||
* @return <p>A location relative to the given location</p>
|
||||
*/
|
||||
public static Location moveLocation(Location location, double right, double down, double out, double yaw) {
|
||||
return location.add(getCoordinateVectorFromRelativeVector(right, down, out, yaw));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a vector in Minecraft's normal X,Y,Z-space from a relative block vector
|
||||
*
|
||||
* @param right <p>The amount of rightward steps from the top-left origin</p>
|
||||
* @param down <p>The amount of downward steps from the top-left origin</p>
|
||||
* @param out <p>The distance outward from the top-left origin</p>
|
||||
* @param yaw <p>The yaw when looking directly outwards from a portal</p>
|
||||
* @return <p>A normal vector</p>
|
||||
*/
|
||||
public static Vector getCoordinateVectorFromRelativeVector(double right, double down, double out, double yaw) {
|
||||
Vector distanceVector = DirectionHelper.getDirectionVectorFromYaw(yaw);
|
||||
distanceVector.multiply(out);
|
||||
|
||||
Vector rightVector = DirectionHelper.getDirectionVectorFromYaw(yaw - 90);
|
||||
rightVector.multiply(right);
|
||||
|
||||
Vector depthVector = new Vector(0, -1, 0);
|
||||
depthVector.multiply(down);
|
||||
|
||||
return distanceVector.add(rightVector).add(depthVector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a yaw to make it positive and no larger than 360 degrees
|
||||
*
|
||||
* @param yaw <p>The yaw to normalize</p>
|
||||
* @return <p>The normalized yaw</p>
|
||||
*/
|
||||
private static double normalizeYaw(double yaw) {
|
||||
while (yaw < 0) {
|
||||
yaw += 360;
|
||||
}
|
||||
yaw = yaw % 360;
|
||||
return yaw;
|
||||
}
|
||||
|
||||
}
|
134
src/main/java/net/knarcraft/stargate/utility/EconomyHelper.java
Normal file
134
src/main/java/net/knarcraft/stargate/utility/EconomyHelper.java
Normal file
@ -0,0 +1,134 @@
|
||||
package net.knarcraft.stargate.utility;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import net.knarcraft.stargate.portal.PortalOwner;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* The economy helper class has helper functions for player payment
|
||||
*/
|
||||
public final class EconomyHelper {
|
||||
|
||||
private EconomyHelper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to make the given user pay the teleport fee
|
||||
*
|
||||
* @param entrancePortal <p>The portal the player is entering</p>
|
||||
* @param player <p>The player wishing to teleport</p>
|
||||
* @param cost <p>The cost of teleportation</p>
|
||||
* @return <p>False if payment was successful. True if the payment was unsuccessful</p>
|
||||
*/
|
||||
public static boolean cannotPayTeleportFee(Portal entrancePortal, Player player, int cost) {
|
||||
boolean success;
|
||||
|
||||
//Try to charge the player. Paying the portal owner is only possible if a UUID is available
|
||||
UUID ownerUUID = entrancePortal.getOwner().getUUID();
|
||||
if (ownerUUID == null) {
|
||||
Stargate.logWarning(String.format("The owner of the portal %s does not have a UUID and payment to owner " +
|
||||
"was therefore not possible. Make the owner re-create the portal to fix this.", entrancePortal));
|
||||
}
|
||||
if (entrancePortal.getGate().getToOwner() && ownerUUID != null) {
|
||||
success = Stargate.getEconomyConfig().chargePlayerIfNecessary(player, ownerUUID, cost);
|
||||
} else {
|
||||
success = Stargate.getEconomyConfig().chargePlayerIfNecessary(player, cost);
|
||||
}
|
||||
|
||||
//Send the insufficient funds message
|
||||
if (!success) {
|
||||
sendInsufficientFundsMessage(entrancePortal.getName(), player, cost);
|
||||
entrancePortal.getPortalOpener().closePortal(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
//Send the deduct-message to the player
|
||||
sendDeductMessage(entrancePortal.getName(), player, cost);
|
||||
|
||||
if (entrancePortal.getGate().getToOwner()) {
|
||||
PortalOwner owner = entrancePortal.getOwner();
|
||||
Player portalOwner;
|
||||
if (owner.getUUID() != null) {
|
||||
portalOwner = Stargate.getInstance().getServer().getPlayer(owner.getUUID());
|
||||
} else {
|
||||
portalOwner = Stargate.getInstance().getServer().getPlayer(owner.getName());
|
||||
}
|
||||
|
||||
//Notify the gate owner of received payment
|
||||
if (portalOwner != null) {
|
||||
sendObtainMessage(entrancePortal.getName(), portalOwner, cost);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the gate owner telling him/her how much he/she earned from a player using his/her gate
|
||||
*
|
||||
* @param portalName <p>The name of the used portal</p>
|
||||
* @param portalOwner <p>The owner of the portal</p>
|
||||
* @param earnings <p>The amount the owner earned</p>
|
||||
*/
|
||||
public static void sendObtainMessage(String portalName, Player portalOwner, int earnings) {
|
||||
String obtainedMsg = Stargate.getString("ecoObtain");
|
||||
obtainedMsg = replaceVars(obtainedMsg, portalName, earnings);
|
||||
Stargate.getMessageSender().sendSuccessMessage(portalOwner, obtainedMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message telling the user how much they paid for interacting with a portal
|
||||
*
|
||||
* @param portalName <p>The name of the portal interacted with</p>
|
||||
* @param player <p>The interacting player</p>
|
||||
* @param cost <p>The cost of the interaction</p>
|
||||
*/
|
||||
public static void sendDeductMessage(String portalName, Player player, int cost) {
|
||||
String deductMsg = Stargate.getString("ecoDeduct");
|
||||
deductMsg = replaceVars(deductMsg, portalName, cost);
|
||||
Stargate.getMessageSender().sendSuccessMessage(player, deductMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message telling the user they don't have enough funds to do a portal interaction
|
||||
*
|
||||
* @param portalName <p>The name of the portal interacted with</p>
|
||||
* @param player <p>The interacting player</p>
|
||||
* @param cost <p>The cost of the interaction</p>
|
||||
*/
|
||||
public static void sendInsufficientFundsMessage(String portalName, Player player, int cost) {
|
||||
String inFundMsg = Stargate.getString("ecoInFunds");
|
||||
inFundMsg = replaceVars(inFundMsg, portalName, cost);
|
||||
Stargate.getMessageSender().sendErrorMessage(player, inFundMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message telling the user how much they are refunded for breaking their portal
|
||||
*
|
||||
* @param portalName <p>The name of the broken portal</p>
|
||||
* @param player <p>The player breaking the portal</p>
|
||||
* @param cost <p>The amount the user has to pay for destroying the portal. (expects a negative value)</p>
|
||||
*/
|
||||
public static void sendRefundMessage(String portalName, Player player, int cost) {
|
||||
String refundMsg = Stargate.getString("ecoRefund");
|
||||
refundMsg = replaceVars(refundMsg, portalName, -cost);
|
||||
Stargate.getMessageSender().sendSuccessMessage(player, refundMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the cost and portal variables in a string
|
||||
*
|
||||
* @param message <p>The message to replace variables in</p>
|
||||
* @param portalName <p>The name of the relevant portal</p>
|
||||
* @param cost <p>The cost for a given interaction</p>
|
||||
* @return <p>The same string with cost and portal variables replaced</p>
|
||||
*/
|
||||
private static String replaceVars(String message, String portalName, int cost) {
|
||||
return Stargate.replaceVars(message, new String[]{"%cost%", "%portal%"},
|
||||
new String[]{Stargate.getEconomyConfig().format(cost), portalName});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package net.knarcraft.stargate.utility;
|
||||
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
/**
|
||||
* This helper class helps with entity properties not immediately available
|
||||
*/
|
||||
public final class EntityHelper {
|
||||
|
||||
private EntityHelper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the max size of an entity along its x and z axis
|
||||
*
|
||||
* <p>This function gets the ceiling of the max size of an entity, thus calculating the smallest box, using whole
|
||||
* blocks as unit, needed to contain the entity. Assuming n is returned, an (n x n) box is needed to contain the
|
||||
* entity.</p>
|
||||
*
|
||||
* @param entity <p>The entity to get max size for</p>
|
||||
* @return <p>The max size of the entity</p>
|
||||
*/
|
||||
public static int getEntityMaxSizeInt(Entity entity) {
|
||||
return (int) Math.ceil((float) getEntityMaxSize(entity));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the max size of an entity along its x and z axis
|
||||
*
|
||||
* @param entity <p>The entity to get max size for</p>
|
||||
* @return <p>The max size of the entity</p>
|
||||
*/
|
||||
public static double getEntityMaxSize(Entity entity) {
|
||||
return Math.max(entity.getBoundingBox().getWidthX(), entity.getBoundingBox().getWidthZ());
|
||||
}
|
||||
|
||||
}
|
127
src/main/java/net/knarcraft/stargate/utility/FileHelper.java
Normal file
127
src/main/java/net/knarcraft/stargate/utility/FileHelper.java
Normal file
@ -0,0 +1,127 @@
|
||||
package net.knarcraft.stargate.utility;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Helper class for reading files
|
||||
*/
|
||||
public final class FileHelper {
|
||||
|
||||
private FileHelper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an input stream from a string pointing to an internal file
|
||||
*
|
||||
* <p>This is used for getting an input stream for reading a file contained within the compiled .jar file. The file
|
||||
* should be in the resources directory, and the file path should start with a forward slash ("/") character.</p>
|
||||
*
|
||||
* @param file <p>The file to read</p>
|
||||
* @return <p>An input stream for the file</p>
|
||||
*/
|
||||
public static InputStream getInputStreamForInternalFile(String file) {
|
||||
return FileHelper.class.getResourceAsStream(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a buffered reader from a string pointing to a file
|
||||
*
|
||||
* @param file <p>The file to read</p>
|
||||
* @return <p>A buffered reader reading the file</p>
|
||||
* @throws FileNotFoundException <p>If the given file does not exist</p>
|
||||
*/
|
||||
public static BufferedReader getBufferedReaderFromString(String file) throws FileNotFoundException {
|
||||
FileInputStream fileInputStream = new FileInputStream(file);
|
||||
return getBufferedReaderFromInputStream(fileInputStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a buffered reader given an input stream
|
||||
*
|
||||
* @param inputStream <p>The input stream to read</p>
|
||||
* @return <p>A buffered reader reading the input stream</p>
|
||||
*/
|
||||
public static BufferedReader getBufferedReaderFromInputStream(InputStream inputStream) {
|
||||
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
|
||||
return new BufferedReader(inputStreamReader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a buffered writer from a string pointing to a file
|
||||
*
|
||||
* @param file <p>The file to write to</p>
|
||||
* @return <p>A buffered writer writing to the file</p>
|
||||
* @throws FileNotFoundException <p>If the file does not exist</p>
|
||||
*/
|
||||
public static BufferedWriter getBufferedWriterFromString(String file) throws FileNotFoundException {
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(file);
|
||||
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8);
|
||||
return new BufferedWriter(outputStreamWriter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads key/value pairs from an input stream
|
||||
*
|
||||
* @param bufferedReader <p>The buffered reader to read</p>
|
||||
* @return <p>A map containing the read pairs</p>
|
||||
* @throws IOException <p>If unable to read from the stream</p>
|
||||
*/
|
||||
public static Map<String, String> readKeyValuePairs(BufferedReader bufferedReader) throws IOException {
|
||||
Map<String, String> readPairs = new HashMap<>();
|
||||
|
||||
String line = bufferedReader.readLine();
|
||||
boolean firstLine = true;
|
||||
while (line != null) {
|
||||
//Strip UTF BOM from the first line
|
||||
if (firstLine) {
|
||||
line = removeUTF8BOM(line);
|
||||
firstLine = false;
|
||||
}
|
||||
//Split at first "="
|
||||
int equalSignIndex = line.indexOf('=');
|
||||
if (equalSignIndex == -1) {
|
||||
line = bufferedReader.readLine();
|
||||
continue;
|
||||
}
|
||||
|
||||
//Read the line
|
||||
String key = line.substring(0, equalSignIndex);
|
||||
String value = ChatColor.translateAlternateColorCodes('&', line.substring(equalSignIndex + 1));
|
||||
readPairs.put(key, value);
|
||||
|
||||
line = bufferedReader.readLine();
|
||||
}
|
||||
bufferedReader.close();
|
||||
|
||||
return readPairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the UTF-8 Byte Order Mark if present
|
||||
*
|
||||
* @param string <p>The string to remove the BOM from</p>
|
||||
* @return <p>A string guaranteed without a BOM</p>
|
||||
*/
|
||||
private static String removeUTF8BOM(String string) {
|
||||
String UTF8_BOM = "\uFEFF";
|
||||
if (string.startsWith(UTF8_BOM)) {
|
||||
string = string.substring(1);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
}
|
210
src/main/java/net/knarcraft/stargate/utility/GateReader.java
Normal file
210
src/main/java/net/knarcraft/stargate/utility/GateReader.java
Normal file
@ -0,0 +1,210 @@
|
||||
package net.knarcraft.stargate.utility;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import org.bukkit.Material;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Helper class for reading gate files
|
||||
*/
|
||||
public final class GateReader {
|
||||
|
||||
private GateReader() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a gate file
|
||||
*
|
||||
* @param scanner <p>The scanner to read from</p>
|
||||
* @param characterMaterialMap <p>The map of characters to store valid symbols in</p>
|
||||
* @param fileName <p>The filename of the loaded gate config file</p>
|
||||
* @param design <p>The list to store the loaded design/layout to</p>
|
||||
* @param frameTypes <p>The set to store frame/border materials to</p>
|
||||
* @param config <p>The map of config values to store to</p>
|
||||
* @return <p>The column count/width of the loaded gate</p>
|
||||
*/
|
||||
public static int readGateFile(Scanner scanner, Map<Character, Material> characterMaterialMap, String fileName,
|
||||
List<List<Character>> design, Set<Material> frameTypes, Map<String, String> config) {
|
||||
boolean designing = false;
|
||||
int columns = 0;
|
||||
try {
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine();
|
||||
|
||||
if (designing) {
|
||||
//If we have reached the gate's layout/design, read it
|
||||
columns = readGateDesignLine(line, columns, characterMaterialMap, fileName, design);
|
||||
if (columns < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (!line.isEmpty() && !line.startsWith("#")) {
|
||||
//Read a normal config value
|
||||
readGateConfigValue(line, characterMaterialMap, frameTypes, config);
|
||||
} else if ((line.isEmpty()) || (!line.contains("=") && !line.startsWith("#"))) {
|
||||
//An empty line marks the start of the gate's layout/design
|
||||
designing = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
Stargate.logSevere(String.format("Could not load Gate %s - %s", fileName, exception.getMessage()));
|
||||
return -1;
|
||||
} finally {
|
||||
if (scanner != null) {
|
||||
scanner.close();
|
||||
}
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads one design line of the gate layout file
|
||||
*
|
||||
* <p>The max columns value is sent through this method in such a way that when the last gate design line is read,
|
||||
* the max columns value contains the largest amount of columns (character) found in any of the design's lines.</p>
|
||||
*
|
||||
* @param line <p>The line to read</p>
|
||||
* @param maxColumns <p>The current max columns value of the design</p>
|
||||
* @param characterMaterialMap <p>The map between characters and the corresponding materials to use</p>
|
||||
* @param fileName <p>The filename of the loaded gate config file</p>
|
||||
* @param design <p>The two-dimensional list to store the loaded design to</p>
|
||||
* @return <p>The new max columns value of the design</p>
|
||||
*/
|
||||
private static int readGateDesignLine(String line, int maxColumns, Map<Character, Material> characterMaterialMap,
|
||||
String fileName, List<List<Character>> design) {
|
||||
List<Character> row = new ArrayList<>();
|
||||
|
||||
//Update the max columns number if this line has more columns
|
||||
if (line.length() > maxColumns) {
|
||||
maxColumns = line.length();
|
||||
}
|
||||
|
||||
for (Character symbol : line.toCharArray()) {
|
||||
//Refuse read gate designs with unknown characters
|
||||
if (symbol.equals('?') || (!characterMaterialMap.containsKey(symbol))) {
|
||||
Stargate.logSevere(String.format("Could not load Gate %s - Unknown symbol '%s' in diagram", fileName,
|
||||
symbol));
|
||||
return -1;
|
||||
}
|
||||
//Add the read character to the row
|
||||
row.add(symbol);
|
||||
}
|
||||
|
||||
//Add this row of the gate's design to the two-dimensional design list
|
||||
design.add(row);
|
||||
return maxColumns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads one config value from the gate layout file
|
||||
*
|
||||
* @param line <p>The line to read</p>
|
||||
* @param characterMaterialMap <p>The character to material map to store to</p>
|
||||
* @param frameTypes <p>The set to store gate frame/border types to</p>
|
||||
* @param config <p>The config value map to store to</p>
|
||||
* @throws Exception <p>If an invalid material is encountered</p>
|
||||
*/
|
||||
private static void readGateConfigValue(String line, Map<Character, Material> characterMaterialMap,
|
||||
Set<Material> frameTypes, Map<String, String> config) throws Exception {
|
||||
String[] split = line.split("=");
|
||||
String key = split[0].trim();
|
||||
String value = split[1].trim();
|
||||
|
||||
if (key.length() == 1) {
|
||||
//Read a gate frame material
|
||||
Character symbol = key.charAt(0);
|
||||
Material material = Material.getMaterial(value);
|
||||
if (material == null) {
|
||||
throw new Exception("Invalid material in line: " + line);
|
||||
}
|
||||
//Register the map between the read symbol and the corresponding material
|
||||
characterMaterialMap.put(symbol, material);
|
||||
//Save the material as one of the frame materials used for this kind of gate
|
||||
frameTypes.add(material);
|
||||
} else {
|
||||
//Read a normal config value
|
||||
config.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an integer configuration value
|
||||
*
|
||||
* @param config <p>The configuration to read</p>
|
||||
* @param fileName <p>The filename of the config file</p>
|
||||
* @param key <p>The config key to read</p>
|
||||
* @return <p>The read value, or -1 if it could not be read</p>
|
||||
*/
|
||||
public static int readGateConfig(Map<String, String> config, String fileName, String key) {
|
||||
if (config.containsKey(key)) {
|
||||
try {
|
||||
return Integer.parseInt(config.get(key));
|
||||
} catch (NumberFormatException ex) {
|
||||
Stargate.logWarning(String.format("%s reading %s: %s is not numeric", ex.getClass().getName(),
|
||||
fileName, key));
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a material configuration value
|
||||
*
|
||||
* @param config <p>The configuration to read</p>
|
||||
* @param fileName <p>The filename of the config file</p>
|
||||
* @param key <p>The config key to read</p>
|
||||
* @param defaultMaterial <p>The default material to use, in case the config is invalid</p>
|
||||
* @return <p>The material specified in the config, or the default material if it could not be read</p>
|
||||
*/
|
||||
public static Material readGateConfig(Map<String, String> config, String fileName, String key,
|
||||
Material defaultMaterial) {
|
||||
if (config.containsKey(key)) {
|
||||
Material material = Material.getMaterial(config.get(key));
|
||||
if (material != null) {
|
||||
return material;
|
||||
} else {
|
||||
Stargate.logWarning(String.format("Error reading %s: %s is not a material", fileName, key));
|
||||
}
|
||||
}
|
||||
return defaultMaterial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a matrix containing the gate layout
|
||||
*
|
||||
* <p>This basically changes the list of lists into a primitive matrix. Additionally, spaces are added to the end of
|
||||
* each row which to too short relative to the longest row.</p>
|
||||
*
|
||||
* @param design <p>The design of the gate layout</p>
|
||||
* @param columns <p>The largest amount of columns in the design</p>
|
||||
* @return <p>A matrix containing the gate's layout</p>
|
||||
*/
|
||||
public static Character[][] generateLayoutMatrix(List<List<Character>> design, int columns) {
|
||||
Character[][] layout = new Character[design.size()][columns];
|
||||
for (int lineIndex = 0; lineIndex < design.size(); lineIndex++) {
|
||||
List<Character> row = design.get(lineIndex);
|
||||
Character[] result = new Character[columns];
|
||||
|
||||
for (int rowIndex = 0; rowIndex < columns; rowIndex++) {
|
||||
if (rowIndex < row.size()) {
|
||||
result[rowIndex] = row.get(rowIndex);
|
||||
} else {
|
||||
//Add spaces to all lines which are too short
|
||||
result[rowIndex] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
layout[lineIndex] = result;
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package net.knarcraft.stargate.utility;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
|
||||
/**
|
||||
* This class helps decide properties of materials not already present in the Spigot API
|
||||
*/
|
||||
public final class MaterialHelper {
|
||||
|
||||
private MaterialHelper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given material is a dead or alive wall coral
|
||||
*
|
||||
* @param material <p>The material to check</p>
|
||||
* @return <p>True if the material is a wall coral</p>
|
||||
*/
|
||||
public static boolean isWallCoral(Material material) {
|
||||
//Unfortunately, there is no tag for dead wall corals, so they need to be checked manually
|
||||
return Tag.WALL_CORALS.isTagged(material) ||
|
||||
material.equals(Material.DEAD_BRAIN_CORAL_WALL_FAN) ||
|
||||
material.equals(Material.DEAD_BUBBLE_CORAL_WALL_FAN) ||
|
||||
material.equals(Material.DEAD_FIRE_CORAL_WALL_FAN) ||
|
||||
material.equals(Material.DEAD_HORN_CORAL_WALL_FAN) ||
|
||||
material.equals(Material.DEAD_TUBE_CORAL_WALL_FAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given material can be used as a button
|
||||
*
|
||||
* @param material <p>The material to check</p>
|
||||
* @return <p>True if the material can be used as a button</p>
|
||||
*/
|
||||
public static boolean isButtonCompatible(Material material) {
|
||||
return Tag.BUTTONS.isTagged(material) || isWallCoral(material) || Tag.SHULKER_BOXES.isTagged(material) ||
|
||||
material == Material.CHEST || material == Material.TRAPPED_CHEST || material == Material.ENDER_CHEST;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,403 @@
|
||||
package net.knarcraft.stargate.utility;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.event.StargateAccessEvent;
|
||||
import net.knarcraft.stargate.portal.PlayerTeleporter;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import net.knarcraft.stargate.portal.PortalOption;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
|
||||
/**
|
||||
* Helper class for deciding which actions a player is allowed to perform
|
||||
*/
|
||||
public final class PermissionHelper {
|
||||
|
||||
private PermissionHelper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a portal if the given player is allowed to, and if the portal is not already open
|
||||
*
|
||||
* @param player <p>The player opening the portal</p>
|
||||
* @param portal <p>The portal to open</p>
|
||||
*/
|
||||
public static void openPortal(Player player, Portal portal) {
|
||||
Portal destination = portal.getPortalActivator().getDestination();
|
||||
|
||||
//For an always open portal, no action is necessary
|
||||
if (portal.getOptions().isAlwaysOn() || portal.getOptions().isRandom() || portal.getOptions().isBungee()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Destination is invalid or the same portal. Send an error message
|
||||
if (destination == null || destination == portal) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("invalidMsg"));
|
||||
return;
|
||||
}
|
||||
|
||||
//Portal is already open
|
||||
if (portal.isOpen()) {
|
||||
//Close the portal if this player opened the portal
|
||||
if (portal.getActivePlayer() == player) {
|
||||
portal.getPortalOpener().closePortal(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//Deny access if another player has activated the portal, and it's still in use
|
||||
if (!portal.getOptions().isFixed() && portal.getPortalActivator().isActive() &&
|
||||
portal.getActivePlayer() != player) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if the player can use the private gate
|
||||
if (portal.getOptions().isPrivate() && !PermissionHelper.canUsePrivatePortal(player, portal)) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
|
||||
return;
|
||||
}
|
||||
|
||||
//Destination is currently in use by another player, blocking teleportation
|
||||
if (destination.isOpen() && !destination.getOptions().isAlwaysOn()) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("blockMsg"));
|
||||
return;
|
||||
}
|
||||
|
||||
//Open the portal
|
||||
portal.getPortalOpener().openPortal(player, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a StargateAccessEvent and gets the updated deny value
|
||||
*
|
||||
* <p>The event is used for other plugins to bypass the permission checks.</p>
|
||||
*
|
||||
* @param player <p>The player trying to use the portal</p>
|
||||
* @param portal <p>The portal the player is trying to use</p>
|
||||
* @param deny <p>Whether the player's access has already been denied by a previous check</p>
|
||||
* @return <p>False if the player should be allowed through the portal</p>
|
||||
*/
|
||||
public static boolean portalAccessDenied(Player player, Portal portal, boolean deny) {
|
||||
StargateAccessEvent event = new StargateAccessEvent(player, portal, deny);
|
||||
Stargate.getInstance().getServer().getPluginManager().callEvent(event);
|
||||
return event.getDeny();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given user cannot travel between two portals
|
||||
*
|
||||
* @param player <p>The player to check</p>
|
||||
* @param entrancePortal <p>The portal the user wants to enter</p>
|
||||
* @param destination <p>The portal the user wants to exit from</p>
|
||||
* @return <p>False if the user is allowed to access the portal</p>
|
||||
*/
|
||||
public static boolean cannotAccessPortal(Player player, Portal entrancePortal, Portal destination) {
|
||||
boolean deny = false;
|
||||
|
||||
if (entrancePortal.getOptions().isBungee()) {
|
||||
if (!PermissionHelper.canAccessServer(player, entrancePortal.getNetwork())) {
|
||||
//If the portal is a bungee portal, and the player cannot access the server, deny
|
||||
Stargate.debug("cannotAccessPortal", "Cannot access server");
|
||||
deny = true;
|
||||
}
|
||||
} else if (PermissionHelper.cannotAccessNetwork(player, entrancePortal.getNetwork())) {
|
||||
//If the player does not have access to the network, deny
|
||||
Stargate.debug("cannotAccessPortal", "Cannot access network");
|
||||
deny = true;
|
||||
} else if (PermissionHelper.cannotAccessWorld(player, destination.getWorld().getName())) {
|
||||
//If the player does not have access to the portal's world, deny
|
||||
Stargate.debug("cannotAccessPortal", "Cannot access world");
|
||||
deny = true;
|
||||
}
|
||||
//Allow other plugins to override whether the player can access the portal
|
||||
return portalAccessDenied(player, entrancePortal, deny);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a player has the given permission
|
||||
*
|
||||
* <p>This is the same as player.hasPermission(), but this function allows for printing permission debugging info.</p>
|
||||
*
|
||||
* @param player <p>The player to check</p>
|
||||
* @param permission <p>The permission to check</p>
|
||||
* @return <p>True if the player has the permission</p>
|
||||
*/
|
||||
public static boolean hasPermission(Player player, String permission) {
|
||||
if (Stargate.getStargateConfig().isPermissionDebuggingEnabled()) {
|
||||
Stargate.debug("hasPerm::Permission(" + player.getName() + ")", permission + " => " +
|
||||
player.hasPermission(permission));
|
||||
}
|
||||
return player.hasPermission(permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a player has been given a permission implicitly
|
||||
*
|
||||
* <p>This should be run if a player has a parent permission to check for the child permission. It is assumed the
|
||||
* player has the child permission unless it's explicitly set to false.</p>
|
||||
*
|
||||
* @param player <p>The player to check</p>
|
||||
* @param permission <p>The permission to check</p>
|
||||
* @return <p>True if the player has the permission implicitly or explicitly</p>
|
||||
*/
|
||||
public static boolean hasPermissionImplicit(Player player, String permission) {
|
||||
if (!player.isPermissionSet(permission)) {
|
||||
if (Stargate.getStargateConfig().isPermissionDebuggingEnabled()) {
|
||||
Stargate.debug("hasPermissionImplicit::Permission", permission + " => implicitly true");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (Stargate.getStargateConfig().isPermissionDebuggingEnabled()) {
|
||||
Stargate.debug("hasPermissionImplicit::Permission", permission + " => " +
|
||||
player.hasPermission(permission));
|
||||
}
|
||||
return player.hasPermission(permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a player can access the given world
|
||||
*
|
||||
* @param player <p>The player trying to access the world</p>
|
||||
* @param world <p>The world the player is trying to access</p>
|
||||
* @return <p>False if the player should be allowed to access the world</p>
|
||||
*/
|
||||
public static boolean cannotAccessWorld(Player player, String world) {
|
||||
//The player can access all worlds
|
||||
if (hasPermission(player, "stargate.world")) {
|
||||
//Check if the world permission has been explicitly denied
|
||||
return !hasPermissionImplicit(player, "stargate.world." + world);
|
||||
}
|
||||
//The player can access the destination world
|
||||
return !hasPermission(player, "stargate.world." + world);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a player can access the given network
|
||||
*
|
||||
* @param player <p>The player to check</p>
|
||||
* @param network <p>The network to check</p>
|
||||
* @return <p>True if the player is denied from accessing the network</p>
|
||||
*/
|
||||
public static boolean cannotAccessNetwork(Player player, String network) {
|
||||
//The player can access all networks
|
||||
if (hasPermission(player, "stargate.network")) {
|
||||
//Check if the world permission has been explicitly denied
|
||||
return !hasPermissionImplicit(player, "stargate.network." + network);
|
||||
}
|
||||
//Check if the player can access this network
|
||||
if (hasPermission(player, "stargate.network." + network)) {
|
||||
return false;
|
||||
}
|
||||
//Is able to create personal gates (Assumption is made they can also access them)
|
||||
String playerName = player.getName();
|
||||
if (playerName.length() > 11) {
|
||||
playerName = playerName.substring(0, 11);
|
||||
}
|
||||
return !network.equals(playerName) || !hasPermission(player, "stargate.create.personal");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a player can access the given bungee server
|
||||
*
|
||||
* @param player <p>The player trying to teleport</p>
|
||||
* @param server <p>The server the player is trying to connect to</p>
|
||||
* @return <p>True if the player is allowed to access the given server</p>
|
||||
*/
|
||||
public static boolean canAccessServer(Player player, String server) {
|
||||
//The player can access all servers
|
||||
if (hasPermission(player, "stargate.server")) {
|
||||
//Check if the server permission has been explicitly denied
|
||||
return hasPermissionImplicit(player, "stargate.server." + server);
|
||||
}
|
||||
//The player can access the destination server
|
||||
return hasPermission(player, "stargate.server." + server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given player can teleport the given stretch for free
|
||||
*
|
||||
* @param player <p>The player trying to teleport</p>
|
||||
* @param src <p>The portal the player is entering</p>
|
||||
* @param dest <p>The portal the player wants to teleport to</p>
|
||||
* @return <p>True if the player can travel for free</p>
|
||||
*/
|
||||
public static boolean isFree(Player player, Portal src, Portal dest) {
|
||||
//This portal is free
|
||||
if (src.getOptions().isFree()) {
|
||||
return true;
|
||||
}
|
||||
//Player can use this portal for free
|
||||
if (hasPermission(player, "stargate.free.use")) {
|
||||
return true;
|
||||
}
|
||||
//Don't charge for free destinations unless specified in the config
|
||||
return dest != null && !Stargate.getEconomyConfig().chargeFreeDestination() && dest.getOptions().isFree();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the player can see this gate (Hidden property check)
|
||||
*
|
||||
* <p>This decides if the player can see the gate on the network selection screen</p>
|
||||
*
|
||||
* @param player <p>The player to check</p>
|
||||
* @param portal <p>The portal to check</p>
|
||||
* @return <p>True if the given player can see the given portal</p>
|
||||
*/
|
||||
public static boolean canSeePortal(Player player, Portal portal) {
|
||||
//The portal is not hidden
|
||||
if (!portal.getOptions().isHidden()) {
|
||||
return true;
|
||||
}
|
||||
//The player can see all hidden portals
|
||||
if (hasPermission(player, "stargate.admin.hidden")) {
|
||||
return true;
|
||||
}
|
||||
//The player is the owner of the portal
|
||||
return portal.isOwner(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given player is allowed to use the given private portal
|
||||
*
|
||||
* @param player <p>The player trying to use the portal</p>
|
||||
* @param portal <p>The private portal used</p>
|
||||
* @return <p>True if the player is allowed to use the portal</p>
|
||||
*/
|
||||
public static boolean canUsePrivatePortal(Player player, Portal portal) {
|
||||
//Check if the player is the owner of the gate
|
||||
if (portal.isOwner(player)) {
|
||||
return true;
|
||||
}
|
||||
//The player is an admin with the ability to use private gates
|
||||
return hasPermission(player, "stargate.admin.private");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given player has access to the given portal option
|
||||
*
|
||||
* @param player <p>The player trying to use the option</p>
|
||||
* @param option <p>The option the player is trying to use</p>
|
||||
* @return <p>True if the player is allowed to create a portal with the given option</p>
|
||||
*/
|
||||
public static boolean canUseOption(Player player, PortalOption option) {
|
||||
return hasPermission(player, option.getPermissionString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given player is allowed to create gates on the given network
|
||||
*
|
||||
* @param player <p>The player trying to create a new gate</p>
|
||||
* @param network <p>The network the player is trying to create a gate on</p>
|
||||
* @return <p>True if the player is allowed to create the new gate</p>
|
||||
*/
|
||||
public static boolean canCreateNetworkGate(Player player, String network) {
|
||||
//Check if the player is allowed to create a portal on any network
|
||||
if (hasPermission(player, "stargate.create.network")) {
|
||||
//Check if the network has been explicitly denied
|
||||
return hasPermissionImplicit(player, "stargate.create.network." + network);
|
||||
}
|
||||
//Check if the player is allowed to create on this specific network
|
||||
return hasPermission(player, "stargate.create.network." + network);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given player is allowed to create a personal gate
|
||||
*
|
||||
* @param player <p>The player trying to create the new gate</p>
|
||||
* @return <p>True if the player is allowed</p>
|
||||
*/
|
||||
public static boolean canCreatePersonalPortal(Player player) {
|
||||
return hasPermission(player, "stargate.create.personal");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given player can create a portal with the given gate layout
|
||||
*
|
||||
* @param player <p>The player trying to create a portal</p>
|
||||
* @param gate <p>The gate type of the new portal</p>
|
||||
* @return <p>True if the player is allowed to create a portal with the given gate layout</p>
|
||||
*/
|
||||
public static boolean canCreatePortal(Player player, String gate) {
|
||||
//Check if the player is allowed to create all gates
|
||||
if (hasPermission(player, "stargate.create.gate")) {
|
||||
//Check if the gate type has been explicitly denied
|
||||
return hasPermissionImplicit(player, "stargate.create.gate." + gate);
|
||||
}
|
||||
//Check if the player can create the specific gate type
|
||||
return hasPermission(player, "stargate.create.gate." + gate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given player can destroy the given portal
|
||||
*
|
||||
* @param player <p>The player trying to destroy the portal</p>
|
||||
* @param portal <p>The portal to destroy</p>
|
||||
* @return <p>True if the player is allowed to destroy the portal</p>
|
||||
*/
|
||||
public static boolean canDestroyPortal(Player player, Portal portal) {
|
||||
String network = portal.getNetwork();
|
||||
|
||||
//Use a special check for bungee portals
|
||||
if (portal.getOptions().isBungee()) {
|
||||
return hasPermission(player, "stargate.admin.bungee");
|
||||
}
|
||||
|
||||
//Check if the player is allowed to destroy on all networks
|
||||
if (hasPermission(player, "stargate.destroy.network")) {
|
||||
//Check if the network has been explicitly denied
|
||||
return hasPermissionImplicit(player, "stargate.destroy.network." + network);
|
||||
}
|
||||
//Check if the player is allowed to destroy on the network
|
||||
if (hasPermission(player, "stargate.destroy.network." + network)) {
|
||||
return true;
|
||||
}
|
||||
//Check if personal portal and if the player is allowed to destroy it
|
||||
return portal.isOwner(player) && hasPermission(player, "stargate.destroy.personal");
|
||||
}
|
||||
|
||||
/**
|
||||
* Decide of the player can teleport through a portal
|
||||
*
|
||||
* @param entrancePortal <p>The portal the player is entering from</p>
|
||||
* @param destination <p>The destination of the portal the player is inside</p>
|
||||
* @param player <p>The player wanting to teleport</p>
|
||||
* @param event <p>The move event causing the teleportation</p>
|
||||
* @return <p>True if the player cannot teleport. False otherwise</p>
|
||||
*/
|
||||
public static boolean playerCannotTeleport(Portal entrancePortal, Portal destination, Player player, PlayerMoveEvent event) {
|
||||
//No portal or not open
|
||||
if (entrancePortal == null || !entrancePortal.isOpen()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Not open for this player
|
||||
if (!entrancePortal.getPortalOpener().isOpenFor(player)) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
|
||||
new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event);
|
||||
return true;
|
||||
}
|
||||
|
||||
//No destination
|
||||
if (!entrancePortal.getOptions().isBungee() && destination == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Player cannot access portal
|
||||
if (PermissionHelper.cannotAccessPortal(player, entrancePortal, destination)) {
|
||||
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("denyMsg"));
|
||||
new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event);
|
||||
entrancePortal.getPortalOpener().closePortal(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
//Player cannot pay for teleportation
|
||||
int cost = Stargate.getEconomyConfig().getUseCost(player, entrancePortal, destination);
|
||||
if (cost > 0) {
|
||||
return EconomyHelper.cannotPayTeleportFee(entrancePortal, player, cost);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,260 @@
|
||||
package net.knarcraft.stargate.utility;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.container.BlockLocation;
|
||||
import net.knarcraft.stargate.portal.Gate;
|
||||
import net.knarcraft.stargate.portal.GateHandler;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import net.knarcraft.stargate.portal.PortalHandler;
|
||||
import net.knarcraft.stargate.portal.PortalLocation;
|
||||
import net.knarcraft.stargate.portal.PortalOptions;
|
||||
import net.knarcraft.stargate.portal.PortalOwner;
|
||||
import net.knarcraft.stargate.portal.PortalRegistry;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Scanner;
|
||||
|
||||
import static net.knarcraft.stargate.portal.PortalSignDrawer.markPortalWithInvalidGate;
|
||||
|
||||
/**
|
||||
* Helper class for saving and loading portal save files
|
||||
*/
|
||||
public final class PortalFileHelper {
|
||||
|
||||
private PortalFileHelper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves all portals for the given world
|
||||
*
|
||||
* @param world <p>The world to save portals for</p>
|
||||
*/
|
||||
public static void saveAllPortals(World world) {
|
||||
Stargate.getStargateConfig().addManagedWorld(world.getName());
|
||||
String saveFileLocation = Stargate.getPortalFolder() + "/" + world.getName() + ".db";
|
||||
|
||||
try {
|
||||
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(saveFileLocation, false));
|
||||
|
||||
for (Portal portal : PortalRegistry.getAllPortals()) {
|
||||
//Skip portals in other worlds
|
||||
String worldName = portal.getWorld().getName();
|
||||
if (!worldName.equalsIgnoreCase(world.getName())) {
|
||||
continue;
|
||||
}
|
||||
//Save the portal
|
||||
savePortal(bufferedWriter, portal);
|
||||
}
|
||||
|
||||
bufferedWriter.close();
|
||||
} catch (Exception e) {
|
||||
Stargate.logSevere(String.format("Exception while writing stargates to %s: %s", saveFileLocation, e));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves one portal
|
||||
*
|
||||
* @param bufferedWriter <p>The buffered writer to write to</p>
|
||||
* @param portal <p>The portal to save</p>
|
||||
* @throws IOException <p>If unable to write to the buffered writer</p>
|
||||
*/
|
||||
private static void savePortal(BufferedWriter bufferedWriter, Portal portal) throws IOException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
BlockLocation button = portal.getStructure().getButton();
|
||||
|
||||
//WARNING: Because of the primitive save format, any change in order will break everything!
|
||||
builder.append(portal.getName()).append(':');
|
||||
builder.append(portal.getSignLocation().toString()).append(':');
|
||||
builder.append((button != null) ? button.toString() : "").append(':');
|
||||
|
||||
//Add removes config values to keep indices consistent
|
||||
builder.append(0).append(':');
|
||||
builder.append(0).append(':');
|
||||
|
||||
builder.append(portal.getYaw()).append(':');
|
||||
builder.append(portal.getTopLeft().toString()).append(':');
|
||||
builder.append(portal.getGate().getFilename()).append(':');
|
||||
|
||||
//Only save the destination name if the gate is fixed as it doesn't matter otherwise
|
||||
builder.append(portal.getOptions().isFixed() ? portal.getDestinationName() : "").append(':');
|
||||
|
||||
builder.append(portal.getNetwork()).append(':');
|
||||
|
||||
//Name is saved as a fallback if the UUID is unavailable
|
||||
builder.append(portal.getOwner().getIdentifier());
|
||||
|
||||
//Save all the portal options
|
||||
savePortalOptions(portal, builder);
|
||||
|
||||
bufferedWriter.append(builder.toString());
|
||||
bufferedWriter.newLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves all portal options for the given portal
|
||||
*
|
||||
* @param portal <p>The portal to save</p>
|
||||
* @param builder <p>The string builder to append to</p>
|
||||
*/
|
||||
private static void savePortalOptions(Portal portal, StringBuilder builder) {
|
||||
PortalOptions options = portal.getOptions();
|
||||
builder.append(':');
|
||||
builder.append(options.isHidden()).append(':');
|
||||
builder.append(options.isAlwaysOn()).append(':');
|
||||
builder.append(options.isPrivate()).append(':');
|
||||
builder.append(portal.getWorld().getName()).append(':');
|
||||
builder.append(options.isFree()).append(':');
|
||||
builder.append(options.isBackwards()).append(':');
|
||||
builder.append(options.isShown()).append(':');
|
||||
builder.append(options.isNoNetwork()).append(':');
|
||||
builder.append(options.isRandom()).append(':');
|
||||
builder.append(options.isBungee());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all portals for the given world
|
||||
*
|
||||
* @param world <p>The world to load portals for</p>
|
||||
* @return <p>True if portals could be loaded</p>
|
||||
*/
|
||||
public static boolean loadAllPortals(World world) {
|
||||
String location = Stargate.getPortalFolder();
|
||||
|
||||
File database = new File(location, world.getName() + ".db");
|
||||
|
||||
if (database.exists()) {
|
||||
return loadPortals(world, database);
|
||||
} else {
|
||||
Stargate.logInfo(String.format("{%s} No stargates for world ", world.getName()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all the given portals
|
||||
*
|
||||
* @param world <p>The world to load portals for</p>
|
||||
* @param database <p>The database file containing the portals</p>
|
||||
* @return <p>True if the portals were loaded successfully</p>
|
||||
*/
|
||||
private static boolean loadPortals(World world, File database) {
|
||||
int lineIndex = 0;
|
||||
try {
|
||||
Scanner scanner = new Scanner(database);
|
||||
while (scanner.hasNextLine()) {
|
||||
//Read the line and do whatever needs to be done
|
||||
readPortalLine(scanner, ++lineIndex, world);
|
||||
}
|
||||
scanner.close();
|
||||
|
||||
//Do necessary tasks after all portals have loaded
|
||||
doPostLoadTasks(world);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Stargate.logSevere(String.format("Exception while reading stargates from %s: %d", database.getName(),
|
||||
lineIndex));
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads one file line containing information about one portal
|
||||
*
|
||||
* @param scanner <p>The scanner to read</p>
|
||||
* @param lineIndex <p>The index of the read line</p>
|
||||
* @param world <p>The world for which portals are currently being read</p>
|
||||
*/
|
||||
private static void readPortalLine(Scanner scanner, int lineIndex, World world) {
|
||||
String line = scanner.nextLine().trim();
|
||||
|
||||
//Ignore empty and comment lines
|
||||
if (line.startsWith("#") || line.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if the min. required portal data is present
|
||||
String[] portalData = line.split(":");
|
||||
if (portalData.length < 8) {
|
||||
Stargate.logInfo(String.format("Invalid line - %s", lineIndex));
|
||||
return;
|
||||
}
|
||||
|
||||
//Load the portal defined in the current line
|
||||
loadPortal(portalData, world, lineIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs tasks which must be run after portals have loaded
|
||||
*
|
||||
* <p>This will open always on portals, print info about loaded stargates and re-draw portal signs for loaded
|
||||
* portals.</p>
|
||||
*
|
||||
* @param world <p>The world portals have been loaded for</p>
|
||||
*/
|
||||
private static void doPostLoadTasks(World world) {
|
||||
//Open any always-on portals. Do this here as it should be more efficient than in the loop.
|
||||
PortalHandler.verifyAllPortals();
|
||||
int portalCount = PortalRegistry.getAllPortals().size();
|
||||
int openCount = PortalHandler.openAlwaysOpenPortals();
|
||||
|
||||
//Print info about loaded stargates so that admins can see if all stargates loaded
|
||||
Stargate.logInfo(String.format("{%s} Loaded %d stargates with %d set as always-on", world.getName(),
|
||||
portalCount, openCount));
|
||||
|
||||
//Re-draw the signs in case a bug in the config prevented the portal from loading and has been fixed since
|
||||
for (Portal portal : PortalRegistry.getAllPortals()) {
|
||||
portal.drawSign();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads one portal from a data array
|
||||
*
|
||||
* @param portalData <p>The array describing the portal</p>
|
||||
* @param world <p>The world to create the portal in</p>
|
||||
* @param lineIndex <p>The line index to report in case the user needs to fix an error</p>
|
||||
*/
|
||||
private static void loadPortal(String[] portalData, World world, int lineIndex) {
|
||||
//Load min. required portal data
|
||||
String name = portalData[0];
|
||||
BlockLocation button = (portalData[2].length() > 0) ? new BlockLocation(world, portalData[2]) : null;
|
||||
|
||||
//Load the portal's location
|
||||
PortalLocation portalLocation = new PortalLocation();
|
||||
portalLocation.setSignLocation(new BlockLocation(world, portalData[1]));
|
||||
portalLocation.setYaw(Float.parseFloat(portalData[5]));
|
||||
portalLocation.setTopLeft(new BlockLocation(world, portalData[6]));
|
||||
|
||||
//Check if the portal's gate type exists and is loaded
|
||||
Gate gate = GateHandler.getGateByName(portalData[7]);
|
||||
if (gate == null) {
|
||||
//Mark the sign as invalid to reduce some player confusion
|
||||
markPortalWithInvalidGate(portalLocation, portalData[7], lineIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
//Load extra portal data
|
||||
String destination = (portalData.length > 8) ? portalData[8] : "";
|
||||
String network = (portalData.length > 9 && !portalData[9].isEmpty()) ? portalData[9] : Stargate.getDefaultNetwork();
|
||||
String ownerString = (portalData.length > 10) ? portalData[10] : "";
|
||||
|
||||
//Get the owner from the owner string
|
||||
PortalOwner owner = new PortalOwner(ownerString);
|
||||
|
||||
//Create the new portal
|
||||
Portal portal = new Portal(portalLocation, button, destination, name, network, gate, owner,
|
||||
PortalHandler.getPortalOptions(portalData));
|
||||
|
||||
//Register the portal, and close it in case it wasn't properly closed when the server stopped
|
||||
PortalHandler.registerPortal(portal);
|
||||
portal.getPortalOpener().closePortal(true);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package net.knarcraft.stargate.utility;
|
||||
|
||||
import net.knarcraft.stargate.Stargate;
|
||||
import net.knarcraft.stargate.portal.Portal;
|
||||
import net.knarcraft.stargate.portal.PortalHandler;
|
||||
import net.knarcraft.stargate.portal.PortalOwner;
|
||||
import net.knarcraft.stargate.portal.PortalRegistry;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Helps migrate player names to UUID where necessary
|
||||
*/
|
||||
public class UUIDMigrationHelper {
|
||||
|
||||
private static Map<String, List<Portal>> playerNamesToMigrate;
|
||||
|
||||
/**
|
||||
* Migrates the player's name to a UUID
|
||||
*
|
||||
* <p>If any portals are missing a UUID for their owner, and the given player is the owner of those portals, the
|
||||
* given player's UUID will be used as UUID for the portals' owner.</p>
|
||||
*
|
||||
* @param player <p>The player to migrate</p>
|
||||
*/
|
||||
public static void migrateUUID(OfflinePlayer player) {
|
||||
Map<String, List<Portal>> playersToMigrate = getPlayersToMigrate();
|
||||
String playerName = player.getName();
|
||||
|
||||
//Nothing to do
|
||||
if (!playersToMigrate.containsKey(playerName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Stargate.debug("PlayerEventListener::migrateUUID", String.format("Migrating name to UUID for player %s",
|
||||
playerName));
|
||||
List<Portal> portalsOwned = playersToMigrate.get(playerName);
|
||||
if (portalsOwned == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
migratePortalsToUUID(portalsOwned, player.getUniqueId());
|
||||
|
||||
//Remove the player to prevent the migration to happen every time the player joins
|
||||
playersToMigrate.remove(playerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrates a list of portals to use UUID instead of only player name
|
||||
*
|
||||
* @param portals <p>The portals to migrate</p>
|
||||
* @param uniqueId <p>The unique ID of the portals' owner</p>
|
||||
*/
|
||||
private static void migratePortalsToUUID(List<Portal> portals, UUID uniqueId) {
|
||||
Set<World> worldsToSave = new HashSet<>();
|
||||
|
||||
//Get the real portal from the copy and set UUID
|
||||
for (Portal portalCopy : portals) {
|
||||
Portal portal = PortalHandler.getByName(portalCopy.getName(), portalCopy.getNetwork());
|
||||
if (portal != null) {
|
||||
portal.getOwner().setUUID(uniqueId);
|
||||
worldsToSave.add(portal.getWorld());
|
||||
}
|
||||
}
|
||||
|
||||
//Need to make sure the changes are saved
|
||||
for (World world : worldsToSave) {
|
||||
PortalFileHelper.saveAllPortals(world);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all player names which need to be migrated to UUIDs
|
||||
*
|
||||
* @return <p>The player names to migrate</p>
|
||||
*/
|
||||
private static Map<String, List<Portal>> getPlayersToMigrate() {
|
||||
//Make sure to only go through portals once
|
||||
if (playerNamesToMigrate != null) {
|
||||
return playerNamesToMigrate;
|
||||
}
|
||||
|
||||
playerNamesToMigrate = new HashMap<>();
|
||||
for (Portal portal : PortalRegistry.getAllPortals()) {
|
||||
PortalOwner owner = portal.getOwner();
|
||||
String ownerName = owner.getName();
|
||||
|
||||
//If a UUID is missing, add the portal to the list owned by the player
|
||||
if (owner.getUUID() == null) {
|
||||
List<Portal> portalList = playerNamesToMigrate.get(ownerName);
|
||||
if (portalList == null) {
|
||||
List<Portal> newList = new ArrayList<>();
|
||||
newList.add(portal);
|
||||
playerNamesToMigrate.put(ownerName, newList);
|
||||
} else {
|
||||
portalList.add(portal);
|
||||
}
|
||||
}
|
||||
}
|
||||
return playerNamesToMigrate;
|
||||
}
|
||||
|
||||
}
|
27
src/main/resources/config-migrations.txt
Normal file
27
src/main/resources/config-migrations.txt
Normal file
@ -0,0 +1,27 @@
|
||||
lang=language
|
||||
portal-folder=folders.portalFolder
|
||||
gate-folder=folders.gateFolder
|
||||
default-gate-network=gates.defaultGateNetwork
|
||||
destroyexplosion=gates.integrity.destroyedByExplosion
|
||||
maxgates=gates.maxGatesEachNetwork
|
||||
destMemory=gates.cosmetic.rememberDestination
|
||||
ignoreEntrance=
|
||||
gates.integrity.ignoreEntrance=
|
||||
handleVehicles=gates.functionality.handleVehicles
|
||||
sortLists=gates.cosmetic.sortNetworkDestinations
|
||||
protectEntrance=gates.integrity.protectEntrance
|
||||
enableBungee=gates.functionality.enableBungee
|
||||
verifyPortals=gates.integrity.verifyPortals
|
||||
signColor=gates.cosmetic.signColor
|
||||
gates.cosmetic.signColor=gates.cosmetic.mainSignColor
|
||||
debug=debugging.debug
|
||||
permdebug=debugging.permissionDebug
|
||||
useiconomy=economy.useEconomy
|
||||
useeconomy=economy.useEconomy
|
||||
createcost=economy.createCost
|
||||
destroycost=economy.destroyCost
|
||||
usecost=economy.useCost
|
||||
toowner=economy.toOwner
|
||||
chargefreedestination=economy.chargeFreeDestination
|
||||
freegatesgreen=economy.freeGatesGreen
|
||||
CheckUpdates=
|
70
src/main/resources/config.yml
Normal file
70
src/main/resources/config.yml
Normal file
@ -0,0 +1,70 @@
|
||||
# stargate Configuration File
|
||||
# Main stargate config
|
||||
# I----------I----------I #
|
||||
# portalFolder - The folder for storing portals
|
||||
# gateFolder - The folder for storing gate layouts
|
||||
# defaultGateNetwork - The default gate network
|
||||
# destroyedByExplosion - Whether to destroy gates with explosions (Creeper, TNT, etc.)
|
||||
# maxGatesEachNetwork - The maximum number of gates allowed on a network - 0 for unlimited
|
||||
# language - The language file to load for messages
|
||||
# rememberDestination - Whether to remember the cursor location between uses
|
||||
# handleVehicles - Whether to allow vehicles through gates. This overrides other vehicle settings
|
||||
# handleEmptyVehicles - Whether to allow empty vehicles through gates (chest/hopper/tnt/furnace minecarts included)
|
||||
# handleCreatureTransportation - Whether to allow players to transport creatures by sending vehicles (minecarts, boats) through gates
|
||||
# handleNonPlayerVehicles - Whether to allow vehicles with a passenger which is not a player through gates. handleCreatureTransportation must be enabled
|
||||
# handleLeashedCreatures - Whether to allow creatures lead by a player to teleport with the player
|
||||
# sortNetworkDestinations - Whether to sort network lists alphabetically
|
||||
# protectEntrance - Whether to protect gate entrance material (More resource intensive. Only enable if using destroyable open/closed material)
|
||||
# mainSignColor - The color used for drawing signs (Default: BLACK).
|
||||
# highlightSignColor - The color used for sign markings (Default: WHITE)
|
||||
# verifyPortals - Whether all the non-sign blocks are checked to match the gate layout when a stargate is loaded.
|
||||
# I------------I-------------I #
|
||||
# stargate economy options #
|
||||
# I------------I-------------I #
|
||||
# useEconomy - Whether to use an economy plugin
|
||||
# createCost - The cost to create a gate
|
||||
# destroyCost - The cost to destroy a gate
|
||||
# useCost - The cost to use a gate
|
||||
# toOwner - Whether the charge for using a gate goes to the gate's owner
|
||||
# chargeFreeDestination - Whether a gate whose destination is a free gate is still charged
|
||||
# freeGatesGreen - Whether a free gate in the destination list is drawn green
|
||||
# I-------I-------I #
|
||||
# Debug options #
|
||||
# I-------I-------I #
|
||||
# debug - Debug -- Only enable if you have issues, massive console output
|
||||
# permissionDebug - This will output any and all Permissions checks to console, used for permissions debugging (Requires debug: true)
|
||||
|
||||
language: en
|
||||
folders:
|
||||
portalFolder: plugins/Stargate/portals/
|
||||
gateFolder: plugins/Stargate/gates/
|
||||
gates:
|
||||
maxGatesEachNetwork: 0
|
||||
defaultGateNetwork: central
|
||||
cosmetic:
|
||||
rememberDestination: false
|
||||
sortNetworkDestinations: false
|
||||
mainSignColor: BLACK
|
||||
highlightSignColor: WHITE
|
||||
integrity:
|
||||
destroyedByExplosion: false
|
||||
verifyPortals: false
|
||||
protectEntrance: false
|
||||
functionality:
|
||||
enableBungee: false
|
||||
handleVehicles: true
|
||||
handleEmptyVehicles: true
|
||||
handleCreatureTransportation: true
|
||||
handleNonPlayerVehicles: true
|
||||
handleLeashedCreatures: true
|
||||
economy:
|
||||
useEconomy: false
|
||||
createCost: 0
|
||||
destroyCost: 0
|
||||
useCost: 0
|
||||
toOwner: false
|
||||
chargeFreeDestination: true
|
||||
freeGatesGreen: false
|
||||
debugging:
|
||||
debug: false
|
||||
permissionDebug: false
|
12
src/main/resources/gates/endgate.gate
Normal file
12
src/main/resources/gates/endgate.gate
Normal file
@ -0,0 +1,12 @@
|
||||
portal-open=END_GATEWAY
|
||||
portal-closed=AIR
|
||||
button=BIRCH_BUTTON
|
||||
toowner=false
|
||||
X=END_STONE_BRICKS
|
||||
-=END_STONE_BRICKS
|
||||
|
||||
XX
|
||||
X..X
|
||||
-..-
|
||||
X*.X
|
||||
XX
|
24
src/main/resources/gates/nethergate.gate
Normal file
24
src/main/resources/gates/nethergate.gate
Normal file
@ -0,0 +1,24 @@
|
||||
#This is the default gate type. You can copy this and make as many .gate files as you need.
|
||||
#The portal-open block can be most blocks which do not fill the entire block or otherwise prevent the player from
|
||||
#entering the portal, but NETHER_PORTAL, AIR, WATER, LAVA, KELP_PLANT, OAK_FENCE, IRON_BARS, CHAIN, BAMBOO, SUGAR_CANE,
|
||||
#COBWEB and VINE gives an impression of which blocks will work.
|
||||
portal-open=NETHER_PORTAL
|
||||
#The portal-closed block can be any of the blocks used for portal-open, but also any solid, full-size block such as DIRT.
|
||||
portal-closed=AIR
|
||||
#The button can be the following: A chest (CHEST), any type of button (STONE_BUTTON, OAK_BUTTON), any type of shulker
|
||||
#box (LIME_SHULKER_BOX), or any wall coral (DEAD_TUBE_CORAL_WALL_FAN, TUBE_CORAL_WALL_FAN, DEAD_BRAIN_CORAL_WALL_FAN,
|
||||
#BRAIN_CORAL_WALL_FAN, etc.)
|
||||
button=STONE_BUTTON
|
||||
#Whether payment for entry should go to this gate's owner
|
||||
toowner=false
|
||||
#The material to use for the normal frame
|
||||
X=OBSIDIAN
|
||||
#The material to use for the sign and button blocks of the frame
|
||||
-=OBSIDIAN
|
||||
#The description of the required portal blocks. X = Frame block. - = Sign/button position. . = Empty blocks. * = Exit
|
||||
|
||||
XX
|
||||
X..X
|
||||
-..-
|
||||
X*.X
|
||||
XX
|
12
src/main/resources/gates/watergate.gate
Normal file
12
src/main/resources/gates/watergate.gate
Normal file
@ -0,0 +1,12 @@
|
||||
portal-open=KELP_PLANT
|
||||
portal-closed=WATER
|
||||
button=BRAIN_CORAL_WALL_FAN
|
||||
toowner=false
|
||||
X=SEA_LANTERN
|
||||
-=SEA_LANTERN
|
||||
|
||||
XX
|
||||
X..X
|
||||
-..-
|
||||
X*.X
|
||||
XX
|
@ -1,28 +1,28 @@
|
||||
author=EduardBaer
|
||||
prefix=[Stargate]
|
||||
teleportMsg=Du wurdest Teleportiert.
|
||||
destroyMsg=Gate zerstört
|
||||
invalidMsg=Ungültiges Ziel
|
||||
blockMsg=Ziel blockiert
|
||||
destEmpty=Zielliste leer
|
||||
denyMsg=Zugriff verweigert
|
||||
|
||||
ecoDeduct=%cost% abgezogen
|
||||
ecoRefund=%cost% zurückerstattet
|
||||
ecoObtain=%cost% von Stargate %portal% erhalten
|
||||
ecoInFunds=Das kannst du dir nicht leisten.
|
||||
|
||||
createMsg=Gate erstellt.
|
||||
createNetDeny=Du hast keinen Zugriff auf dieses Netzwerk.
|
||||
createGateDeny=Du hast keinen Zugriff auf dieses Gate-Layout.
|
||||
createPersonal=Gate im persönlichen Netzwerk erstellt.
|
||||
createNameLength=Name zu kurz oder zu lang.
|
||||
createExists=Ein Gate mit diesem Name existiert bereits.
|
||||
createFull=Dieses Netzwerk ist voll.
|
||||
createWorldDeny=Du hast keinen Zugriff auf diese Welt.
|
||||
createConflict=Dieses Gate steht im Konflikt mit einem bereits existierenden.
|
||||
|
||||
signRightClick=Right click
|
||||
signToUse=to use gate
|
||||
signRandom=Random
|
||||
author=EduardBaer
|
||||
prefix=[Stargate]
|
||||
teleportMsg=Du wurdest Teleportiert.
|
||||
destroyMsg=Gate zerstört
|
||||
invalidMsg=Ungültiges Ziel
|
||||
blockMsg=Ziel blockiert
|
||||
destEmpty=Zielliste leer
|
||||
denyMsg=Zugriff verweigert
|
||||
|
||||
ecoDeduct=%cost% abgezogen
|
||||
ecoRefund=%cost% zurückerstattet
|
||||
ecoObtain=%cost% von Stargate %portal% erhalten
|
||||
ecoInFunds=Das kannst du dir nicht leisten.
|
||||
|
||||
createMsg=Gate erstellt.
|
||||
createNetDeny=Du hast keinen Zugriff auf dieses Netzwerk.
|
||||
createGateDeny=Du hast keinen Zugriff auf dieses Gate-Layout.
|
||||
createPersonal=Gate im persönlichen Netzwerk erstellt.
|
||||
createNameLength=Name zu kurz oder zu lang.
|
||||
createExists=Ein Gate mit diesem Name existiert bereits.
|
||||
createFull=Dieses Netzwerk ist voll.
|
||||
createWorldDeny=Du hast keinen Zugriff auf diese Welt.
|
||||
createConflict=Dieses Gate steht im Konflikt mit einem bereits existierenden.
|
||||
|
||||
signRightClick=Right click
|
||||
signToUse=to use gate
|
||||
signRandom=Random
|
||||
signDisconnected=Disconnected
|
@ -1,32 +1,37 @@
|
||||
prefix=[Stargate]
|
||||
teleportMsg=Teleported
|
||||
destroyMsg=Gate Destroyed
|
||||
invalidMsg=Invalid Destination
|
||||
blockMsg=Destination Blocked
|
||||
destEmpty=Destination List Empty
|
||||
denyMsg=Access Denied
|
||||
|
||||
ecoDeduct=Deducted %cost%
|
||||
ecoRefund=Refunded %cost%
|
||||
ecoObtain=Obtained %cost% from Stargate %portal%
|
||||
ecoInFunds=Insufficient Funds
|
||||
|
||||
createMsg=Gate Created
|
||||
createNetDeny=You do not have access to that network
|
||||
createGateDeny=You do not have access to that gate layout
|
||||
createPersonal=Creating gate on personal network
|
||||
createNameLength=Name too short or too long.
|
||||
createExists=A gate by that name already exists
|
||||
createFull=This network is full
|
||||
createWorldDeny=You do not have access to that world
|
||||
createConflict=Gate conflicts with existing gate
|
||||
|
||||
signRightClick=Right click
|
||||
signToUse=to use gate
|
||||
signRandom=Random
|
||||
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
|
||||
prefix=[Stargate]
|
||||
teleportMsg=Teleported
|
||||
destroyMsg=Gate Destroyed
|
||||
invalidMsg=Invalid Destination
|
||||
blockMsg=Destination Blocked
|
||||
destEmpty=Destination List Empty
|
||||
denyMsg=Access Denied
|
||||
reloaded=Stargate Reloaded
|
||||
|
||||
ecoDeduct=Deducted %cost%
|
||||
ecoRefund=Refunded %cost%
|
||||
ecoObtain=Obtained %cost% from Stargate %portal%
|
||||
ecoInFunds=Insufficient Funds
|
||||
ecoLoadError=Vault was loaded, but no economy plugin could be hooked into
|
||||
vaultLoadError=Economy is enabled but Vault could not be loaded. Economy disabled
|
||||
vaultLoaded=Vault v%version% found
|
||||
|
||||
createMsg=Gate Created
|
||||
createNetDeny=You do not have access to that network
|
||||
createGateDeny=You do not have access to that gate layout
|
||||
createPersonal=Creating gate on personal network
|
||||
createNameLength=Name too short or too long.
|
||||
createExists=A gate by that name already exists
|
||||
createFull=This network is full
|
||||
createWorldDeny=You do not have access to that world
|
||||
createConflict=Gate conflicts with existing gate
|
||||
|
||||
signRightClick=Right click
|
||||
signToUse=to use gate
|
||||
signRandom=Random
|
||||
signDisconnected=Disconnected
|
||||
signInvalidGate=Invalid gate
|
||||
|
||||
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
|
@ -1,10 +1,10 @@
|
||||
author=Manuestaire
|
||||
prefix=[Stargate]
|
||||
teleportMsg=Teletransportado
|
||||
destroyMsg=Portal Destruído
|
||||
destroyMsg=Portal Destruído
|
||||
invalidMsg=Elige Destino
|
||||
blockMsg=Destino Bloqueado
|
||||
destEmpty=La lista de destinos está vacía
|
||||
destEmpty=La lista de destinos está vacía
|
||||
denyMsg=Acceso denegado
|
||||
|
||||
ecoDeduct=Pagaste %cost%
|
||||
@ -14,11 +14,11 @@ ecoInFunds=No tienes suficiente dinero
|
||||
|
||||
createMsg=Portal creado
|
||||
createNetDeny=No tienes acceso a esta red
|
||||
createGateDeny=No tienes acceso a este diseño de portal
|
||||
createGateDeny=No tienes acceso a este diseño de portal
|
||||
createPersonal=Creando el portal en una red personal
|
||||
createNameLength=Nombre demasiado largo o demasiado corto
|
||||
createExists=Ya existe una puerta con este nombre
|
||||
createFull=Esta red está llena
|
||||
createFull=Esta red está llena
|
||||
createWorldDeny=No tienes permisos para acceder a ese mundo
|
||||
createConflict=El portal entra en conflicto con un portal ya existente
|
||||
|
@ -1,4 +1,4 @@
|
||||
author=Dauphin14
|
||||
author=Dauphin14
|
||||
prefix=[Stargate]
|
||||
teleportMsg=Téléportation Réussie.
|
||||
destroyMsg=Portail detruit.
|
37
src/main/resources/lang/nb-no.txt
Normal file
37
src/main/resources/lang/nb-no.txt
Normal file
@ -0,0 +1,37 @@
|
||||
author=EpicKnarvik97
|
||||
prefix=[Stjerneport]
|
||||
teleportMsg=Teleporterte
|
||||
destroyMsg=Port Ødelagt
|
||||
invalidMsg=Ugyldig Destinasjon
|
||||
blockMsg=Destinasjon Blokkert
|
||||
destEmpty=Destinasjonslisten Er Tom
|
||||
denyMsg=Tilgang Avslått
|
||||
reloaded=Stjerneport Ble Lastet Inn På Nytt
|
||||
|
||||
ecoDeduct=Fratrekk %cost%
|
||||
ecoRefund=Refundert %cost%
|
||||
ecoObtain=Fikk %cost% fra Stjerneport %portal%
|
||||
ecoInFunds=Manglende Midler
|
||||
ecoLoadError=Vault ble lastet inn men ingen brukbar økonomi-utvidelse ble funnet
|
||||
vaultLoadError=Økonomi er skrudd på, men Vault kunne ikke lastes inn. Økonomi er skrudd av
|
||||
vaultLoaded=Vault v%version% funnet
|
||||
|
||||
createMsg=Port opprettet
|
||||
createNetDeny=Du har ikke tilgang til det nettverket
|
||||
createGateDeny=Du har ikke tilgang til den portutformingen
|
||||
createPersonal=Oppretter port på personlig nettverk
|
||||
createNameLength=Navnet er for kort eller for langt.
|
||||
createExists=En port ved det navnet eksisterer allerede
|
||||
createFull=Dette nettverket er fullt
|
||||
createWorldDeny=Du har ikke tilgang til den verdenen
|
||||
createConflict=Port er i konflikt med en eksisterende port
|
||||
|
||||
signRightClick=Høyreklikk
|
||||
signToUse=for å bruke port
|
||||
signRandom=Tilfeldig
|
||||
signDisconnected=Koblet fra
|
||||
|
||||
bungeeDisabled=BungeeCord støtte er slått av.
|
||||
bungeeDeny=Du har ikke tillatelse til å opprette BungeeCord porter.
|
||||
bungeeEmpty=BungeeCord porter behøver bade en destinasjon og et nettverk.
|
||||
bungeeSign=Teleporter til
|
@ -16,7 +16,7 @@ createMsg=Gate gemaakt
|
||||
createNetDeny=Je hebt geen toegang tot dat netwerk.
|
||||
createGateDeny=Je mag die Gate-Layout niet gebruiken
|
||||
createPersonal=Gate op persoonlijk netwerk gemaakt.
|
||||
createNameLength=Naam te lang of te kort.
|
||||
createNameLength=Naam te chosenLanguage of te kort.
|
||||
createExists=Er bestaat al een gate met die naam
|
||||
createFull=Dit netwerk is vol.
|
||||
createWorldDeny=Je mag niet in die wereld komen.
|
37
src/main/resources/lang/nn-no.txt
Normal file
37
src/main/resources/lang/nn-no.txt
Normal file
@ -0,0 +1,37 @@
|
||||
author=EpicKnarvik97
|
||||
prefix=[Stjerneport]
|
||||
teleportMsg=Teleporterte
|
||||
destroyMsg=Port Øydelagd
|
||||
invalidMsg=Ugyldig Destinasjon
|
||||
blockMsg=Destinasjon Blokkert
|
||||
destEmpty=Destinasjonslista Er Tom
|
||||
denyMsg=Tilgang Avslått
|
||||
reloaded=Stjerneport Vart Lasta Inn På Nytt
|
||||
|
||||
ecoDeduct=Fråtrekk %cost%
|
||||
ecoRefund=Refundert %cost%
|
||||
ecoObtain=Mottok %cost% frå Stjerneport %portal%
|
||||
ecoInFunds=Manglande Midlar
|
||||
ecoLoadError=Vault vart lasta inn men inga brukbar økonomi-utviding vart funnen
|
||||
vaultLoadError=Økonomi er skrudd på, men Vault kunne ikkje lastas inn. Økonomi er skrudd av
|
||||
vaultLoaded=Vault v%version% funnen
|
||||
|
||||
createMsg=Port oppretta
|
||||
createNetDeny=Du har ikkje tilgang til det nettverket
|
||||
createGateDeny=Du har ikkje tilgang til den portutforminga
|
||||
createPersonal=Opprettar port på personleg nettverk
|
||||
createNameLength=Namnet er for kort eller for langt.
|
||||
createExists=Ein port med det namnet eksisterar allereie
|
||||
createFull=Dette nettverket er fullt
|
||||
createWorldDeny=Du har ikkje tilgang til den verda
|
||||
createConflict=Port er i konflikt med ein eksisterande port
|
||||
|
||||
signRightClick=Høgreklikk
|
||||
signToUse=for å bruke port
|
||||
signRandom=Tilfeldig
|
||||
signDisconnected=Kopla frå
|
||||
|
||||
bungeeDisabled=BungeeCord støtte er slått av.
|
||||
bungeeDeny=Du har ikkje løyve til å opprette BungeeCord portar.
|
||||
bungeeEmpty=BungeeCord portar treng bade ein destinasjon og eit nettverk.
|
||||
bungeeSign=Teleporter til
|
@ -17,7 +17,7 @@ createNetDeny=Voce nao tem acesso a essa rede.
|
||||
createGateDeny=Voce nao tem acesso a esse portal layout.
|
||||
createPersonal=Criando portal em rede pessoal.
|
||||
createNameLength=Nome muito curto ou muito grande.
|
||||
createExists=Já existe um portal com esse nome.
|
||||
createExists=Já existe um portal com esse nome.
|
||||
createFull=Esta rede esta cheia.
|
||||
createWorldDeny=Voce nao tem acesso a esse mundo.
|
||||
createConflict=Portal em conflito com um portal ja existente.
|
@ -1,4 +1,4 @@
|
||||
author=ckr@jk
|
||||
author=ckr@jk
|
||||
prefix=[Портал]
|
||||
teleportMsg=Вы перемещены
|
||||
destroyMsg=Портал уничтожен
|
143
src/main/resources/plugin.yml
Normal file
143
src/main/resources/plugin.yml
Normal file
@ -0,0 +1,143 @@
|
||||
name: Stargate
|
||||
main: net.knarcraft.stargate.Stargate
|
||||
version: 0.9.0.5
|
||||
description: Stargate mod for Bukkit Revived
|
||||
author: EpicKnarvik97
|
||||
authors: [ Drakia, PseudoKnight, EpicKnarvik97 ]
|
||||
website: https://git.knarcraft.net/EpicKnarvik97/Stargate
|
||||
api-version: 1.17
|
||||
softdepend: [ Vault ]
|
||||
commands:
|
||||
stargate:
|
||||
aliases:
|
||||
- sg
|
||||
description: Used to see stargate info
|
||||
usage: /<command> <reload/about> - Used to see stargate info or reload the plugin
|
||||
permissions:
|
||||
stargate.*:
|
||||
description: Wildcard permission which gives all Stargate permissions
|
||||
default: false
|
||||
children:
|
||||
stargate.admin: true
|
||||
stargate.use: true
|
||||
stargate.create: true
|
||||
stargate.destroy: true
|
||||
stargate.free: true
|
||||
stargate.option: true
|
||||
stargate.server: true
|
||||
stargate.reload:
|
||||
description: Allows reloading the plugin
|
||||
default: false
|
||||
stargate.use:
|
||||
description: Allow use of all stargates linking to any world in any network
|
||||
default: true
|
||||
children:
|
||||
stargate.world: true
|
||||
stargate.network: true
|
||||
stargate.server: true
|
||||
stargate.world:
|
||||
description: Allow use of stargates in any world
|
||||
default: false
|
||||
stargate.network:
|
||||
description: Allows use of stargates in any network
|
||||
default: false
|
||||
stargate.create:
|
||||
description: Allow creating stargates on any network using any gate type
|
||||
default: op
|
||||
children:
|
||||
stargate.create.personal: true
|
||||
stargate.create.network: true
|
||||
stargate.create.gate: true
|
||||
stargate.create.personal:
|
||||
description: Allows the creation of a personal stargate if a player is missing permission for the given network
|
||||
default: false
|
||||
stargate.create.network:
|
||||
description: Allows the creation of a stargate on any network
|
||||
default: false
|
||||
stargate.create.gate:
|
||||
description: Allows the creation of a stargate using any gate type
|
||||
default: false
|
||||
stargate.destroy:
|
||||
description: Allows the destruction of all stargates
|
||||
default: op
|
||||
children:
|
||||
stargate.destroy.network: true
|
||||
stargate.destroy.personal: true
|
||||
stargate.destroy.network:
|
||||
description: Allows the destruction of stargates on any network
|
||||
default: false
|
||||
stargate.destroy.personal:
|
||||
description: Allows the destruction of any personal stargates the player has created
|
||||
default: false
|
||||
stargate.free:
|
||||
description: Allow free use/creation/destruction of stargates
|
||||
default: op
|
||||
children:
|
||||
stargate.free.use: true
|
||||
stargate.free.create: true
|
||||
stargate.free.destroy: true
|
||||
stargate.free.use:
|
||||
description: Allows free usage of all stargates
|
||||
default: false
|
||||
stargate.free.create:
|
||||
description: Allows creating stargates for free
|
||||
default: false
|
||||
stargate.free.destroy:
|
||||
description: Allows destroying stargates for free
|
||||
default: false
|
||||
stargate.option:
|
||||
description: Allows use of all options
|
||||
default: op
|
||||
children:
|
||||
stargate.option.hidden: true
|
||||
stargate.option.alwayson: true
|
||||
stargate.option.private: true
|
||||
stargate.option.free: true
|
||||
stargate.option.backwards: true
|
||||
stargate.option.show: true
|
||||
stargate.option.nonetwork: true
|
||||
stargate.option.random: true
|
||||
stargate.option.hidden:
|
||||
description: Allows the creation of a hidden stargate
|
||||
default: false
|
||||
stargate.option.alwayson:
|
||||
description: Allows the creation of an always open stargate
|
||||
default: false
|
||||
stargate.option.private:
|
||||
description: Allows the creation of a private stargate
|
||||
default: false
|
||||
stargate.option.free:
|
||||
description: Allows the creation of a stargate which is free regardless of any set prices
|
||||
default: false
|
||||
stargate.option.backwards:
|
||||
description: Allows the creation of a stargate where players will exit through the back
|
||||
default: false
|
||||
stargate.option.show:
|
||||
description: Allows the creation of a stargate which is shown on the network, even if always on
|
||||
default: false
|
||||
stargate.option.nonetwork:
|
||||
description: Allows the creation of a stargate with a hidden network name
|
||||
default: false
|
||||
stargate.option.random:
|
||||
description: Allows the creation of a stargate with a random destination
|
||||
default: false
|
||||
stargate.admin.hidden:
|
||||
description: Allows this player to see all hidden stargates
|
||||
default: false
|
||||
stargate.admin.private:
|
||||
description: Allows this player to use all private stargates
|
||||
default: false
|
||||
stargate.admin.bungee:
|
||||
description: Allows the creation and destruction of a stargate between BungeeCord servers
|
||||
default: false
|
||||
stargate.server:
|
||||
description: Allows the creation of a BungeeCord stargate going to any server
|
||||
default: false
|
||||
stargate.admin:
|
||||
description: Allow all admin features and commands (Hidden/Private bypass, BungeeCord, Reload)
|
||||
default: op
|
||||
children:
|
||||
stargate.admin.reload: true
|
||||
stargate.admin.hidden: true
|
||||
stargate.admin.private: true
|
||||
stargate.admin.bungee: true
|
@ -1,173 +0,0 @@
|
||||
package net.TheDgtl.Stargate;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Sign;
|
||||
import org.bukkit.block.data.type.WallSign;
|
||||
|
||||
/**
|
||||
* Stargate - A portal plugin for Bukkit
|
||||
* Copyright (C) 2011 Shaun (sturmeh)
|
||||
* Copyright (C) 2011 Dinnerbone
|
||||
* Copyright (C) 2011, 2012 Steven "Drakia" Scott <Contact@TheDgtl.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class Blox {
|
||||
private final int x;
|
||||
private final int y;
|
||||
private final int z;
|
||||
private final World world;
|
||||
private Blox parent = null;
|
||||
|
||||
public Blox (World world, int x, int y, int z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public Blox (Block block) {
|
||||
this.x = block.getX();
|
||||
this.y = block.getY();
|
||||
this.z = block.getZ();
|
||||
this.world = block.getWorld();
|
||||
}
|
||||
|
||||
public Blox (Location location) {
|
||||
this.x = location.getBlockX();
|
||||
this.y = location.getBlockY();
|
||||
this.z = location.getBlockZ();
|
||||
this.world = location.getWorld();
|
||||
}
|
||||
|
||||
public Blox (World world, String string) {
|
||||
String[] split = string.split(",");
|
||||
this.x = Integer.parseInt(split[0]);
|
||||
this.y = Integer.parseInt(split[1]);
|
||||
this.z = Integer.parseInt(split[2]);
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public Blox makeRelative(int x, int y, int z) {
|
||||
return new Blox(this.world, this.x + x, this.y + y, this.z + z);
|
||||
}
|
||||
|
||||
public Location makeRelativeLoc(double x, double y, double z, float rotX, float rotY) {
|
||||
return new Location(this.world, (double)this.x + x, (double)this.y + y, (double)this.z + z, rotX, rotY);
|
||||
}
|
||||
|
||||
public Blox modRelative(int right, int depth, int distance, int modX, int modY, int modZ) {
|
||||
return makeRelative(-right * modX + distance * modZ, -depth * modY, -right * modZ + -distance * modX);
|
||||
}
|
||||
|
||||
public Location modRelativeLoc(double right, double depth, double distance, float rotX, float rotY, int modX, int modY, int modZ) {
|
||||
return makeRelativeLoc(0.5 + -right * modX + distance * modZ, depth, 0.5 + -right * modZ + -distance * modX, rotX, 0);
|
||||
}
|
||||
|
||||
public void setType(Material type) {
|
||||
world.getBlockAt(x, y, z).setType(type);
|
||||
}
|
||||
|
||||
public Material getType() {
|
||||
return world.getBlockAt(x, y, z).getType();
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return world.getBlockAt(x, y, z);
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return new Location(world, x, y, z);
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public int getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public Block getParent() {
|
||||
if (parent == null) findParent();
|
||||
if (parent == null) return null;
|
||||
return parent.getBlock();
|
||||
}
|
||||
|
||||
private void findParent() {
|
||||
int offsetX = 0;
|
||||
int offsetY = 0;
|
||||
int offsetZ = 0;
|
||||
|
||||
BlockData blk = getBlock().getBlockData();
|
||||
if (blk instanceof WallSign) {
|
||||
BlockFace facing = ((WallSign) blk).getFacing().getOppositeFace();
|
||||
offsetX = facing.getModX();
|
||||
offsetZ = facing.getModZ();
|
||||
} else if (blk instanceof Sign) {
|
||||
offsetY = -1;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
parent = new Blox(world, getX() + offsetX, getY() + offsetY, getZ() + offsetZ);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
//builder.append(world.getName());
|
||||
//builder.append(',');
|
||||
builder.append(x);
|
||||
builder.append(',');
|
||||
builder.append(y);
|
||||
builder.append(',');
|
||||
builder.append(z);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 18;
|
||||
|
||||
result = result * 27 + x;
|
||||
result = result * 27 + y;
|
||||
result = result * 27 + z;
|
||||
result = result * 27 + world.getName().hashCode();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
|
||||
Blox blox = (Blox) obj;
|
||||
return (x == blox.x) && (y == blox.y) && (z == blox.z) && (world.getName().equals(blox.world.getName()));
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
package net.TheDgtl.Stargate;
|
||||
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.Material;
|
||||
|
||||
public class BloxPopulator {
|
||||
private Blox blox;
|
||||
private Material nextMat;
|
||||
private Axis nextAxis;
|
||||
|
||||
public BloxPopulator(Blox b, Material m) {
|
||||
blox = b;
|
||||
nextMat = m;
|
||||
nextAxis = null;
|
||||
}
|
||||
|
||||
public BloxPopulator(Blox b, Material m, Axis a) {
|
||||
blox = b;
|
||||
nextMat = m;
|
||||
nextAxis = a;
|
||||
}
|
||||
|
||||
public void setBlox(Blox b) {
|
||||
blox = b;
|
||||
}
|
||||
|
||||
public void setMat(Material m) {
|
||||
nextMat = m;
|
||||
}
|
||||
|
||||
public void setAxis(Axis a) {
|
||||
nextAxis = a;
|
||||
}
|
||||
|
||||
public Blox getBlox() {
|
||||
return blox;
|
||||
}
|
||||
|
||||
public Material getMat() {
|
||||
return nextMat;
|
||||
}
|
||||
|
||||
public Axis getAxis() {
|
||||
return nextAxis;
|
||||
}
|
||||
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
package net.TheDgtl.Stargate;
|
||||
|
||||
import net.milkbowl.vault.economy.Economy;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Stargate - A portal plugin for Bukkit
|
||||
* Copyright (C) 2011, 2012 Steven "Drakia" Scott <Contact@TheDgtl.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class EconomyHandler {
|
||||
public static boolean economyEnabled = false;
|
||||
public static Economy economy = null;
|
||||
public static Plugin vault = null;
|
||||
|
||||
public static int useCost = 0;
|
||||
public static int createCost = 0;
|
||||
public static int destroyCost = 0;
|
||||
public static boolean toOwner = false;
|
||||
public static boolean chargeFreeDestination = true;
|
||||
public static boolean freeGatesGreen = false;
|
||||
|
||||
public static double getBalance(Player player) {
|
||||
if (!economyEnabled) return 0;
|
||||
return economy.getBalance(player);
|
||||
}
|
||||
|
||||
public static boolean chargePlayer(Player player, String target, double amount) {
|
||||
if (!economyEnabled) return true;
|
||||
if(player.getName().equals(target)) return true;
|
||||
if(economy != null) {
|
||||
if(!economy.has(player, amount)) return false;
|
||||
economy.withdrawPlayer(player, amount);
|
||||
economy.depositPlayer(target, amount);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean chargePlayer(Player player, UUID target, double amount) {
|
||||
if (!economyEnabled) return true;
|
||||
if(player.getUniqueId().compareTo(target) == 0) return true;
|
||||
if(economy != null) {
|
||||
if(!economy.has(player, amount)) return false;
|
||||
economy.withdrawPlayer(player, amount);
|
||||
economy.depositPlayer(Bukkit.getOfflinePlayer(target), amount);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean chargePlayer(Player player, double amount) {
|
||||
if (!economyEnabled) return true;
|
||||
if(economy != null) {
|
||||
if(!economy.has(player, amount)) return false;
|
||||
economy.withdrawPlayer(player, amount);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String format(int amt) {
|
||||
if (economyEnabled) {
|
||||
return economy.format(amt);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static boolean setupEconomy(PluginManager pm) {
|
||||
if (!economyEnabled) return false;
|
||||
// Check for Vault
|
||||
Plugin p = pm.getPlugin("Vault");
|
||||
if (p != null && p.isEnabled()) {
|
||||
RegisteredServiceProvider<Economy> economyProvider = Stargate.server.getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
|
||||
if (economyProvider != null) {
|
||||
economy = economyProvider.getProvider();
|
||||
vault = p;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
economyEnabled = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean useEconomy() {
|
||||
return economyEnabled && economy != null;
|
||||
}
|
||||
|
||||
}
|
@ -1,513 +0,0 @@
|
||||
package net.TheDgtl.Stargate;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
/**
|
||||
* Stargate - A portal plugin for Bukkit
|
||||
* Copyright (C) 2011 Shaun (sturmeh)
|
||||
* Copyright (C) 2011 Dinnerbone
|
||||
* Copyright (C) 2011, 2012 Steven "Drakia" Scott <Contact@TheDgtl.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class Gate {
|
||||
private static final Character ANYTHING = ' ';
|
||||
private static final Character ENTRANCE = '.';
|
||||
private static final Character EXIT = '*';
|
||||
private static final HashMap<String, Gate> gates = new HashMap<>();
|
||||
private static final HashMap<Material, ArrayList<Gate>> controlBlocks = new HashMap<>();
|
||||
private static final HashSet<Material> frameBlocks = new HashSet<>();
|
||||
|
||||
private final String filename;
|
||||
private final Character[][] layout;
|
||||
private final HashMap<Character, Material> types;
|
||||
private RelativeBlockVector[] entrances = new RelativeBlockVector[0];
|
||||
private RelativeBlockVector[] border = new RelativeBlockVector[0];
|
||||
private RelativeBlockVector[] controls = new RelativeBlockVector[0];
|
||||
private RelativeBlockVector exitBlock = null;
|
||||
private final HashMap<RelativeBlockVector, Integer> exits = new HashMap<>();
|
||||
private Material portalBlockOpen = Material.NETHER_PORTAL;
|
||||
private Material portalBlockClosed = Material.AIR;
|
||||
private Material button = Material.STONE_BUTTON;
|
||||
|
||||
// Economy information
|
||||
private int useCost = -1;
|
||||
private int createCost = -1;
|
||||
private int destroyCost = -1;
|
||||
private boolean toOwner = false;
|
||||
|
||||
public Gate(String filename, Character[][] layout, HashMap<Character, Material> types) {
|
||||
this.filename = filename;
|
||||
this.layout = layout;
|
||||
this.types = types;
|
||||
|
||||
populateCoordinates();
|
||||
}
|
||||
|
||||
private void populateCoordinates() {
|
||||
ArrayList<RelativeBlockVector> entranceList = new ArrayList<>();
|
||||
ArrayList<RelativeBlockVector> borderList = new ArrayList<>();
|
||||
ArrayList<RelativeBlockVector> controlList = new ArrayList<>();
|
||||
RelativeBlockVector[] relativeExits = new RelativeBlockVector[layout[0].length];
|
||||
int[] exitDepths = new int[layout[0].length];
|
||||
RelativeBlockVector lastExit = null;
|
||||
|
||||
for (int y = 0; y < layout.length; y++) {
|
||||
for (int x = 0; x < layout[y].length; x++) {
|
||||
Character key = layout[y][x];
|
||||
if (key.equals('-')) {
|
||||
controlList.add(new RelativeBlockVector(x, y, 0));
|
||||
}
|
||||
|
||||
if (key.equals(ENTRANCE) || key.equals(EXIT)) {
|
||||
entranceList.add(new RelativeBlockVector(x, y, 0));
|
||||
exitDepths[x] = y;
|
||||
if (key.equals(EXIT)) {
|
||||
this.exitBlock = new RelativeBlockVector(x, y, 0);
|
||||
}
|
||||
} else if (!key.equals(ANYTHING)) {
|
||||
borderList.add(new RelativeBlockVector(x, y, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = 0; x < exitDepths.length; x++) {
|
||||
relativeExits[x] = new RelativeBlockVector(x, exitDepths[x], 0);
|
||||
}
|
||||
|
||||
for (int x = relativeExits.length - 1; x >= 0; x--) {
|
||||
if (relativeExits[x] != null) {
|
||||
lastExit = relativeExits[x];
|
||||
} else {
|
||||
relativeExits[x] = lastExit;
|
||||
}
|
||||
|
||||
if (exitDepths[x] > 0) this.exits.put(relativeExits[x], x);
|
||||
}
|
||||
|
||||
this.entrances = entranceList.toArray(this.entrances);
|
||||
this.border = borderList.toArray(this.border);
|
||||
this.controls = controlList.toArray(this.controls);
|
||||
}
|
||||
|
||||
public void save(String gateFolder) {
|
||||
try {
|
||||
BufferedWriter bw = new BufferedWriter(new FileWriter(gateFolder + filename));
|
||||
|
||||
writeConfig(bw, "portal-open", portalBlockOpen.name());
|
||||
writeConfig(bw, "portal-closed", portalBlockClosed.name());
|
||||
writeConfig(bw, "button", button.name());
|
||||
if (useCost != -1)
|
||||
writeConfig(bw, "usecost", useCost);
|
||||
if (createCost != -1)
|
||||
writeConfig(bw, "createcost", createCost);
|
||||
if (destroyCost != -1)
|
||||
writeConfig(bw, "destroycost", destroyCost);
|
||||
writeConfig(bw, "toowner", toOwner);
|
||||
|
||||
for (Map.Entry<Character, Material> entry : types.entrySet()) {
|
||||
Character type = entry.getKey();
|
||||
Material value = entry.getValue();
|
||||
// Skip control values
|
||||
if (type.equals(ANYTHING) || type.equals(ENTRANCE) || type.equals(EXIT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bw.append(type);
|
||||
bw.append('=');
|
||||
if(value != null) {
|
||||
bw.append(value.toString());
|
||||
}
|
||||
bw.newLine();
|
||||
}
|
||||
|
||||
bw.newLine();
|
||||
|
||||
for(Character[] aLayout : layout) {
|
||||
for(Character symbol : aLayout) {
|
||||
bw.append(symbol);
|
||||
}
|
||||
bw.newLine();
|
||||
}
|
||||
|
||||
bw.close();
|
||||
} catch (IOException ex) {
|
||||
Stargate.log.log(Level.SEVERE, "Could not save Gate " + filename + " - " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void writeConfig(BufferedWriter bw, String key, int value) throws IOException {
|
||||
bw.append(String.format("%s=%d", key, value));
|
||||
bw.newLine();
|
||||
}
|
||||
|
||||
private void writeConfig(BufferedWriter bw, String key, boolean value) throws IOException {
|
||||
bw.append(String.format("%s=%b", key, value));
|
||||
bw.newLine();
|
||||
}
|
||||
|
||||
private void writeConfig(BufferedWriter bw, String key, String value) throws IOException {
|
||||
bw.append(String.format("%s=%s", key, value));
|
||||
bw.newLine();
|
||||
}
|
||||
|
||||
public Character[][] getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
public HashMap<Character, Material> getTypes() {
|
||||
return types;
|
||||
}
|
||||
|
||||
public RelativeBlockVector[] getEntrances() {
|
||||
return entrances;
|
||||
}
|
||||
|
||||
public RelativeBlockVector[] getBorder() {
|
||||
return border;
|
||||
}
|
||||
|
||||
public RelativeBlockVector[] getControls() {
|
||||
return controls;
|
||||
}
|
||||
|
||||
public HashMap<RelativeBlockVector, Integer> getExits() {
|
||||
return exits;
|
||||
}
|
||||
public RelativeBlockVector getExit() {
|
||||
return exitBlock;
|
||||
}
|
||||
|
||||
public Material getControlBlock() {
|
||||
return types.get('-');
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public Material getPortalBlockOpen() {
|
||||
return portalBlockOpen;
|
||||
}
|
||||
|
||||
public void setPortalBlockOpen(Material type) {
|
||||
portalBlockOpen = type;
|
||||
}
|
||||
|
||||
public Material getPortalBlockClosed() {
|
||||
return portalBlockClosed;
|
||||
}
|
||||
|
||||
public void setPortalBlockClosed(Material type) {
|
||||
portalBlockClosed = type;
|
||||
}
|
||||
|
||||
public Material getButton() {
|
||||
return button;
|
||||
}
|
||||
|
||||
public int getUseCost() {
|
||||
if (useCost < 0) return EconomyHandler.useCost;
|
||||
return useCost;
|
||||
}
|
||||
|
||||
public Integer getCreateCost() {
|
||||
if (createCost < 0) return EconomyHandler.createCost;
|
||||
return createCost;
|
||||
}
|
||||
|
||||
public Integer getDestroyCost() {
|
||||
if (destroyCost < 0) return EconomyHandler.destroyCost;
|
||||
return destroyCost;
|
||||
}
|
||||
|
||||
public Boolean getToOwner() {
|
||||
return toOwner;
|
||||
}
|
||||
|
||||
public boolean matches(Blox topleft, int modX, int modZ) {
|
||||
return matches(topleft, modX, modZ, false);
|
||||
}
|
||||
|
||||
public boolean matches(Blox topleft, int modX, int modZ, boolean onCreate) {
|
||||
HashMap<Character, Material> portalTypes = new HashMap<>(types);
|
||||
for (int y = 0; y < layout.length; y++) {
|
||||
for (int x = 0; x < layout[y].length; x++) {
|
||||
Character key = layout[y][x];
|
||||
|
||||
if (key.equals(ENTRANCE) || key.equals(EXIT)) {
|
||||
if (Stargate.ignoreEntrance) continue;
|
||||
|
||||
Material type = topleft.modRelative(x, y, 0, modX, 1, modZ).getType();
|
||||
|
||||
// Ignore entrance if it's air and we're creating a new gate
|
||||
if (onCreate && type == Material.AIR) continue;
|
||||
|
||||
if (type != portalBlockClosed && type != portalBlockOpen) {
|
||||
Stargate.debug("Gate::Matches", "Entrance/Exit Material Mismatch: " + type);
|
||||
return false;
|
||||
}
|
||||
} else if (!key.equals(ANYTHING)) {
|
||||
Material id = portalTypes.get(key);
|
||||
if(id == null) {
|
||||
portalTypes.put(key, topleft.modRelative(x, y, 0, modX, 1, modZ).getType());
|
||||
} else if(topleft.modRelative(x, y, 0, modX, 1, modZ).getType() != id) {
|
||||
Stargate.debug("Gate::Matches", "Block Type Mismatch: " + topleft.modRelative(x, y, 0, modX, 1, modZ).getType() + " != " + id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void registerGate(Gate gate) {
|
||||
gates.put(gate.getFilename(), gate);
|
||||
|
||||
Material blockID = gate.getControlBlock();
|
||||
|
||||
if (!controlBlocks.containsKey(blockID)) {
|
||||
controlBlocks.put(blockID, new ArrayList<>());
|
||||
}
|
||||
|
||||
controlBlocks.get(blockID).add(gate);
|
||||
}
|
||||
|
||||
public static Gate loadGate(File file) {
|
||||
Scanner scanner = null;
|
||||
boolean designing = false;
|
||||
ArrayList<ArrayList<Character>> design = new ArrayList<>();
|
||||
HashMap<Character, Material> types = new HashMap<>();
|
||||
HashMap<String, String> config = new HashMap<>();
|
||||
HashSet<Material> frameTypes = new HashSet<>();
|
||||
int cols = 0;
|
||||
|
||||
// Init types map
|
||||
types.put(ENTRANCE, Material.AIR);
|
||||
types.put(EXIT, Material.AIR);
|
||||
types.put(ANYTHING, Material.AIR);
|
||||
|
||||
try {
|
||||
scanner = new Scanner(file);
|
||||
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine();
|
||||
|
||||
if (designing) {
|
||||
ArrayList<Character> row = new ArrayList<>();
|
||||
|
||||
if (line.length() > cols) {
|
||||
cols = line.length();
|
||||
}
|
||||
|
||||
for (Character symbol : line.toCharArray()) {
|
||||
if ((symbol.equals('?')) || (!types.containsKey(symbol))) {
|
||||
Stargate.log.log(Level.SEVERE, "Could not load Gate " + file.getName() + " - Unknown symbol '" + symbol + "' in diagram");
|
||||
return null;
|
||||
}
|
||||
row.add(symbol);
|
||||
}
|
||||
|
||||
design.add(row);
|
||||
} else {
|
||||
if ((line.isEmpty()) || (!line.contains("="))) {
|
||||
designing = true;
|
||||
} else {
|
||||
String[] split = line.split("=");
|
||||
String key = split[0].trim();
|
||||
String value = split[1].trim();
|
||||
|
||||
if (key.length() == 1) {
|
||||
Character symbol = key.charAt(0);
|
||||
Material id = Material.getMaterial(value);
|
||||
if(id == null) {
|
||||
throw new Exception("Invalid material in line: " + line);
|
||||
}
|
||||
types.put(symbol, id);
|
||||
frameTypes.add(id);
|
||||
} else {
|
||||
config.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Stargate.log.log(Level.SEVERE, "Could not load Gate " + file.getName() + " - " + ex.getMessage());
|
||||
return null;
|
||||
} finally {
|
||||
if (scanner != null) scanner.close();
|
||||
}
|
||||
|
||||
Character[][] layout = new Character[design.size()][cols];
|
||||
|
||||
for (int y = 0; y < design.size(); y++) {
|
||||
ArrayList<Character> row = design.get(y);
|
||||
Character[] result = new Character[cols];
|
||||
|
||||
for (int x = 0; x < cols; x++) {
|
||||
if (x < row.size()) {
|
||||
result[x] = row.get(x);
|
||||
} else {
|
||||
result[x] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
layout[y] = result;
|
||||
}
|
||||
|
||||
Gate gate = new Gate(file.getName(), layout, types);
|
||||
|
||||
gate.portalBlockOpen = readConfig(config, gate, file, "portal-open", gate.portalBlockOpen);
|
||||
gate.portalBlockClosed = readConfig(config, gate, file, "portal-closed", gate.portalBlockClosed);
|
||||
gate.button = readConfig(config, gate, file, "button", gate.button);
|
||||
gate.useCost = readConfig(config, gate, file, "usecost", -1);
|
||||
gate.destroyCost = readConfig(config, gate, file, "destroycost", -1);
|
||||
gate.createCost = readConfig(config, gate, file, "createcost", -1);
|
||||
gate.toOwner = (config.containsKey("toowner") ? Boolean.valueOf(config.get("toowner")) : EconomyHandler.toOwner);
|
||||
|
||||
if (gate.getControls().length != 2) {
|
||||
Stargate.log.log(Level.SEVERE, "Could not load Gate " + file.getName() + " - Gates must have exactly 2 control points.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Tag.BUTTONS.isTagged(gate.button)) {
|
||||
Stargate.log.log(Level.SEVERE, "Could not load Gate " + file.getName() + " - Gate button must be a type of button.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Merge frame types, add open mat to list
|
||||
frameBlocks.addAll(frameTypes);
|
||||
|
||||
gate.save(file.getParent() + "/"); // Updates format for version changes
|
||||
return gate;
|
||||
}
|
||||
|
||||
private static int readConfig(HashMap<String, String> config, Gate gate, File file, String key, int def) {
|
||||
if (config.containsKey(key)) {
|
||||
try {
|
||||
return Integer.parseInt(config.get(key));
|
||||
} catch (NumberFormatException ex) {
|
||||
Stargate.log.log(Level.WARNING, String.format("%s reading %s: %s is not numeric", ex.getClass().getName(), file, key));
|
||||
}
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
private static Material readConfig(HashMap<String, String> config, Gate gate, File file, String key, Material def) {
|
||||
if (config.containsKey(key)) {
|
||||
Material mat = Material.getMaterial(config.get(key));
|
||||
if(mat != null) {
|
||||
return mat;
|
||||
}
|
||||
Stargate.log.log(Level.WARNING, String.format("Error reading %s: %s is not a material", file, key));
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
public static void loadGates(String gateFolder) {
|
||||
File dir = new File(gateFolder);
|
||||
File[] files;
|
||||
|
||||
if (dir.exists()) {
|
||||
files = dir.listFiles(new StargateFilenameFilter());
|
||||
} else {
|
||||
files = new File[0];
|
||||
}
|
||||
|
||||
if (files == null || files.length == 0) {
|
||||
if (dir.mkdir()) {
|
||||
populateDefaults(gateFolder);
|
||||
}
|
||||
} else {
|
||||
for (File file : files) {
|
||||
Gate gate = loadGate(file);
|
||||
if (gate != null) registerGate(gate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void populateDefaults(String gateFolder) {
|
||||
Character[][] layout = new Character[][] {
|
||||
{' ', 'X','X', ' '},
|
||||
{'X', '.', '.', 'X'},
|
||||
{'-', '.', '.', '-'},
|
||||
{'X', '*', '.', 'X'},
|
||||
{' ', 'X', 'X', ' '},
|
||||
};
|
||||
HashMap<Character, Material> types = new HashMap<>();
|
||||
types.put(ENTRANCE, Material.AIR);
|
||||
types.put(EXIT, Material.AIR);
|
||||
types.put(ANYTHING, Material.AIR);
|
||||
types.put('X', Material.OBSIDIAN);
|
||||
types.put('-', Material.OBSIDIAN);
|
||||
|
||||
Gate gate = new Gate("nethergate.gate", layout, types);
|
||||
gate.save(gateFolder);
|
||||
registerGate(gate);
|
||||
}
|
||||
|
||||
public static Gate[] getGatesByControlBlock(Block block) {
|
||||
return getGatesByControlBlock(block.getType());
|
||||
}
|
||||
|
||||
public static Gate[] getGatesByControlBlock(Material type) {
|
||||
Gate[] result = new Gate[0];
|
||||
ArrayList<Gate> lookup = controlBlocks.get(type);
|
||||
|
||||
if (lookup != null) result = lookup.toArray(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Gate getGateByName(String name) {
|
||||
return gates.get(name);
|
||||
}
|
||||
|
||||
public static int getGateCount() {
|
||||
return gates.size();
|
||||
}
|
||||
|
||||
public static boolean isGateBlock(Material type) {
|
||||
return frameBlocks.contains(type);
|
||||
}
|
||||
|
||||
static class StargateFilenameFilter implements FilenameFilter {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.endsWith(".gate");
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearGates() {
|
||||
gates.clear();
|
||||
controlBlocks.clear();
|
||||
frameBlocks.clear();
|
||||
}
|
||||
}
|
@ -1,226 +0,0 @@
|
||||
package net.TheDgtl.Stargate;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Stargate - A portal plugin for Bukkit
|
||||
* Copyright (C) 2011, 2012 Steven "Drakia" Scott <Contact@TheDgtl.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class LangLoader {
|
||||
private final String UTF8_BOM = "\uFEFF";
|
||||
// Variables
|
||||
private final String datFolder;
|
||||
private String lang;
|
||||
private HashMap<String, String> strList;
|
||||
private final HashMap<String, String> defList;
|
||||
|
||||
public LangLoader(String datFolder, String lang) {
|
||||
this.lang = lang;
|
||||
this.datFolder = datFolder;
|
||||
|
||||
File tmp = new File(datFolder, lang + ".txt");
|
||||
if (!tmp.exists()) {
|
||||
tmp.getParentFile().mkdirs();
|
||||
}
|
||||
updateLanguage(lang);
|
||||
|
||||
strList = load(lang);
|
||||
// We have a default hashMap used for when new text is added.
|
||||
InputStream is = Stargate.class.getResourceAsStream("resources/" + lang + ".txt");
|
||||
if (is != null) {
|
||||
defList = load("en", is);
|
||||
} else {
|
||||
defList = null;
|
||||
Stargate.log.severe("[Stargate] Error loading backup language. There may be missing text ingame");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean reload() {
|
||||
// This extracts/updates the language as needed
|
||||
updateLanguage(lang);
|
||||
strList = load(lang);
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getString(String name) {
|
||||
String val = strList.get(name);
|
||||
if (val == null && defList != null) val = defList.get(name);
|
||||
if (val == null) return "";
|
||||
return val;
|
||||
}
|
||||
|
||||
public void setLang(String lang) {
|
||||
this.lang = lang;
|
||||
}
|
||||
|
||||
// This function updates on-disk language files
|
||||
// with missing lines from the in-JAR files
|
||||
private void updateLanguage(String lang) {
|
||||
// Load the current language file
|
||||
ArrayList<String> keyList = new ArrayList<>();
|
||||
ArrayList<String> valList = new ArrayList<>();
|
||||
|
||||
HashMap<String, String> curLang = load(lang);
|
||||
|
||||
InputStream is = Stargate.class.getResourceAsStream("resources/" + lang + ".txt");
|
||||
if (is == null) return;
|
||||
|
||||
boolean updated = false;
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
// Input stuff
|
||||
InputStreamReader isr = new InputStreamReader(is);
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
|
||||
String line = br.readLine();
|
||||
boolean firstLine = true;
|
||||
while (line != null) {
|
||||
// Strip UTF BOM
|
||||
if (firstLine) line = removeUTF8BOM(line);
|
||||
firstLine = false;
|
||||
// Split at first "="
|
||||
int eq = line.indexOf('=');
|
||||
if (eq == -1) {
|
||||
keyList.add("");
|
||||
valList.add("");
|
||||
line = br.readLine();
|
||||
continue;
|
||||
}
|
||||
String key = line.substring(0, eq);
|
||||
String val = line.substring(eq);
|
||||
|
||||
if (curLang == null || curLang.get(key) == null) {
|
||||
keyList.add(key);
|
||||
valList.add(val);
|
||||
updated = true;
|
||||
} else {
|
||||
keyList.add(key);
|
||||
valList.add("=" + curLang.get(key).replace('\u00A7', '&'));
|
||||
curLang.remove(key);
|
||||
}
|
||||
line = br.readLine();
|
||||
}
|
||||
br.close();
|
||||
|
||||
// Save file
|
||||
fos = new FileOutputStream(datFolder + lang + ".txt");
|
||||
OutputStreamWriter out = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
|
||||
BufferedWriter bw = new BufferedWriter(out);
|
||||
|
||||
// Output normal Language data
|
||||
for (int i = 0; i < keyList.size(); i++) {
|
||||
bw.write(keyList.get(i) + valList.get(i));
|
||||
bw.newLine();
|
||||
}
|
||||
bw.newLine();
|
||||
// Output any custom language strings the user had
|
||||
if(curLang != null) {
|
||||
for (String key : curLang.keySet()) {
|
||||
bw.write(key + "=" + curLang.get(key));
|
||||
bw.newLine();
|
||||
}
|
||||
}
|
||||
|
||||
bw.close();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {fos.close();} catch (Exception ex) {}
|
||||
}
|
||||
}
|
||||
if (updated)
|
||||
Stargate.log.info("[Stargate] Your language file (" + lang + ".txt) has been updated");
|
||||
}
|
||||
|
||||
private HashMap<String, String> load(String lang) {
|
||||
return load(lang, null);
|
||||
}
|
||||
|
||||
private HashMap<String, String> load(String lang, InputStream is) {
|
||||
HashMap<String, String> strings = new HashMap<>();
|
||||
FileInputStream fis = null;
|
||||
InputStreamReader isr = null;
|
||||
try {
|
||||
if (is == null) {
|
||||
fis = new FileInputStream(datFolder + lang + ".txt");
|
||||
isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
|
||||
} else {
|
||||
isr = new InputStreamReader(is, StandardCharsets.UTF_8);
|
||||
}
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
String line = br.readLine();
|
||||
boolean firstLine = true;
|
||||
while (line != null) {
|
||||
// Strip UTF BOM
|
||||
if (firstLine) line = removeUTF8BOM(line);
|
||||
firstLine = false;
|
||||
// Split at first "="
|
||||
int eq = line.indexOf('=');
|
||||
if (eq == -1) {
|
||||
line = br.readLine();
|
||||
continue;
|
||||
}
|
||||
String key = line.substring(0, eq);
|
||||
String val = ChatColor.translateAlternateColorCodes('&', line.substring(eq + 1));
|
||||
strings.put(key, val);
|
||||
line = br.readLine();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (Exception ex) {}
|
||||
}
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
|
||||
public void debug() {
|
||||
Set<String> keys = strList.keySet();
|
||||
for (String key : keys) {
|
||||
Stargate.debug("LangLoader::Debug::strList", key + " => " + strList.get(key));
|
||||
}
|
||||
if (defList == null) return;
|
||||
keys = defList.keySet();
|
||||
for (String key : keys) {
|
||||
Stargate.debug("LangLoader::Debug::defList", key + " => " + defList.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
private String removeUTF8BOM(String s) {
|
||||
if (s.startsWith(UTF8_BOM)) {
|
||||
s = s.substring(1);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,45 +0,0 @@
|
||||
package net.TheDgtl.Stargate;
|
||||
|
||||
/**
|
||||
* Stargate - A portal plugin for Bukkit
|
||||
* Copyright (C) 2011 Shaun (sturmeh)
|
||||
* Copyright (C) 2011 Dinnerbone
|
||||
* Copyright (C) 2011, 2012 Steven "Drakia" Scott <Contact@TheDgtl.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class RelativeBlockVector {
|
||||
private int right = 0;
|
||||
private int depth = 0;
|
||||
private int distance = 0;
|
||||
|
||||
public RelativeBlockVector(int right, int depth, int distance) {
|
||||
this.right = right;
|
||||
this.depth = depth;
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
public int getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
public int getDepth() {
|
||||
return depth;
|
||||
}
|
||||
|
||||
public int getDistance() {
|
||||
return distance;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,59 +0,0 @@
|
||||
package net.TheDgtl.Stargate.event;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
import net.TheDgtl.Stargate.Portal;
|
||||
|
||||
/**
|
||||
* Stargate - A portal plugin for Bukkit
|
||||
* Copyright (C) 2011, 2012 Steven "Drakia" Scott <Contact@TheDgtl.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class StargateAccessEvent extends StargateEvent {
|
||||
private final Player player;
|
||||
private boolean deny;
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public StargateAccessEvent(Player player, Portal portal, boolean deny) {
|
||||
super("StargateAccessEvent", portal);
|
||||
|
||||
this.player = player;
|
||||
this.deny = deny;
|
||||
}
|
||||
|
||||
public boolean getDeny() {
|
||||
return this.deny;
|
||||
}
|
||||
|
||||
public void setDeny(boolean deny) {
|
||||
this.deny = deny;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
package net.TheDgtl.Stargate.event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
import net.TheDgtl.Stargate.Portal;
|
||||
|
||||
/**
|
||||
* Stargate - A portal plugin for Bukkit
|
||||
* Copyright (C) 2011, 2012 Steven "Drakia" Scott <Contact@TheDgtl.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class StargateActivateEvent extends StargateEvent {
|
||||
private final Player player;
|
||||
private ArrayList<String> destinations;
|
||||
private String destination;
|
||||
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
public StargateActivateEvent(Portal portal, Player player, ArrayList<String> destinations, String destination) {
|
||||
super("StargatActivateEvent", portal);
|
||||
|
||||
this.player = player;
|
||||
this.destinations = destinations;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public ArrayList<String> getDestinations() {
|
||||
return destinations;
|
||||
}
|
||||
|
||||
public void setDestinations(ArrayList<String> destinations) {
|
||||
this.destinations = destinations;
|
||||
}
|
||||
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public void setDestination(String destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user