3
0
Fork 0

Initial Commit

This commit is contained in:
BuildTools 2021-06-19 19:46:54 +02:00
commit cc8e3f5b79
96 changed files with 5062 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
# Project exclude paths
/target/
/.idea/

82
pom.xml Normal file
View file

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<groupId>nl.iobyte</groupId>
<artifactId>themeparkconnector</artifactId>
<version>3.0.0</version>
<repositories>
<repository>
<id>vault-repo</id>
<url>http://nexus.hc.to/content/repositories/pub_releases</url>
</repository>
<repository>
<id>codemc-repo</id>
<url>https://repo.codemc.org/repository/maven-public/</url>
<layout>default</layout>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.socket</groupId>
<artifactId>socket.io-client</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>nl.iobyte</groupId>
<artifactId>themepark</artifactId>
<version>3.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>de.mkammerer.snowflake-id</groupId>
<artifactId>snowflake-id</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>de.tr7zw</groupId>
<artifactId>item-nbt-api</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>net.milkbowl.vault</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.7</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View file

@ -0,0 +1,103 @@
package nl.iobyte.themeparkconnector;
import com.google.gson.Gson;
import net.milkbowl.vault.economy.Economy;
import nl.iobyte.themeparkconnector.api.ThemeParkConnectorAPI;
import nl.iobyte.themeparkconnector.api.config.enums.StorageKey;
import nl.iobyte.themeparkconnector.commands.ThemeParkConnectorCommand;
import nl.iobyte.themeparkconnector.listeners.*;
import nl.iobyte.themeparkconnector.sbd.License;
import nl.iobyte.themeparkconnector.sbd.UpdateManager;
import org.bukkit.Bukkit;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
public class ThemeParkConnector extends JavaPlugin {
private final static Gson gson = ThemeParkConnectorGson.getInstance();
private static ThemeParkConnector instance;
private final ThemeParkConnectorAPI api = new ThemeParkConnectorAPI();
private Economy econ = null;
private boolean disabling = false;
public void onEnable() {
if (!setupEconomy() ) {
Bukkit.getLogger().info(String.format("[%s] - No Vault dependency found!", getDescription().getName()));
}
instance = this;
api.enable();
//License stuff
new License(this, "TPP", api.getConfigurationManager().getString(StorageKey.LICENSE));
loadCommands();
loadListeners();
//Check Version
new UpdateManager(this, 4, UpdateManager.CheckType.SBDPLUGINS).handleResponse((versionResponse, version) -> {
if (versionResponse == UpdateManager.VersionResponse.FOUND_NEW) {
Bukkit.getLogger().warning("[ThemeParkConnector] There is a new version available! Curent: " + getDescription().getVersion() + " New: " + version);
} else if (versionResponse == UpdateManager.VersionResponse.LATEST) {
Bukkit.getLogger().info("[ThemeParkConnector] You are running the latest version [" + getDescription().getVersion() + "]!");
} else if (versionResponse == UpdateManager.VersionResponse.UNAVAILABLE) {
Bukkit.getLogger().severe("[ThemeParkConnector] Unable to perform an update check.");
}
}).check();
}
private boolean setupEconomy() {
if(getServer().getPluginManager().getPlugin("Vault") == null)
return false;
RegisteredServiceProvider<Economy> rsp = getServer().getServicesManager().getRegistration(Economy.class);
if (rsp == null)
return false;
econ = rsp.getProvider();
return econ != null;
}
private void loadCommands() {
new ThemeParkConnectorCommand();
}
private void loadListeners() {
PluginManager pm = Bukkit.getPluginManager();
pm.registerEvents(new PlayerListener(), this);
pm.registerEvents(new OperatorListener(), this);
pm.registerEvents(new AttractionListener(), this);
pm.registerEvents(new RideCountListener(), this);
pm.registerEvents(new TicketListener(), this);
pm.registerEvents(new RideOperatorListener(), this);
}
public void onDisable() {
disabling = true;
api.disable();
instance = null;
}
public static Gson getGson() {
return gson;
}
public static ThemeParkConnector getInstance() {
return instance;
}
public Economy getEconomy() {
return econ;
}
public ThemeParkConnectorAPI getAPI() {
return api;
}
public boolean isDisabling() {
return disabling;
}
}

View file

@ -0,0 +1,30 @@
package nl.iobyte.themeparkconnector;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import nl.iobyte.themepark.api.attraction.enums.Status;
import nl.iobyte.themeparkconnector.api.operator.adapter.OperatorItemAdapter;
import nl.iobyte.themeparkconnector.api.operator.adapter.OperatorPanelAdapter;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItem;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorPanel;
import nl.iobyte.themeparkconnector.api.packet.adapter.PacketPayloadAdapter;
import nl.iobyte.themeparkconnector.api.packet.adapter.StatusAdapter;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacketPayload;
public class ThemeParkConnectorGson {
public static Gson getInstance() {
GsonBuilder builder = new GsonBuilder();
//Packet
builder.registerTypeAdapter(AbstractPacketPayload.class, new PacketPayloadAdapter())
.registerTypeAdapter(Status.class, new StatusAdapter());
//Operator
builder.registerTypeAdapter(OperatorPanel.class, new OperatorPanelAdapter())
.registerTypeAdapter(OperatorItem.class, new OperatorItemAdapter());
return builder.create();
}
}

View file

@ -0,0 +1,133 @@
package nl.iobyte.themeparkconnector.api;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.authentication.AuthenticationService;
import nl.iobyte.themeparkconnector.api.config.ConfigurationManager;
import nl.iobyte.themeparkconnector.api.event.EventDispatcher;
import nl.iobyte.themeparkconnector.api.load.DataLoadService;
import nl.iobyte.themeparkconnector.api.network.NetworkingService;
import nl.iobyte.themeparkconnector.api.operator.OperatorService;
import nl.iobyte.themeparkconnector.api.player.PlayerStateService;
import nl.iobyte.themeparkconnector.api.show.ShowService;
import nl.iobyte.themeparkconnector.api.state.StateService;
import nl.iobyte.themeparkconnector.logger.ThemeParkConnectorLogger;
public class ThemeParkConnectorAPI {
//Data
private ConfigurationManager configurationManager;
private final DataLoadService dataLoadService = new DataLoadService();
private final ShowService showService = new ShowService();
//ThemeParkConnector System
private final NetworkingService networkingService = new NetworkingService();
private final StateService stateService = new StateService();
private final PlayerStateService playerStateService = new PlayerStateService();
private AuthenticationService authenticationService;
//Attraction
private final OperatorService operatorService = new OperatorService();
//General
private EventDispatcher eventDispatcher;
/**
* Enable the API
*/
public void enable() {
eventDispatcher = new EventDispatcher(ThemeParkConnector.getInstance());
//Prepare Configuration
configurationManager = new ConfigurationManager(ThemeParkConnector.getInstance());
//Load data
dataLoadService.init();
authenticationService = new AuthenticationService();
networkingService.init();
}
/**
* Disable the API
*/
public void disable() {
try {
if (stateService.isConnected())
networkingService.stop();
} catch (NoClassDefFoundError e) {
ThemeParkConnectorLogger.toConsole("Bukkit already unloaded the networking classes, can't kill socket.");
}
}
/**
* Get the show service
* @return ShowService
*/
public ShowService getShowService() {
return showService;
}
/**
* Get the networking service
* @return NetworkingService
*/
public NetworkingService getNetworkingService() {
return networkingService;
}
/**
* Get the configuration manager
* @return ConfigurationManager
*/
public ConfigurationManager getConfigurationManager() {
return configurationManager;
}
/**
* Get the state service
* @return StateService
*/
public StateService getStateService() {
return stateService;
}
/**
* Get the player state service
* @return PlayerStateService
*/
public PlayerStateService getPlayerStateService() {
return playerStateService;
}
/**
* Get the data load service
* @return DataLoadService
*/
public DataLoadService getDataLoadService() {
return dataLoadService;
}
/**
* Get the operator service
* @return OperatorService
*/
public OperatorService getOperatorService() {
return operatorService;
}
/**
* Get event dispatcher
* @return EventDispatcher
*/
public EventDispatcher getEventDispatcher() {
return eventDispatcher;
}
/**
* Get authentication service
* @return AuthenticationService
*/
public AuthenticationService getAuthenticationService() {
return authenticationService;
}
}

View file

@ -0,0 +1,50 @@
package nl.iobyte.themeparkconnector.api.authentication;
import de.mkammerer.snowflakeid.SnowflakeIdGenerator;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.authentication.objects.WeakConcurrentHashMap;
import java.util.Map;
import java.util.UUID;
public class AuthenticationService {
private final SnowflakeIdGenerator generator = SnowflakeIdGenerator.createDefault(42);
private final Map<UUID, String> tokens = new WeakConcurrentHashMap<>(ThemeParkConnector.getInstance(), 15 * 1000);
private final Map<UUID, String> attractions = new WeakConcurrentHashMap<>(ThemeParkConnector.getInstance(), 15 * 1000);
public String generateToken(UUID uuid, String id) {
long snowflake = generator.next();
//ID to Token and store Token
String token = Long.toString(snowflake);
tokens.put(uuid, token);
attractions.put(uuid, id);
return token;
}
public boolean hasToken(UUID uuid) {
return tokens.containsKey(uuid);
}
public boolean matchToken(UUID uuid, String token, String id) {
String str = tokens.get(uuid);
if(str == null || str.isEmpty())
return false;
if(!str.equals(token))
return false;
str = attractions.get(uuid);
if(str == null || str.isEmpty())
return false;
if(!str.equals(id))
return false;
tokens.remove(uuid);
attractions.remove(uuid);
return true;
}
}

View file

@ -0,0 +1,151 @@
package nl.iobyte.themeparkconnector.api.authentication.objects;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* A Weak Concurrent HashMap Solution which stores the keys and values only for a specific amount of time, and then expires after that
* time.
*
* This HashMap uses the Bukkit scheduler for the cleanup.
*
* @author Vivekananthan M, Stijn Bannink
*
* @param <K> The key in the hashmap
* @param <V> The value in the hashmap
*/
public class WeakConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> {
private static final long serialVersionUID = 1L;
private final Map<K, Long> timeMap = new ConcurrentHashMap<>();
private final long expiryInMillis;
private Listener<K, V> listener;
private boolean mapAlive = true;
public WeakConcurrentHashMap(JavaPlugin plugin) {
this.expiryInMillis = 10000;
initialize(plugin);
}
public WeakConcurrentHashMap(JavaPlugin plugin, Listener<K, V> listener) {
this.listener = listener;
this.expiryInMillis = 10000;
initialize(plugin);
}
public WeakConcurrentHashMap(JavaPlugin plugin, long expiryInMillis) {
this.expiryInMillis = expiryInMillis;
initialize(plugin);
}
public WeakConcurrentHashMap(JavaPlugin plugin, long expiryInMillis, Listener<K, V> listener) {
this.expiryInMillis = expiryInMillis;
this.listener = listener;
initialize(plugin);
}
private void initialize(JavaPlugin plugin) {
new CleanerRunnable().runTaskTimerAsynchronously(plugin, expiryInMillis / 2, expiryInMillis / 2);
}
/**
* {@inheritDoc}
*
* @throws IllegalStateException if trying to insert values into map after quiting
*/
@Override
public V put(K key, V value) {
if (!mapAlive) {
throw new IllegalStateException("WeakConcurrent Hashmap is no more alive.. Try creating a new one."); // No I18N
}
Date date = new Date();
timeMap.put(key, date.getTime());
V returnVal = super.put(key, value);
if (listener != null) {
listener.notifyOnAdd(key, value);
}
return returnVal;
}
/**
* {@inheritDoc}
*
* @throws IllegalStateException if trying to insert values into map after quiting
*/
@Override
public void putAll(Map<? extends K, ? extends V> m) {
if (!mapAlive) {
throw new IllegalStateException("WeakConcurrent Hashmap is no more alive.. Try creating a new one."); // No I18N
}
for (K key : m.keySet()) {
put(key, m.get(key));
}
}
/**
* {@inheritDoc}
*
* @throws IllegalStateException if trying to insert values into map after quiting
*/
@Override
public V putIfAbsent(K key, V value) {
if (!mapAlive) {
throw new IllegalStateException("WeakConcurrent Hashmap is no more alive.. Try creating a new one."); // No I18N
}
if (!containsKey(key)) {
return put(key, value);
} else {
return get(key);
}
}
/**
* Should call this method when it's no longer required
*/
public void quitMap() {
mapAlive = false;
}
public boolean isAlive() {
return mapAlive;
}
/**
*
* This thread performs the cleaning operation on the concurrent hashmap once in a specified interval. This wait interval is half of the
* time from the expiry time.
*
*
*/
private class CleanerRunnable extends BukkitRunnable {
@Override
public void run() {
if (mapAlive) cleanMap();
else cancel();
}
private void cleanMap() {
long currentTime = new Date().getTime();
for (K key : timeMap.keySet()) {
if (currentTime > (timeMap.get(key) + expiryInMillis)) {
V value = remove(key);
timeMap.remove(key);
if (listener != null) {
listener.notifyOnRemoval(key, value);
}
}
}
}
}
public interface Listener<K,V> {
void notifyOnAdd(K key, V value);
void notifyOnRemoval(K key, V value);
}
}

View file

@ -0,0 +1,182 @@
package nl.iobyte.themeparkconnector.api.client;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.message.MessageKey;
import nl.iobyte.themeparkconnector.api.network.packet.KickClientPacket;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class ClientConnection {
//General
private final UUID uuid;
private final String name;
//Connect
private boolean waitingForToken = false;
private boolean isConnected = false;
private String usedToken = null;
private String attraction;
private final List<Runnable> onConnect = new ArrayList<>();
private final List<Runnable> onDisconnect = new ArrayList<>();
private final Publisher publisher;
public ClientConnection(Player player) {
this.uuid = player.getUniqueId();
this.name = player.getName();
this.publisher = new Publisher(this);
}
/**
* Get Name of Client
* @return Client Name
*/
public String getOwnerName() {
return name;
}
/**
* Get UUID of Client
* @return Client UUID
*/
public UUID getOwnerUUID() {
return uuid;
}
/**
* Get Player
* @return Player instance
*/
public Player getPlayer() {
return Bukkit.getPlayer(getOwnerUUID());
}
/**
* Check if client is connected
* @return connection boolean
*/
public boolean isConnected() {
return isConnected;
}
/**
* When client connection is opened
*/
public void onConnect() {
if(isConnected)
return;
isConnected = true;
MessageKey.CLIENT_CONNECTION_OPEN.send(getPlayer());
for(Runnable runnable : onConnect)
runnable.run();
}
/**
* When client connection is closed
*/
public void onDisconnect() {
if(!isConnected)
return;
isConnected = false;
usedToken = null;
ThemeParkConnector.getInstance().getAPI().getOperatorService().stopOperating(uuid);
MessageKey.CLIENT_CONNECTION_CLOSED.send(getPlayer());
for(Runnable runnable : onDisconnect)
runnable.run();
}
/**
* Get token used to connect
* @return String
*/
public String getUsedToken() {
return usedToken;
}
/**
* Set token used to connect
* @param token String
*/
public void setUsedToken(String token) {
usedToken = token;
}
/**
* Get if client is waiting for token
* @return boolean
*/
public boolean isWaitingForToken() {
return waitingForToken;
}
/**
* Set if client is waiting for token
* @param waitingForToken boolean
*/
public void setWaitingForToken(boolean waitingForToken) {
this.waitingForToken = waitingForToken;
}
/**
* Set if client is waiting for token
* @param waitingForToken boolean
*/
public void setWaitingForToken(boolean waitingForToken, String attraction) {
setWaitingForToken(waitingForToken);
this.attraction = attraction;
}
public void publishURL() {
publisher.startClientSession(attraction);
}
/**
* Try generating url for client
*/
public void publishURL(String id) {
publisher.startClientSession(id);
}
/**
* Close the clients web client
*/
public void kick() {
ThemeParkConnector.getInstance().getAPI().getNetworkingService().send(this, new KickClientPacket());
ThemeParkConnector.getInstance().getAPI().getOperatorService().stopOperating(uuid);
}
/**
* When ClientConnection gets removed
*/
public void remove() {
ThemeParkConnector.getInstance().getAPI().getNetworkingService().send(this, new KickClientPacket());
ThemeParkConnector.getInstance().getAPI().getOperatorService().stopOperating(uuid);
}
/**
* Add handler run on connect
* @param runnable Runnable
* @return ClientConnection
*/
public ClientConnection addOnConnectHandler(Runnable runnable) {
onConnect.add(runnable);
return this;
}
/**
* Add handler run on disconnect
* @param runnable Runnable
* @return ClientConnection
*/
public ClientConnection addOnDisconnectHandler(Runnable runnable) {
onDisconnect.add(runnable);
return this;
}
}

