Compare commits
16 commits
master
...
1.9-rewrit
Author | SHA1 | Date | |
---|---|---|---|
TheClashFruit | 9172c74955 | ||
TheClashFruit | 65108639b0 | ||
TheClashFruit | 15a081e1b2 | ||
TheClashFruit | ec74347012 | ||
TheClashFruit | b5a03a71e2 | ||
TheClashFruit | 77bca40bef | ||
TheClashFruit | 988cfbdd5b | ||
TheClashFruit | 0179fae1b8 | ||
TheClashFruit | 1fe2412786 | ||
TheClashFruit | a1c1c50c5c | ||
TheClashFruit | 282387aabe | ||
TheClashFruit | d3fb96b681 | ||
TheClashFruit | 032c94c716 | ||
TheClashFruit | db42422328 | ||
TheClashFruit | 836d9f62ee | ||
TheClashFruit | 62a8d78d2c |
11
LICENSE
Normal file
11
LICENSE
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
TheClashFruit's Source Only License v1
|
||||||
|
|
||||||
|
Copyright (c) 2023-2024 CRSS
|
||||||
|
|
||||||
|
You may not:
|
||||||
|
* Distribute or modify the software.
|
||||||
|
* Use the software for any commercial purpose.
|
||||||
|
* Include the software in any other product.
|
||||||
|
|
||||||
|
This software is provided "as-is" and without warranty.
|
||||||
|
The CRSS team is not liable for any damages resulting from the use of this software.
|
26
README.md
Normal file
26
README.md
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# CRSS Server's Plugin
|
||||||
|
|
||||||
|
This is the official plugin for the CRSS Server.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
* [/](./docs)
|
||||||
|
* [gateway.md](./docs/gateway.md)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
```
|
||||||
|
TheClashFruit's Source Only License v1
|
||||||
|
|
||||||
|
Copyright (c) 2023-2024 CRSS
|
||||||
|
|
||||||
|
You may not:
|
||||||
|
* Distribute or modify the software.
|
||||||
|
* Use the software for any commercial purpose.
|
||||||
|
* Include the software in any other product.
|
||||||
|
|
||||||
|
This software is provided "as-is" and without warranty.
|
||||||
|
The CRSS team is not liable for any damages resulting from the use of this software.
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [LICENSE](LICENSE) file for more information.
|
34
build.gradle
34
build.gradle
|
@ -15,32 +15,26 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
maven {
|
maven {
|
||||||
name = "Vault"
|
name = "Sonatype"
|
||||||
url = "https://nexus.hc.to/content/repositories/pub_releases"
|
url = "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||||
}
|
}
|
||||||
|
|
||||||
maven {
|
maven {
|
||||||
name = "Sonatype"
|
name "Minecraft Libraries"
|
||||||
url = "https://oss.sonatype.org/content/repositories/snapshots/"
|
url "https://libraries.minecraft.net/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testImplementation platform('org.junit:junit-bom:5.9.1')
|
compileOnly("org.spigotmc:spigot-api:${project.bukkit_version}")
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
compileOnly("com.mojang:authlib:1.5.21")
|
||||||
|
|
||||||
shadow implementation("org.spigotmc:spigot-api:${project.bukkit_version}")
|
implementation 'org.eclipse.jetty:jetty-server:12.0.8'
|
||||||
shadow implementation("net.milkbowl.vault:VaultAPI:1.5")
|
implementation 'org.eclipse.jetty.ee10:jetty-ee10-servlet:12.0.8'
|
||||||
|
implementation 'org.eclipse.jetty.ee10.websocket:jetty-ee10-websocket-jetty-server:12.0.8'
|
||||||
implementation 'org.eclipse.jetty:jetty-server:9.4.52.v20230823'
|
|
||||||
implementation 'org.eclipse.jetty:jetty-servlet:9.4.52.v20230823'
|
|
||||||
implementation 'org.eclipse.jetty.websocket:websocket-server:9.4.52.v20230823'
|
|
||||||
implementation 'org.eclipse.jetty.websocket:websocket-servlet:9.4.52.v20230823'
|
|
||||||
|
|
||||||
implementation 'javax.servlet:javax.servlet-api:4.0.1'
|
|
||||||
implementation 'javax.websocket:javax.websocket-api:1.1'
|
|
||||||
|
|
||||||
implementation 'com.google.code.gson:gson:2.10.1'
|
implementation 'com.google.code.gson:gson:2.10.1'
|
||||||
|
implementation 'org.mariadb.jdbc:mariadb-java-client:3.4.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
|
@ -83,6 +77,14 @@ shadowJar {
|
||||||
// exclude devrunner from jar
|
// exclude devrunner from jar
|
||||||
exclude('me/theclashfruit/devrunner')
|
exclude('me/theclashfruit/devrunner')
|
||||||
|
|
||||||
|
// relocate stuff
|
||||||
|
relocate('com.google.gson', 'me.theclashfruit.deps.gson')
|
||||||
|
relocate('org.eclipse.jetty', 'me.theclashfruit.deps.jetty')
|
||||||
|
relocate('jakarta', 'me.theclashfruit.deps.jakarta')
|
||||||
|
relocate('org.slf4j', 'me.theclashfruit.deps.slf4j')
|
||||||
|
relocate('org.objectweb.asm', 'me.theclashfruit.deps.asm')
|
||||||
|
// relocate('org.mariadb', 'me.theclashfruit.deps.mariadb')
|
||||||
|
|
||||||
archiveBaseName.set(rootProject.name)
|
archiveBaseName.set(rootProject.name)
|
||||||
archiveClassifier.set('')
|
archiveClassifier.set('')
|
||||||
archiveVersion.set(project.version)
|
archiveVersion.set(project.version)
|
||||||
|
|
267
docs/gateway.md
Normal file
267
docs/gateway.md
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
# Gateway
|
||||||
|
|
||||||
|
Listen to events from the server such as player movement.
|
||||||
|
|
||||||
|
Path: `ws(s)://crss.blurryface.xyz/api/v2/gateway`
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
* [Requesting API Endpoints](#requesting-api-endpoints)
|
||||||
|
* [Subscribing to Events](#subscribing-to-events)
|
||||||
|
* [Ping-Pong](#ping-pong)
|
||||||
|
* [Endpoints](#endpoints)
|
||||||
|
* [`status`](#status)
|
||||||
|
* [`players`](#players)
|
||||||
|
* [`tile`](#tile)
|
||||||
|
* [Events](#events)
|
||||||
|
* [`player_join`](#player_join)
|
||||||
|
* [`player_leave`](#player_leave)
|
||||||
|
* [`player_move`](#player_move)
|
||||||
|
* [`player_chat`](#player_chat)
|
||||||
|
* [`player_death`](#player_death)
|
||||||
|
|
||||||
|
## Requesting API Endpoints
|
||||||
|
|
||||||
|
Send a JSON object with the `type` field set to `api` and the `endpoints` field set to an array of endpoints you want to request.
|
||||||
|
|
||||||
|
### Possible Endpoints
|
||||||
|
|
||||||
|
* `status`
|
||||||
|
* `players`
|
||||||
|
* `tile`
|
||||||
|
|
||||||
|
### Example
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "api",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"path": "status",
|
||||||
|
"data": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "players",
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Subscribing to Events
|
||||||
|
|
||||||
|
Send a JSON object with the `type` field set to `subscribe` and the `events` field set to an array of events you want to subscribe to.
|
||||||
|
|
||||||
|
### Possible Events
|
||||||
|
|
||||||
|
* `player_join`
|
||||||
|
* `player_leave`
|
||||||
|
* `player_move`
|
||||||
|
* `player_chat`
|
||||||
|
* `player_death`
|
||||||
|
|
||||||
|
### Example
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "subscribe",
|
||||||
|
"events": [
|
||||||
|
"player_join",
|
||||||
|
"player_leave",
|
||||||
|
"player_move",
|
||||||
|
"player_chat",
|
||||||
|
"player_death"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ping-Pong
|
||||||
|
|
||||||
|
You need to send a "ping" message every 5 minutes to keep the connection alive:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "ping"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The server will respond with:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "pong"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If that doesn't happen, connect to the WebSocket again.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
### `status`
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "api",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"path": "status",
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"type": "api",
|
||||||
|
"endpoint": "status",
|
||||||
|
"response": "{ ... }" // see status endpoint docs
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `players`
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "api",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"path": "players",
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"type": "api",
|
||||||
|
"endpoint": "players",
|
||||||
|
"response": "{ ... }" // see players endpoint docs
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `tile`
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "api",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"path": "tile",
|
||||||
|
"data": {
|
||||||
|
"world": "world",
|
||||||
|
"x": 0,
|
||||||
|
"z": 0,
|
||||||
|
"size": 256,
|
||||||
|
"zoom": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
"type": "api",
|
||||||
|
"endpoint": "tile",
|
||||||
|
"response": "...", // base64 encoded PNG image
|
||||||
|
"request": { // the original request data
|
||||||
|
"world": "world",
|
||||||
|
"x": 0,
|
||||||
|
"z": 0,
|
||||||
|
"size": 256,
|
||||||
|
"zoom": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Events
|
||||||
|
|
||||||
|
### `player_join`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "player_join",
|
||||||
|
"player": {
|
||||||
|
"name": "TheClashFruit",
|
||||||
|
"uuid": "942ae64d-e4e5-4dd0-a153-b6aba7817ca9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `player_leave`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "player_leave",
|
||||||
|
"player": {
|
||||||
|
"name": "TheClashFruit",
|
||||||
|
"uuid": "942ae64d-e4e5-4dd0-a153-b6aba7817ca9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `player_move`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "player_move",
|
||||||
|
"player": {
|
||||||
|
"name": "TheClashFruit",
|
||||||
|
"uuid": "942ae64d-e4e5-4dd0-a153-b6aba7817ca9"
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"distance": 0.0785923757599716,
|
||||||
|
"from": {
|
||||||
|
"world": "world",
|
||||||
|
"x": 98.31441469694991,
|
||||||
|
"y": 83.0,
|
||||||
|
"z": 254.93694099796153
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"world": "world",
|
||||||
|
"x": 98.38312726494456,
|
||||||
|
"y": 83.0,
|
||||||
|
"z": 254.8987920198995
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `player_chat`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "player_chat",
|
||||||
|
"player": {
|
||||||
|
"name": "TheClashFruit",
|
||||||
|
"uuid": "942ae64d-e4e5-4dd0-a153-b6aba7817ca9"
|
||||||
|
},
|
||||||
|
"message": "Hello, world!"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `player_death`
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "player_death",
|
||||||
|
"player": {
|
||||||
|
"name": "TheClashFruit",
|
||||||
|
"uuid": "942ae64d-e4e5-4dd0-a153-b6aba7817ca9"
|
||||||
|
},
|
||||||
|
"message": "TheClashFruit was slain by a zombie."
|
||||||
|
}
|
||||||
|
```
|
|
@ -1,2 +1,2 @@
|
||||||
bukkit_version = 1.8.8-R0.1-SNAPSHOT
|
bukkit_version = 1.10.2-R0.1-SNAPSHOT
|
||||||
plugin_version = 2.0.0-alpha+mc1.8.8
|
plugin_version = 2.0.0-alpha+mc1.9.4
|
120
src/main/java/me/theclashfruit/crss/CRSSPlugin.java
Normal file
120
src/main/java/me/theclashfruit/crss/CRSSPlugin.java
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
package me.theclashfruit.crss;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.backend.error.ErrorHandler;
|
||||||
|
import me.theclashfruit.crss.backend.error.GoneServlet;
|
||||||
|
import me.theclashfruit.crss.backend.IndexServlet;
|
||||||
|
import me.theclashfruit.crss.backend.v2.map.MarkersServlet;
|
||||||
|
import me.theclashfruit.crss.backend.v2.map.TileServlet;
|
||||||
|
import me.theclashfruit.crss.backend.v2.PlayersServlet;
|
||||||
|
import me.theclashfruit.crss.backend.v2.StatusServlet;
|
||||||
|
import me.theclashfruit.crss.backend.v2.gateway.GatewayServlet;
|
||||||
|
import me.theclashfruit.crss.banking.commands.AtmCommand;
|
||||||
|
import me.theclashfruit.crss.banking.commands.DatabaseCheck;
|
||||||
|
import me.theclashfruit.crss.listeners.InventoryListener;
|
||||||
|
import me.theclashfruit.crss.listeners.PlayerListener;
|
||||||
|
import me.theclashfruit.crss.utils.ReqMiddleware;
|
||||||
|
import me.theclashfruit.crss.utils.SqlUtil;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||||
|
import org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletContainerInitializer;
|
||||||
|
import org.eclipse.jetty.server.*;
|
||||||
|
import org.eclipse.jetty.util.Jetty;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class CRSSPlugin extends JavaPlugin {
|
||||||
|
Server server = new Server(getConfig().getInt("web.port"));
|
||||||
|
Connector connector = new ServerConnector(server);
|
||||||
|
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||||
|
|
||||||
|
public static Logger LOGGER = Bukkit.getLogger();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
getLogger().info("Plugin enabled!");
|
||||||
|
|
||||||
|
saveDefaultConfig();
|
||||||
|
|
||||||
|
saveResource("unmined_settings.json", false);
|
||||||
|
saveResource("data/markers.json", false);
|
||||||
|
|
||||||
|
PluginManager pluginManager = getServer().getPluginManager();
|
||||||
|
|
||||||
|
context.setContextPath("/api");
|
||||||
|
|
||||||
|
// slash
|
||||||
|
context.addServlet(IndexServlet.class, "");
|
||||||
|
|
||||||
|
// v1
|
||||||
|
context.addServlet(GoneServlet.class, "/v1/*");
|
||||||
|
|
||||||
|
// v2
|
||||||
|
context.addServlet(StatusServlet.class, "/v2/status");
|
||||||
|
context.addServlet(PlayersServlet.class, "/v2/players");
|
||||||
|
context.addServlet(GatewayServlet.class, "/v2/gateway");
|
||||||
|
|
||||||
|
// map api
|
||||||
|
if (getConfig().getBoolean("web.map.enabled")) {
|
||||||
|
context.addServlet(TileServlet.class, "/v2/map/tile/*");
|
||||||
|
context.addServlet(MarkersServlet.class, "/v2/map/markers");
|
||||||
|
}
|
||||||
|
|
||||||
|
// websocket
|
||||||
|
JettyWebSocketServletContainerInitializer.configure(context, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
server.setServerInfo("crss/" + getDescription().getVersion() + "+jetty" + Jetty.VERSION);
|
||||||
|
|
||||||
|
ReqMiddleware reqMiddleware = new ReqMiddleware();
|
||||||
|
|
||||||
|
reqMiddleware.setHandler(context);
|
||||||
|
|
||||||
|
server.setHandler(reqMiddleware);
|
||||||
|
server.setErrorHandler(new ErrorHandler());
|
||||||
|
|
||||||
|
server.addConnector(connector);
|
||||||
|
|
||||||
|
if (getConfig().getBoolean("web.enabled") && getConfig().getBoolean("web.api.enabled")) {
|
||||||
|
server.start();
|
||||||
|
|
||||||
|
getLogger().info("API server started on port " + getConfig().getInt("web.port"));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().throwing(this.getName(), "onEnable", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Events
|
||||||
|
pluginManager.registerEvents(new PlayerListener(), this);
|
||||||
|
pluginManager.registerEvents(new InventoryListener(), this);
|
||||||
|
|
||||||
|
// Commands
|
||||||
|
getCommand("atm").setExecutor(new AtmCommand());
|
||||||
|
getCommand("checkdb").setExecutor(new DatabaseCheck());
|
||||||
|
|
||||||
|
// Database
|
||||||
|
SqlUtil.setConnectionDetails(
|
||||||
|
getConfig().getString("sql.connection"),
|
||||||
|
getConfig().getString("sql.username"),
|
||||||
|
getConfig().getString("sql.password")
|
||||||
|
);
|
||||||
|
|
||||||
|
SqlUtil.openConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
getLogger().info("Plugin disabled!");
|
||||||
|
|
||||||
|
try {
|
||||||
|
server.stop();
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().throwing(this.getName(), "onDisable", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
SqlUtil.closeConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,121 +0,0 @@
|
||||||
package me.theclashfruit.crss;
|
|
||||||
|
|
||||||
import me.theclashfruit.crss.api.ChatServlet;
|
|
||||||
import me.theclashfruit.crss.api.GatewaySocket;
|
|
||||||
import me.theclashfruit.crss.api.PlayersServlet;
|
|
||||||
import me.theclashfruit.crss.api.StatusServlet;
|
|
||||||
import me.theclashfruit.crss.commands.BalanceCommand;
|
|
||||||
import me.theclashfruit.crss.listener.ChatListener;
|
|
||||||
import me.theclashfruit.crss.listener.PlayerJoinListener;
|
|
||||||
import me.theclashfruit.crss.listener.SleepingListener;
|
|
||||||
import me.theclashfruit.crss.map.MapServlet;
|
|
||||||
import me.theclashfruit.crss.models.SocketData;
|
|
||||||
import me.theclashfruit.crss.models.SocketMessage;
|
|
||||||
import net.milkbowl.vault.economy.Economy;
|
|
||||||
import org.bukkit.plugin.PluginManager;
|
|
||||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
import org.eclipse.jetty.server.Connector;
|
|
||||||
import org.eclipse.jetty.server.Server;
|
|
||||||
import org.eclipse.jetty.server.ServerConnector;
|
|
||||||
import org.eclipse.jetty.servlet.ServletHandler;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public class Plugin extends JavaPlugin {
|
|
||||||
GatewaySocket chatSocket;
|
|
||||||
|
|
||||||
Server server = new Server(25580);
|
|
||||||
Connector connector = new ServerConnector(server);
|
|
||||||
ServletHandler handler = new ServletHandler();
|
|
||||||
|
|
||||||
private static Economy economy = null;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnable() {
|
|
||||||
getLogger().info("Plugin enabled!");
|
|
||||||
|
|
||||||
saveDefaultConfig();
|
|
||||||
|
|
||||||
PluginManager pluginManager = getServer().getPluginManager();
|
|
||||||
|
|
||||||
if (!setupEconomy()) {
|
|
||||||
getLogger().severe("Vault not found! Disabling plugin.");
|
|
||||||
|
|
||||||
// pluginManager.disablePlugin(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create api server
|
|
||||||
// ContextHandler context = new ContextHandler(new ApiHandler(), "/v1");
|
|
||||||
|
|
||||||
if(getConfig().getBoolean("web.api.enabled")) {
|
|
||||||
handler.addServletWithMapping(ChatServlet.class, "/api/v1/gateway");
|
|
||||||
handler.addServletWithMapping(PlayersServlet.class, "/api/v1/players");
|
|
||||||
handler.addServletWithMapping(StatusServlet.class, "/api/v1/status");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(getConfig().getBoolean("web.map.enabled")) {
|
|
||||||
handler.addServletWithMapping(MapServlet.class, "/map");
|
|
||||||
|
|
||||||
if (!new File(this.getDataFolder(), getConfig().getString("web.map.path")).exists())
|
|
||||||
new File(this.getDataFolder(), getConfig().getString("web.map.path")).mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
server.addConnector(connector);
|
|
||||||
server.setHandler(handler);
|
|
||||||
|
|
||||||
if (!new File(this.getDataFolder(), "/natives").exists())
|
|
||||||
new File(this.getDataFolder(), "/natives").mkdirs();
|
|
||||||
|
|
||||||
try {
|
|
||||||
if(getConfig().getBoolean("web.enabled"))
|
|
||||||
server.start();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// register events
|
|
||||||
pluginManager.registerEvents(new SleepingListener(), this);
|
|
||||||
pluginManager.registerEvents(new ChatListener(), this);
|
|
||||||
pluginManager.registerEvents(new PlayerJoinListener(), this);
|
|
||||||
|
|
||||||
// register commands
|
|
||||||
getCommand("balance").setExecutor(new BalanceCommand());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisable() {
|
|
||||||
getLogger().info("Plugin disabled!");
|
|
||||||
|
|
||||||
// stop chat socket
|
|
||||||
try {
|
|
||||||
GatewaySocket.broadcast(new SocketMessage(
|
|
||||||
"serverStop",
|
|
||||||
new SocketData(
|
|
||||||
null,
|
|
||||||
"Server stopped.",
|
|
||||||
false
|
|
||||||
)
|
|
||||||
));
|
|
||||||
|
|
||||||
server.stop();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean setupEconomy() {
|
|
||||||
RegisteredServiceProvider<Economy> economyProvider = getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
|
|
||||||
|
|
||||||
if (economyProvider != null)
|
|
||||||
economy = economyProvider.getProvider();
|
|
||||||
|
|
||||||
return (economy != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Economy getEconomy() {
|
|
||||||
return economy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
package me.theclashfruit.crss.api;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
|
||||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
|
||||||
|
|
||||||
import javax.servlet.annotation.WebServlet;
|
|
||||||
|
|
||||||
@WebServlet(name = "Chat WebSocket API")
|
|
||||||
public class ChatServlet extends WebSocketServlet {
|
|
||||||
@Override
|
|
||||||
public void configure(WebSocketServletFactory factory) {
|
|
||||||
factory.register(GatewaySocket.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
package me.theclashfruit.crss.api;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import me.theclashfruit.crss.models.GatewayConnection;
|
|
||||||
import me.theclashfruit.crss.models.SocketData;
|
|
||||||
import me.theclashfruit.crss.models.SocketMessage;
|
|
||||||
import org.eclipse.jetty.websocket.api.Session;
|
|
||||||
import org.eclipse.jetty.websocket.api.annotations.*;
|
|
||||||
|
|
||||||
import javax.websocket.EncodeException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
|
||||||
|
|
||||||
import static org.bukkit.Bukkit.getLogger;
|
|
||||||
|
|
||||||
@WebSocket
|
|
||||||
public class GatewaySocket {
|
|
||||||
private static final Set<GatewaySocket> gatewayConnections = new CopyOnWriteArraySet<>();
|
|
||||||
|
|
||||||
private Session session;
|
|
||||||
|
|
||||||
@OnWebSocketConnect
|
|
||||||
public void onConnect(Session session) throws IOException {
|
|
||||||
this.session = session;
|
|
||||||
|
|
||||||
gatewayConnections.add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnWebSocketMessage
|
|
||||||
public void onMessage(String message) throws IOException, EncodeException {
|
|
||||||
getLogger().info(message);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Gson gson = new Gson();
|
|
||||||
GatewayConnection socketMessage = gson.fromJson(message, GatewayConnection.class);
|
|
||||||
|
|
||||||
getLogger().info(socketMessage.getClientName());
|
|
||||||
|
|
||||||
for (String subscription : socketMessage.getSubscriptions()) {
|
|
||||||
getLogger().info(subscription);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
getLogger().throwing(GatewaySocket.class.getName(), "WebSocket", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnWebSocketClose
|
|
||||||
public void onClose(int statusCode, String reason) throws IOException {
|
|
||||||
gatewayConnections.remove(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnWebSocketError
|
|
||||||
public void onError(Throwable throwable) {
|
|
||||||
getLogger().throwing(GatewaySocket.class.getName(), "WebSocket", throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void broadcast(SocketMessage message) {
|
|
||||||
gatewayConnections.forEach(endpoint -> {
|
|
||||||
try {
|
|
||||||
Gson gson = new Gson();
|
|
||||||
|
|
||||||
endpoint
|
|
||||||
.session
|
|
||||||
.getRemote()
|
|
||||||
.sendString(
|
|
||||||
gson.toJson(message)
|
|
||||||
);
|
|
||||||
} catch (IOException e) {
|
|
||||||
getLogger().throwing(GatewaySocket.class.getName(), "WebSocket", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package me.theclashfruit.crss.api;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import me.theclashfruit.crss.models.PlayerList;
|
|
||||||
import me.theclashfruit.crss.models.PlayerLocation;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.annotation.WebServlet;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
@WebServlet(name = "Players API")
|
|
||||||
public class PlayersServlet extends HttpServlet {
|
|
||||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
|
||||||
response.setContentType("application/json");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
|
|
||||||
var onlinePlayers =Bukkit.getOnlinePlayers().toArray();
|
|
||||||
|
|
||||||
PlayerList[] playerList = new PlayerList[onlinePlayers.length];
|
|
||||||
|
|
||||||
for (int i = 0; i < onlinePlayers.length; i++) {
|
|
||||||
Player player = (Player) onlinePlayers[i];
|
|
||||||
|
|
||||||
playerList[i] = new PlayerList(
|
|
||||||
player.getUniqueId().toString(),
|
|
||||||
player.getDisplayName(),
|
|
||||||
player.getGameMode().getValue(),
|
|
||||||
player.getWorld().getName(),
|
|
||||||
new PlayerLocation(
|
|
||||||
player.getLocation().getX(),
|
|
||||||
player.getLocation().getY(),
|
|
||||||
player.getLocation().getZ()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
|
||||||
response.getWriter().println(gson.toJson(playerList));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
package me.theclashfruit.crss.api;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import me.theclashfruit.crss.models.Status;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.annotation.WebServlet;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
@WebServlet(name = "Status API")
|
|
||||||
public class StatusServlet extends HttpServlet {
|
|
||||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
|
||||||
response.setContentType("application/json");
|
|
||||||
|
|
||||||
Gson gson = new Gson();
|
|
||||||
|
|
||||||
Status status = new Status(
|
|
||||||
true,
|
|
||||||
Bukkit.getBukkitVersion(),
|
|
||||||
Bukkit.getOnlinePlayers().toArray().length,
|
|
||||||
Bukkit.getMaxPlayers(),
|
|
||||||
Bukkit.getMotd()
|
|
||||||
);
|
|
||||||
|
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
|
||||||
response.getWriter().println(gson.toJson(status));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package me.theclashfruit.crss.backend;
|
||||||
|
|
||||||
|
import jakarta.servlet.annotation.WebServlet;
|
||||||
|
import jakarta.servlet.http.HttpServlet;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import me.theclashfruit.crss.models.IndexResponse;
|
||||||
|
import me.theclashfruit.crss.models.Version;
|
||||||
|
import me.theclashfruit.crss.utils.JsonUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@WebServlet(name = "API Index")
|
||||||
|
public class IndexServlet extends HttpServlet {
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
|
||||||
|
res.setContentType("application/json");
|
||||||
|
|
||||||
|
IndexResponse response = new IndexResponse(
|
||||||
|
"2.0.0-alpha+mc1.9.4",
|
||||||
|
new ArrayList<>(
|
||||||
|
) {{
|
||||||
|
add(new Version(
|
||||||
|
"1.0.0+mc1.1-alpha",
|
||||||
|
"/api/v1",
|
||||||
|
true
|
||||||
|
));
|
||||||
|
add(new Version(
|
||||||
|
"2.0.0-alpha+mc1.9.4",
|
||||||
|
"/api/v2",
|
||||||
|
false
|
||||||
|
));
|
||||||
|
}}
|
||||||
|
);
|
||||||
|
|
||||||
|
String resJson = JsonUtil.gson.toJson(response);
|
||||||
|
|
||||||
|
res.setStatus(200);
|
||||||
|
res.getWriter().println(resJson);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package me.theclashfruit.crss.backend.error;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.models.ErrorResponse;
|
||||||
|
import org.eclipse.jetty.http.MimeTypes;
|
||||||
|
import org.eclipse.jetty.server.Request;
|
||||||
|
import org.eclipse.jetty.server.Response;
|
||||||
|
import org.eclipse.jetty.util.Callback;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import static org.eclipse.jetty.server.handler.ErrorHandler.ERROR_MESSAGE;
|
||||||
|
|
||||||
|
public class ErrorHandler implements Request.Handler {
|
||||||
|
@Override
|
||||||
|
public boolean handle(Request req, Response res, Callback callback) throws Exception {
|
||||||
|
int status = res.getStatus();
|
||||||
|
|
||||||
|
MimeTypes.Type type = MimeTypes.Type.APPLICATION_JSON;
|
||||||
|
|
||||||
|
res.getHeaders().put(type.getContentTypeField(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
String message = (String) req.getAttribute(ERROR_MESSAGE);
|
||||||
|
|
||||||
|
ErrorResponse error = new ErrorResponse(
|
||||||
|
status,
|
||||||
|
status == 404 ? "This endpoint does not exist." : (message != null ? message : "An error occurred.")
|
||||||
|
);
|
||||||
|
|
||||||
|
String resJson = error.toJson();
|
||||||
|
|
||||||
|
res.write(true, ByteBuffer.wrap(resJson.getBytes()), callback);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package me.theclashfruit.crss.backend.error;
|
||||||
|
|
||||||
|
import jakarta.servlet.annotation.WebServlet;
|
||||||
|
import jakarta.servlet.http.HttpServlet;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import me.theclashfruit.crss.models.ErrorResponse;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@WebServlet(name = "API Version Gone")
|
||||||
|
public class GoneServlet extends HttpServlet {
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
|
||||||
|
res.setContentType("application/json");
|
||||||
|
|
||||||
|
ErrorResponse error = new ErrorResponse(
|
||||||
|
410,
|
||||||
|
"This version of the API is no longer available."
|
||||||
|
);
|
||||||
|
|
||||||
|
String resJson = error.toJson();
|
||||||
|
|
||||||
|
res.setStatus(410);
|
||||||
|
res.getWriter().println(resJson);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package me.theclashfruit.crss.backend.v2;
|
||||||
|
|
||||||
|
import jakarta.servlet.annotation.WebServlet;
|
||||||
|
import jakarta.servlet.http.HttpServlet;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import me.theclashfruit.crss.models.PlayerLevels;
|
||||||
|
import me.theclashfruit.crss.models.Player;
|
||||||
|
import me.theclashfruit.crss.models.PlayerPosition;
|
||||||
|
import me.theclashfruit.crss.models.PlayersResponse;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@WebServlet(name = "Players API")
|
||||||
|
public class PlayersServlet extends HttpServlet {
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
|
||||||
|
res.setContentType("application/json");
|
||||||
|
|
||||||
|
ArrayList<Player> players = new ArrayList<>();
|
||||||
|
|
||||||
|
Bukkit.getOnlinePlayers().forEach(player -> {
|
||||||
|
players.add(new Player(
|
||||||
|
player.getUniqueId().toString(),
|
||||||
|
player.getName(),
|
||||||
|
player.getGameMode().getValue(), // TODO: Find a non-deprecated way.
|
||||||
|
new PlayerLevels(
|
||||||
|
player.getHealth(),
|
||||||
|
player.getFoodLevel(),
|
||||||
|
player.getSaturation()
|
||||||
|
),
|
||||||
|
new PlayerPosition(
|
||||||
|
player.getLocation().getX(),
|
||||||
|
player.getLocation().getY(),
|
||||||
|
player.getLocation().getZ()
|
||||||
|
)
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
PlayersResponse response = new PlayersResponse(
|
||||||
|
Bukkit.getOnlinePlayers().size(),
|
||||||
|
players
|
||||||
|
);
|
||||||
|
|
||||||
|
String resJson = response.toJson();
|
||||||
|
|
||||||
|
res.setStatus(200);
|
||||||
|
res.getWriter().println(resJson);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package me.theclashfruit.crss.backend.v2;
|
||||||
|
|
||||||
|
import jakarta.servlet.annotation.WebServlet;
|
||||||
|
import jakarta.servlet.http.HttpServlet;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import me.theclashfruit.crss.models.StatusResponse;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@WebServlet(name = "Status API")
|
||||||
|
public class StatusServlet extends HttpServlet {
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
|
||||||
|
res.setContentType("application/json");
|
||||||
|
|
||||||
|
StatusResponse response = new StatusResponse(
|
||||||
|
Bukkit.getBukkitVersion().split("-")[0],
|
||||||
|
Bukkit.getOnlinePlayers().size(),
|
||||||
|
Bukkit.getWorlds().stream().map(World::getName).toArray(String[]::new)
|
||||||
|
);
|
||||||
|
|
||||||
|
String resJson = response.toJson();
|
||||||
|
|
||||||
|
res.setStatus(200);
|
||||||
|
res.getWriter().println(resJson);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package me.theclashfruit.crss.backend.v2.gateway;
|
||||||
|
|
||||||
|
import jakarta.servlet.annotation.WebServlet;
|
||||||
|
import org.eclipse.jetty.ee10.websocket.server.JettyWebSocketServlet;
|
||||||
|
import org.eclipse.jetty.ee10.websocket.server.JettyWebSocketServletFactory;
|
||||||
|
|
||||||
|
@WebServlet(name = "Gateway WebSocket API")
|
||||||
|
public class GatewayServlet extends JettyWebSocketServlet {
|
||||||
|
@Override
|
||||||
|
protected void configure(JettyWebSocketServletFactory factory) {
|
||||||
|
factory.register(GatewaySocket.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
package me.theclashfruit.crss.backend.v2.gateway;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.enums.Channels;
|
||||||
|
import me.theclashfruit.crss.models.ErrorResponse;
|
||||||
|
import me.theclashfruit.crss.models.SocketReqMessage;
|
||||||
|
import org.eclipse.jetty.websocket.api.Session;
|
||||||
|
import org.eclipse.jetty.websocket.api.annotations.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
|
import static org.bukkit.Bukkit.getLogger;
|
||||||
|
|
||||||
|
@WebSocket
|
||||||
|
public class GatewaySocket {
|
||||||
|
private static final Set<GatewaySocket> gatewayConnections = new CopyOnWriteArraySet<>();
|
||||||
|
|
||||||
|
private Session session;
|
||||||
|
|
||||||
|
private final ArrayList<Channels> subscriptions = new ArrayList<>();
|
||||||
|
|
||||||
|
@OnWebSocketOpen
|
||||||
|
public void onOpen(Session session) {
|
||||||
|
this.session = session;
|
||||||
|
|
||||||
|
gatewayConnections.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnWebSocketClose
|
||||||
|
public void onClose(int statusCode, String reason) {
|
||||||
|
gatewayConnections.remove(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnWebSocketMessage
|
||||||
|
public void onMessage(String message) {
|
||||||
|
// TODO: implement stuff from /docs/gateway.md
|
||||||
|
|
||||||
|
try {
|
||||||
|
SocketReqMessage reqMessage = (SocketReqMessage) SocketReqMessage.fromJson(message, SocketReqMessage.class);
|
||||||
|
|
||||||
|
if (Objects.equals(reqMessage.getType(), "subscribe")) {
|
||||||
|
for (String channel : reqMessage.getEvents()) {
|
||||||
|
this.subscriptions.add(Channels.getChannel(channel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
getLogger().throwing(GatewaySocket.class.getName(), "onMessage", e);
|
||||||
|
|
||||||
|
String[] stackTrace = Arrays.stream(e.getStackTrace()).map(StackTraceElement::toString).toArray(String[]::new);
|
||||||
|
StringBuilder stackTraceString = new StringBuilder();
|
||||||
|
|
||||||
|
for (String stackTraceElement : stackTrace) {
|
||||||
|
stackTraceString
|
||||||
|
.append(stackTraceElement)
|
||||||
|
.append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ErrorResponse error = new ErrorResponse(
|
||||||
|
1011,
|
||||||
|
stackTraceString.toString()
|
||||||
|
);
|
||||||
|
|
||||||
|
this.session.sendText(error.toJson(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void broadcastToChannel(Channels channel, String message) {
|
||||||
|
gatewayConnections.stream()
|
||||||
|
.filter(gateway -> gateway.subscriptions != null)
|
||||||
|
.filter(gateway -> {
|
||||||
|
for (Channels subscription : gateway.subscriptions) {
|
||||||
|
if (subscription.equals(channel)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
.forEach(gateway -> {
|
||||||
|
gateway.session.sendText(message, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package me.theclashfruit.crss.backend.v2.map;
|
||||||
|
|
||||||
|
import jakarta.servlet.annotation.WebServlet;
|
||||||
|
import jakarta.servlet.http.HttpServlet;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import me.theclashfruit.crss.models.StatusResponse;
|
||||||
|
import me.theclashfruit.crss.utils.DataUtils;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@WebServlet(name = "Markers API")
|
||||||
|
public class MarkersServlet extends HttpServlet {
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
|
||||||
|
res.setContentType("application/json");
|
||||||
|
|
||||||
|
String resJson = DataUtils.getMarkers().toJson();
|
||||||
|
|
||||||
|
res.setStatus(200);
|
||||||
|
res.getWriter().println(resJson);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package me.theclashfruit.crss.backend.v2.map;
|
||||||
|
|
||||||
|
import jakarta.servlet.annotation.WebServlet;
|
||||||
|
import jakarta.servlet.http.HttpServlet;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import me.theclashfruit.crss.utils.UnminedCLI;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
@WebServlet(name = "Tile API")
|
||||||
|
public class TileServlet extends HttpServlet {
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
|
||||||
|
String pathInfo = req.getPathInfo();
|
||||||
|
|
||||||
|
String[] pathParts = pathInfo.split("/");
|
||||||
|
|
||||||
|
int iZoom = Integer.parseInt(pathParts[2]);
|
||||||
|
int iX = Integer.parseInt(pathParts[3].split("\\.")[0]);
|
||||||
|
int iY = Integer.parseInt(pathParts[3].split("\\.")[1]);
|
||||||
|
|
||||||
|
String world = pathParts[1];
|
||||||
|
|
||||||
|
UnminedCLI unminedCLI = new UnminedCLI();
|
||||||
|
|
||||||
|
try {
|
||||||
|
String eTag = req.getHeader("If-None-Match");
|
||||||
|
|
||||||
|
byte[] tile = unminedCLI.renderTile(iZoom, iX, iY, world);
|
||||||
|
|
||||||
|
String tTag = generateETag(tile);
|
||||||
|
|
||||||
|
res.setHeader("ETag", tTag);
|
||||||
|
|
||||||
|
if (eTag != null && eTag.equals(tTag)) {
|
||||||
|
res.setStatus(304);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.setStatus(200);
|
||||||
|
res.setContentType("image/png");
|
||||||
|
|
||||||
|
res.getOutputStream().write(tile);
|
||||||
|
} catch (InterruptedException | IOException e) {
|
||||||
|
res.setStatus(500);
|
||||||
|
res.setContentType("plain/text");
|
||||||
|
|
||||||
|
res.getWriter().println("Internal Server Error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String generateETag(byte[] data) {
|
||||||
|
try {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||||
|
byte[] hash = digest.digest(data);
|
||||||
|
return Base64.getEncoder().encodeToString(hash);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException("Unable to find SHA-256 algorithm", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package me.theclashfruit.crss.banking.commands;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.banking.gui.MainPage;
|
||||||
|
import me.theclashfruit.crss.utils.ChestGui;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class AtmCommand implements CommandExecutor {
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
if(sender instanceof Player) {
|
||||||
|
Player player = (Player) sender;
|
||||||
|
|
||||||
|
ChestGui menuGui = new MainPage(player);
|
||||||
|
|
||||||
|
menuGui.openInventory();
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("You must be a player to use this command.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package me.theclashfruit.crss.banking.commands;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.utils.SqlUtil;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
public class DatabaseCheck implements CommandExecutor {
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
if (SqlUtil.isConnected()) {
|
||||||
|
sender.sendMessage("Connected to database!");
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("Not connected to database!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
package me.theclashfruit.crss.banking.gui;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.constants.GlassPane;
|
||||||
|
import me.theclashfruit.crss.utils.ChestGui;
|
||||||
|
import me.theclashfruit.crss.utils.SkullUtil;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.SkullType;
|
||||||
|
import org.bukkit.entity.Item;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.inventory.meta.SkullMeta;
|
||||||
|
import org.bukkit.material.Skull;
|
||||||
|
|
||||||
|
public class MainPage extends ChestGui {
|
||||||
|
public MainPage(Player player) {
|
||||||
|
super(player, SIX_ROWS, "ATM");
|
||||||
|
|
||||||
|
ItemStack playerHead = new ItemStack(Material.SKULL_ITEM, 1, (short) SkullType.PLAYER.ordinal());
|
||||||
|
SkullMeta playerMeta = ((SkullMeta) playerHead.getItemMeta());
|
||||||
|
|
||||||
|
playerMeta.setOwner(player.getName());
|
||||||
|
playerMeta.setDisplayName(player.getName());
|
||||||
|
|
||||||
|
playerHead.setItemMeta(playerMeta);
|
||||||
|
|
||||||
|
// ----
|
||||||
|
|
||||||
|
ItemMeta glassPaneMeta = Bukkit.getItemFactory().getItemMeta(Material.STAINED_GLASS_PANE);
|
||||||
|
|
||||||
|
glassPaneMeta.setDisplayName(" ");
|
||||||
|
|
||||||
|
ItemStack lightGrayPane = GlassPane.LIGHT_GRAY;
|
||||||
|
ItemStack limePane = GlassPane.LIME;
|
||||||
|
ItemStack pinkPane = GlassPane.PINK;
|
||||||
|
ItemStack whitePane = GlassPane.WHITE;
|
||||||
|
ItemStack redPane = GlassPane.RED;
|
||||||
|
|
||||||
|
lightGrayPane.setItemMeta(glassPaneMeta);
|
||||||
|
limePane.setItemMeta(glassPaneMeta);
|
||||||
|
pinkPane.setItemMeta(glassPaneMeta);
|
||||||
|
whitePane.setItemMeta(glassPaneMeta);
|
||||||
|
redPane.setItemMeta(glassPaneMeta);
|
||||||
|
|
||||||
|
for (int i = 0; i < SIX_ROWS; i++) {
|
||||||
|
inventory.setItem(i, lightGrayPane);
|
||||||
|
}
|
||||||
|
|
||||||
|
inventory.setItem(
|
||||||
|
8,
|
||||||
|
SkullUtil.getCustomSkull(
|
||||||
|
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmViNTg4YjIxYTZmOThhZDFmZjRlMDg1YzU1MmRjYjA1MGVmYzljYWI0MjdmNDYwNDhmMThmYzgwMzQ3NWY3In19fQ==",
|
||||||
|
"Exit"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
inventory.setItem(9, limePane);
|
||||||
|
inventory.setItem(17, limePane);
|
||||||
|
inventory.setItem(18, pinkPane);
|
||||||
|
inventory.setItem(26, pinkPane);
|
||||||
|
inventory.setItem(27, whitePane);
|
||||||
|
inventory.setItem(35, whitePane);
|
||||||
|
inventory.setItem(36, redPane);
|
||||||
|
inventory.setItem(44, redPane);
|
||||||
|
|
||||||
|
inventory.setItem(20, playerHead);
|
||||||
|
|
||||||
|
inventory.setItem(
|
||||||
|
21,
|
||||||
|
SkullUtil.getCustomSkull("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzQzNzM0NmQ4YmRhNzhkNTI1ZDE5ZjU0MGE5NWU0ZTc5ZGFlZGE3OTVjYmM1YTEzMjU2MjM2MzEyY2YifX19")
|
||||||
|
);
|
||||||
|
inventory.setItem(
|
||||||
|
22,
|
||||||
|
SkullUtil.getCustomSkull(
|
||||||
|
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzA0MGZlODM2YTZjMmZiZDJjN2E5YzhlYzZiZTUxNzRmZGRmMWFjMjBmNTVlMzY2MTU2ZmE1ZjcxMmUxMCJ9fX0="
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
inventory.setItem(23, new ItemStack(Material.WATCH));
|
||||||
|
inventory.setItem(24, new ItemStack(Material.BARRIER));
|
||||||
|
|
||||||
|
for (int i = 29; i < 34; i++) {
|
||||||
|
inventory.setItem(i, new ItemStack(Material.BARRIER));
|
||||||
|
}
|
||||||
|
|
||||||
|
player.updateInventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handleClick(int slot) {
|
||||||
|
if (slot == 8) {
|
||||||
|
player.closeInventory();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +0,0 @@
|
||||||
package me.theclashfruit.crss.commands;
|
|
||||||
|
|
||||||
import me.theclashfruit.crss.Plugin;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
|
|
||||||
public class BalanceCommand implements CommandExecutor {
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) {
|
|
||||||
commandSender.sendMessage("Your balance is: " + Plugin.getEconomy().getBalance(commandSender.getName()));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
23
src/main/java/me/theclashfruit/crss/constants/GlassPane.java
Normal file
23
src/main/java/me/theclashfruit/crss/constants/GlassPane.java
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package me.theclashfruit.crss.constants;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
public class GlassPane {
|
||||||
|
public static final ItemStack WHITE = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 0));
|
||||||
|
public static final ItemStack ORANGE = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 1));
|
||||||
|
public static final ItemStack MAGENTA = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 2));
|
||||||
|
public static final ItemStack LIGHT_BLUE = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 3));
|
||||||
|
public static final ItemStack YELLOW = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 4));
|
||||||
|
public static final ItemStack LIME = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 5));
|
||||||
|
public static final ItemStack PINK = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 6));
|
||||||
|
public static final ItemStack GRAY = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 7));
|
||||||
|
public static final ItemStack LIGHT_GRAY = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 8));
|
||||||
|
public static final ItemStack CYAN = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 9));
|
||||||
|
public static final ItemStack PURPLE = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 10));
|
||||||
|
public static final ItemStack BLUE = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 11));
|
||||||
|
public static final ItemStack BROWN = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 12));
|
||||||
|
public static final ItemStack GREEN = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 13));
|
||||||
|
public static final ItemStack RED = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 14));
|
||||||
|
public static final ItemStack BLACK = new ItemStack(Material.STAINED_GLASS_PANE, 1, ((short) 0), ((byte) 15));
|
||||||
|
}
|
15
src/main/java/me/theclashfruit/crss/enums/Channels.java
Normal file
15
src/main/java/me/theclashfruit/crss/enums/Channels.java
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package me.theclashfruit.crss.enums;
|
||||||
|
|
||||||
|
public enum Channels {
|
||||||
|
PLAYER_MOVE,
|
||||||
|
PLAYER_JOIN,
|
||||||
|
PLAYER_LEAVE,
|
||||||
|
PLAYER_CHAT,
|
||||||
|
PLAYER_DEATH;
|
||||||
|
|
||||||
|
// TODO: add more
|
||||||
|
|
||||||
|
public static Channels getChannel(String channel) {
|
||||||
|
return valueOf(channel.toUpperCase());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,82 +0,0 @@
|
||||||
package me.theclashfruit.crss.listener;
|
|
||||||
|
|
||||||
import me.theclashfruit.crss.api.GatewaySocket;
|
|
||||||
import me.theclashfruit.crss.models.*;
|
|
||||||
import me.theclashfruit.crss.util.StringUtil;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
|
||||||
import org.bukkit.event.player.PlayerChatEvent;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
|
||||||
import org.bukkit.event.server.ServerCommandEvent;
|
|
||||||
|
|
||||||
public class ChatListener implements Listener {
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onChat(PlayerChatEvent event) {
|
|
||||||
GatewaySocket.broadcast(new SocketMessage(
|
|
||||||
"chatMessage",
|
|
||||||
new SocketData(
|
|
||||||
event.getPlayer().getName(),
|
|
||||||
event.getMessage(),
|
|
||||||
false
|
|
||||||
)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onJoin(PlayerJoinEvent event) {
|
|
||||||
GatewaySocket.broadcast(new SocketMessage(
|
|
||||||
"playerJoin",
|
|
||||||
new SocketData(
|
|
||||||
null,
|
|
||||||
event.getPlayer().getName() + " joined the game.",
|
|
||||||
false
|
|
||||||
)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onQuit(PlayerQuitEvent event) {
|
|
||||||
GatewaySocket.broadcast(new SocketMessage(
|
|
||||||
"playerQuit",
|
|
||||||
new SocketData(
|
|
||||||
null,
|
|
||||||
event.getPlayer().getName() + " left the game.",
|
|
||||||
false
|
|
||||||
)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onDeath(PlayerDeathEvent event) {
|
|
||||||
GatewaySocket.broadcast(new SocketMessage(
|
|
||||||
"playerDeath",
|
|
||||||
new SocketData(
|
|
||||||
null,
|
|
||||||
event.getDeathMessage(),
|
|
||||||
false
|
|
||||||
)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onServerCommand(ServerCommandEvent event) {
|
|
||||||
switch (StringUtil.getFirstPartBeforeSpace(event.getCommand())) {
|
|
||||||
case "say":
|
|
||||||
GatewaySocket.broadcast(new SocketMessage(
|
|
||||||
"serverSay",
|
|
||||||
new SocketData(
|
|
||||||
null,
|
|
||||||
ChatColor.stripColor(event.getCommand().substring(4)),
|
|
||||||
false
|
|
||||||
)
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package me.theclashfruit.crss.listener;
|
|
||||||
|
|
||||||
import me.theclashfruit.crss.Plugin;
|
|
||||||
import net.milkbowl.vault.economy.Economy;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
|
|
||||||
public class PlayerJoinListener implements Listener {
|
|
||||||
private Economy economy = Plugin.getEconomy();
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
|
||||||
Player player = event.getPlayer();
|
|
||||||
|
|
||||||
if (!economy.hasAccount(player))
|
|
||||||
economy.createPlayerAccount(player);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package me.theclashfruit.crss.listener;
|
|
||||||
|
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
|
||||||
import org.bukkit.event.player.PlayerMoveEvent;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerBedEnterEvent;
|
|
||||||
import org.bukkit.plugin.PluginManager;
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
import static org.bukkit.Bukkit.getServer;
|
|
||||||
|
|
||||||
public class SleepingListener implements Listener {
|
|
||||||
|
|
||||||
Plugin plugin = getServer().getPluginManager().getPlugin("CRSS");
|
|
||||||
FileConfiguration config = plugin.getConfig();
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void playerBedEnterEvent(PlayerBedEnterEvent event) {
|
|
||||||
World world = event.getBed().getWorld();
|
|
||||||
|
|
||||||
AtomicInteger sleeping = new AtomicInteger();
|
|
||||||
int players = world.getPlayers().size();
|
|
||||||
int sleepingPercentage = config.getInt("gameRules.playerSleepingPercentage");
|
|
||||||
|
|
||||||
world.getPlayers().forEach(player -> {
|
|
||||||
if(player.isSleeping())
|
|
||||||
sleeping.incrementAndGet();
|
|
||||||
});
|
|
||||||
|
|
||||||
if(sleeping.get() >= players * sleepingPercentage / 100) {
|
|
||||||
long rTime = 24000 - world.getTime();
|
|
||||||
|
|
||||||
world.setFullTime(world.getFullTime() + rTime);
|
|
||||||
|
|
||||||
if(world.isThundering() || world.hasStorm()) {
|
|
||||||
world.setThundering(false);
|
|
||||||
world.setStorm(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package me.theclashfruit.crss.listeners;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.utils.ChestGui;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class InventoryListener implements Listener {
|
||||||
|
public static HashMap<String, ChestGui> inventories = new HashMap<>();
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onClick(InventoryClickEvent event) {
|
||||||
|
if (event.getClickedInventory() == null) return;
|
||||||
|
|
||||||
|
ChestGui gui = inventories.get(event.getClickedInventory().getTitle());
|
||||||
|
|
||||||
|
if (gui == null) return;
|
||||||
|
|
||||||
|
event.setCancelled(
|
||||||
|
gui.handleClick(event.getSlot())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
package me.theclashfruit.crss.listeners;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.backend.v2.gateway.GatewaySocket;
|
||||||
|
import me.theclashfruit.crss.enums.Channels;
|
||||||
|
import me.theclashfruit.crss.utils.SqlUtil;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||||
|
import org.bukkit.event.player.*;
|
||||||
|
|
||||||
|
public class PlayerListener implements Listener {
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
String msg = "{" +
|
||||||
|
"\"type\":\"player_join\"," +
|
||||||
|
"\"player\":{" +
|
||||||
|
"\"name\":\"" + player.getName() + "\"," +
|
||||||
|
"\"uuid\":\"" + player.getUniqueId() + "\"" +
|
||||||
|
"}" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
GatewaySocket.broadcastToChannel(Channels.PLAYER_JOIN, msg);
|
||||||
|
|
||||||
|
if (SqlUtil.isPlayerExists(player.getUniqueId().toString())) {
|
||||||
|
SqlUtil.updatePlayerOnlineStatus(
|
||||||
|
player.getUniqueId().toString(),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
SqlUtil.addPlayer(
|
||||||
|
player.getUniqueId().toString(),
|
||||||
|
player.getName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
String msg = "{" +
|
||||||
|
"\"type\":\"player_leave\"," +
|
||||||
|
"\"player\":{" +
|
||||||
|
"\"name\":\"" + player.getName() + "\"," +
|
||||||
|
"\"uuid\":\"" + player.getUniqueId() + "\"" +
|
||||||
|
"}" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
GatewaySocket.broadcastToChannel(Channels.PLAYER_LEAVE, msg);
|
||||||
|
|
||||||
|
SqlUtil.updatePlayerLastOnline(
|
||||||
|
player.getUniqueId().toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerMove(PlayerMoveEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
// too lazy to make classes for these lmao
|
||||||
|
String msg = "{" +
|
||||||
|
"\"type\":\"player_move\"," +
|
||||||
|
"\"player\":{" +
|
||||||
|
"\"name\":\"" + player.getName() + "\"," +
|
||||||
|
"\"uuid\":\"" + player.getUniqueId() + "\"" +
|
||||||
|
"}," +
|
||||||
|
"\"position\":{" +
|
||||||
|
"\"distance\":" + event.getFrom().distance(event.getTo()) + "," +
|
||||||
|
"\"from\":{" +
|
||||||
|
"\"world\":\"" + event.getFrom().getWorld().getName() + "\"," +
|
||||||
|
"\"x\":" + event.getFrom().getX() + "," +
|
||||||
|
"\"y\":" + event.getFrom().getY() + "," +
|
||||||
|
"\"z\":" + event.getFrom().getZ() +
|
||||||
|
"}," +
|
||||||
|
"\"to\":{" +
|
||||||
|
"\"world\":\"" + event.getTo().getWorld().getName() + "\"," +
|
||||||
|
"\"x\":" + event.getTo().getX() + "," +
|
||||||
|
"\"y\":" + event.getTo().getY() + "," +
|
||||||
|
"\"z\":" + event.getTo().getZ() +
|
||||||
|
"}" +
|
||||||
|
"}" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
if (event.getFrom().distance(event.getTo()) != 0)
|
||||||
|
GatewaySocket.broadcastToChannel(Channels.PLAYER_MOVE, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerChat(AsyncPlayerChatEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
String msg = "{" +
|
||||||
|
"\"type\":\"player_chat\"," +
|
||||||
|
"\"player\":{" +
|
||||||
|
"\"name\":\"" + player.getName() + "\"," +
|
||||||
|
"\"uuid\":\"" + player.getUniqueId() + "\"" +
|
||||||
|
"}," +
|
||||||
|
"\"message\":\"" + event.getMessage() + "\"" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
GatewaySocket.broadcastToChannel(Channels.PLAYER_CHAT, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerDeath(PlayerDeathEvent event) {
|
||||||
|
Player player = event.getEntity();
|
||||||
|
|
||||||
|
String msg = "{" +
|
||||||
|
"\"type\":\"player_death\"," +
|
||||||
|
"\"player\":{" +
|
||||||
|
"\"name\":\"" + player.getName() + "\"," +
|
||||||
|
"\"uuid\":\"" + player.getUniqueId() + "\"" +
|
||||||
|
"}," +
|
||||||
|
"\"message\":\"" + event.getDeathMessage() + "\"" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
GatewaySocket.broadcastToChannel(Channels.PLAYER_DEATH, msg);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
package me.theclashfruit.crss.map;
|
|
||||||
|
|
||||||
import javax.servlet.annotation.WebServlet;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
@WebServlet(name = "Map Tile Servlet")
|
|
||||||
public class MapServlet extends HttpServlet {
|
|
||||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
|
||||||
response.setContentType("text/plain");
|
|
||||||
|
|
||||||
/*
|
|
||||||
MapUtils mapUtils = new MapUtils();
|
|
||||||
|
|
||||||
mapUtils.generateTiles();
|
|
||||||
*/
|
|
||||||
|
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
|
||||||
response.getWriter().println("Hello, World!");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
package me.theclashfruit.crss.map;
|
|
||||||
|
|
||||||
import me.theclashfruit.crss.util.FileUtil;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
|
|
||||||
import static org.bukkit.Bukkit.getLogger;
|
|
||||||
import static org.bukkit.Bukkit.getServer;
|
|
||||||
|
|
||||||
public class MapUtils {
|
|
||||||
Plugin plugin = getServer().getPluginManager().getPlugin("CRSS");
|
|
||||||
|
|
||||||
public void generateTiles() {
|
|
||||||
plugin.getConfig().getStringList("web.map.worlds").forEach(world -> {
|
|
||||||
try {
|
|
||||||
String unminedPath =
|
|
||||||
String.format(
|
|
||||||
"%s/natives/unmined/unmined-cli",
|
|
||||||
plugin.getDataFolder()
|
|
||||||
);
|
|
||||||
|
|
||||||
String worldFolder =
|
|
||||||
getServer().getWorld(world).getWorldFolder().getAbsolutePath().replace("./", "");
|
|
||||||
|
|
||||||
String outputPath =
|
|
||||||
String.format(
|
|
||||||
"%s/tmp/%s",
|
|
||||||
plugin.getDataFolder(),
|
|
||||||
world
|
|
||||||
);
|
|
||||||
|
|
||||||
String finalOutputPath =
|
|
||||||
outputPath.replace(
|
|
||||||
"tmp",
|
|
||||||
plugin.getConfig().getString("web.map.path")
|
|
||||||
);
|
|
||||||
|
|
||||||
String mapSettingPath =
|
|
||||||
String.format(
|
|
||||||
"%s/unmined_settings.json",
|
|
||||||
plugin.getDataFolder()
|
|
||||||
);
|
|
||||||
|
|
||||||
if(!new File(unminedPath).exists())
|
|
||||||
throw new RuntimeException("Unmined CLI not found!");
|
|
||||||
|
|
||||||
Process process = Runtime
|
|
||||||
.getRuntime()
|
|
||||||
.exec(
|
|
||||||
String.format(
|
|
||||||
"%s web render --imageformat png --world %s --output %s --mapsettings %s --zoomout 4",
|
|
||||||
unminedPath,
|
|
||||||
worldFolder,
|
|
||||||
outputPath,
|
|
||||||
mapSettingPath
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
|
||||||
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
|
||||||
|
|
||||||
String lines;
|
|
||||||
|
|
||||||
while ((lines = stdInput.readLine()) != null) {
|
|
||||||
getLogger().info(lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((lines = stdError.readLine()) != null) {
|
|
||||||
getLogger().severe(lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(new File(finalOutputPath).exists())
|
|
||||||
FileUtil.deleteDirectory(new File(finalOutputPath));
|
|
||||||
|
|
||||||
Files.move(Paths.get(new File(outputPath, "tiles").getAbsolutePath()), Paths.get(new File(finalOutputPath).getAbsolutePath()), StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
|
|
||||||
FileUtil.deleteDirectory(new File(outputPath));
|
|
||||||
} catch (IOException e) {
|
|
||||||
getLogger().severe("Error while generating map tiles!");
|
|
||||||
getLogger().severe(e.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package me.theclashfruit.crss.models;
|
||||||
|
|
||||||
|
public class ErrorResponse extends Model {
|
||||||
|
private Integer error;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public ErrorResponse(Integer error, String message) {
|
||||||
|
this.error = error;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getError() {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setError(Integer error) {
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,27 +0,0 @@
|
||||||
package me.theclashfruit.crss.models;
|
|
||||||
|
|
||||||
public class GatewayConnection {
|
|
||||||
private String clientName;
|
|
||||||
private String[] subscriptions;
|
|
||||||
|
|
||||||
public GatewayConnection(String clientName, String[] subscriptions) {
|
|
||||||
this.clientName = clientName;
|
|
||||||
this.subscriptions = subscriptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getClientName() {
|
|
||||||
return clientName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getSubscriptions() {
|
|
||||||
return subscriptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setClientName(String clientName) {
|
|
||||||
this.clientName = clientName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSubscriptions(String[] subscriptions) {
|
|
||||||
this.subscriptions = subscriptions;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package me.theclashfruit.crss.models;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class IndexResponse extends Model {
|
||||||
|
private String latestVersion;
|
||||||
|
public ArrayList<Version> versions;
|
||||||
|
|
||||||
|
public IndexResponse(String latestVersion, ArrayList<Version> versions) {
|
||||||
|
this.latestVersion = latestVersion;
|
||||||
|
this.versions = versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLatestVersion() {
|
||||||
|
return latestVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLatestVersion(String latestVersion) {
|
||||||
|
this.latestVersion = latestVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Version> getVersions() {
|
||||||
|
return versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersions(ArrayList<Version> versions) {
|
||||||
|
this.versions = versions;
|
||||||
|
}
|
||||||
|
}
|
13
src/main/java/me/theclashfruit/crss/models/Model.java
Normal file
13
src/main/java/me/theclashfruit/crss/models/Model.java
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package me.theclashfruit.crss.models;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.utils.JsonUtil;
|
||||||
|
|
||||||
|
public class Model {
|
||||||
|
public String toJson() {
|
||||||
|
return JsonUtil.gson.toJson(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object fromJson(String json, Class<? extends Model> clazz) {
|
||||||
|
return JsonUtil.gson.fromJson(json, clazz);
|
||||||
|
}
|
||||||
|
}
|
57
src/main/java/me/theclashfruit/crss/models/Player.java
Normal file
57
src/main/java/me/theclashfruit/crss/models/Player.java
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package me.theclashfruit.crss.models;
|
||||||
|
|
||||||
|
public class Player {
|
||||||
|
private String uuid;
|
||||||
|
private String name;
|
||||||
|
private Integer gameMode;
|
||||||
|
private PlayerLevels foodLevels;
|
||||||
|
private PlayerPosition position;
|
||||||
|
|
||||||
|
public Player(String uuid, String name, Integer gameMode, PlayerLevels foodLevels, PlayerPosition position) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.name = name;
|
||||||
|
this.gameMode = gameMode;
|
||||||
|
this.foodLevels = foodLevels;
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getGameMode() {
|
||||||
|
return gameMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerLevels getFoodLevels() {
|
||||||
|
return foodLevels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerPosition getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuid(String uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGameMode(Integer gameMode) {
|
||||||
|
this.gameMode = gameMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFoodLevels(PlayerLevels foodLevels) {
|
||||||
|
this.foodLevels = foodLevels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPosition(PlayerPosition position) {
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
}
|
37
src/main/java/me/theclashfruit/crss/models/PlayerLevels.java
Normal file
37
src/main/java/me/theclashfruit/crss/models/PlayerLevels.java
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package me.theclashfruit.crss.models;
|
||||||
|
|
||||||
|
public class PlayerLevels extends Model {
|
||||||
|
private Double health;
|
||||||
|
private Integer food;
|
||||||
|
private Float saturation;
|
||||||
|
|
||||||
|
public PlayerLevels(Double health, Integer food, Float saturation) {
|
||||||
|
this.health = health;
|
||||||
|
this.food = food;
|
||||||
|
this.saturation = saturation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getHealth() {
|
||||||
|
return health;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFood() {
|
||||||
|
return food;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getSaturation() {
|
||||||
|
return saturation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHealth(Double health) {
|
||||||
|
this.health = health;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFood(Integer food) {
|
||||||
|
this.food = food;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSaturation(Float saturation) {
|
||||||
|
this.saturation = saturation;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,59 +0,0 @@
|
||||||
package me.theclashfruit.crss.models;
|
|
||||||
|
|
||||||
import org.bukkit.World;
|
|
||||||
|
|
||||||
public class PlayerList {
|
|
||||||
private String uniqueId;
|
|
||||||
private String displayName;
|
|
||||||
private int gameMode;
|
|
||||||
private String world;
|
|
||||||
private PlayerLocation location;
|
|
||||||
|
|
||||||
public PlayerList(String uniqueId, String displayName, int gameMode, String world, PlayerLocation location) {
|
|
||||||
this.uniqueId = uniqueId;
|
|
||||||
this.displayName = displayName;
|
|
||||||
this.gameMode = gameMode;
|
|
||||||
this.world = world;
|
|
||||||
this.location = location;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUniqueId() {
|
|
||||||
return uniqueId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisplayName() {
|
|
||||||
return displayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getGameMode() {
|
|
||||||
return gameMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getWorld() {
|
|
||||||
return world;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlayerLocation getLocation() {
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUniqueId(String uniqueId) {
|
|
||||||
this.uniqueId = uniqueId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDisplayName(String displayName) {
|
|
||||||
this.displayName = displayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGameMode(int gameMode) {
|
|
||||||
this.gameMode = gameMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWorld(String world) {
|
|
||||||
this.world = world;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLocation(PlayerLocation location) {
|
|
||||||
this.location = location;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +1,11 @@
|
||||||
package me.theclashfruit.crss.models;
|
package me.theclashfruit.crss.models;
|
||||||
|
|
||||||
public class PlayerLocation {
|
public class PlayerPosition extends Model {
|
||||||
private double x;
|
private double x;
|
||||||
private double y;
|
private double y;
|
||||||
private double z;
|
private double z;
|
||||||
|
|
||||||
public PlayerLocation(double x, double y, double z) {
|
public PlayerPosition(double x, double y, double z) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.z = z;
|
this.z = z;
|
|
@ -0,0 +1,29 @@
|
||||||
|
package me.theclashfruit.crss.models;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class PlayersResponse extends Model {
|
||||||
|
private Integer online;
|
||||||
|
private ArrayList<Player> players;
|
||||||
|
|
||||||
|
public PlayersResponse(Integer online, ArrayList<Player> players) {
|
||||||
|
this.online = online;
|
||||||
|
this.players = players;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getOnline() {
|
||||||
|
return online;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Player> getPlayers() {
|
||||||
|
return players;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnline(Integer online) {
|
||||||
|
this.online = online;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPlayers(ArrayList<Player> players) {
|
||||||
|
this.players = players;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,37 +0,0 @@
|
||||||
package me.theclashfruit.crss.models;
|
|
||||||
|
|
||||||
public class SocketData {
|
|
||||||
private String username;
|
|
||||||
private String message;
|
|
||||||
private Boolean isSystemMessage;
|
|
||||||
|
|
||||||
public SocketData(String username, String message, Boolean isSystemMessage) {
|
|
||||||
this.username = username;
|
|
||||||
this.message = message;
|
|
||||||
this.isSystemMessage = isSystemMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUsername() {
|
|
||||||
return username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getIsSystemMessage() {
|
|
||||||
return isSystemMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUsername(String username) {
|
|
||||||
this.username = username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsSystemMessage(Boolean isSystemMessage) {
|
|
||||||
this.isSystemMessage = isSystemMessage;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package me.theclashfruit.crss.models;
|
|
||||||
|
|
||||||
public class SocketMessage {
|
|
||||||
private String event;
|
|
||||||
private SocketData data;
|
|
||||||
|
|
||||||
public SocketMessage(String event, SocketData data) {
|
|
||||||
this.event = event;
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEvent() {
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SocketData getData() {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEvent(String event) {
|
|
||||||
this.event = event;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setData(SocketData data) {
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package me.theclashfruit.crss.models;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.enums.Channels;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class SocketReqMessage extends Model {
|
||||||
|
private String type;
|
||||||
|
private String[] events;
|
||||||
|
|
||||||
|
public SocketReqMessage(String type, String[] events) {
|
||||||
|
this.type = type;
|
||||||
|
this.events = events;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getEvents() {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvents(String[] events) {
|
||||||
|
this.events = events;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,57 +0,0 @@
|
||||||
package me.theclashfruit.crss.models;
|
|
||||||
|
|
||||||
public class Status {
|
|
||||||
private Boolean status;
|
|
||||||
private String version;
|
|
||||||
private int players;
|
|
||||||
private int maxPlayers;
|
|
||||||
private String motd;
|
|
||||||
|
|
||||||
public Status(Boolean status, String version, int players, int maxPlayers, String motd) {
|
|
||||||
this.status = status;
|
|
||||||
this.version = version;
|
|
||||||
this.players = players;
|
|
||||||
this.maxPlayers = maxPlayers;
|
|
||||||
this.motd = motd;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getStatus() {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVersion() {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPlayers() {
|
|
||||||
return players;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMaxPlayers() {
|
|
||||||
return maxPlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMotd() {
|
|
||||||
return motd;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStatus(Boolean status) {
|
|
||||||
this.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVersion(String version) {
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPlayers(int players) {
|
|
||||||
this.players = players;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMaxPlayers(int maxPlayers) {
|
|
||||||
this.maxPlayers = maxPlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMotd(String motd) {
|
|
||||||
this.motd = motd;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package me.theclashfruit.crss.models;
|
||||||
|
|
||||||
|
public class StatusResponse extends Model {
|
||||||
|
private String version;
|
||||||
|
private Integer online;
|
||||||
|
private String[] worlds;
|
||||||
|
|
||||||
|
public StatusResponse(String version, Integer online, String[] worlds) {
|
||||||
|
this.version = version;
|
||||||
|
this.online = online;
|
||||||
|
this.worlds = worlds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getOnline() {
|
||||||
|
return online;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getWorlds() {
|
||||||
|
return worlds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersion(String version) {
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnline(Integer online) {
|
||||||
|
this.online = online;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWorlds(String[] worlds) {
|
||||||
|
this.worlds = worlds;
|
||||||
|
}
|
||||||
|
}
|
37
src/main/java/me/theclashfruit/crss/models/Version.java
Normal file
37
src/main/java/me/theclashfruit/crss/models/Version.java
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package me.theclashfruit.crss.models;
|
||||||
|
|
||||||
|
public class Version extends Model {
|
||||||
|
private String name;
|
||||||
|
private String path;
|
||||||
|
private Boolean deprecated;
|
||||||
|
|
||||||
|
public Version(String name, String path, Boolean deprecated) {
|
||||||
|
this.name = name;
|
||||||
|
this.path = path;
|
||||||
|
this.deprecated = deprecated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getDeprecated() {
|
||||||
|
return deprecated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeprecated(Boolean deprecated) {
|
||||||
|
this.deprecated = deprecated;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package me.theclashfruit.crss.models.data;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.models.Model;
|
||||||
|
|
||||||
|
public class MarkerCategory extends Model {
|
||||||
|
private String color;
|
||||||
|
private String icon;
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
public MarkerCategory(String color, String icon, String title) {
|
||||||
|
this.color = color;
|
||||||
|
this.icon = icon;
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIcon() {
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(String color) {
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIcon(String icon) {
|
||||||
|
this.icon = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "MarkerCategory{color=" + color + ", icon=" + icon + ", title=" + title + "}";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package me.theclashfruit.crss.models.data;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.models.Model;
|
||||||
|
|
||||||
|
public class MarkerMarker extends Model {
|
||||||
|
private String category;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private Float x;
|
||||||
|
private Float y;
|
||||||
|
|
||||||
|
public MarkerMarker(String category, String title, String description, Float x, Float y) {
|
||||||
|
this.category = category;
|
||||||
|
this.title = title;
|
||||||
|
this.description = description;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCategory() {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCategory(String category) {
|
||||||
|
this.category = category;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX(Float x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setY(Float y) {
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "MarkerMarker{category=" + category + ", title=" + title + ", description=" + description + ", x=" + x + ", y=" + y + "}";
|
||||||
|
}
|
||||||
|
}
|
46
src/main/java/me/theclashfruit/crss/models/data/Markers.java
Normal file
46
src/main/java/me/theclashfruit/crss/models/data/Markers.java
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package me.theclashfruit.crss.models.data;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.models.Model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Markers extends Model {
|
||||||
|
private Integer version;
|
||||||
|
private Map<String, MarkerCategory> categories;
|
||||||
|
private ArrayList<MarkerMarker> markers;
|
||||||
|
|
||||||
|
public Markers(Integer version, Map<String, MarkerCategory> categories, ArrayList<MarkerMarker> markers) {
|
||||||
|
this.version = version;
|
||||||
|
this.categories = categories;
|
||||||
|
this.markers = markers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, MarkerCategory> getCategories() {
|
||||||
|
return categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<MarkerMarker> getMarkers() {
|
||||||
|
return markers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersion(Integer version) {
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCategories(Map<String, MarkerCategory> categories) {
|
||||||
|
this.categories = categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMarkers(ArrayList<MarkerMarker> markers) {
|
||||||
|
this.markers = markers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "Markers{version=" + version + ", categories=" + categories + ", markers=" + markers + "}";
|
||||||
|
}
|
||||||
|
}
|
64
src/main/java/me/theclashfruit/crss/models/tile/Tile.java
Normal file
64
src/main/java/me/theclashfruit/crss/models/tile/Tile.java
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
package me.theclashfruit.crss.models.tile;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.models.Model;
|
||||||
|
|
||||||
|
public class Tile extends Model {
|
||||||
|
private String eTag;
|
||||||
|
|
||||||
|
private Integer zoom;
|
||||||
|
|
||||||
|
private Integer x;
|
||||||
|
private Integer z;
|
||||||
|
|
||||||
|
private String world;
|
||||||
|
|
||||||
|
private Integer timestamp;
|
||||||
|
|
||||||
|
public Tile(String eTag, Integer zoom, Integer x, Integer z, String world) {
|
||||||
|
this.eTag = eTag;
|
||||||
|
this.zoom = zoom;
|
||||||
|
this.x = x;
|
||||||
|
this.z = z;
|
||||||
|
this.world = world;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getETag() {
|
||||||
|
return eTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getZoom() {
|
||||||
|
return zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getZ() {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWorld() {
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setETag(String eTag) {
|
||||||
|
this.eTag = eTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZoom(Integer zoom) {
|
||||||
|
this.zoom = zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX(Integer x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZ(Integer z) {
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWorld(String world) {
|
||||||
|
this.world = world;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package me.theclashfruit.crss.models.tile;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.models.Model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class TileCache extends Model {
|
||||||
|
private ArrayList<Tile> tiles;
|
||||||
|
|
||||||
|
public TileCache(ArrayList<Tile> tiles) {
|
||||||
|
this.tiles = tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Tile> getTiles() {
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTiles(ArrayList<Tile> tiles) {
|
||||||
|
this.tiles = tiles;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +0,0 @@
|
||||||
package me.theclashfruit.crss.util;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class FileUtil {
|
|
||||||
public static boolean deleteDirectory(File directoryToBeDeleted) {
|
|
||||||
File[] allContents = directoryToBeDeleted.listFiles();
|
|
||||||
if (allContents != null) {
|
|
||||||
for (File file : allContents) {
|
|
||||||
deleteDirectory(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return directoryToBeDeleted.delete();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package me.theclashfruit.crss.util;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import me.theclashfruit.crss.models.SocketMessage;
|
|
||||||
|
|
||||||
import javax.websocket.DecodeException;
|
|
||||||
import javax.websocket.Decoder;
|
|
||||||
import javax.websocket.EndpointConfig;
|
|
||||||
|
|
||||||
public class MessageDecoder implements Decoder.Text<SocketMessage> {
|
|
||||||
|
|
||||||
private static final Gson gson = new Gson();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SocketMessage decode(String s) throws DecodeException {
|
|
||||||
return gson.fromJson(s, SocketMessage.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean willDecode(String s) {
|
|
||||||
return (s != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(EndpointConfig endpointConfig) {
|
|
||||||
// Custom initialization logic
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy() {
|
|
||||||
// Close resources
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package me.theclashfruit.crss.util;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import me.theclashfruit.crss.models.SocketMessage;
|
|
||||||
|
|
||||||
import javax.websocket.EncodeException;
|
|
||||||
import javax.websocket.Encoder;
|
|
||||||
import javax.websocket.EndpointConfig;
|
|
||||||
|
|
||||||
public class MessageEncoder implements Encoder.Text<SocketMessage> {
|
|
||||||
|
|
||||||
private static final Gson gson = new Gson();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String encode(SocketMessage message) throws EncodeException {
|
|
||||||
return gson.toJson(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(EndpointConfig endpointConfig) {
|
|
||||||
// Custom initialization logic
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy() {
|
|
||||||
// Close resources
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package me.theclashfruit.crss.util;
|
|
||||||
|
|
||||||
public interface StringUtil {
|
|
||||||
static String getFirstPartBeforeSpace(String input) {
|
|
||||||
int index = input.contains(" ") ? input.indexOf(" ") : 0;
|
|
||||||
return input.substring(0, index);
|
|
||||||
}
|
|
||||||
}
|
|
41
src/main/java/me/theclashfruit/crss/utils/ChestGui.java
Normal file
41
src/main/java/me/theclashfruit/crss/utils/ChestGui.java
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package me.theclashfruit.crss.utils;
|
||||||
|
|
||||||
|
import me.theclashfruit.crss.listeners.InventoryListener;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
|
|
||||||
|
public class ChestGui {
|
||||||
|
public static final int ONE_ROW = 9;
|
||||||
|
public static final int TWO_ROWS = 18;
|
||||||
|
public static final int THREE_ROWS = 27;
|
||||||
|
public static final int FOUR_ROWS = 36;
|
||||||
|
public static final int FIVE_ROWS = 45;
|
||||||
|
public static final int SIX_ROWS = 54;
|
||||||
|
|
||||||
|
protected final Player player;
|
||||||
|
private String title;
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
protected Inventory inventory;
|
||||||
|
|
||||||
|
public ChestGui(Player player, int size, String title) {
|
||||||
|
this.player = player;
|
||||||
|
|
||||||
|
this.inventory = Bukkit.createInventory(player, size, title);
|
||||||
|
|
||||||
|
InventoryListener.inventories.put(title, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return `true` if the inventor click event should be cancelled.
|
||||||
|
*/
|
||||||
|
public boolean handleClick(int slot) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openInventory() {
|
||||||
|
player.openInventory(inventory);
|
||||||
|
}
|
||||||
|
}
|
50
src/main/java/me/theclashfruit/crss/utils/DataUtils.java
Normal file
50
src/main/java/me/theclashfruit/crss/utils/DataUtils.java
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package me.theclashfruit.crss.utils;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import me.theclashfruit.crss.models.data.Markers;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class DataUtils {
|
||||||
|
public static Markers getMarkers() throws IOException {
|
||||||
|
File markersFile = Bukkit
|
||||||
|
.getPluginManager()
|
||||||
|
.getPlugin("CRSS")
|
||||||
|
.getDataFolder()
|
||||||
|
.toPath()
|
||||||
|
.resolve("data")
|
||||||
|
.resolve("markers.json")
|
||||||
|
.toFile();
|
||||||
|
|
||||||
|
if (!markersFile.exists()) {
|
||||||
|
throw new RuntimeException("Markers file not found!");
|
||||||
|
}
|
||||||
|
|
||||||
|
try (FileReader fileReader = new FileReader(markersFile)) {
|
||||||
|
return JsonUtil.gson.fromJson(fileReader, Markers.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveMarkers(Markers markers) throws IOException {
|
||||||
|
File markersFile = Bukkit
|
||||||
|
.getPluginManager()
|
||||||
|
.getPlugin("CRSS")
|
||||||
|
.getDataFolder()
|
||||||
|
.toPath()
|
||||||
|
.resolve("data")
|
||||||
|
.resolve("markers.json")
|
||||||
|
.toFile();
|
||||||
|
|
||||||
|
if (!markersFile.exists()) {
|
||||||
|
throw new RuntimeException("Markers file not found!");
|
||||||
|
}
|
||||||
|
|
||||||
|
try (FileWriter fileWriter = new FileWriter(markersFile, false)) {
|
||||||
|
fileWriter.write(JsonUtil.gson.toJson(markers));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
src/main/java/me/theclashfruit/crss/utils/JsonUtil.java
Normal file
11
src/main/java/me/theclashfruit/crss/utils/JsonUtil.java
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package me.theclashfruit.crss.utils;
|
||||||
|
|
||||||
|
import com.google.gson.FieldNamingPolicy;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
|
public class JsonUtil {
|
||||||
|
public static Gson gson = new GsonBuilder()
|
||||||
|
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
|
||||||
|
.create();
|
||||||
|
}
|
23
src/main/java/me/theclashfruit/crss/utils/ReqMiddleware.java
Normal file
23
src/main/java/me/theclashfruit/crss/utils/ReqMiddleware.java
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package me.theclashfruit.crss.utils;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.eclipse.jetty.server.Handler;
|
||||||
|
import org.eclipse.jetty.server.Request;
|
||||||
|
import org.eclipse.jetty.server.Response;
|
||||||
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
|
import org.eclipse.jetty.util.Callback;
|
||||||
|
import org.eclipse.jetty.util.Jetty;
|
||||||
|
|
||||||
|
import static me.theclashfruit.crss.CRSSPlugin.LOGGER;
|
||||||
|
|
||||||
|
public class ReqMiddleware extends ContextHandler {
|
||||||
|
@Override
|
||||||
|
public boolean handle(Request req, Response res, Callback callback) throws Exception {
|
||||||
|
req.setAttribute("me.theclashfruit.crss.currentTimeMillis", System.currentTimeMillis());
|
||||||
|
|
||||||
|
res.getHeaders().put("X-Powered-By", "Minecraft " + Bukkit.getBukkitVersion());
|
||||||
|
res.getHeaders().put("Access-Control-Allow-Origin", "*");
|
||||||
|
|
||||||
|
return super.handle(req, res, callback);
|
||||||
|
}
|
||||||
|
}
|
52
src/main/java/me/theclashfruit/crss/utils/SkullUtil.java
Normal file
52
src/main/java/me/theclashfruit/crss/utils/SkullUtil.java
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package me.theclashfruit.crss.utils;
|
||||||
|
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.mojang.authlib.properties.Property;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.SkullMeta;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static me.theclashfruit.crss.CRSSPlugin.LOGGER;
|
||||||
|
|
||||||
|
public class SkullUtil {
|
||||||
|
public static ItemStack getCustomSkull(String base64) {
|
||||||
|
ItemStack skull = new ItemStack(Material.SKULL_ITEM, 1, (short) 3);
|
||||||
|
|
||||||
|
if (base64 == null || base64.isEmpty())
|
||||||
|
return skull;
|
||||||
|
|
||||||
|
SkullMeta skullMeta = (SkullMeta) skull.getItemMeta();
|
||||||
|
|
||||||
|
GameProfile profile = new GameProfile(UUID.randomUUID(), null);
|
||||||
|
|
||||||
|
profile.getProperties().put("textures", new Property("textures", base64));
|
||||||
|
|
||||||
|
try {
|
||||||
|
Field profileField = skullMeta.getClass().getDeclaredField("profile");
|
||||||
|
|
||||||
|
profileField.setAccessible(true);
|
||||||
|
profileField.set(skullMeta, profile);
|
||||||
|
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
|
||||||
|
LOGGER.throwing(SkullUtil.class.getName(), "getCustomSkull", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
skull.setItemMeta(skullMeta);
|
||||||
|
|
||||||
|
return skull;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemStack getCustomSkull(String base64, String name) {
|
||||||
|
ItemStack skull = getCustomSkull(base64);
|
||||||
|
|
||||||
|
SkullMeta skullMeta = (SkullMeta) skull.getItemMeta();
|
||||||
|
|
||||||
|
skullMeta.setDisplayName(name);
|
||||||
|
|
||||||
|
skull.setItemMeta(skullMeta);
|
||||||
|
|
||||||
|
return skull;
|
||||||
|
}
|
||||||
|
}
|
123
src/main/java/me/theclashfruit/crss/utils/SqlUtil.java
Normal file
123
src/main/java/me/theclashfruit/crss/utils/SqlUtil.java
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
package me.theclashfruit.crss.utils;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import static me.theclashfruit.crss.CRSSPlugin.LOGGER;
|
||||||
|
|
||||||
|
public class SqlUtil {
|
||||||
|
private static Connection connection;
|
||||||
|
|
||||||
|
private static String connectionString;
|
||||||
|
private static String username;
|
||||||
|
private static String password;
|
||||||
|
|
||||||
|
public static void setConnectionDetails(String connectionString, String username, String password) {
|
||||||
|
SqlUtil.connectionString = connectionString;
|
||||||
|
|
||||||
|
SqlUtil.username = username;
|
||||||
|
SqlUtil.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void openConnection(String connectionString, String username, String password) {
|
||||||
|
try {
|
||||||
|
if (!isConnected()) {
|
||||||
|
connection = DriverManager.getConnection(connectionString, username, password);
|
||||||
|
|
||||||
|
LOGGER.info("Connected to database!");
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
LOGGER.throwing(SqlUtil.class.getName(), "SqlUtil", e);
|
||||||
|
|
||||||
|
LOGGER.severe("Could not connect to database!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void openConnection() {
|
||||||
|
if (connectionString == null) {
|
||||||
|
LOGGER.warning("Connection string is null, cannot connect to database!");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.info("Connecting to database...");
|
||||||
|
|
||||||
|
openConnection(connectionString, username, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void closeConnection() {
|
||||||
|
try {
|
||||||
|
if (isConnected()) {
|
||||||
|
connection.close();
|
||||||
|
|
||||||
|
LOGGER.info("Disconnected from database!");
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
LOGGER.throwing(SqlUtil.class.getName(), "closeConnection", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isConnected() {
|
||||||
|
return (connection != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Connection getConnection() {
|
||||||
|
openConnection(connectionString, username, password);
|
||||||
|
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addPlayer(String uuid, String username) {
|
||||||
|
try {
|
||||||
|
PreparedStatement statement = connection.prepareStatement("INSERT INTO players (uuid, username, first_join, last_online, is_online) VALUES (?, ?, current_timestamp, current_timestamp, 1)");
|
||||||
|
|
||||||
|
statement.setString(1, uuid);
|
||||||
|
statement.setString(2, username);
|
||||||
|
|
||||||
|
statement.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
LOGGER.throwing(SqlUtil.class.getName(), "addPlayer", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updatePlayerOnlineStatus(String uuid, boolean isOnline) {
|
||||||
|
try {
|
||||||
|
PreparedStatement statement = connection.prepareStatement("UPDATE players SET is_online = ? WHERE uuid = ?");
|
||||||
|
|
||||||
|
statement.setInt(1, isOnline ? 1 : 0);
|
||||||
|
statement.setString(2, uuid);
|
||||||
|
|
||||||
|
statement.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
LOGGER.throwing(SqlUtil.class.getName(), "updatePlayerOnlineStatus", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updatePlayerLastOnline(String uuid) {
|
||||||
|
try {
|
||||||
|
PreparedStatement statement = connection.prepareStatement("UPDATE players SET last_online = current_timestamp, is_online = 0 WHERE uuid = ?");
|
||||||
|
|
||||||
|
statement.setString(1, uuid);
|
||||||
|
|
||||||
|
statement.executeUpdate();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
LOGGER.throwing(SqlUtil.class.getName(), "updatePlayerLastOnline", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPlayerExists(String uuid) {
|
||||||
|
try {
|
||||||
|
PreparedStatement statement = connection.prepareStatement("SELECT * FROM players WHERE uuid = ?");
|
||||||
|
|
||||||
|
statement.setString(1, uuid);
|
||||||
|
|
||||||
|
return statement.executeQuery().next();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
LOGGER.throwing(SqlUtil.class.getName(), "isPlayerExists", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
228
src/main/java/me/theclashfruit/crss/utils/UnminedCLI.java
Normal file
228
src/main/java/me/theclashfruit/crss/utils/UnminedCLI.java
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
package me.theclashfruit.crss.utils;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import me.theclashfruit.crss.models.tile.TileCache;
|
||||||
|
import org.apache.commons.lang.SystemUtils;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.RenderedImage;
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
import static me.theclashfruit.crss.CRSSPlugin.LOGGER;
|
||||||
|
|
||||||
|
public class UnminedCLI {
|
||||||
|
public static Path executablePath =
|
||||||
|
Bukkit
|
||||||
|
.getPluginManager()
|
||||||
|
.getPlugin("CRSS")
|
||||||
|
.getDataFolder()
|
||||||
|
.toPath()
|
||||||
|
.resolve("lib")
|
||||||
|
.resolve("unmined")
|
||||||
|
.resolve(SystemUtils.IS_OS_WINDOWS ? "unmined-cli.exe" : "unmined-cli");
|
||||||
|
|
||||||
|
private static final Semaphore semaphore = new Semaphore(1);
|
||||||
|
|
||||||
|
private static ArrayList<ArrayList<Integer>> tilesBeingRendered = new ArrayList<>();
|
||||||
|
|
||||||
|
public UnminedCLI() { }
|
||||||
|
|
||||||
|
public byte[] renderTile(int zoom, int chunkX, int chunkZ, String world) throws InterruptedException {
|
||||||
|
semaphore.acquire();
|
||||||
|
|
||||||
|
String safeWorld = world.replaceAll("[^a-zA-Z0-9_\\-]", "");
|
||||||
|
|
||||||
|
String[] bukkitWorlds = Bukkit.getWorlds().stream().map(World::getName).toArray(String[]::new);
|
||||||
|
|
||||||
|
if (!Arrays.asList(bukkitWorlds).contains(safeWorld))
|
||||||
|
return createErrorImage("World not found!");
|
||||||
|
|
||||||
|
int size;
|
||||||
|
int dimension;
|
||||||
|
|
||||||
|
if (chunkX > 32767 || chunkZ > 32767 || chunkX < -32767 || chunkZ < -32767)
|
||||||
|
return createErrorImage("Out of bounds!");
|
||||||
|
else if (zoom < 0)
|
||||||
|
size = (16 * (zoom * -2));
|
||||||
|
else if (zoom < 3 && zoom > 0)
|
||||||
|
size = (16 / (zoom * 2));
|
||||||
|
else
|
||||||
|
size = 16;
|
||||||
|
|
||||||
|
if (safeWorld.endsWith("_nether"))
|
||||||
|
dimension = -1;
|
||||||
|
else if (safeWorld.endsWith("_the_end"))
|
||||||
|
dimension = 1;
|
||||||
|
else
|
||||||
|
dimension = 0;
|
||||||
|
|
||||||
|
Path tilesPath = Bukkit
|
||||||
|
.getPluginManager()
|
||||||
|
.getPlugin("CRSS")
|
||||||
|
.getDataFolder()
|
||||||
|
.toPath()
|
||||||
|
.resolve("tiles")
|
||||||
|
.resolve(safeWorld)
|
||||||
|
.resolve(Integer.toString(zoom));
|
||||||
|
|
||||||
|
Path logPath = Bukkit
|
||||||
|
.getPluginManager()
|
||||||
|
.getPlugin("CRSS")
|
||||||
|
.getDataFolder()
|
||||||
|
.toPath()
|
||||||
|
.resolve("log.txt");
|
||||||
|
|
||||||
|
Path settingsPath = Bukkit
|
||||||
|
.getPluginManager()
|
||||||
|
.getPlugin("CRSS")
|
||||||
|
.getDataFolder()
|
||||||
|
.toPath()
|
||||||
|
.resolve("unmined_settings.json");
|
||||||
|
|
||||||
|
if (!tilesPath.toFile().exists())
|
||||||
|
tilesPath.toFile().mkdirs();
|
||||||
|
|
||||||
|
Thread thread = new Thread(() -> {
|
||||||
|
Process proc = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ProcessBuilder processBuilder = new ProcessBuilder();
|
||||||
|
|
||||||
|
tilesBeingRendered.add(new ArrayList<>(Arrays.asList(chunkX * size, chunkZ * size)));
|
||||||
|
|
||||||
|
processBuilder.command(
|
||||||
|
executablePath.toString(),
|
||||||
|
"image",
|
||||||
|
"render",
|
||||||
|
"--mapsettings", settingsPath.toAbsolutePath().toString(),
|
||||||
|
"--zoom", Integer.toString(size == 16 ? 0 : zoom),
|
||||||
|
"--area", "\"c(" + (chunkX * size) + "," + (chunkZ * size) + "," + size + "," + size + ")\"",
|
||||||
|
"--world",
|
||||||
|
Bukkit
|
||||||
|
.getServer()
|
||||||
|
.getWorldContainer()
|
||||||
|
.toPath()
|
||||||
|
.resolve(
|
||||||
|
safeWorld
|
||||||
|
)
|
||||||
|
.toAbsolutePath()
|
||||||
|
.toString(),
|
||||||
|
"--dimension", String.valueOf(dimension),
|
||||||
|
"--output",
|
||||||
|
tilesPath
|
||||||
|
.resolve(chunkX + "." + chunkZ + ".png")
|
||||||
|
.toAbsolutePath()
|
||||||
|
.toString()
|
||||||
|
);
|
||||||
|
|
||||||
|
proc = processBuilder.start();
|
||||||
|
|
||||||
|
StringBuilder iOutput = new StringBuilder();
|
||||||
|
StringBuilder eOutput = new StringBuilder();
|
||||||
|
|
||||||
|
BufferedReader iReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
|
||||||
|
BufferedReader eReader = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
|
||||||
|
|
||||||
|
String iLine;
|
||||||
|
String eLine;
|
||||||
|
|
||||||
|
while ((iLine = iReader.readLine()) != null) {
|
||||||
|
iOutput.append(iLine).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((eLine = eReader.readLine()) != null) {
|
||||||
|
eOutput.append(eLine).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
try (FileWriter writer = new FileWriter(logPath.toFile(), true)) {
|
||||||
|
writer.append(iOutput.toString());
|
||||||
|
writer.append(eOutput.toString());
|
||||||
|
writer.append("----\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.waitFor();
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
LOGGER.throwing(this.getClass().getName(), "renderTile", e);
|
||||||
|
} finally {
|
||||||
|
if (proc != null) {
|
||||||
|
proc.destroyForcibly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
semaphore.release();
|
||||||
|
|
||||||
|
File tileFile = tilesPath
|
||||||
|
.resolve(chunkX + "." + chunkZ + ".png")
|
||||||
|
.toFile();
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
if (!tileFile.exists() && !tilesBeingRendered.contains(new ArrayList<>(Arrays.asList(chunkX * size, chunkZ * size)))) {
|
||||||
|
thread.start();
|
||||||
|
|
||||||
|
try {
|
||||||
|
thread.join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
|
||||||
|
LOGGER.throwing(this.getClass().getName(), "renderTile", e);
|
||||||
|
} finally {
|
||||||
|
tilesBeingRendered.remove(new ArrayList<>(Arrays.asList(chunkX * size, chunkZ * size)));
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] img = readTileImage(tileFile);
|
||||||
|
|
||||||
|
if (img != null)
|
||||||
|
return img;
|
||||||
|
|
||||||
|
return createErrorImage("Failed to render tile.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return readTileImage(tileFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] readTileImage(File tileFile) {
|
||||||
|
try {
|
||||||
|
return Files.readAllBytes(tileFile.toPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOGGER.throwing(this.getClass().getName(), "renderTile", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] createErrorImage(String msg) {
|
||||||
|
BufferedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
|
||||||
|
Graphics2D graphics = image.createGraphics();
|
||||||
|
|
||||||
|
graphics.setColor(Color.RED);
|
||||||
|
graphics.setFont(new Font("Arial", Font.BOLD, 24));
|
||||||
|
|
||||||
|
graphics.drawString(msg, 8, 32);
|
||||||
|
|
||||||
|
// image to byte array
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
try {
|
||||||
|
ImageIO.write(image, "png", outputStream);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOGGER.throwing(this.getClass().getName(), "renderTile", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputStream.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ import java.nio.file.Paths;
|
||||||
* <p>
|
* <p>
|
||||||
* This class is used to run the server in development mode.
|
* This class is used to run the server in development mode.
|
||||||
* </p>
|
* </p>
|
||||||
* <p>Copyright 2023-2024 TheClashFruit</p>
|
* <p>Copyright (c) 2023-2024 TheClashFruit</p>
|
||||||
*/
|
*/
|
||||||
public class DevRunner {
|
public class DevRunner {
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
|
@ -25,7 +25,7 @@ public class DevRunner {
|
||||||
|
|
||||||
ProcessBuilder pb = new ProcessBuilder();
|
ProcessBuilder pb = new ProcessBuilder();
|
||||||
|
|
||||||
pb.command("cmd", "/c", "start", "java", "-Xms128M", "-XX:MaxRAMPercentage=95.0", "-jar", "server.jar");
|
pb.command("cmd", "/c", "start", "java", "-Xms128M", "-XX:MaxRAMPercentage=95.0", "-jar", "server.jar", "nogui");
|
||||||
pb.directory(runDir);
|
pb.directory(runDir);
|
||||||
|
|
||||||
pb.start();
|
pb.start();
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
prefix: '§7[§cCRSS§7]§r '
|
prefix: '§7[§cCRSS§7]§r '
|
||||||
|
|
||||||
web:
|
web:
|
||||||
enabled: true
|
enabled: false
|
||||||
port: 25580
|
port: 25580
|
||||||
api:
|
api:
|
||||||
enabled: true
|
enabled: true
|
||||||
map:
|
map:
|
||||||
|
enabled: true
|
||||||
|
access_log:
|
||||||
enabled: false
|
enabled: false
|
||||||
path: 'tiles'
|
token: 'changeme'
|
||||||
worlds:
|
|
||||||
- world
|
sql:
|
||||||
|
connection: 'jdbc:mariadb://localhost:3306/crss'
|
||||||
|
username: 'crss'
|
||||||
|
password: 'crss1234'
|
||||||
|
|
||||||
gameRules:
|
gameRules:
|
||||||
playerSleepingPercentage: 100
|
playerSleepingPercentage: 100
|
27
src/main/resources/data/markers.json
Normal file
27
src/main/resources/data/markers.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://theclashfruit.theclashfruit.page/jsonschemas/crss/markers-1.0.json",
|
||||||
|
"version": 1,
|
||||||
|
"categories": {
|
||||||
|
"main": {
|
||||||
|
"color": "#FF0000",
|
||||||
|
"icon": "icon.png",
|
||||||
|
"title": "Main"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"markers": [
|
||||||
|
{
|
||||||
|
"category": "main",
|
||||||
|
"title": "Marker 1",
|
||||||
|
"description": "Description 1",
|
||||||
|
"x": 0.5,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "main",
|
||||||
|
"title": "2000; 2000",
|
||||||
|
"description": "The two-thousandth marker.",
|
||||||
|
"x": 2000,
|
||||||
|
"y": 2000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,15 +1,22 @@
|
||||||
name: CRSS
|
name: CRSS
|
||||||
main: me.theclashfruit.crss.Plugin
|
main: me.theclashfruit.crss.CRSSPlugin
|
||||||
version: ${version}
|
version: ${version}
|
||||||
database: true
|
database: true
|
||||||
|
|
||||||
author: TheClashFruit
|
author: TheClashFruit
|
||||||
|
|
||||||
commands:
|
|
||||||
balance:
|
|
||||||
description: Check your balance
|
|
||||||
usage: /balance
|
|
||||||
|
|
||||||
load: POSTWORLD
|
load: POSTWORLD
|
||||||
depend:
|
|
||||||
- Vault
|
commands:
|
||||||
|
crss:
|
||||||
|
description: Your description
|
||||||
|
usage: /<command>
|
||||||
|
permission: crss.admin
|
||||||
|
checkdb:
|
||||||
|
description: Your description
|
||||||
|
usage: /<command>
|
||||||
|
permission: crss.admin
|
||||||
|
atm:
|
||||||
|
description: Your description
|
||||||
|
usage: /<command>
|
||||||
|
permission: crss.banking.atm
|
Reference in a new issue