View file

@ -0,0 +1,72 @@
package nl.iobyte.themeparkconnector.api.client;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import nl.iobyte.themepark.scheduler.ThemeParkScheduler;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.config.enums.StorageKey;
import nl.iobyte.themeparkconnector.api.message.MessageKey;
import nl.iobyte.themeparkconnector.api.state.objects.AbstractState;
import nl.iobyte.themeparkconnector.api.state.states.IdleState;
public class Publisher {
private final ClientConnection clientConnection;
public Publisher(ClientConnection clientConnection) {
this.clientConnection = clientConnection;
}
/**
* Attempt to generate url
*/
public void startClientSession(String id) {
if(id == null)
return;
//Check if already connected
if (clientConnection.isConnected()) {
MessageKey.CLIENT_CONNECTION_EXISTS.send(clientConnection.getPlayer());
return;
}
if(!clientConnection.isWaitingForToken())
MessageKey.CLIENT_GENERATE_TO_CONNECT.send(clientConnection.getPlayer());
//Check if state allows connections
AbstractState currentState = ThemeParkConnector.getInstance().getAPI().getStateService().getCurrentState();
if(!currentState.canClientConnect()) {
clientConnection.setWaitingForToken(true, id);
if(currentState instanceof IdleState)
ThemeParkScheduler.runAsync(() -> ThemeParkConnector.getInstance().getAPI().getNetworkingService().connectIfDown());
return;
}
//Sending waiting message
clientConnection.setWaitingForToken(true, id);
String token = ThemeParkConnector.getInstance().getAPI().getAuthenticationService().generateToken(clientConnection.getOwnerUUID(), id);
String url = ThemeParkConnector.getInstance().getAPI().getConfigurationManager().getString(StorageKey.SOCKET_PANEL_URL);
url = url.replaceAll("%TOKEN%", token);
url = url.replaceAll("%ID%", id);
TextComponent message = new TextComponent(
MessageKey.CLIENT_CLICK_TO_CONNECT.getMessage()
);
TextComponent[] hover = new TextComponent[]{
new TextComponent(
MessageKey.CLIENT_HOVER_TO_CONNECT.getMessage()
)
};
message.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url));
message.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hover));
clientConnection.getPlayer().spigot().sendMessage(message);
clientConnection.setWaitingForToken(false, null);
}
}

View file

@ -0,0 +1,56 @@
package nl.iobyte.themeparkconnector.api.client.objects;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.network.packet.NotificationPacket;
public class Notification {
private String title, message;
public Notification(String title, String message) {
this.title = title;
this.message = message;
}
/**
* Get Title of Notification
* @return String
*/
public String getTitle() {
return title;
}
/**
* Set Title of Notification
* @param title String
*/
public void setTitle(String title) {
this.title = title;
}
/**
* Get Message of Notification
* @return String
*/
public String getMessage() {
return message;
}
/**
* Set Message of Notification
* @param message String
*/
public void setMessage(String message) {
this.message = message;
}
/**
* Send Notification to client
* @param client ClientConnection
*/
public void send(ClientConnection client) {
ThemeParkConnector.getInstance().getAPI().getNetworkingService().send(client, new NotificationPacket(this));
}
}

View file

@ -0,0 +1,252 @@
package nl.iobyte.themeparkconnector.api.config;
import nl.iobyte.themepark.api.config.objects.Configuration;
import nl.iobyte.themeparkconnector.api.config.enums.StorageKey;
import nl.iobyte.themeparkconnector.api.config.enums.StorageLocation;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.plugin.Plugin;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ConfigurationManager {
private final Map<StorageLocation, Configuration> locations = new HashMap<>();
public ConfigurationManager(Plugin plugin) {
for(StorageLocation location : StorageLocation.values())
locations.put(location, new Configuration(plugin, location.getName(), true));
}
/**
* Get configuration instance belonging to a storage location
* @param location StorageLocation
* @return Configuration instance
*/
public Configuration getConfiguration(StorageLocation location) {
if(location == null)
return null;
return locations.get(location);
}
/**
* Save specific storage location
* @param location StorageLocation
*/
public void save(StorageLocation location) {
if(location == null)
return;
getConfiguration(location).save();
}
/**
* Save all storage locations
*/
public void saveAll() {
for(Configuration configuration : locations.values())
configuration.save();
}
/**
* Check if configuration contains storage key
* @param key StorageKey
* @return Boolean
*/
public boolean contains(StorageKey key) {
if(key == null)
return false;
return contains(key.getLocation(), key.getPath());
}
/**
* Check if storage location contains path
* @param location StorageLocation
* @param path String
* @return Boolean
*/
public boolean contains(StorageLocation location, String path) {
if(location == null)
return false;
return getConfiguration(location).contains(path);
}
/**
* Set value to StorageKey
* @param key StorageKey
* @param value Object to set StorageKey to
*/
public void set(StorageKey key, Object value) {
if(key == null)
return;
set(key.getLocation(), key.getPath(), value);
}
/**
* Set value to path in storage location
* @param location StorageLocation
* @param path String
* @param value Object to set path to
*/
public void set(StorageLocation location, String path, Object value) {
if(location == null)
return;
getConfiguration(location).set(path, value);
}
/**
* Get object value of storage key
* @param key StorageKey
* @return Object
*/
public Object get(StorageKey key) {
if(key == null)
return null;
return get(key.getLocation(), key.getPath());
}
/**
* Get object value of path in storage location
* @param location StorageLocation
* @param path Path
* @return Object
*/
public Object get(StorageLocation location, String path) {
if(location == null)
return null;
return getConfiguration(location).get(path);
}
/**
* Get string value of storage key
* @param key StorageKey
* @return String
*/
public String getString(StorageKey key) {
if(key == null)
return null;
return getString(key.getLocation(), key.getPath());
}
/**
* Get string value of path in storage location
* @param location StorageLocation
* @param path Path
* @return String
*/
public String getString(StorageLocation location, String path) {
if(location == null)
return null;
return getConfiguration(location).getString(path);
}
/**
* Get int value of storage key
* @param key StorageKey
* @return int
*/
public int getInt(StorageKey key) {
if(key == null)
return 0;
return getInt(key.getLocation(), key.getPath());
}
/**
* Get int value of path in storage location
* @param location StorageLocation
* @param path Path
* @return int
*/
public int getInt(StorageLocation location, String path) {
if(location == null)
return 0;
return getConfiguration(location).getInt(path);
}
/**
* Get boolean value of storage key
* @param key StorageKey
* @return boolean
*/
public boolean getBoolean(StorageKey key) {
if(key == null)
return false;
return getBoolean(key.getLocation(), key.getPath());
}
/**
* Get boolean value of path in storage location
* @param location StorageLocation
* @param path Path
* @return boolean
*/
public boolean getBoolean(StorageLocation location, String path) {
if(location == null)
return false;
return getConfiguration(location).getBoolean(path);
}
/**
* Get string list value of storage key
* @param key StorageKey
* @return List<String>
*/
public List<String> getStringList(StorageKey key) {
if(key == null)
return null;
return getStringList(key.getLocation(), key.getPath());
}
/**
* Get string list value of path in storage location
* @param location StorageLocation
* @param path Path
* @return List<String>
*/
public List<String> getStringList(StorageLocation location, String path) {
if(location == null)
return null;
return getConfiguration(location).getStringList(path);
}
/**
* Get string list value of storage key
* @param key StorageKey
* @return List<String>
*/
public ConfigurationSection getSection(StorageKey key) {
if(key == null)
return null;
return getSection(key.getLocation(), key.getPath());
}
/**
* Get string list value of path in storage location
* @param location StorageLocation
* @param path Path
* @return List<String>
*/
public ConfigurationSection getSection(StorageLocation location, String path) {
if(location == null)
return null;
return getConfiguration(location).getSection(path);
}
}

View file

@ -0,0 +1,43 @@
package nl.iobyte.themeparkconnector.api.config.enums;
public enum StorageKey {
//General
LICENSE(StorageLocation.SETTINGS, "license"),
ACTIONFOTO(StorageLocation.SETTINGS, "actionfoto"),
//Sign
SIGN_CONTROL_NAME(StorageLocation.SETTINGS, "sign.control.name"),
SIGN_CONTROL_TITLE(StorageLocation.SETTINGS, "sign.control.title"),
SIGN_SCAN_NAME(StorageLocation.SETTINGS, "sign.scan.name"),
SIGN_SCAN_TITLE(StorageLocation.SETTINGS, "sign.scan.title"),
//Socket
SOCKET_ID(StorageLocation.SETTINGS, "socket.id"),
SOCKET_URL(StorageLocation.SETTINGS, "socket.url"),
SOCKET_PANEL_URL(StorageLocation.SETTINGS, "socket.panel");
private final StorageLocation location;
private final String path;
StorageKey(StorageLocation location, String path) {
this.location = location;
this.path = path;
}
/**
* Get storage location key is stored in
* @return StorageLocation
*/
public StorageLocation getLocation() {
return location;
}
/**
* Get path to value
* @return String
*/
public String getPath() {
return path;
}
}

View file

@ -0,0 +1,21 @@
package nl.iobyte.themeparkconnector.api.config.enums;
public enum StorageLocation {
SETTINGS("settings.yml"),
MESSAGE("message.yml");
private final String name;
StorageLocation(String name) {
this.name = name;
}
/**
* Returns filename of StorageLocation
* @return String
*/
public String getName() {
return name;
}
}

View file

@ -0,0 +1,45 @@
package nl.iobyte.themeparkconnector.api.event;
import nl.iobyte.themeparkconnector.logger.ThemeParkConnectorLogger;
import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
public class EventDispatcher {
private final Plugin plugin;
public EventDispatcher(Plugin plugin) {
this.plugin = plugin;
}
/**
* Dispatch Event without Callback
* @param event Event
*/
public void call(Event event) {
call(event, null);
}
/**
* Dispatch Event with Callback
* @param event Event
* @param callback Runnable
*/
public void call(Event event, Runnable callback) {
PluginManager pm = Bukkit.getPluginManager();
if(Bukkit.isPrimaryThread()) {
pm.callEvent(event);
if(callback != null)
callback.run();
} else {
Bukkit.getScheduler().runTask(plugin, () -> {
pm.callEvent(event);
if(callback != null)
Bukkit.getScheduler().runTaskAsynchronously(plugin, callback);
});
}
}
}

View file

@ -0,0 +1,32 @@
package nl.iobyte.themeparkconnector.api.event.objects;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class ChangeEvent<T> extends Event {
private static final HandlerList handlers = new HandlerList();
private final T old, current;
public ChangeEvent(T old, T current) {
this.old = old;
this.current = current;
}
public T getOld() {
return old;
}
public T getCurrent() {
return current;
}
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View file

@ -0,0 +1,18 @@
package nl.iobyte.themeparkconnector.api.event.objects;
import nl.iobyte.themeparkconnector.api.operator.objects.AttractionOperator;
public class OperatorEvent<T> extends ChangeEvent<T> {
private final AttractionOperator operator;
public OperatorEvent(AttractionOperator operator, T old, T current) {
super(old, current);
this.operator = operator;
}
public AttractionOperator getOperator() {
return operator;
}
}

View file

@ -0,0 +1,14 @@
package nl.iobyte.themeparkconnector.api.event.operator;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.event.objects.OperatorEvent;
import nl.iobyte.themeparkconnector.api.operator.objects.AttractionOperator;
public class OperatorConnectEvent extends OperatorEvent<ClientConnection> {
public OperatorConnectEvent(AttractionOperator operator, ClientConnection connection) {
super(operator, null, connection);
}
}

View file

@ -0,0 +1,14 @@
package nl.iobyte.themeparkconnector.api.event.operator;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.event.objects.OperatorEvent;
import nl.iobyte.themeparkconnector.api.operator.objects.AttractionOperator;
public class OperatorDisconnectEvent extends OperatorEvent<ClientConnection> {
public OperatorDisconnectEvent(AttractionOperator operator, ClientConnection connection) {
super(operator, connection, null);
}
}

View file

@ -0,0 +1,28 @@
package nl.iobyte.themeparkconnector.api.event.operator;
import nl.iobyte.themeparkconnector.api.event.objects.OperatorEvent;
import nl.iobyte.themeparkconnector.api.operator.objects.AttractionOperator;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItem;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItemState;
public class OperatorStateEvent extends OperatorEvent<OperatorItemState> {
private final OperatorItem item;
private final String data;
public OperatorStateEvent(AttractionOperator operator, OperatorItem item, OperatorItemState old, OperatorItemState current, String data) {
super(operator, old, current);
this.item = item;
this.data = data;
}
public OperatorItem getItem() {
return item;
}
public String getData() {
return data;
}
}

View file

@ -0,0 +1,55 @@
package nl.iobyte.themeparkconnector.api.event.ticket;
import nl.iobyte.themeparkconnector.api.show.objects.Ticket;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import java.util.UUID;
public class TicketScanEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final UUID uuid;
private final Ticket ticket;
private final boolean valid;
private boolean cancel = false;
public TicketScanEvent(UUID uuid, Ticket ticket, boolean valid) {
this.uuid = uuid;
this.ticket = ticket;
this.valid = valid;
}
public UUID getUUID() {
return uuid;
}
public Ticket getTicket() {
return ticket;
}
public boolean isValid() {
return valid;
}
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancel;
}
@Override
public void setCancelled(boolean b) {
cancel = b;
}
}

View file

@ -0,0 +1,33 @@
package nl.iobyte.themeparkconnector.api.load;
import nl.iobyte.themeparkconnector.api.load.interfaces.IDataLoader;
import nl.iobyte.themeparkconnector.api.load.objects.*;
import java.util.ArrayList;
import java.util.List;
public class DataLoadService {
private final List<IDataLoader> loaders = new ArrayList<>();
public DataLoadService() {
addLoader(new DatabaseLoader());
addLoader(new OperatorDataLoader());
}
/**
* Add IDataLoader
* @param dataLoader IDataLoader
*/
public void addLoader(IDataLoader dataLoader) {
loaders.add(dataLoader);
}
/**
* Call all IDataLoaders
*/
public void init() {
for(IDataLoader loader : loaders)
loader.load();
}
}

View file

@ -0,0 +1,10 @@
package nl.iobyte.themeparkconnector.api.load.interfaces;
public interface IDataLoader {
/**
* Called when loading data
*/
void load();
}

View file

@ -0,0 +1,36 @@
package nl.iobyte.themeparkconnector.api.load.objects;
import nl.iobyte.themepark.ThemePark;
import nl.iobyte.themepark.api.database.DatabaseService;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.config.enums.StorageKey;
import nl.iobyte.themeparkconnector.api.load.interfaces.IDataLoader;
public class DatabaseLoader implements IDataLoader {
public void load() {
DatabaseService service = ThemePark.getInstance().getAPI().getDatabaseService();
//Create MySQL Tables
service.execute(
"remote",
"CREATE TABLE IF NOT EXISTS ridecounts(uuid VARCHAR(255) NOT NULL, attraction_id VARCHAR(255) NOT NULL, year SMALLINT(2), month SMALLINT(2), week SMALLINT(2), day SMALLINT(2), count SMALLINT(2), UNIQUE(uuid, attraction_id, year, day))",
null
);
service.execute(
"remote",
"CREATE TABLE IF NOT EXISTS seats(id BIGINT(20) NOT NULL AUTO_INCREMENT, show_id VARCHAR(256) NOT NULL, vault_price VARCHAR(256) NOT NULL, date TIMESTAMP NOT NULL, seat INT(11) NOT NULL, uuid VARCHAR(256) NOT NULL, loaded TINYINT(1) DEFAULT 0, paid TINYINT(1) DEFAULT 0, UNIQUE(show_id, date, uuid), UNIQUE(show_id, seat, date), PRIMARY KEY(id))",
null
);
if(ThemeParkConnector.getInstance().getAPI().getConfigurationManager().getBoolean(StorageKey.ACTIONFOTO)) {
service.execute(
"remote",
"CREATE TABLE IF NOT EXISTS actionfotos (id BIGINT(20) NOT NULL AUTO_INCREMENT, uuid VARCHAR(256) NOT NULL, ride VARCHAR(256) NOT NULL, base64 BLOB NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP(), UNIQUE(uuid, ride), PRIMARY KEY(id))",
null
);
}
}
}

View file

@ -0,0 +1,250 @@
package nl.iobyte.themeparkconnector.api.load.objects;
import nl.iobyte.themepark.ThemePark;
import nl.iobyte.themepark.api.ThemeParkAPI;
import nl.iobyte.themepark.api.config.objects.Configuration;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.load.interfaces.IDataLoader;
import nl.iobyte.themeparkconnector.api.operator.OperatorService;
import nl.iobyte.themeparkconnector.api.operator.objects.AttractionOperator;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItem;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItemState;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorPanel;
import nl.iobyte.themeparkconnector.logger.ThemeParkConnectorLogger;
import org.bukkit.configuration.ConfigurationSection;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class OperatorDataLoader implements IDataLoader {
/**
* Called when loading data
*/
public void load() {
ThemeParkAPI api = ThemePark.getInstance().getAPI();
File folder = new File(ThemeParkConnector.getInstance().getDataFolder(), "panels");
if(!folder.exists()) {
if (!folder.mkdirs()) {
ThemeParkConnectorLogger.toConsole("Unable to create 'panels' folder");
return;
}
}
Set<String> keys = new HashSet<>(api.getAttractionService().getRegions().keySet());
if(!new File(folder, "templates").exists()) {
keys.add("templates");
} else {
loadPanels(api, "panels/templates");
}
File[] files = folder.listFiles();
if(files != null && files.length != 0) {
for (File file : files) {
String name = file.getName();
if (name.equals("templates"))
continue;
if (file.isFile()) {
ThemeParkConnectorLogger.toConsole("File '" + name + "' in 'panels' folder not allowed");
if (!file.delete())
ThemeParkConnectorLogger.toConsole("Unable to delete file '" + name + "' in 'panels' folder");
continue;
}
if (!api.getAttractionService().hasRegion(name)) {
ThemeParkConnectorLogger.toConsole("Folder '" + name + "' in 'panels' folder not allowed");
if (!file.delete())
ThemeParkConnectorLogger.toConsole("Unable to delete folder '" + name + "' in 'panels' folder");
continue;
}
keys.remove(name);
loadPanels(api, "panels/"+name);
}
}
for(String name : keys) {
if (!new File(ThemeParkConnector.getInstance().getDataFolder(), "panels/" + name).mkdir()) {
ThemeParkConnectorLogger.toConsole("Unable to create folder '" + name + "' in 'panels' folder");
continue;
}
loadPanels(api, "panels/"+name);
}
for(String id : ThemeParkConnector.getInstance().getAPI().getOperatorService().getPanels().keySet()) {
if(api.getAttractionService().hasAttraction(id))
continue;
ThemeParkConnector.getInstance().getAPI().getOperatorService().removePanel(id);
}
}
private void loadPanels(ThemeParkAPI api, String path) {
File folder = new File(ThemeParkConnector.getInstance().getDataFolder(), path);
File[] files = folder.listFiles();
Set<String> keys;
if(folder.getName().equals("templates")) {
keys = new HashSet<>();
} else {
keys = new HashSet<>(api.getAttractionService().getRegion(folder.getName()).getAttractions().keySet());
}
if(files != null && files.length != 0) {
for (File file : files) {
String name = file.getName();
if (!file.isFile()) {
ThemeParkConnectorLogger.toConsole("Folder '" + name + "' in '" + path + "' folder not allowed");
if (!file.delete())
ThemeParkConnectorLogger.toConsole("Unable to delete folder '" + name + "' in 'panels' folder");
continue;
}
if (!name.endsWith(".yml") && !name.endsWith(".json")) {
ThemeParkConnectorLogger.toConsole("Extension of file '" + name + "' in '" + path + "' folder not allowed");
continue;
}
keys.remove(name.replaceAll("(.json|.yml)", ""));
loadPanel(api, path, name);
}
}
for(String name : keys)
loadPanel(api, path, name+".yml");
}
private void loadPanel(ThemeParkAPI api, String path, String id) {
Configuration configuration = new Configuration(ThemeParkConnector.getInstance(), path+"/"+id, false);
id = id.replaceAll("(.json|.yml)", "");
if(configuration.contains("template")) {
loadTemplatedPanel(ThemeParkConnector.getInstance().getAPI().getOperatorService(), configuration, id);
if(!api.getAttractionService().hasAttraction(id) || !ThemeParkConnector.getInstance().getAPI().getOperatorService().hasPanel(id))
return;
String permission = configuration.getString("permission");
String start_command = configuration.getString("start_command");
String stop_command = configuration.getString("stop_command");
ThemeParkConnector.getInstance().getAPI().getOperatorService().addOperator(new AttractionOperator(
id,
permission,
start_command,
stop_command
));
return;
}
if(!configuration.contains("items"))
return;
ConfigurationSection items = configuration.getSection("items");
if(items == null || items.getKeys(false).isEmpty())
return;
ConfigurationSection states;
OperatorPanel panel = new OperatorPanel(id);
for(String item_id : items.getKeys(false)) {
path = "items."+item_id;
String name = configuration.getString(path+".name");
String active_state = configuration.getString(path+".active_state");
if(!configuration.contains(path+".states"))
continue;
states = configuration.getSection(path+".states");
if(states == null || states.getKeys(false).isEmpty())
continue;
OperatorItem item = new OperatorItem(item_id, name, active_state);
for(String state_id : states.getKeys(false)) {
path = "items." + item_id + ".states." + state_id;
name = configuration.getString(path+".name");
String cover = configuration.getString(path+".cover");
String command = configuration.getString(path+".command");
String text_color = configuration.getString(path+".text_color");
String background_color = configuration.getString(path+".background_color");
if(text_color != null && !text_color.isEmpty() && background_color != null && !background_color.isEmpty()) {
boolean glow = configuration.getBoolean(path+".glow");
item.addState(new OperatorItemState(state_id, name, cover, command, text_color, background_color, glow));
continue;
}
item.addState(new OperatorItemState(state_id, name, cover, command));
}
panel.addItem(item);
}
if(panel.getItems().size() == 0)
return;
ThemeParkConnector.getInstance().getAPI().getOperatorService().addPanel(panel);
if(!api.getAttractionService().hasAttraction(id))
return;
String permission = configuration.getString("permission");
String start_command = configuration.getString("start_command");
String stop_command = configuration.getString("stop_command");
ThemeParkConnector.getInstance().getAPI().getOperatorService().addOperator(new AttractionOperator(
id,
permission,
start_command,
stop_command
));
}
private void loadTemplatedPanel(OperatorService service, Configuration configuration, String id) {
OperatorPanel panel = service.getPanel(configuration.getString("template"));
if(panel == null)
return;
if(!configuration.contains("items"))
return;
ConfigurationSection items = configuration.getSection("items");
if(items == null || items.getKeys(false).isEmpty())
return;
String path;
Map<String, String> map;
ConfigurationSection states;
Map<String, Map<String, String>> commandMap = new LinkedHashMap<>();
for(String item_id : items.getKeys(false)) {
path = "items."+item_id;
if(!configuration.contains(path+".states"))
continue;
states = configuration.getSection("states");
if(states == null || states.getKeys(false).isEmpty())
continue;
map = new LinkedHashMap<>();
for(String state_id : items.getKeys(false)) {
path = "items." + item_id + ".states." + state_id;
String command = configuration.getString(path+".command");
map.put(state_id, command);
}
if(map.size() == 0)
continue;
commandMap.put(item_id, map);
}
if(commandMap.size() == 0)
return;
service.addPanel(panel.copy(id, commandMap));
}
}

View file

@ -0,0 +1,56 @@
package nl.iobyte.themeparkconnector.api.message;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.config.enums.StorageLocation;
import org.bukkit.entity.Player;
public enum MessageKey {
//Prefix
PREFIX("prefix"),
//Session
CLIENT_UNABLE_TO_CONNECT("client.connect.unable"),
CLIENT_GENERATE_TO_CONNECT("client.connect.generate"),
CLIENT_CLICK_TO_CONNECT("client.connect.click"),
CLIENT_HOVER_TO_CONNECT("client.connect.hover"),
//Connection
CLIENT_CONNECTION_EXISTS("client.connection.exists"),
CLIENT_CONNECTION_OPEN("client.connection.open"),
CLIENT_CONNECTION_CLOSED("client.connection.closed");
private final String path;
MessageKey(String path) {
this.path = path;
}
/**
* Get path to message
* @return String
*/
public String getPath() {
return path;
}
/**
* Get and color message from config
* @return String
*/
public String getMessage() {
String msg = Text.color(ThemeParkConnector.getInstance().getAPI().getConfigurationManager().getString(StorageLocation.MESSAGE, path));
if(this != MessageKey.PREFIX)
msg = msg.replace("{prefix}", MessageKey.PREFIX.getMessage());
return msg;
}
/**
* Send message with color to Player
* @param player Player
*/
public void send(Player player) {
player.sendMessage(getMessage());
}
}

View file

@ -0,0 +1,25 @@
package nl.iobyte.themeparkconnector.api.message;
import org.bukkit.ChatColor;
public class Text {
/**
* Color text
* @param str String
* @return String
*/
public static String color(String str) {
return ChatColor.translateAlternateColorCodes('&', str);
}
/**
* Strip text of color
* @param str String
* @return String
*/
public static String strip(String str) {
return ChatColor.stripColor(color(str));
}
}

View file

@ -0,0 +1,152 @@
package nl.iobyte.themeparkconnector.api.network;
import nl.iobyte.themepark.scheduler.ThemeParkScheduler;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.network.handlers.ClientConnectivityHandler;
import nl.iobyte.themeparkconnector.api.network.handlers.ClientOperatorHandler;
import nl.iobyte.themeparkconnector.api.network.io.SocketConnector;
import nl.iobyte.themeparkconnector.api.network.objects.INetworkingEvent;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.packet.enums.PacketChannel;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacket;
import nl.iobyte.themeparkconnector.api.packet.objects.PayloadHandler;
import nl.iobyte.themeparkconnector.logger.ThemeParkConnectorLogger;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.*;
public class NetworkingService {
private final Set<INetworkingEvent> eventHandlers = new HashSet<>();
private final Map<UUID, ClientConnection> clientMap = new HashMap<>();
private final Map<String, List<PayloadHandler<?>>> packetHandlerMap = new HashMap<>();
private SocketConnector socketConnector;
/**
* Initialize SocketConnector
*/
public void init() {
if(socketConnector != null)
return;
socketConnector = new SocketConnector();
//Connect, Disconnect, Kick
ClientConnectivityHandler.load(this);
//Operator
ClientOperatorHandler.load(this);
}
/**
* Establish a socket connection if the connection is down
*/
public void connectIfDown() {
ThemeParkScheduler.runAsync(() -> socketConnector.setupConnection());
}
public void send(ClientConnection client, AbstractPacket packet) {
for (INetworkingEvent event : getEvents())
event.onPacketSend(client, packet);
socketConnector.send(client, packet);
}
/**
* Get handler for packet and call it
* @param abstractPacket Received Packet
*/
public void triggerPacket(AbstractPacket abstractPacket) {
if (packetHandlerMap.get(abstractPacket.getChannel()) == null) {
ThemeParkConnectorLogger.toConsole("Unknown handler for packet channel " + abstractPacket.getChannel());
return;
}
packetHandlerMap.get(abstractPacket.getChannel()).forEach(handler -> handler.handle(abstractPacket));
}
public void registerHandler(PacketChannel channel, PayloadHandler<?> handler) {
registerHandler(channel.toString(), handler);
}
/**
* Link a handler to a packet type
* @param channel Channel of the packet
* @param handler Handler for the incoming data
*/
public void registerHandler(String channel, PayloadHandler<?> handler) {
List<PayloadHandler<?>> handlers = packetHandlerMap.getOrDefault(channel, new ArrayList<>());
handlers.add(handler);
packetHandlerMap.put(channel, handlers);
}
/**
* Get Client from UUID
* @param uuid UUID of client
* @return ClientConnection instance
*/
public ClientConnection getClient(UUID uuid) {
if (clientMap.containsKey(uuid))
return clientMap.get(uuid);
Player player = Bukkit.getPlayer(uuid);
if (player == null)
return null;
return register(player);
}
/**
* Returns all ClientConnections
* @return Collection of all ClientConnections
*/
public Collection<ClientConnection> getClients() {
return clientMap.values();
}
/**
* Remove client from the NetworkingService
* @param player Player's UUID
*/
public void remove(UUID player) {
if (!clientMap.containsKey(player))
return;
clientMap.remove(player).remove();
}
/**
* Register client to the NetworkingService
* @param player Player
* @return ClientConnection instance
*/
public ClientConnection register(Player player) {
ClientConnection clientConnection = new ClientConnection(player);
clientMap.put(player.getUniqueId(), clientConnection);
return clientConnection;
}
/**
* Force the socket connection to close
*/
public void stop() {
socketConnector.disconnect();
}
/**
* Get networking events
* @return Set of NetworkingEvents
*/
public Set<INetworkingEvent> getEvents() {
return eventHandlers;
}
/**
* Add event handler for networking activity
* @param events Networking event
*/
public void addEventHandler(INetworkingEvent events) {
eventHandlers.add(events);
}
}

View file

@ -0,0 +1,29 @@
package nl.iobyte.themeparkconnector.api.network.drivers;
import io.socket.client.Socket;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.network.io.SocketConnector;
import nl.iobyte.themeparkconnector.api.network.objects.SocketDriver;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacket;
import nl.iobyte.themeparkconnector.logger.ThemeParkConnectorLogger;
public class ClientDriver extends SocketDriver {
/**
* Register event to handle incoming packets
* @param socket Socket
* @param connector SocketConnector
*/
public void boot(Socket socket, SocketConnector connector) {
socket.on("data", args -> {
try {
AbstractPacket packet = ThemeParkConnector.getGson().fromJson(args[0].toString(), AbstractPacket.class);
ThemeParkConnector.getInstance().getAPI().getNetworkingService().triggerPacket(packet);
} catch (Exception e) {
ThemeParkConnectorLogger.toConsole("Failed to parse incoming packet. The received data was: " + args[0].toString());
e.printStackTrace();
}
});
}
}

View file

@ -0,0 +1,85 @@
package nl.iobyte.themeparkconnector.api.network.drivers;
import io.socket.client.Manager;
import io.socket.client.Socket;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.ThemeParkConnectorAPI;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.message.MessageKey;
import nl.iobyte.themeparkconnector.api.network.io.SocketConnector;
import nl.iobyte.themeparkconnector.api.network.objects.SocketDriver;
import nl.iobyte.themeparkconnector.api.state.states.ConnectedState;
import nl.iobyte.themeparkconnector.api.state.states.IdleState;
import nl.iobyte.themeparkconnector.logger.ThemeParkConnectorLogger;
public class SystemDriver extends SocketDriver {
/**
* Register what to do whit connection
* @param socket Socket
* @param connector SocketConnector
*/
public void boot(Socket socket, SocketConnector connector) {
//What to do when connecting
socket.on(Socket.EVENT_CONNECT, args -> {
ThemeParkConnectorAPI api = ThemeParkConnector.getInstance().getAPI();
api.getStateService().setState(new ConnectedState());
api.getPlayerStateService().start();
for(ClientConnection client : ThemeParkConnector.getInstance().getAPI().getNetworkingService().getClients()) {
if(!client.isWaitingForToken())
continue;
client.publishURL();
}
});
//What to do when losing connection
socket.on(Socket.EVENT_DISCONNECT, args -> {
if(ThemeParkConnector.getInstance() == null || ThemeParkConnector.getInstance().isDisabling())
return;
cancelWaitForToken();
ThemeParkConnectorAPI api = ThemeParkConnector.getInstance().getAPI();
if(!(api.getStateService().getCurrentState() instanceof IdleState))
api.getStateService().setState(new IdleState("Disconnected from socket"));
api.getPlayerStateService().stop();
for(ClientConnection client : ThemeParkConnector.getInstance().getAPI().getNetworkingService().getClients()) {
if(!client.isConnected())
continue;
client.onDisconnect();
}
});
//What to do when can't connect
socket.on(Socket.EVENT_CONNECT_ERROR, args -> {
cancelWaitForToken();
ThemeParkConnectorAPI api = ThemeParkConnector.getInstance().getAPI();
api.getStateService().setState(new IdleState("Socket connection error"));
api.getPlayerStateService().stop();
ThemeParkConnectorLogger.toConsole(ThemeParkConnector.getGson().toJson(args));
});
socket.on(Manager.EVENT_ERROR, args -> ThemeParkConnectorLogger.toConsole(ThemeParkConnector.getGson().toJson(args)));
}
/**
* Cancel tokens for all people waiting for one
*/
private void cancelWaitForToken() {
if(ThemeParkConnector.getInstance() == null)
return;
for(ClientConnection client : ThemeParkConnector.getInstance().getAPI().getNetworkingService().getClients()) {
if(!client.isWaitingForToken())
continue;
client.setWaitingForToken(false);
MessageKey.CLIENT_UNABLE_TO_CONNECT.send(client.getPlayer());
}
}
}

View file

@ -0,0 +1,15 @@
package nl.iobyte.themeparkconnector.api.network.handlers;
import nl.iobyte.themeparkconnector.api.network.NetworkingService;
import nl.iobyte.themeparkconnector.api.packet.enums.PacketChannel;
import nl.iobyte.themeparkconnector.api.packet.handlers.ClientConnectHandler;
import nl.iobyte.themeparkconnector.api.packet.handlers.ClientDisconnectHandler;
public class ClientConnectivityHandler {
public static void load(NetworkingService service) {
service.registerHandler(PacketChannel.SERVER_IN_REGISTER_CLIENT, new ClientConnectHandler());
service.registerHandler(PacketChannel.SERVER_IN_UNREGISTER_CLIENT, new ClientDisconnectHandler());
}
}

View file

@ -0,0 +1,13 @@
package nl.iobyte.themeparkconnector.api.network.handlers;
import nl.iobyte.themeparkconnector.api.network.NetworkingService;
import nl.iobyte.themeparkconnector.api.packet.enums.PacketChannel;
import nl.iobyte.themeparkconnector.api.packet.handlers.operator.ClientOperatorClickHandler;
public class ClientOperatorHandler {
public static void load(NetworkingService service) {
service.registerHandler(PacketChannel.SERVER_IN_OPERATOR_CLICK, new ClientOperatorClickHandler());
}
}

View file

@ -0,0 +1,26 @@
package nl.iobyte.themeparkconnector.api.network.io;
import java.io.IOException;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.util.Collections;
import java.util.List;
public class NullProxySelector extends ProxySelector {
@Override
public List<Proxy> select(URI uri) {
if (uri == null) {
throw new IllegalArgumentException("uri must not be null");
}
return Collections.singletonList(Proxy.NO_PROXY);
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
ioe.printStackTrace();
}
}

View file

@ -0,0 +1,122 @@
package nl.iobyte.themeparkconnector.api.network.io;
import io.socket.client.IO;
import io.socket.client.Socket;
import nl.iobyte.themepark.scheduler.ThemeParkScheduler;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.config.enums.StorageKey;
import nl.iobyte.themeparkconnector.api.message.MessageKey;
import nl.iobyte.themeparkconnector.api.network.drivers.ClientDriver;
import nl.iobyte.themeparkconnector.api.network.drivers.SystemDriver;
import nl.iobyte.themeparkconnector.api.network.objects.CertificateHelper;
import nl.iobyte.themeparkconnector.api.network.objects.SocketDriver;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacket;
import nl.iobyte.themeparkconnector.api.state.states.ConnectingState;
import nl.iobyte.themeparkconnector.api.state.states.IdleState;
import nl.iobyte.themeparkconnector.logger.ThemeParkConnectorLogger;
import okhttp3.OkHttpClient;
import java.net.URISyntaxException;
public class SocketConnector {
private static final SocketDriver[] drivers = {
new SystemDriver(),
new ClientDriver(),
};
private Socket socket;
/**
* Try to establish connection to the ThemeParkConnector network
*/
public void setupConnection() {
if(!ThemeParkConnector.getInstance().getAPI().getStateService().getCurrentState().canConnect())
return;
//Preparing socket.io settings
OkHttpClient okHttpClient = CertificateHelper.ignore(new OkHttpClient.Builder().proxySelector(new NullProxySelector())).build();
IO.Options opts = new IO.Options();
opts.callFactory = okHttpClient;
opts.reconnection = false;
opts.webSocketFactory = okHttpClient;
// authentication headers
opts.query = String.format(
"type=server&id=%s",
ThemeParkConnector.getInstance().getAPI().getConfigurationManager().getString(StorageKey.SOCKET_ID)
);
//Setup socket.io connection
try {
socket = IO.socket(
ThemeParkConnector.getInstance().getAPI().getConfigurationManager().getString(StorageKey.SOCKET_URL),
opts
);
} catch (URISyntaxException e) {
e.printStackTrace();
}
//Register state to be connecting
ThemeParkConnector.getInstance().getAPI().getStateService().setState(new ConnectingState());
//Schedule timeout check
ThemeParkScheduler.runSyncLater(() -> {
if (!(ThemeParkConnector.getInstance().getAPI().getStateService().getCurrentState() instanceof ConnectingState))
return;
cancelWaitingForToken();
ThemeParkConnectorLogger.toConsole("Connecting timed out.");
ThemeParkConnector.getInstance().getAPI().getStateService().setState(new IdleState("Connecting to the socket timed out"));
}, 20 * 35);
//Register drivers
for(SocketDriver driver : drivers)
driver.boot(socket, this);
socket.connect();
}
/**
* Close connection with Socket
*/
public void disconnect() {
if(socket != null)
socket.disconnect();
}
/**
* Send Packet
* @param client ClientConnection
* @param packet AbstractPacket
*/
public void send(ClientConnection client, AbstractPacket packet) {
if(client == null || packet == null)
return;
if (!ThemeParkConnector.getInstance().getAPI().getStateService().isConnected())
return;
if(!client.isConnected())
return;
String data = client.getUsedToken() + "@" + ThemeParkConnector.getGson().toJson(packet);
socket.emit("data", data);
}
/**
* Cancel tokens for all people waiting for one
*/
public void cancelWaitingForToken() {
for(ClientConnection client : ThemeParkConnector.getInstance().getAPI().getNetworkingService().getClients()) {
if(!client.isWaitingForToken())
continue;
client.setWaitingForToken(false);
MessageKey.CLIENT_UNABLE_TO_CONNECT.send(client.getPlayer());
}
}
}

View file

@ -0,0 +1,43 @@
package nl.iobyte.themeparkconnector.api.network.objects;
import nl.iobyte.themeparkconnector.logger.ThemeParkConnectorLogger;
import okhttp3.OkHttpClient;
import javax.net.ssl.*;
import java.security.cert.CertificateException;
public class CertificateHelper {
public static OkHttpClient.Builder ignore(OkHttpClient.Builder builder) {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) { }
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) { }
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
builder.hostnameVerifier((hostname, session) -> true);
} catch (Exception e) {
ThemeParkConnectorLogger.toConsole("Failed to middleman ssl, should probably be fine");
}
return builder;
}
}

View file

@ -0,0 +1,27 @@
package nl.iobyte.themeparkconnector.api.network.objects;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacket;
public interface INetworkingEvent {
/**
* Event to call when packet is being send
* @param client ClientConnection
* @param packet AbstractPacket
*/
default void onPacketSend(ClientConnection client, AbstractPacket packet) {}
/**
* Event to call when the client opens the connection
* @param client ClientConnection
*/
default void onClientOpen(ClientConnection client) {}
/**
* Event to call when the client closes the connection
* @param client ClientConnection
*/
default void onClientClose(ClientConnection client) {}
}

View file

@ -0,0 +1,15 @@
package nl.iobyte.themeparkconnector.api.network.objects;
import io.socket.client.Socket;
import nl.iobyte.themeparkconnector.api.network.io.SocketConnector;
public abstract class SocketDriver {
/**
* Called to register stuff to the socket/connector
* @param socket Socket
* @param connector SocketConnector
*/
public abstract void boot(Socket socket, SocketConnector connector);
}

View file

@ -0,0 +1,12 @@
package nl.iobyte.themeparkconnector.api.network.packet;
import nl.iobyte.themeparkconnector.api.packet.enums.PacketChannel;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacket;
public class KickClientPacket extends AbstractPacket {
public KickClientPacket() {
super(PacketChannel.CLIENT_KICK, null);
}
}

View file

@ -0,0 +1,14 @@
package nl.iobyte.themeparkconnector.api.network.packet;
import nl.iobyte.themeparkconnector.api.client.objects.Notification;
import nl.iobyte.themeparkconnector.api.network.payload.NotificationPayload;
import nl.iobyte.themeparkconnector.api.packet.enums.PacketChannel;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacket;
public class NotificationPacket extends AbstractPacket {
public NotificationPacket(Notification notification) {
super(PacketChannel.CLIENT_NOTIFICATION, new NotificationPayload(notification));
}
}

View file

@ -0,0 +1,26 @@
package nl.iobyte.themeparkconnector.api.network.packet.operator;
import nl.iobyte.themeparkconnector.api.operator.enums.OperatorRequestReply;
import nl.iobyte.themeparkconnector.api.network.payload.operator.OperatorRequestReplyPayload;
import nl.iobyte.themeparkconnector.api.packet.enums.PacketChannel;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacket;
public class OperatorRequestReplyPacket extends AbstractPacket {
public OperatorRequestReplyPacket(OperatorRequestReply requestReply, String message) {
super(PacketChannel.CLIENT_OPERATOR_REQUEST_REPLY, new OperatorRequestReplyPayload(
requestReply,
message,
null
));
}
public OperatorRequestReplyPacket(OperatorRequestReply requestReply, String message, Object data) {
super(PacketChannel.CLIENT_OPERATOR_REQUEST_REPLY, new OperatorRequestReplyPayload(
requestReply,
message,
data
));
}
}

View file

@ -0,0 +1,18 @@
package nl.iobyte.themeparkconnector.api.network.packet.operator;
import nl.iobyte.themeparkconnector.api.network.payload.operator.OperatorStatePayload;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItemState;
import nl.iobyte.themeparkconnector.api.packet.enums.PacketChannel;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacket;
public class OperatorStatePacket extends AbstractPacket {
public OperatorStatePacket(String item_id, OperatorItemState state, String data) {
super(PacketChannel.CLIENT_OPERATOR_STATE, new OperatorStatePayload(
item_id,
state,
data
));
}
}

View file

@ -0,0 +1,18 @@
package nl.iobyte.themeparkconnector.api.network.packet.operator;
import nl.iobyte.themepark.api.attraction.enums.Status;
import nl.iobyte.themeparkconnector.api.network.payload.operator.OperatorStatePayload;
import nl.iobyte.themeparkconnector.api.network.payload.operator.StatusChangePayload;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItemState;
import nl.iobyte.themeparkconnector.api.packet.enums.PacketChannel;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacket;
public class StatusChangePacket extends AbstractPacket {
public StatusChangePacket(Status status) {
super(PacketChannel.CLIENT_ATTRACTION_STATE, new StatusChangePayload(
status
));
}
}

View file

@ -0,0 +1,15 @@
package nl.iobyte.themeparkconnector.api.network.payload;
import nl.iobyte.themeparkconnector.api.client.objects.Notification;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacketPayload;
public class NotificationPayload extends AbstractPacketPayload {
private String title, message;
public NotificationPayload(Notification notification) {
this.title = notification.getTitle();
this.message = notification.getMessage();
}
}

View file

@ -0,0 +1,18 @@
package nl.iobyte.themeparkconnector.api.network.payload.operator;
import nl.iobyte.themeparkconnector.api.operator.enums.OperatorRequestReply;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacketPayload;
public class OperatorRequestReplyPayload extends AbstractPacketPayload {
private OperatorRequestReply requestReply;
private String message;
private Object data;
public OperatorRequestReplyPayload(OperatorRequestReply requestReply, String message, Object data) {
this.requestReply = requestReply;
this.message = message;
this.data = data;
}
}

View file

@ -0,0 +1,18 @@
package nl.iobyte.themeparkconnector.api.network.payload.operator;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItemState;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacketPayload;
public class OperatorStatePayload extends AbstractPacketPayload {
private String item_id;
private OperatorItemState state;
private String data;
public OperatorStatePayload(String item_id, OperatorItemState state, String data) {
this.item_id = item_id;
this.state = state;
this.data = data;
}
}

View file

@ -0,0 +1,14 @@
package nl.iobyte.themeparkconnector.api.network.payload.operator;
import nl.iobyte.themepark.api.attraction.enums.Status;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacketPayload;
public class StatusChangePayload extends AbstractPacketPayload {
private Status status;
public StatusChangePayload(Status status) {
this.status = status;
}
}

View file

@ -0,0 +1,89 @@
package nl.iobyte.themeparkconnector.api.operator;
import nl.iobyte.themeparkconnector.api.operator.objects.AttractionOperator;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorPanel;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class OperatorService {
private final Map<String, AttractionOperator> operators = new HashMap<>();
private final Map<String, OperatorPanel> panels = new HashMap<>();
private final Map<UUID, String> operating = new HashMap<>();
public void addOperator(AttractionOperator operator) {
if(operator == null)
return;
operators.put(operator.getAttractionID(), operator);
}
public boolean hasOperator(String id) {
return operators.containsKey(id);
}
public AttractionOperator getOperator(String id) {
return operators.get(id);
}
public Map<String, AttractionOperator> getOperators() {
return operators;
}
public void addPanel(OperatorPanel panel) {
if(panel == null)
return;
panels.put(panel.getID(), panel);
}
public boolean hasPanel(String id) {
return panels.containsKey(id);
}
public OperatorPanel getPanel(String id) {
return panels.get(id);
}
public Map<String, OperatorPanel> getPanels() {
return panels;
}
public void removePanel(String id) {
panels.remove(id);
}
public void startOperating(UUID uuid, String id) {
AttractionOperator operator = getOperator(id);
if(operator == null)
return;
if(!operator.isAvailable())
return;
operator.setClient(uuid);
operating.put(uuid, id);
}
public boolean isOperating(UUID uuid) {
return operating.containsKey(uuid);
}
public void stopOperating(UUID uuid) {
String id = operating.remove(uuid);
if(id == null)
return;
AttractionOperator operator = getOperator(id);
if(operator == null)
return;
operator.setClient(null);
}
public Map<UUID, String> getOperating() {
return operating;
}
}

View file

@ -0,0 +1,29 @@
package nl.iobyte.themeparkconnector.api.operator.adapter;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItem;
import java.lang.reflect.Type;
public class OperatorItemAdapter implements JsonSerializer<OperatorItem> {
/**
* Serializes OperatorItem to json
* @param src OperatorItem
* @param typeOfSrc Type
* @param context JsonSerializationContext
* @return JsonElement
*/
@Override
public JsonElement serialize(OperatorItem src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject result = new JsonObject();
result.add("id", context.serialize(src.getID()));
result.add("name", context.serialize(src.getName()));
result.add("state", context.serialize(src.getActiveState()));
return result;
}
}

View file

@ -0,0 +1,28 @@
package nl.iobyte.themeparkconnector.api.operator.adapter;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorPanel;
import java.lang.reflect.Type;
public class OperatorPanelAdapter implements JsonSerializer<OperatorPanel> {
/**
* Serializes OperatorPanel to json
* @param src OperatorPanel
* @param typeOfSrc Type
* @param context JsonSerializationContext
* @return JsonElement
*/
@Override
public JsonElement serialize(OperatorPanel src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject result = new JsonObject();
result.add("id", context.serialize(src.getID()));
result.add("items", context.serialize(src.getItems().values()));
return result;
}
}

View file

@ -0,0 +1,8 @@
package nl.iobyte.themeparkconnector.api.operator.enums;
public enum OperatorRequestReply {
ACCEPT,
DENY
}

View file

@ -0,0 +1,102 @@
package nl.iobyte.themeparkconnector.api.operator.objects;
import nl.iobyte.themepark.ThemePark;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.ThemeParkConnectorAPI;
import nl.iobyte.themepark.api.attraction.objects.Attraction;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.event.operator.OperatorConnectEvent;
import nl.iobyte.themeparkconnector.api.event.operator.OperatorDisconnectEvent;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorPanel;
import java.util.UUID;
public class AttractionOperator {
private UUID client_uuid;
private final String attraction_id, permission, start_command, stop_command;
public AttractionOperator(Attraction attraction, String permission, String start_command, String stop_command) {
this.attraction_id = attraction.getID();
this.permission = permission;
this.start_command = start_command;
this.stop_command = stop_command;
}
public AttractionOperator(String attraction_id, String permission, String start_command, String stop_command) {
this.attraction_id = attraction_id;
this.permission = permission;
this.start_command = start_command;
this.stop_command = stop_command;
}
public UUID getClientUUID() {
return client_uuid;
}
public ClientConnection getClientConnection() {
return ThemeParkConnector.getInstance().getAPI().getNetworkingService().getClient(client_uuid);
}
public boolean canClientConnect(ClientConnection connection) {
if(connection == null)
return false;
if(client_uuid != null)
return false;
if(hasPermission())
return connection.getPlayer().hasPermission(permission);
return true;
}
public void setClient(UUID client_uuid) {
ThemeParkConnectorAPI api = ThemeParkConnector.getInstance().getAPI();
if(client_uuid == null) {
api.getEventDispatcher().call(new OperatorDisconnectEvent(
this,
api.getNetworkingService().getClient(this.client_uuid)
));
} else {
api.getEventDispatcher().call(new OperatorConnectEvent(
this,
api.getNetworkingService().getClient(client_uuid)
));
}
this.client_uuid = client_uuid;
}
public String getAttractionID() {
return attraction_id;
}
public Attraction getAttraction() {
return ThemePark.getInstance().getAPI().getAttractionService().getAttraction(attraction_id);
}
public String getPermission() {
return permission;
}
public boolean hasPermission() {
return permission != null && !permission.isEmpty();
}
public String getStartCommand() {
return start_command;
}
public String getStopCommand() {
return stop_command;
}
public boolean isAvailable() {
return client_uuid == null;
}
public OperatorPanel getPanel() {
return ThemeParkConnector.getInstance().getAPI().getOperatorService().getPanel(attraction_id);
}
}

View file

@ -0,0 +1,84 @@
package nl.iobyte.themeparkconnector.api.operator.objects.panel;
import nl.iobyte.themepark.scheduler.ThemeParkScheduler;
import org.bukkit.Bukkit;
import java.util.HashMap;
import java.util.Map;
public class OperatorItem {
private final String id, name;
private final Map<String, OperatorItemState> states;
private String active_state;
public OperatorItem(String id, String name, String active_state) {
this.id = id;
this.name = name;
this.active_state = active_state;
this.states = new HashMap<>();
}
public OperatorItem(String id, String name, String active_state, Map<String, OperatorItemState> states) {
this.id = id;
this.name = name;
this.active_state = active_state;
this.states = states;
}
public String getID() {
return id;
}
public String getName() {
return name;
}
public OperatorItemState getActiveState() {
return getState(active_state);
}
public void setActiveState(String active_state) {
this.active_state = active_state;
}
public void addState(OperatorItemState state) {
if(hasState(state.getID()))
return;
states.put(state.getID(), state);
}
public boolean hasState(String id) {
return states.containsKey(id);
}
public OperatorItemState getState(String id) {
return states.get(id);
}
public void click() {
if(!states.containsKey(active_state))
return;
String cmd = getActiveState().getCommand();
if(cmd == null || cmd.isEmpty())
return;
ThemeParkScheduler.runSync(() -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd));
}
public OperatorItem copy(Map<String, String> commands) {
Map<String, OperatorItemState> states = new HashMap<>();
OperatorItemState state;
for(Map.Entry<String, OperatorItemState> entrySet : this.states.entrySet()) {
state = entrySet.getValue();
states.put(
entrySet.getKey(),
state.copy(commands.containsKey(entrySet.getKey()) ? commands.get(entrySet.getKey()) : state.getCommand())
);
}
return new OperatorItem(id, name, active_state, states);
}
}

View file

@ -0,0 +1,67 @@
package nl.iobyte.themeparkconnector.api.operator.objects.panel;
public class OperatorItemState {
private final String id, name, cover, text_color, background_color;
private final transient String command;
private final boolean glow;
public OperatorItemState(String id, String name, String cover, String command) {
if(command !=null && command.startsWith("/"))
command = command.replaceFirst("/", "");
this.id = id;
this.name = name;
this.cover = cover;
this.command = command;
this.text_color = "#fff";
this.background_color = "#666";
this.glow = false;
}
public OperatorItemState(String id, String name, String cover, String command, String text_color, String background_color, boolean glow) {
if(command !=null && command.startsWith("/"))
command = command.replaceFirst("/", "");
this.id = id;
this.name = name;
this.cover = cover;
this.command = command;
this.text_color = text_color;
this.background_color = background_color;
this.glow = glow;
}
public String getID() {
return id;
}
public String getName() {
return name;
}
public String getCover() {
return cover;
}
public String getCommand() {
return command;
}
public String getTextColor() {
return text_color;
}
public String getBackgroundColor() {
return background_color;
}
public boolean isGlowing() {
return glow;
}
public OperatorItemState copy(String command) {
return new OperatorItemState(id, name, cover, command, text_color, background_color, glow);
}
}

View file

@ -0,0 +1,71 @@
package nl.iobyte.themeparkconnector.api.operator.objects.panel;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class OperatorPanel {
private final String id;
private final Map<String, OperatorItem> items;
public OperatorPanel(String id) {
this.id = id;
this.items = new LinkedHashMap<>();
}
public OperatorPanel(String id, Map<String, OperatorItem> items) {
this.id = id;
this.items = items;
}
public String getID() {
return id;
}
public void addItem(OperatorItem item) {
if(item == null)
return;
if(hasItem(item.getID()))
return;
items.put(item.getID(), item);
}
public void addItems(List<OperatorItem> items) {
for(OperatorItem item : items)
addItem(item);
}
public void addItems(Map<String, OperatorItem> items) {
this.items.putAll(items);
}
public boolean hasItem(String id) {
return items.containsKey(id);
}
public OperatorItem getItem(String id) {
return items.get(id);
}
public Map<String, OperatorItem> getItems() {
return items;
}
public OperatorPanel copy(String id, Map<String, Map<String, String>> commandMap) {
Map<String, OperatorItem> items = new LinkedHashMap<>();
OperatorItem item;
for(Map.Entry<String, OperatorItem> entrySet : this.items.entrySet()) {
item = entrySet.getValue();
items.put(
entrySet.getKey(),
item.copy(commandMap.containsKey(entrySet.getKey()) ? commandMap.get(entrySet.getKey()) : new LinkedHashMap<>())
);
}
return new OperatorPanel(id, items);
}
}

View file

@ -0,0 +1,53 @@
package nl.iobyte.themeparkconnector.api.packet.adapter;
import com.google.gson.*;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacketPayload;
import nl.iobyte.themeparkconnector.logger.ThemeParkConnectorLogger;
import java.lang.reflect.Type;
public class PacketPayloadAdapter implements JsonSerializer<AbstractPacketPayload>, JsonDeserializer<AbstractPacketPayload> {
/**
* Serializes AbstractPacketPayload to json
* @param src AbstractPacketPayload
* @param typeOfSrc Type
* @param context JsonSerializationContext
* @return JsonElement
*/
@Override
public JsonElement serialize(AbstractPacketPayload src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject result = new JsonObject();
result.add("type", new JsonPrimitive(src.getClass().getName()));
result.add("payload", context.serialize(src, src.getClass()));
return result;
}
/**
* Deserializes AbstractPacketPayload to correct type
* @param element JsonElement
* @param typeOf Type
* @param context JsonDeserializationContext
* @return AbstractPacketPayload
* @throws JsonParseException Exception that might occur
*/
@Override
public AbstractPacketPayload deserialize(JsonElement element, Type typeOf, JsonDeserializationContext context) throws JsonParseException {
try {
JsonObject object = element.getAsJsonObject();
String type = object.get("type").toString().replace("\"", "");
JsonElement payload = object.get("payload");
if(!type.contains("."))
type = "nl.iobyte.themeparkconnector.api.packet.payloads."+type;
return context.deserialize(payload, Class.forName(type));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View file

@ -0,0 +1,29 @@
package nl.iobyte.themeparkconnector.api.packet.adapter;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import nl.iobyte.themepark.api.attraction.enums.Status;
import java.lang.reflect.Type;
public class StatusAdapter implements JsonSerializer<Status> {
/**
* Serializes Status to json
* @param src Status
* @param type Type
* @param context JsonSerializationContext
* @return JsonElement
*/
@Override
public JsonElement serialize(Status src, Type type, JsonSerializationContext context) {
JsonObject result = new JsonObject();
result.add("id", context.serialize(src.getID()));
result.add("name", context.serialize(src.getName()));
result.add("hex", context.serialize(src.getHexColor()));
return result;
}
}

View file

@ -0,0 +1,21 @@
package nl.iobyte.themeparkconnector.api.packet.enums;
public enum PacketChannel {
//Server in
SERVER_IN_REGISTER_CLIENT,
SERVER_IN_UNREGISTER_CLIENT,
//Server in Operator
SERVER_IN_OPERATOR_CLICK,
//Client
CLIENT_NOTIFICATION,
CLIENT_KICK,
//Client Operator
CLIENT_OPERATOR_REQUEST_REPLY,
CLIENT_OPERATOR_STATE,
CLIENT_ATTRACTION_STATE
}

View file

@ -0,0 +1,104 @@
package nl.iobyte.themeparkconnector.api.packet.handlers;
import nl.iobyte.themepark.ThemePark;
import nl.iobyte.themepark.api.attraction.objects.Attraction;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.ThemeParkConnectorAPI;
import nl.iobyte.themeparkconnector.api.message.Text;
import nl.iobyte.themeparkconnector.api.network.objects.INetworkingEvent;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.network.packet.operator.OperatorRequestReplyPacket;
import nl.iobyte.themeparkconnector.api.operator.enums.OperatorRequestReply;
import nl.iobyte.themeparkconnector.api.operator.objects.AttractionOperator;
import nl.iobyte.themeparkconnector.api.packet.objects.PayloadHandler;
import nl.iobyte.themeparkconnector.api.packet.payloads.ClientConnectPayload;
import java.util.UUID;
public class ClientConnectHandler extends PayloadHandler<ClientConnectPayload> {
/**
* Player established connection with ThemeParkConnector
* @param payload ClientConnectPayload
*/
public void onReceive(ClientConnectPayload payload) {
ClientConnection connection = ThemeParkConnector.getInstance().getAPI().getNetworkingService().getClient(payload.getUUID());
if(connection == null)
return;
ThemeParkConnectorAPI api = ThemeParkConnector.getInstance().getAPI();
if(!api.getAuthenticationService().matchToken(payload.getUUID(), payload.getToken(), payload.getAttractionID())) {
denyRequest(
api,
payload.getUUID(),
"Invalid token used to connect"
);
return;
}
if(api.getOperatorService().isOperating(payload.getUUID())) {
denyRequest(
api,
payload.getUUID(),
"You're already operating an attraction"
);
return;
}
Attraction attraction = ThemePark.getInstance().getAPI().getAttractionService().getAttraction(payload.getAttractionID());
if(attraction == null) {
denyRequest(
api,
payload.getUUID(),
"Unable to find requested attraction"
);
return;
}
AttractionOperator operator = api.getOperatorService().getOperator(payload.getAttractionID());
if(operator == null) {
denyRequest(
api,
payload.getUUID(),
"No operator found for attraction: " + Text.strip(attraction.getName())
);
return;
}
if(!operator.canClientConnect(connection)) {
denyRequest(
api,
payload.getUUID(),
"You're not allowed to operate attraction: " + Text.strip(attraction.getName())
);
return;
}
api.getOperatorService().startOperating(payload.getUUID(), payload.getAttractionID());
api.getNetworkingService().send(
api.getNetworkingService().getClient(payload.getUUID()),
new OperatorRequestReplyPacket(
OperatorRequestReply.ACCEPT,
"You're now operating attraction: " + Text.strip(attraction.getName()),
operator.getPanel()
)
);
connection.setUsedToken(payload.getToken());
connection.onConnect();
for(INetworkingEvent event : ThemeParkConnector.getInstance().getAPI().getNetworkingService().getEvents())
event.onClientOpen(connection);
}
private void denyRequest(ThemeParkConnectorAPI api, UUID uuid, String message) {
api.getNetworkingService().send(
api.getNetworkingService().getClient(uuid),
new OperatorRequestReplyPacket(
OperatorRequestReply.DENY,
message
)
);
}
}

View file

@ -0,0 +1,23 @@
package nl.iobyte.themeparkconnector.api.packet.handlers;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.packet.objects.PayloadHandler;
import nl.iobyte.themeparkconnector.api.packet.payloads.ClientDisconnectPayload;
public class ClientDisconnectHandler extends PayloadHandler<ClientDisconnectPayload> {
/**
* Player closed connection with ThemeParkConnector
* @param payload ClientDisconnectPayload
*/
public void onReceive(ClientDisconnectPayload payload) {
ClientConnection connection = ThemeParkConnector.getInstance().getAPI().getNetworkingService().getClient(payload.getUUID());
if(connection == null)
return;
connection.onDisconnect();
ThemeParkConnector.getInstance().getAPI().getOperatorService().stopOperating(payload.getUUID());
}
}

View file

@ -0,0 +1,40 @@
package nl.iobyte.themeparkconnector.api.packet.handlers.operator;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.ThemeParkConnectorAPI;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.operator.OperatorService;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItem;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorPanel;
import nl.iobyte.themeparkconnector.api.packet.objects.PayloadHandler;
import nl.iobyte.themeparkconnector.api.packet.payloads.operator.ClientOperatorClickPayload;
public class ClientOperatorClickHandler extends PayloadHandler<ClientOperatorClickPayload> {
/**
* Player click ThemeParkConnector Ride Operator
* @param payload ClientOperatorClickPayload
*/
public void onReceive(ClientOperatorClickPayload payload) {
ThemeParkConnectorAPI api = ThemeParkConnector.getInstance().getAPI();
ClientConnection connection = api.getNetworkingService().getClient(payload.getUUID());
if(connection == null)
return;
OperatorService service = ThemeParkConnector.getInstance().getAPI().getOperatorService();
String attraction_id = service.getOperating().get(payload.getUUID());
if(attraction_id == null)
return;
OperatorPanel panel = service.getPanel(attraction_id);
if(panel == null)
return;
OperatorItem item = panel.getItem(payload.getItemID());
if(item == null)
return;
item.click();
}
}

View file

@ -0,0 +1,35 @@
package nl.iobyte.themeparkconnector.api.packet.objects;
import nl.iobyte.themeparkconnector.api.packet.enums.PacketChannel;
public class AbstractPacket {
private String channel;
private AbstractPacketPayload data;
public AbstractPacket(PacketChannel channel, AbstractPacketPayload data) {
this(channel.toString(), data);
}
public AbstractPacket(String channel, AbstractPacketPayload data) {
this.channel = channel;
this.data = data;
}
/**
* Get packet channel
* @return PacketChannel
*/
public String getChannel() {
return channel;
}
/**
* Get payload data
* @return AbstractPacketPayload
*/
public AbstractPacketPayload getData() {
return data;
}
}

View file

@ -0,0 +1,3 @@
package nl.iobyte.themeparkconnector.api.packet.objects;
public class AbstractPacketPayload { }

View file

@ -0,0 +1,20 @@
package nl.iobyte.themeparkconnector.api.packet.objects;
public abstract class PayloadHandler<E> {
/**
* Handle incoming packet
* @param packet AbstractPacket
*/
@SuppressWarnings("unchecked cast")
public void handle(AbstractPacket packet) {
onReceive((E) packet.getData());
}
/**
* Called when receiving payload
* @param payload Class<E>
*/
public abstract void onReceive(E payload);
}

View file

@ -0,0 +1,24 @@
package nl.iobyte.themeparkconnector.api.packet.payloads;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacketPayload;
import java.util.UUID;
public class ClientConnectPayload extends AbstractPacketPayload {
private UUID uuid;
private String token;
private String attraction_id;
public UUID getUUID() {
return uuid;
}
public String getToken() {
return token;
}
public String getAttractionID() {
return attraction_id;
}
}

View file

@ -0,0 +1,15 @@
package nl.iobyte.themeparkconnector.api.packet.payloads;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacketPayload;
import java.util.UUID;
public class ClientDisconnectPayload extends AbstractPacketPayload {
private UUID uuid;
public UUID getUUID() {
return uuid;
}
}

View file

@ -0,0 +1,19 @@
package nl.iobyte.themeparkconnector.api.packet.payloads.operator;
import nl.iobyte.themeparkconnector.api.packet.objects.AbstractPacketPayload;
import java.util.UUID;
public class ClientOperatorClickPayload extends AbstractPacketPayload {
private UUID uuid;
private String item_id;
public UUID getUUID() {
return uuid;
}
public String getItemID() {
return item_id;
}
}

View file

@ -0,0 +1,61 @@
package nl.iobyte.themeparkconnector.api.player;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.ThemeParkConnectorAPI;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.state.states.IdleState;
import org.bukkit.Bukkit;
import java.util.concurrent.atomic.AtomicLong;
public class PlayerStateService {
private int TaskID = 0;
private int strike = 0;
/**
* Try to start pushing player state data
*/
public void start() {
if(TaskID != 0)
return;
//Check if shutting down
if(ThemeParkConnector.getInstance().isDisabling())
return;
//Start pushing data asynchronously
strike = -1;
AtomicLong stamp = new AtomicLong(System.currentTimeMillis());
ThemeParkConnectorAPI api = ThemeParkConnector.getInstance().getAPI();
TaskID = Bukkit.getScheduler().runTaskTimerAsynchronously(ThemeParkConnector.getInstance(), () -> {
int connected = 0;
for(ClientConnection client : api.getNetworkingService().getClients())
if(client.isConnected())
connected++;
//If no players connected add strike
if(connected != 0) {
strike = 0;
return;
}
strike++;
if(strike > 2) {
api.getNetworkingService().stop();
api.getStateService().setState(new IdleState("No users online, closed connection"));
}
}, 0, 10 * 20).getTaskId();
}
/**
* Stop pushing player state data
*/
public void stop() {
if(TaskID == 0)
return;
Bukkit.getScheduler().cancelTask(TaskID);
TaskID = 0;
}
}

View file

@ -0,0 +1,130 @@
package nl.iobyte.themeparkconnector.api.show;
import com.google.gson.Gson;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTItem;
import nl.iobyte.menuapi.item.ItemBuilder;
import nl.iobyte.themepark.ThemePark;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.show.objects.Ticket;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
public class ShowService {
private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
public String redeemTicket(UUID uuid, String voucher) {
if(ThemeParkConnector.getInstance().getEconomy() == null)
return "No economy manager found";
if(uuid == null || voucher == null)
return "Invalid parameters";
try {
ArrayList<Map<String, Object>> resultSet = ThemePark.getInstance().getAPI().getDatabaseService().executeQuery(
"remote",
"SELECT `shows`.id, `shows`.title, seats.seat, seats.date, `shows`.vault_price, paid FROM seats INNER JOIN `shows` ON `shows`.id=seats.show_id WHERE uuid=? AND voucher=? AND loaded=0 LIMIT 1",
new HashMap<>(){{
put(1, uuid.toString().replace("-", ""));
put(2, voucher);
}}
);
if(resultSet == null)
return "Database error";
if(resultSet.isEmpty())
return "No results";
String id = "";
String name = "";
int seat = 0;
Date date = new Date();
Ticket ticket = new Ticket(voucher, id, seat, date, uuid);
for(Map<String, Object> map : resultSet) {
id = map.get("id").toString();
double price = Double.parseDouble((String) map.get("vault_price"));
if(!((boolean) map.get("paid"))) {
if (!ThemeParkConnector.getInstance().getEconomy().withdrawPlayer(Bukkit.getOfflinePlayer(uuid), price).transactionSuccess()) {
String finalId = id;
ThemePark.getInstance().getAPI().getDatabaseService().execute(
"remote",
"DELETE FROM seats WHERE uuid=? AND voucher=? AND show_id=?",
new HashMap<>(){{
put(1, uuid.toString().replace("-", ""));
put(2, voucher);
put(3, finalId);
}}
);
return "Not enough money";
}
}
name = (String) map.get("title");
seat = (int) map.get("seat");
date = (Timestamp) map.get("date");
ticket = new Ticket(voucher, id, seat, date, uuid);
String finalId = id;
ThemePark.getInstance().getAPI().getDatabaseService().execute(
"remote",
"UPDATE seats SET paid=1 WHERE uuid=? AND voucher=? AND show_id=?",
new HashMap<>(){{
put(1, uuid.toString().replace("-", ""));
put(2, voucher);
put(3, finalId);
}}
);
}
ItemBuilder builder = new ItemBuilder(Material.PAPER);
builder.setName("&f" + name);
List<String> list = new ArrayList<>();
list.add("&6Seat: &f" + ticket.getSeat());
list.add("&6Date: &f" +format.format(ticket.getShowDate()));
builder.setLore(list);
Gson g = new Gson();
NBTItem item = new NBTItem(builder.getItem());
NBTCompound compound = item.addCompound("data");
compound.setString("ticket", g.toJson(ticket, Ticket.class));
Player player = Bukkit.getPlayer(uuid);
player.getInventory().addItem(item.getItem());
return "true";
} catch(Exception e) {
e.printStackTrace();
}
return "Something went wrong";
}
public boolean setValid(Ticket ticket) {
if(ticket == null)
return false;
try {
int i = ThemePark.getInstance().getAPI().getDatabaseService().executeUpdate(
"remote",
"UPDATE seats SET loaded=1 WHERE uuid=? AND voucher=? AND show_id=?",
new HashMap<>(){{
put(1, ticket.getUUID().toString().replace("-", ""));
put(2, ticket.getID());
put(3, ticket.getShowID());
}}
);
if(i > 0)
return true;
} catch(Exception e) {
e.printStackTrace();
}
return false;
}
}

View file

@ -0,0 +1,41 @@
package nl.iobyte.themeparkconnector.api.show.objects;
import java.util.Date;
import java.util.UUID;
public class Ticket {
private final String show, id;
private final int seat;
private final Date date;
private final UUID uuid;
public Ticket(String id, String show, int seat, Date date, UUID uuid) {
this.id = id;
this.show = show;
this.seat = seat;
this.date = date;
this.uuid = uuid;
}
public String getID() {
return id;
}
public String getShowID() {
return show;
}
public int getSeat() {
return seat;
}
public Date getShowDate() {
return date;
}
public UUID getUUID() {
return uuid;
}
}

View file

@ -0,0 +1,51 @@
package nl.iobyte.themeparkconnector.api.state;
import nl.iobyte.themeparkconnector.api.state.objects.AbstractState;
import nl.iobyte.themeparkconnector.api.state.states.ConnectedState;
import nl.iobyte.themeparkconnector.api.state.states.ConnectingState;
import nl.iobyte.themeparkconnector.api.state.states.IdleState;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
public class StateService {
private AbstractState currentState = new IdleState();
private final List<BiConsumer<AbstractState, AbstractState>> listeners = new ArrayList<>();
/**
* Register listener for State changes
* @param listener BiConsumer<AbstractState, AbstractState>
*/
public void addListener(BiConsumer<AbstractState, AbstractState> listener) {
listeners.add(listener);
}
/**
* Get current state
* @return AbstractState
*/
public AbstractState getCurrentState() {
return currentState;
}
public boolean isConnecting() {
return currentState instanceof ConnectingState;
}
public boolean isConnected() {
return currentState instanceof ConnectedState;
}
/**
* Set current state
* @param currentState AbstractState
*/
public void setState(AbstractState currentState) {
AbstractState oldState = this.currentState;
this.currentState = currentState;
for(BiConsumer<AbstractState, AbstractState> listener : listeners)
listener.accept(oldState, currentState);
}
}

View file

@ -0,0 +1,47 @@
package nl.iobyte.themeparkconnector.api.state.objects;
public class AbstractState {
private final String name, description;
private final boolean canConnect, clientConnect;
public AbstractState(String name, String description, boolean canConnect, boolean clientConnect) {
this.name = name;
this.description = description;
this.canConnect = canConnect;
this.clientConnect = clientConnect;
}
/**
* Get state name
* @return String
*/
public String getType() {
return name;
}
/**
* Get description of state
* @return String
*/
public String getDescription() {
return description;
}
/**
* Get if server can connect
* @return boolean
*/
public boolean canConnect() {
return canConnect;
}
/**
* Get if client can connect
* @return boolean
*/
public boolean canClientConnect() {
return clientConnect;
}
}

View file

@ -0,0 +1,11 @@
package nl.iobyte.themeparkconnector.api.state.states;
import nl.iobyte.themeparkconnector.api.state.objects.AbstractState;
public class ConnectedState extends AbstractState {
public ConnectedState() {
super("Connected", "Connected to ThemeParkConnector network", false, true);
}
}

View file

@ -0,0 +1,11 @@
package nl.iobyte.themeparkconnector.api.state.states;
import nl.iobyte.themeparkconnector.api.state.objects.AbstractState;
public class ConnectingState extends AbstractState {
public ConnectingState() {
super("Connecting", "Attempting to connect to ThemeParkConnector network", false, false);
}
}

View file

@ -0,0 +1,15 @@
package nl.iobyte.themeparkconnector.api.state.states;
import nl.iobyte.themeparkconnector.api.state.objects.AbstractState;
public class IdleState extends AbstractState {
public IdleState() {
this("Nothing going on");
}
public IdleState(String description) {
super("Idle", description, true, false);
}
}

View file

@ -0,0 +1,32 @@
package nl.iobyte.themeparkconnector.commands;
import nl.iobyte.commandapi.CommandFactory;
import nl.iobyte.commandapi.middlewares.PermissionMiddleware;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.commands.subcommands.*;
import nl.iobyte.themeparkconnector.commands.subcommands.operator.OperatorCommands;
public class ThemeParkConnectorCommand {
//Load command data
public ThemeParkConnectorCommand() {
CommandFactory factory = new CommandFactory("themeparkconnector");
factory.addSubCommand(new HelpCommand(factory))
.addSubCommand(new ConnectCommand());
//Admin
factory.addSubCommand(new StatusCommand())
.addSubCommand(new NotificationCommand())
.addSubCommand(new DisconnectCommand());
//Operator
OperatorCommands.load(factory);
//Middleware
factory.addMiddleware(new PermissionMiddleware());
//Register command
factory.registerCommand(ThemeParkConnector.getInstance());
}
}

View file

@ -0,0 +1,67 @@
package nl.iobyte.themeparkconnector.commands.arguments;
import nl.iobyte.commandapi.interfaces.ICommandArgument;
import nl.iobyte.commandapi.objects.ArgumentCheck;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.operator.objects.AttractionOperator;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItem;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItemState;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import java.util.Arrays;
import java.util.List;
public class OperatorArgument implements ICommandArgument<OperatorItemState> {
/**
* Message to display when giving an error
* @return String
*/
public String getMessage(String[] args) {
return "Incorrect operator information: "+ ChatColor.WHITE +
String.join(
",",
Arrays.asList(args).subList(0, Math.min(args.length, 3))
);
}
/**
* Check if argument is valid OperatorItemState
* @param sender CommandSender
* @param args Arguments passed by Command
* @param previousArguments Previous arguments
* @return Boolean
*/
public ArgumentCheck checkArgument(CommandSender sender, String[] args, List<Object> previousArguments) {
if(args.length < 3)
return new ArgumentCheck(false, 1);
AttractionOperator operator = ThemeParkConnector.getInstance().getAPI().getOperatorService().getOperator(args[0]);
if(operator == null)
return new ArgumentCheck(false, 1);
OperatorItem item = operator.getPanel().getItem(args[1]);
if(item == null)
return new ArgumentCheck(false, 1);
return new ArgumentCheck(item.hasState(args[2]), 3);
}
/**
* Get OperatorItemState passed by command
* @param sender CommandSender
* @param args Arguments passed by Command
* @param previousArguments Previous arguments
* @return OperatorItemState
*/
public OperatorItemState getArgument(CommandSender sender, String[] args, List<Object> previousArguments) {
AttractionOperator operator = ThemeParkConnector.getInstance().getAPI().getOperatorService().getOperator(args[0]);
previousArguments.add(operator);
OperatorItem item = operator.getPanel().getItem(args[1]);
previousArguments.add(item);
return item.getState(args[2]);
}
}

View file

@ -0,0 +1,46 @@
package nl.iobyte.themeparkconnector.commands.subcommands;
import nl.iobyte.commandapi.interfaces.SubCommand;
import nl.iobyte.themepark.api.attraction.objects.Attraction;
import nl.iobyte.themepark.commands.arguments.AttractionArgument;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.message.Text;
import nl.iobyte.themeparkconnector.api.operator.objects.AttractionOperator;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
public class ConnectCommand extends SubCommand {
public ConnectCommand() {
super(new String[]{"connect"});
addSyntax("/themeparkconnector connect <attraction>")
.addArgument(new AttractionArgument())
.setAllowConsole(false);
}
//Attempt to generate an url for the Player
public void onPlayerCommand(Player player, List<Object> list, int i) {
Attraction attraction = (Attraction) list.get(0);
AttractionOperator operator = ThemeParkConnector.getInstance().getAPI().getOperatorService().getOperator(attraction.getID());
if(operator == null) {
player.sendMessage(Text.color("&6&lThemeParkConnectorMC &f➢ &4There is no operator for this attraction"));
return;
}
ClientConnection client = ThemeParkConnector.getInstance().getAPI().getNetworkingService().getClient(
player.getUniqueId()
);
if(!operator.canClientConnect(client)) {
player.sendMessage(Text.color("&6&lThemeParkConnectorMC &f➢ &4You can't connect to the operator of this attraction"));
return;
}
client.publishURL(attraction.getID());
}
public void onConsoleCommand(CommandSender commandSender, List<Object> list, int i) { }
}

View file

@ -0,0 +1,38 @@
package nl.iobyte.themeparkconnector.commands.subcommands;
import nl.iobyte.commandapi.interfaces.SubCommand;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.ThemeParkConnectorAPI;
import nl.iobyte.themeparkconnector.api.message.Text;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
public class DisconnectCommand extends SubCommand {
public DisconnectCommand() {
super("themeparkconnector.admin", "disconnect");
addSyntax("/themeparkconnector disconnect");
}
//Attempt to generate an url for the Player
public void onPlayerCommand(Player player, List<Object> list, int i) {
onConsoleCommand(player, list, i);
}
public void onConsoleCommand(CommandSender sender, List<Object> list, int i) {
ThemeParkConnectorAPI api = ThemeParkConnector.getInstance().getAPI();
try {
if (api.getStateService().isConnected())
api.getNetworkingService().stop();
} catch (Exception e) {
e.printStackTrace();
sender.sendMessage(Text.color("&6&lThemeParkConnectorMC &f➢ &4Something went wrong while closing connection"));
return;
}
sender.sendMessage(Text.color("&6&lThemeParkConnectorMC &f➢ &aConnection has been closed"));
}
}

View file

@ -0,0 +1,71 @@
package nl.iobyte.themeparkconnector.commands.subcommands;
import nl.iobyte.commandapi.CommandFactory;
import nl.iobyte.commandapi.arguments.number.IntegerArgument;
import nl.iobyte.commandapi.interfaces.SubCommand;
import nl.iobyte.themeparkconnector.api.message.Text;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
public class HelpCommand extends SubCommand {
private final CommandFactory factory;
public HelpCommand(CommandFactory factory) {
super(new String[]{"help"});
this.factory = factory;
addSyntax("/themeparkconnector help");
addSyntax("/themeparkconnector help <page>")
.addArgument(new IntegerArgument());
}
public void onPlayerCommand(Player player, List<Object> list, int i) {
onConsoleCommand(player, list, i);
}
//Send CommandSender list of commands it has access to
public void onConsoleCommand(CommandSender sender, List<Object> list, int i) {
List<SubCommand> commands = factory.getApplicableSubCommands(sender);
if(commands.size() <= 5) {
sendSinglePage(sender, commands);
return;
}
sendMultiPage(sender, commands, list, i);
}
private void sendSinglePage(CommandSender sender, List<SubCommand> commands) {
sender.sendMessage(Text.color("&f&l>==== &6&lThemeParkConnector &l&f====<"));
for (SubCommand command : commands)
sender.sendMessage(Text.color("&f" + command.getApplicableSyntaxList(sender).get(0).getUsage()));
sender.sendMessage(Text.color("&f&l>==== &6&lThemeParkConnector &l&f====<"));
}
private void sendMultiPage(CommandSender sender, List<SubCommand> commands, List<Object> list, int i) {
int page = 1;
int pages = (int) Math.ceil(((double) commands.size()) / 5);
if(i == 1)
page = (Integer) list.get(0);
if(page < 1 || page > pages) {
sender.sendMessage(Text.color("&6&lThemeParkConnectorMC &f➢ Page &6"+page+" &fdoesn't exist"));
return;
}
page--;
int start = page * 5;
int end = page * 5 + 5;
if(end > commands.size())
end = commands.size();
sender.sendMessage(Text.color("&f&l>==== &6&lThemeParkConnector &f(&6"+(page + 1)+"&f/&6"+pages+"&f) &l&f====<"));
for(i = start; i < end; i++)
sender.sendMessage(Text.color("&f" + commands.get(i).getApplicableSyntaxList(sender).get(0).getUsage()));
sender.sendMessage(Text.color("&f&l>==== &6&lThemeParkConnector &l&f====<"));
}
}

View file

@ -0,0 +1,44 @@
package nl.iobyte.themeparkconnector.commands.subcommands;
import nl.iobyte.commandapi.arguments.MessageArgument;
import nl.iobyte.commandapi.arguments.PlayersArgument;
import nl.iobyte.commandapi.interfaces.SubCommand;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.message.Text;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.client.objects.Notification;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
public class NotificationCommand extends SubCommand {
public NotificationCommand() {
super("themeparkconnector.admin", "notification");
addSyntax("/themeparkconnector notification <player> <title> <message>")
.addArgument(new PlayersArgument())
.addArgument(new MessageArgument())
.addArgument(new MessageArgument());
}
public void onPlayerCommand(Player player, List<Object> objects, int i) {
onConsoleCommand(player, objects, i);
}
//Get Notification data and send to Player(s)
public void onConsoleCommand(CommandSender sender, List<Object> objects, int i) {
Notification notification = new Notification((String) objects.get(1), (String) objects.get(2));
for(Player player : (List<Player>) objects.get(0)) {
ClientConnection client = ThemeParkConnector.getInstance().getAPI().getNetworkingService().getClient(player.getUniqueId());
if(!client.isConnected())
continue;
i++;
notification.send(client);
}
sender.sendMessage(Text.color("&6&lThemeParkConnectorMC &f➢ The notification has been send to &6"+i+" &fclients"));
}
}

View file

@ -0,0 +1,49 @@
package nl.iobyte.themeparkconnector.commands.subcommands;
import nl.iobyte.commandapi.interfaces.SubCommand;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.ThemeParkConnectorAPI;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.state.objects.AbstractState;
import nl.iobyte.themeparkconnector.api.message.Text;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
public class StatusCommand extends SubCommand {
public StatusCommand() {
super("themeparkconnector.admin", "status");
addSyntax("/themeparkconnector status");
}
public void onPlayerCommand(Player player, List<Object> objects, int i) {
onConsoleCommand(player, objects, i);
}
//Give CommandSender overview of Plugin status
public void onConsoleCommand(CommandSender sender, List<Object> objects, int i) {
ThemeParkConnectorAPI api = ThemeParkConnector.getInstance().getAPI();
AbstractState state = api.getStateService().getCurrentState();
sender.sendMessage(Text.color("&f&l>==== &6&lThemeParkConnector &l&f====<"));
sender.sendMessage(Text.color("&6State: &f"+state.getType()));
sender.sendMessage(Text.color("&6Clients: &f"+getClientCount()+"&6/&f"+ Bukkit.getOnlinePlayers().size()));
sender.sendMessage(Text.color("&6Description:"));
sender.sendMessage(Text.color("&f"+state.getDescription()));
sender.sendMessage(Text.color("&f&l>==== &6&lThemeParkConnector &l&f====<"));
}
//Get clients connected to ThemeParkConnector
private String getClientCount() {
int i = 0;
for(ClientConnection client : ThemeParkConnector.getInstance().getAPI().getNetworkingService().getClients())
if(client.isConnected())
i++;
return Integer.toString(i);
}
}

View file

@ -0,0 +1,12 @@
package nl.iobyte.themeparkconnector.commands.subcommands.operator;
import nl.iobyte.commandapi.CommandFactory;
public class OperatorCommands {
public static void load(CommandFactory factory) {
factory.addSubCommand(new OperatorReloadCommand())
.addSubCommand(new OperatorStateCommand());
}
}

View file

@ -0,0 +1,29 @@
package nl.iobyte.themeparkconnector.commands.subcommands.operator;
import nl.iobyte.commandapi.interfaces.SubCommand;
import nl.iobyte.themeparkconnector.api.load.objects.OperatorDataLoader;
import nl.iobyte.themeparkconnector.api.message.Text;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
public class OperatorReloadCommand extends SubCommand {
public OperatorReloadCommand() {
super("themeparkconnector.admin", "operator", "reload");
addSyntax("/themeparkconnector operator reload");
}
@Override
public void onPlayerCommand(Player player, List<Object> list, int i) {
onConsoleCommand(player, list, i);
}
@Override
public void onConsoleCommand(CommandSender sender, List<Object> list, int i) {
sender.sendMessage(Text.color("&6&lThemeParkConnectorMC &f➢ &6Attempting to load ride operators"));
new OperatorDataLoader().load();
}
}

View file

@ -0,0 +1,60 @@
package nl.iobyte.themeparkconnector.commands.subcommands.operator;
import nl.iobyte.commandapi.arguments.StringArgument;
import nl.iobyte.commandapi.interfaces.SubCommand;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.event.operator.OperatorStateEvent;
import nl.iobyte.themeparkconnector.api.message.Text;
import nl.iobyte.themeparkconnector.api.operator.objects.AttractionOperator;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItem;
import nl.iobyte.themeparkconnector.api.operator.objects.panel.OperatorItemState;
import nl.iobyte.themeparkconnector.commands.arguments.OperatorArgument;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
public class OperatorStateCommand extends SubCommand {
public OperatorStateCommand() {
super("themeparkconnector.admin", "operator", "state");
addSyntax("/themeparkconnector operator state <attraction> <item> <state>")
.addArgument(new OperatorArgument());
addSyntax("/themeparkconnector operator state <attraction> <item> <state> <data>")
.addArgument(new OperatorArgument())
.addArgument(new StringArgument());
}
@Override
public void onPlayerCommand(Player player, List<Object> list, int i) {
onConsoleCommand(player, list, i);
}
@Override
public void onConsoleCommand(CommandSender sender, List<Object> list, int i) {
AttractionOperator operator = (AttractionOperator) list.get(0);
OperatorItem item = (OperatorItem) list.get(1);
OperatorItemState state = (OperatorItemState) list.get(2);
OperatorItemState old = item.getActiveState();
if(state.getID().equals(old.getID())) {
if(sender instanceof Player)
sender.sendMessage(Text.color("&6&lThemeParkConnectorMC &f➢ &4Item already in state: &f"+state.getID()));
return;
}
item.setActiveState(state.getID());
ThemeParkConnector.getInstance().getAPI().getEventDispatcher().call(new OperatorStateEvent(
operator,
item,
old,
state,
i == 0 ? "" : (String) list.get(3)
));
if(sender instanceof Player)
sender.sendMessage(Text.color("&6&lThemeParkConnectorMC &f➢ &aSuccessfully changed state of item to: &f"+state.getID()));
}
}

View file

@ -0,0 +1,32 @@
package nl.iobyte.themeparkconnector.listeners;
import nl.iobyte.themepark.api.event.attraction.AttractionStatusChangeEvent;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.client.ClientConnection;
import nl.iobyte.themeparkconnector.api.network.packet.operator.StatusChangePacket;
import nl.iobyte.themeparkconnector.api.operator.objects.AttractionOperator;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class AttractionListener implements Listener {
@EventHandler
public void onChange(AttractionStatusChangeEvent e) {
AttractionOperator operator = ThemeParkConnector.getInstance().getAPI().getOperatorService().getOperator(e.getAttraction().getID());
if(operator == null)
return;
ClientConnection client = operator.getClientConnection();
if(client == null)
return;
//Packet
ThemeParkConnector.getInstance().getAPI().getNetworkingService().send(
client,
new StatusChangePacket(
e.getCurrent()
)
);
}
}

View file

@ -0,0 +1,45 @@
package nl.iobyte.themeparkconnector.listeners;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.event.operator.OperatorConnectEvent;
import nl.iobyte.themeparkconnector.api.event.operator.OperatorDisconnectEvent;
import nl.iobyte.themeparkconnector.api.event.operator.OperatorStateEvent;
import nl.iobyte.themeparkconnector.api.network.packet.operator.OperatorStatePacket;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class OperatorListener implements Listener {
@EventHandler
public void onConnect(OperatorConnectEvent e) {
String command = e.getOperator().getStartCommand();
if(command == null || command.isEmpty())
return;
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
}
@EventHandler
public void onState(OperatorStateEvent e) {
//Change Packet
ThemeParkConnector.getInstance().getAPI().getNetworkingService().send(
e.getOperator().getClientConnection(),
new OperatorStatePacket(
e.getItem().getID(),
e.getCurrent(),
e.getData()
)
);
}
@EventHandler
public void onDisconnect(OperatorDisconnectEvent e) {
String command = e.getOperator().getStopCommand();
if(command == null || command.isEmpty())
return;
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
}
}

View file

@ -0,0 +1,31 @@
package nl.iobyte.themeparkconnector.listeners;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.ThemeParkConnectorAPI;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.UUID;
public class PlayerListener implements Listener {
@EventHandler
public void onJoin(PlayerJoinEvent e) {
Player player = e.getPlayer();
ThemeParkConnectorAPI api = ThemeParkConnector.getInstance().getAPI();
//Register ClientConnection
api.getNetworkingService().register(player);
}
@EventHandler
public void onQuit(PlayerQuitEvent e) {
Player player = e.getPlayer();
UUID uuid = player.getUniqueId();
//Remove ClientConnection
ThemeParkConnector.getInstance().getAPI().getNetworkingService().remove(uuid);
}
}

View file

@ -0,0 +1,31 @@
package nl.iobyte.themeparkconnector.listeners;
import nl.iobyte.themepark.ThemePark;
import nl.iobyte.themepark.api.event.ridecount.RideCountAddEvent;
import nl.iobyte.themepark.api.ridecount.objects.RideCount;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import java.util.HashMap;
public class RideCountListener implements Listener {
@EventHandler
public void onAdd(RideCountAddEvent e) {
RideCount rc = e.getRideCount();
ThemePark.getInstance().getAPI().getDatabaseService().executeAsync(
"remote",
"INSERT INTO ridecounts(uuid, attraction_id, year, month, week, day, count) VALUES (?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE count=?",
new HashMap<>() {{
put(1, rc.getUUID().toString());
put(2, rc.getAttractionID());
put(3, rc.getYear());
put(4, rc.getMonth());
put(5, rc.getWeek());
put(6, rc.getDay());
put(7, rc.getCount());
put(8, rc.getCount());
}}
);
}
}

View file

@ -0,0 +1,79 @@
package nl.iobyte.themeparkconnector.listeners;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.TextComponent;
import nl.iobyte.themepark.ThemePark;
import nl.iobyte.themepark.api.attraction.objects.Attraction;
import nl.iobyte.themepark.api.message.MessageKey;
import nl.iobyte.themepark.utils.LocationUtil;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.config.enums.StorageKey;
import nl.iobyte.themeparkconnector.api.message.Text;
import nl.iobyte.themeparkconnector.api.operator.objects.AttractionOperator;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
public class RideOperatorListener implements Listener {
@EventHandler
public void onPlace(SignChangeEvent e) {
if(e.getLines().length < 2)
return;
if(!e.getLine(0).equalsIgnoreCase(ThemeParkConnector.getInstance().getAPI().getConfigurationManager().getString(StorageKey.SIGN_CONTROL_NAME)))
return;
String id = e.getLine(1);
if(!ThemePark.getInstance().getAPI().getAttractionService().hasAttraction(id)) {
e.getPlayer().sendMessage(Text.color("&6&lThemeParkConnectorMC &f➢ &4There is no attraction with ID: &f"+id));
return;
}
if(!ThemeParkConnector.getInstance().getAPI().getOperatorService().hasOperator(id)) {
e.getPlayer().sendMessage(Text.color("&6&lThemeParkConnectorMC &f➢ &4There is no operator for this attraction"));
return;
}
e.setLine(0, Text.color(ThemeParkConnector.getInstance().getAPI().getConfigurationManager().getString(StorageKey.SIGN_CONTROL_TITLE)));
e.getPlayer().sendMessage(Text.color("&6&lThemeParkConnectorMC &f➢ &aSuccessfully made an operator sign"));
}
@EventHandler
public void onClick(PlayerInteractEvent e) {
if(e.getAction() == Action.LEFT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_AIR)
return;
if(e.getClickedBlock() == null)
return;
Block block = e.getClickedBlock();
if(!(block.getState() instanceof Sign))
return;
Sign sign = (Sign) block.getState();
if(!ChatColor.stripColor(sign.getLine(0)).equals(Text.color(ThemeParkConnector.getInstance().getAPI().getConfigurationManager().getString(StorageKey.SIGN_CONTROL_TITLE))))
return;
String id = ChatColor.stripColor(sign.getLine(1));
if(id == null || id.isEmpty())
return;
Player player = e.getPlayer();
if(!ThemePark.getInstance().getAPI().getAttractionService().hasAttraction(id)) {
player.sendMessage(Text.color("&6&lThemeParkConnectorMC &f➢ &4No attraction with ID: &f"+id));
return;
}
Bukkit.dispatchCommand(player, "/tpc connect "+id);
}
}

View file

@ -0,0 +1,180 @@
package nl.iobyte.themeparkconnector.listeners;
import com.google.gson.Gson;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTItem;
import nl.iobyte.themepark.utils.LocationUtil;
import nl.iobyte.themeparkconnector.ThemeParkConnector;
import nl.iobyte.themeparkconnector.api.config.enums.StorageKey;
import nl.iobyte.themeparkconnector.api.event.ticket.TicketScanEvent;
import nl.iobyte.themeparkconnector.api.message.Text;
import nl.iobyte.themeparkconnector.api.show.objects.Ticket;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TicketListener implements Listener {
private final SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
@EventHandler
public void onPlace(SignChangeEvent e) {
if(e.getLines().length < 4)
return;
if(!e.getLine(0).equalsIgnoreCase(ThemeParkConnector.getInstance().getAPI().getConfigurationManager().getString(StorageKey.SIGN_SCAN_NAME)))
return;
Player player = e.getPlayer();
if(e.getLine(1) == null || e.getLine(1).isEmpty()) {
player.sendMessage(Text.color("&4Can't make a TicketScanner with empty show ID."));
return;
}
if(e.getLine(2) == null || e.getLine(2).isEmpty()) {
player.sendMessage(Text.color("&4Can't make a TicketScanner with empty show Date."));
return;
}
String date = e.getLine(2);
if(isValidFormat("HH:mm", date) && isValidFormat("HH:mm dd-MM-yyyy", date)) {
player.sendMessage(Text.color("&4Can't make a TicketScanner with incorrect date, example: 20:00 or 20:00 04-04-2019"));
return;
}
if(e.getLine(3) == null || e.getLine(3).isEmpty()) {
player.sendMessage(Text.color("&4Can't make a TicketScanner with empty teleport location."));
return;
}
String world = player.getLocation().getWorld().getName();
if(LocationUtil.fromString(world + ":" + e.getLine(3)) == null) {
player.sendMessage(Text.color("&4Can't make a TicketScanner with incorrect teleport location."));
return;
}
e.setLine(0, Text.color(ThemeParkConnector.getInstance().getAPI().getConfigurationManager().getString(StorageKey.SIGN_SCAN_TITLE)));
player.sendMessage(Text.color("&aSuccessfully made a TicketScanner"));
}
@EventHandler
public void onScan(PlayerInteractEvent e) {
if(e.getAction() == Action.LEFT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_AIR)
return;
if(e.getClickedBlock() == null)
return;
Block block = e.getClickedBlock();
if(!(block.getState() instanceof Sign))
return;
Sign sign = (Sign) block.getState();
if(!sign.getLine(0).equals(Text.color(ThemeParkConnector.getInstance().getAPI().getConfigurationManager().getString(StorageKey.SIGN_SCAN_TITLE)))) {
return;
}
String id = ChatColor.stripColor(sign.getLine(1));
if(id == null || id.isEmpty())
return;
String date = ChatColor.stripColor(sign.getLine(2));
if(date == null || date.isEmpty())
return;
if(isValidFormat("HH:mm", date) && isValidFormat("HH:mm dd-MM-yyyy", date)) {
System.out.println("Invalid date format");
return;
}
if(isValidFormat("HH:mm dd-MM-yyyy", date))
date = date + " " + format.format(new Date());
Location location = LocationUtil.fromString(sign.getLocation().getWorld().getName() + ":" + sign.getLine(3));
if(location == null) {
System.out.println("Invalid Location");
return;
}
if(e.getItem() == null)
return;
ItemStack item = e.getItem();
if(item.getType() != Material.PAPER)
return;
NBTItem it = new NBTItem(item);
if(!it.hasKey("data")) {
System.out.println("Missing data key");
return;
}
NBTCompound compound = it.getCompound("data");
if(!compound.hasKey("ticket")) {
System.out.println("Missing ticket key");
return;
}
Gson g = new Gson();
Ticket ticket = g.fromJson(it.getCompound("data").getString("ticket"), Ticket.class);
if(ticket == null) {
System.out.println("Couldn't get ticket class using Gson");
return;
}
if(!id.equals(ticket.getShowID())) {
System.out.println("Different show id");
return;
}
if(!date.equals(new SimpleDateFormat("HH:mm dd-MM-yyyy").format(ticket.getShowDate()))) {
System.out.println("Different date");
return;
}
Player player = e.getPlayer();
boolean b = ThemeParkConnector.getInstance().getAPI().getShowService().setValid(ticket);
TicketScanEvent event = new TicketScanEvent(player.getUniqueId(), ticket, b);
Bukkit.getPluginManager().callEvent(event);
int i = player.getInventory().getHeldItemSlot();
player.getInventory().remove(player.getInventory().getItem(i));
if(!b) {
player.sendMessage(Text.color("&4Invalid ticket."));
return;
}
if(!event.isCancelled())
player.teleport(location);
player.sendMessage(Text.color("&6Used ticket for Show: " + item.getItemMeta().getDisplayName()));
}
private static boolean isValidFormat(String format, String value) {
try {
SimpleDateFormat sdf = new SimpleDateFormat(format);
Date date = sdf.parse(value);
if(!value.equals(sdf.format(date)))
date = null;
return date == null;
} catch(ParseException ex) {
return true;
}
}
}

View file

@ -0,0 +1,13 @@
package nl.iobyte.themeparkconnector.logger;
public class ThemeParkConnectorLogger {
/**
* Print message to the console
* @param msg Message string
*/
public static void toConsole(String msg) {
System.out.println("[ThemeParkConnector] "+msg);
}
}

View file

@ -0,0 +1,302 @@
package nl.iobyte.themeparkconnector.sbd;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* License class for SBDevelopment
*
* v1.6 - Changed on 06-08-2020
*
* @author Stijn [SBDeveloper]
* @since 23-12-2019
*/
public class License implements Listener {
/*
This file is part of ThemeParkRidecountAddon.
Copyright (c) 2018-2020 SBDevelopment - All Rights Reserved
Unauthorized copying of this file, via any medium is strictly prohibited
Proprietary and confidential
Written by Stijn Bannink <stijnbannink23@gmail.com>, January 2020
*/
private JavaPlugin plugin; // The plugin instance
private String license; // The license code
private String prefix; // The correct prefix for this plugin
private String invalidReason; // The reason the license is invalid, if null it's not invalid!
private static Boolean valid; // If true, it's valid, if false, it's not valid, if null it's not checked!
/**
* Construct a new license
* @param plugin The Main class [Javaplugin]
* @param prefix The prefix, like TPP or AF
* @param license The license from the config
*/
public License(JavaPlugin plugin, String prefix, String license) {
this.prefix = prefix;
this.plugin = plugin;
this.license = license;
Bukkit.getPluginManager().registerEvents(this, plugin);
validateLicense();
}
@EventHandler
public void onJoin(PlayerJoinEvent e) {
if (this.invalidReason == null) return;
Player p = e.getPlayer();
if (p.isOp() || p.hasPermission("sbd.licensemessages")) {
Bukkit.getScheduler().runTaskLater(this.plugin, () -> p.sendMessage(ChatColor.GOLD + "[" + ChatColor.RED + this.plugin.getName() + ChatColor.GOLD + "] " + ChatColor.RED + "The license is incorrect! Reason: " + ChatColor.GOLD + this.invalidReason), 3 * 20L /* 3 sec */);
}
}
/**
* Check a license
*
*/
private void validateLicense() {
//STEP 1: Check prefix
if (!this.license.split("-")[0].contains(this.prefix)) {
disable("You used the wrong license for this product.");
return;
}
//STEP 2: Send license request
String url = "https://sbdplugins.nl/wp-json/lmfwc/v2/licenses/" + this.license;
JsonObject response;
try {
response = sendGETRequestJSON(url);
} catch (IOException e) {
disable("Couldn't send the request.");
return;
}
if (response == null) {
disable("Couldn't send the request.");
return;
}
JsonObject dataObject = response.get("data").getAsJsonObject();
//STEP 3: Check status
switch(dataObject.get("status").getAsString()) {
case "2":
//Delivered -> Try to activate (double check timesActivated)
break;
case "3":
//Activated!
break;
default:
disable("Your license has a wrong status.");
return;
}
//STEP 4: Check times activated, and if not activated, activate.
if (dataObject.get("timesActivated").isJsonNull() || dataObject.get("timesActivated").getAsString().equalsIgnoreCase("0")) {
activate();
return;
}
//STEP 5: Check expire date
if (dataObject.get("expiresAt").isJsonNull()) {
disable("Your license has no expire date.");
return;
}
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date;
try {
date = format.parse(dataObject.get("expiresAt").getAsString());
} catch (ParseException e) {
e.printStackTrace();
disable("Your license has a wrong expire date.");
return;
}
if (date == null) {
disable("Your license has a wrong expire date.");
return;
}
if (!(date.after(new Date()))) {
disable("Your license has expired.");
return;
}
//STEP 6: Check IP and port.
if (!dataObject.get("ipcheck").getAsBoolean()) {
disable("Your license has been used with another IP. Update it in our Discord.");
return;
}
if (dataObject.get("port").isJsonNull()) {
disable("Your license has no port.");
return;
}
String por = dataObject.get("port").getAsString();
if (!checkPortValue(Bukkit.getServer().getPort(), por)) {
disable("Your license has been used with another Port. Update it in our Discord.");
return;
}
valid = true;
}
/**
* Activate the license
*
*/
private void activate() {
//STEP 1: Send license activate request
String url = "https://sbdplugins.nl/wp-json/lmfwc/v2/licenses/activate/" + this.license + "?port=" + Bukkit.getServer().getPort();
JsonObject response;
try {
response = sendGETRequestJSON(url);
} catch (IOException e) {
disable("Couldn't send the activate request.");
return;
}
if (response == null) {
disable("Couldn't send the activate request.");
return;
}
JsonObject dataObject = response.get("data").getAsJsonObject();
//STEP 2: Check status
switch(dataObject.get("status").getAsString()) {
case "2":
//Delivered -> STILL NOT ACTIVATED?! -> Double check
break;
case "3":
//Activated!
break;
default:
disable("Your license has a wrong status.");
return;
}
//STEP 3: Check times activated, and if still not activated, disable.
if (dataObject.get("timesActivated").isJsonNull() || dataObject.get("timesActivated").getAsString().equalsIgnoreCase("0")) {
disable("Couldn't activate the license.");
}
}
/**
* Disable the plugin (private)
*
* @param reason The disabling reason
*/
private void disable(String reason) {
this.invalidReason = reason;
Bukkit.getScheduler().runTask(this.plugin, () -> {
valid = false;
Bukkit.getLogger().severe("[" + this.plugin.getName() + "] Stopping plugin because licensing system check failed.");
Bukkit.getLogger().severe("[" + this.plugin.getName() + "] Reason: " + reason);
Bukkit.getLogger().severe("[" + this.plugin.getName() + "] Contact the developer if you believe something is wrong on their side.");
Bukkit.getPluginManager().disablePlugin(this.plugin);
});
}
/**
* Send an GET request with JSONObject response
*
* @param uri The URL
*
* @return The JSONObject
* @throws IOException URL errors
*/
private JsonObject sendGETRequestJSON(String uri) throws IOException {
URL url = new URL(uri);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "Mozilla/5.0");
String authStringEnc = "Y2tfMGEzNWEzMWE2NzExNmM3NDg2MGEwYTJhNjUxNGVjZjM4NTBmM2JmMDpjc185NmYxZGNlYjI4MWRkZDExOTBjMzQ3ZjJjYzMwMGNjZTIzYWNhODI1";
con.setRequestProperty("Authorization", "Basic " + authStringEnc);
int code = con.getResponseCode();
if (code == 404) {
disable("404_error");
return null;
}
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
JsonParser parser = new JsonParser();
return parser.parse(response.toString()).getAsJsonObject();
}
private boolean checkPortValue(int input, String dataValue) {
//STEP 1: Check wildcard
if (dataValue.equals("*")) return true;
//STEP 2: Check if equals
try {
int dataVal = Integer.parseInt(dataValue);
return input == dataVal;
} catch (NumberFormatException ignored) {}
//STEP 3: Check if range
if (dataValue.contains("-")) {
String[] dataSplit = dataValue.split("-");
//STEP 3.1: Check if min or max is wildcard
if (dataSplit[0].equals("*") && !dataSplit[1].equals("*")) {
int max = Integer.parseInt(dataSplit[1]);
return input <= max;
} else if (dataSplit[1].equals("*") && !dataSplit[0].equals("*")) {
int min = Integer.parseInt(dataSplit[0]);
return min <= input;
} else {
try {
int min = Integer.parseInt(dataSplit[0]);
int max = Integer.parseInt(dataSplit[1]);
return (min <= input) && (input <= max);
} catch (NumberFormatException ex) {
return false;
}
}
}
//Else, invalid value
return false;
}
/**
* Check if the license is valid
*
* @return true -> VALID, false -> INVALID, null -> UNCHECKED
*/
public static boolean isValid() {
return valid;
}
}

View file

@ -0,0 +1,120 @@
package nl.iobyte.themeparkconnector.sbd;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.function.BiConsumer;
/**
* Update class for SBDevelopment
* @author Stijn [SBDeveloper]
* @since 18-01-2020
* @version 1.2
*
* © Stijn Bannink <stijnbannink23@gmail.com> - All rights reserved.
*/
public class UpdateManager {
private static String SPIGOT_API = "http://api.spiget.org/v2/resources/%d/versions?size=1&sort=-releaseDate";
private static String SBDPLUGINS_API = "http://updates.sbdplugins.nl:4000/api/resources/%d";
private Plugin plugin;
private String currentVersion;
private int resourceID;
private CheckType type;
private BiConsumer<VersionResponse, String> versionResponse;
/**
* Construct a new UpdateManager
*
* @param plugin The javaplugin (Main class)
* @param resourceID The resourceID on spigot/sbdplugins
* @param type The check type
*/
public UpdateManager(Plugin plugin, int resourceID, CheckType type) {
this.plugin = plugin;
this.currentVersion = plugin.getDescription().getVersion();
this.resourceID = resourceID;
this.type = type;
}
/**
* Handle the response given by check();
* @param versionResponse The response
* @return The updatemanager
*/
public UpdateManager handleResponse(BiConsumer<VersionResponse, String> versionResponse) {
this.versionResponse = versionResponse;
return this;
}
/**
* Check for a new version
*/
public void check() {
Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> {
try {
HttpURLConnection con = null;
if (type == CheckType.SPIGOT) {
con = (HttpURLConnection) new URL(String.format(SPIGOT_API, this.resourceID)).openConnection();
} else if (type == CheckType.SBDPLUGINS) {
con = (HttpURLConnection) new URL(String.format(SBDPLUGINS_API, this.resourceID)).openConnection();
}
if (con == null) return;
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "Mozilla/5.0");
String version = null;
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
JsonParser parser = new JsonParser();
if (type == CheckType.SPIGOT) {
JsonArray array = parser.parse(response.toString()).getAsJsonArray();
version = array.get(0).getAsJsonObject().get("name").getAsString();
} else if (type == CheckType.SBDPLUGINS) {
JsonObject object = parser.parse(response.toString()).getAsJsonObject();
version = object.get("data").getAsJsonObject().get("version").getAsString();
}
if (version == null) return;
boolean latestVersion = version.equalsIgnoreCase(this.currentVersion);
String finalVersion = version;
Bukkit.getScheduler().runTask(this.plugin, () -> this.versionResponse.accept(latestVersion ? VersionResponse.LATEST : VersionResponse.FOUND_NEW, latestVersion ? this.currentVersion : finalVersion));
} catch (IOException | NullPointerException e) {
e.printStackTrace();
Bukkit.getScheduler().runTask(this.plugin, () -> this.versionResponse.accept(VersionResponse.UNAVAILABLE, null));
}
});
}
public enum CheckType {
SPIGOT, SBDPLUGINS
}
public enum VersionResponse {
LATEST, FOUND_NEW, UNAVAILABLE
}
}

View file

@ -0,0 +1,14 @@
version: 1.0
prefix: '&6&lThemeParkConnectorMC &r&f➢'
client:
connect:
click: "{prefix} &fClick here to connect to the &6&lRideOperator"
hover: "&6Minecraft will prompt you to open the web client when you click this message"
unable: "{prefix} &4Currently unable to generate a session"
generate: "{prefix} &6Attempting to generate session..."
connection:
exists: "{prefix} &4Already connected to RideOperator"
open: "{prefix} &aSuccessfully connected to RideOperator"
closed: "{prefix} &4Connection with RideOperator was closed"

View file

@ -0,0 +1,11 @@
name: ThemeParkConnector
version: 3.0.0
author: IOByte
website: 'https://www.iobyte.nl'
main: nl.iobyte.themeparkconnector.ThemeParkConnector
depend: [ThemePark]
softdepend: [Vault,PlaceholderAPI,Train_Carts,Multiverse-Core,MultiWorld]
api-version: 1.13
commands:
tpc:
aliases: [themeparkconnector]

View file

@ -0,0 +1,16 @@
version: 1.0
license: ''
socket:
id: 'themepark'
url: 'websocket.iobyte.nl'
panel: 'panel.example.com/control/%ID%/%TOKEN%'
sign:
control:
name: '[Operator]'
title: '&f[&6&lOperator&f]'
scan:
name: '[TicketScan]'
title: '&f[&6&lTicketScan&f]'

35
themeparkconnector.iml Normal file
View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_11">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.spigotmc:spigot-api:1.12.2-R0.1-SNAPSHOT" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: commons-lang:commons-lang:2.6" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.googlecode.json-simple:json-simple:1.1.1" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: junit:junit:4.10" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.hamcrest:hamcrest-core:1.1" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.google.guava:guava:21.0" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: com.google.code.gson:gson:2.8.0" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.yaml:snakeyaml:1.19" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: net.md-5:bungeecord-chat:1.12-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: io.socket:socket.io-client:1.0.1" level="project" />
<orderEntry type="library" name="Maven: io.socket:engine.io-client:1.0.1" level="project" />
<orderEntry type="library" name="Maven: com.squareup.okhttp3:okhttp:3.12.12" level="project" />
<orderEntry type="library" name="Maven: com.squareup.okio:okio:1.15.0" level="project" />
<orderEntry type="library" name="Maven: org.json:json:20090211" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: nl.iobyte:themepark:3.0.0" level="project" />
<orderEntry type="library" name="Maven: de.mkammerer.snowflake-id:snowflake-id:0.0.1" level="project" />
<orderEntry type="library" name="Maven: de.tr7zw:item-nbt-api:2.8.0" level="project" />
<orderEntry type="library" name="Maven: de.tr7zw:functional-annotations:0.1-SNAPSHOT" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: net.milkbowl.vault:VaultAPI:1.7" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.bukkit:bukkit:1.13.1-R0.1-SNAPSHOT" level="project" />
</component>
</module>