Compare commits
71
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e85e42bd0 | ||
|
|
3f2ec3d40f | ||
|
|
ed80083fe8 | ||
|
|
d041e0a8d1 | ||
|
|
de85be5832 | ||
|
|
81d59d8bf5 | ||
|
|
0c2d2f4e0a | ||
|
|
3d9108fb48 | ||
|
|
25c616bc32 | ||
|
|
148187025a | ||
|
|
115b0dc078 | ||
|
|
78bf6ba3bf | ||
|
|
e31c391af4 | ||
|
|
6ed4be9a64 | ||
|
|
d626e7e4b1 | ||
|
|
e7dd4fee51 | ||
|
|
146075de69 | ||
|
|
9fce6c54f6 | ||
|
|
f189eb3b7e | ||
|
|
2d4fe301cf | ||
|
|
e5fe1fe565 | ||
|
|
83010f1a28 | ||
|
|
864e50e38c | ||
|
|
0a99258f3e | ||
|
|
b345baf20e | ||
|
|
d532052c7b | ||
|
|
1c02fb4387 | ||
|
|
2a99649e1e | ||
|
|
994bf922af | ||
|
|
36094e2bea | ||
|
|
6243b41956 | ||
|
|
32170cc089 | ||
|
|
c1a3d48944 | ||
|
|
75855826e7 | ||
|
|
d35363b10c | ||
|
|
ad1b733498 | ||
|
|
9159dfbb7d | ||
|
|
b8acd339b3 | ||
|
|
51e035eb3e | ||
|
|
2fd8e3edc3 | ||
|
|
faf20ee36e | ||
|
|
e1494808f3 | ||
|
|
05cf052204 | ||
|
|
242f05fc77 | ||
|
|
dd29fcc1dd | ||
|
|
d5013546d1 | ||
|
|
058c0837f0 | ||
|
|
e01c646562 | ||
|
|
3afca50930 | ||
|
|
94ca18e95c | ||
|
|
707eae92a8 | ||
|
|
b4a4519876 | ||
|
|
4f41b7aa6e | ||
|
|
b9267a3dfc | ||
|
|
a53c4214f0 | ||
|
|
343695e23e | ||
|
|
e17e9c8ce9 | ||
|
|
676c3a2e3d | ||
|
|
e821611744 | ||
|
|
d69c492577 | ||
|
|
eb91eefc80 | ||
|
|
f570c81366 | ||
|
|
b3f23278b1 | ||
|
|
3fa2bfa7cf | ||
|
|
582d6bef1a | ||
|
|
04c65cc59e | ||
|
|
268c4982c3 | ||
|
|
8983a0c024 | ||
|
|
1cbe901e4d | ||
|
|
4894abd1f1 | ||
|
|
46f8453b5b |
No files matched your search
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 💬 Multiverse Discord Server
|
||||
url: https://discord.gg/NZtfKky
|
||||
about: Need help with using Multiverse-Core or just want to chat with the devs? Join the Multiverse Discord Server for help!
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
name: ❓ Help!
|
||||
about: Encountered a problem with Multiverse-Core? Not sure how to fix it?
|
||||
title: ''
|
||||
labels: 'Type: Assistance'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Multiverse-Core help guide
|
||||
|
||||
Don't write inside the arrows as they will be hidden when you post your issue.
|
||||
|
||||
Get latest build from: http://ci.onarandombox.com/view/Multiverse/
|
||||
|
||||
If you need help other submodules of Multiverse, go to their respective git repo:
|
||||
Multiverse-Portals: https://github.com/Multiverse/Multiverse-Portals/issues
|
||||
Multiverse-NetherPortals: https://github.com/Multiverse/Multiverse-NetherPortals/issues
|
||||
Multiverse-Inventories: https://github.com/Multiverse/Multiverse-Inventories/issues
|
||||
Multiverse-SignPortals: https://github.com/Multiverse/Multiverse-SignPortals/issues
|
||||
|
||||
Or come join our Discord server to get help sooner: https://discord.gg/NZtfKky
|
||||
|
||||
If you're happy to wait (or you were sent here from Discord), read on:
|
||||
|
||||
1. Check the Usage and FAQ pages to see if it answers your queries:
|
||||
https://github.com/Multiverse/Multiverse-Core/wiki/Basics
|
||||
https://github.com/Multiverse/Multiverse-Core/wiki/FAQ
|
||||
|
||||
2. Fill out the template.
|
||||
This will help us understand what problem you've encountered and help us
|
||||
find a solution.
|
||||
|
||||
3. When linking files, do not attach them to the post!
|
||||
Copy and paste any logs into https://gist.github.com/ or other similar service.
|
||||
|
||||
4. Delete this line and all above lines before posting your issue! -->
|
||||
|
||||
### Information
|
||||
|
||||
* **Server version:** <!-- Insert output of `/version` command -->
|
||||
|
||||
* **Full output of `/mv version -p`:** <!-- Replace this with the command output's https://paste.gg/ link -->
|
||||
|
||||
* **Server log:** <!-- Upload `logs/latest.log` to https://gist.github.com/ -->
|
||||
|
||||
### Help request
|
||||
|
||||
**Problem**
|
||||
<!-- What problem did you encounter? -->
|
||||
|
||||
**What I have tried**
|
||||
<!-- What have you tried so far? -->
|
||||
|
||||
**Screenshots**
|
||||
<!-- If relevant, include any screenshots here. -->
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
name: 🐛 Report a Bug
|
||||
about: Report a Multiverse-Core bug. Only use this if you're 100% sure it's something wrong with Multiverse-Core - otherwise, try "Help!".
|
||||
title: ''
|
||||
labels: 'Bug: Unconfirmed'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Multiverse-Core bug reporting guide
|
||||
|
||||
Don't put anything inside this block, as it won't be included in the issue.
|
||||
|
||||
Get latest build from: http://ci.onarandombox.com/view/Multiverse/
|
||||
|
||||
If you are having issues with other submodules of Multiverse, go to their respective git repo:
|
||||
Multiverse-Portals: https://github.com/Multiverse/Multiverse-Portals/issues
|
||||
Multiverse-NetherPortals: https://github.com/Multiverse/Multiverse-NetherPortals/issues
|
||||
Multiverse-Inventories: https://github.com/Multiverse/Multiverse-Inventories/issues
|
||||
Multiverse-SignPortals: https://github.com/Multiverse/Multiverse-SignPortals/issues
|
||||
|
||||
If you are reporting a bug, please follow the following steps:
|
||||
|
||||
1. Fill out the template in full.
|
||||
Run the commands in the console. Don't just put "latest" as a version,
|
||||
or we will ignore it.
|
||||
|
||||
2. When linking files, do not attach them to the post!
|
||||
Copy and paste any logs into https://gist.github.com/, then paste a
|
||||
link to them in the relevant parts of the template.
|
||||
**DO NOT drag files into this box!**
|
||||
|
||||
3. Make sure not to write between the arrows, as anything there will be
|
||||
hidden.
|
||||
|
||||
4. Delete this line and all above lines before posting your issue! -->
|
||||
|
||||
### Information
|
||||
|
||||
* **Server version:** <!-- Insert output of `/version` command -->
|
||||
|
||||
* **Full output of `/mv version -p`:** <!-- Replace this with the command output's https://paste.gg/ link -->
|
||||
|
||||
* **Server log:** <!-- Upload `logs/latest.log` to https://gist.github.com/ -->
|
||||
|
||||
### Details
|
||||
I was **`<able / not able>`** to reproduce my issue on a freshly setup and up-to-date server with the latest version of Multiverse plugins with no other plugins and with no kinds of other server or client mods.
|
||||
|
||||
**Description**
|
||||
<!-- Replace this with a brief summary of the bug. -->
|
||||
|
||||
**Steps to reproduce**
|
||||
<!-- Replace this with exactly what you did to cause the bug. -->
|
||||
|
||||
**Expected behavior**
|
||||
<!-- Replace this with what you expected to happen. -->
|
||||
|
||||
**Screenshots**
|
||||
<!-- Replace this with screenshots, if necessary. -->
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
name: 💡 Request a Feature
|
||||
about: Suggest a feature you want to see in Multiverse-Core!
|
||||
title: ''
|
||||
labels: 'Type: Idea'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Multiverse-Core feature request guide
|
||||
|
||||
Fill out the template. Don't write inside the arrows as they will be hidden
|
||||
when you post your issue.
|
||||
|
||||
Get latest build from: http://ci.onarandombox.com/view/Multiverse/
|
||||
|
||||
If you are look for other submodules of Multiverse, go to their respective git repo:
|
||||
Multiverse-Portals: https://github.com/Multiverse/Multiverse-Portals/issues
|
||||
Multiverse-NetherPortals: https://github.com/Multiverse/Multiverse-NetherPortals/issues
|
||||
Multiverse-Inventories: https://github.com/Multiverse/Multiverse-Inventories/issues
|
||||
Multiverse-SignPortals: https://github.com/Multiverse/Multiverse-SignPortals/issues
|
||||
|
||||
Not sure if your feature fits in Multiverse-Core? Feel free to ask on our Discord
|
||||
server: https://discord.gg/NZtfKky
|
||||
|
||||
If you have a feature suggestion for Multiverse-Core, read the following tips:
|
||||
|
||||
1. Fill out the template.
|
||||
This will help us understand what you're requesting and why you want us
|
||||
to add it.
|
||||
|
||||
2. Keep it simple.
|
||||
Make sure it's easy to understand what you're requesting. A good way is
|
||||
to keep it to one request per GitHub issue, as we can then easily track
|
||||
feature requests.
|
||||
|
||||
3. Check whether it has already been asked or added.
|
||||
You can search the issue tracker to see if your feature has already been
|
||||
requested at https://github.com/Multiverse/Multiverse-Core/issues.
|
||||
|
||||
4. Ask yourself: "Does this belong in Multiverse-Core?"
|
||||
There are lots of features that we reject because most servers won't
|
||||
need or use them. If your feature is very specific or already exists in
|
||||
another plugin, it might not be a good fit for Multiverse-Core.
|
||||
|
||||
5. Delete this line and all above lines before posting your issue! -->
|
||||
|
||||
### Feature request
|
||||
|
||||
**Feature description**
|
||||
<!-- What feature are you suggesting? -->
|
||||
|
||||
**How the feature is useful**
|
||||
<!-- How is the feature useful to players, server owners and/or developers? -->
|
||||
@@ -13,4 +13,4 @@ Copyright (c) 2011, The Multiverse Team All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the The Multiverse Team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
File renamed without changes.
@@ -3,18 +3,19 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.onarandombox.multiversecore</groupId>
|
||||
<artifactId>Multiverse-Core</artifactId>
|
||||
<version>4.1.1-SNAPSHOT</version>
|
||||
<version>4.2.3-SNAPSHOT</version>
|
||||
<name>Multiverse-Core</name>
|
||||
<description>World Management Plugin</description>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.build.number>UNKNOWN</project.build.number>
|
||||
<project.bitly-access-token>bitly-access-token</project.bitly-access-token>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<!-- Spigot -->
|
||||
<repository>
|
||||
<id>spigotmc-repo</id>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
@@ -33,10 +34,9 @@
|
||||
<id>minebench-repo</id>
|
||||
<url>https://repo.minebench.de/</url>
|
||||
</repository>
|
||||
<!-- Has a copy of metrics R8-SNAPSHOT !-->
|
||||
<repository>
|
||||
<id>elmakers-repo</id>
|
||||
<url>http://maven.elmakers.com/repository/</url>
|
||||
<id>CodeMC</id>
|
||||
<url>https://repo.codemc.org/repository/maven-public</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
@@ -70,6 +70,17 @@
|
||||
<project.build.number>${env.BUILD_NUMBER}</project.build.number>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>bitly</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>env.BITLY_ACCESS_TOKEN</name>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<project.bitly-access-token>${env.BITLY_ACCESS_TOKEN}</project.bitly-access-token>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
@@ -91,21 +102,44 @@
|
||||
<version>1.4.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>replace-bitly-access-token</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>replace</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<basedir>${project.build.sourceDirectory}</basedir>
|
||||
<includes>
|
||||
<include>com/onarandombox/MultiverseCore/utils/webpaste/BitlyURLShortener.java</include>
|
||||
</includes>
|
||||
<replacements>
|
||||
<replacement>
|
||||
<token>bitly-access-token</token>
|
||||
<value>${project.bitly-access-token}</value>
|
||||
</replacement>
|
||||
</replacements>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>replace-maven-version-number</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>replace</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<basedir>${project.build.directory}/classes</basedir>
|
||||
<includes>
|
||||
<include>plugin.yml</include>
|
||||
</includes>
|
||||
<replacements>
|
||||
<replacement>
|
||||
<token>maven-version-number</token>
|
||||
<value>${project.version}-b${project.build.number}</value>
|
||||
</replacement>
|
||||
</replacements>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<file>target/classes/plugin.yml</file>
|
||||
<replacements>
|
||||
<replacement>
|
||||
<token>maven-version-number</token>
|
||||
<value>${project.version}-b${project.build.number}</value>
|
||||
</replacement>
|
||||
</replacements>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- Jar Plugin -->
|
||||
<plugin>
|
||||
@@ -162,17 +196,6 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>net.sf.doodleproject</artifactId>
|
||||
<artifactId>doxygen-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<alphabeticalIndex>true</alphabeticalIndex>
|
||||
<inputDirectory>${basedir}/src/main/java</inputDirectory>
|
||||
<filePatterns>*.java</filePatterns>
|
||||
<recursive>true</recursive>
|
||||
<outputDirectory>${project.reporting.outputDirectory}/doxygen</outputDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.10.4</version>
|
||||
@@ -214,8 +237,8 @@
|
||||
<shadedPattern>com.onarandombox.buscript</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.mcstats</pattern>
|
||||
<shadedPattern>com.onarandombox.mcstats</shadedPattern>
|
||||
<pattern>org.bstats</pattern>
|
||||
<shadedPattern>com.onarandombox.bstats</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.dumptruckman.minecraft.util.Logging</pattern>
|
||||
@@ -294,9 +317,9 @@
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mcstats.bukkit</groupId>
|
||||
<artifactId>metrics</artifactId>
|
||||
<version>R8-SNAPSHOT</version>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bukkit</artifactId>
|
||||
<version>1.7</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.bukkit</groupId>
|
||||
|
||||
@@ -17,11 +17,9 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import buscript.Buscript;
|
||||
@@ -34,7 +32,6 @@ import com.onarandombox.MultiverseCore.api.MVPlugin;
|
||||
import com.onarandombox.MultiverseCore.api.MVWorldManager;
|
||||
import com.onarandombox.MultiverseCore.api.MultiverseCoreConfig;
|
||||
import com.onarandombox.MultiverseCore.api.MultiverseMessaging;
|
||||
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
|
||||
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
|
||||
import com.onarandombox.MultiverseCore.commands.AnchorCommand;
|
||||
import com.onarandombox.MultiverseCore.commands.CheckCommand;
|
||||
@@ -96,6 +93,8 @@ import com.onarandombox.MultiverseCore.utils.MVMessaging;
|
||||
import com.onarandombox.MultiverseCore.utils.MVPermissions;
|
||||
import com.onarandombox.MultiverseCore.utils.MVPlayerSession;
|
||||
import com.onarandombox.MultiverseCore.utils.MaterialConverter;
|
||||
import com.onarandombox.MultiverseCore.utils.TestingMode;
|
||||
import com.onarandombox.MultiverseCore.utils.metrics.MetricsConfigurator;
|
||||
import com.onarandombox.MultiverseCore.utils.SimpleBlockSafety;
|
||||
import com.onarandombox.MultiverseCore.utils.SimpleLocationManipulation;
|
||||
import com.onarandombox.MultiverseCore.utils.SimpleSafeTTeleporter;
|
||||
@@ -109,7 +108,6 @@ import org.bukkit.ChatColor;
|
||||
import org.bukkit.Difficulty;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.Configuration;
|
||||
@@ -122,7 +120,6 @@ import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
import org.mcstats.Metrics;
|
||||
|
||||
/**
|
||||
* The implementation of the Multiverse-{@link Core}.
|
||||
@@ -346,104 +343,23 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
|
||||
}
|
||||
}
|
||||
|
||||
private void setupMetrics() {
|
||||
if (TestingMode.isDisabled()) {
|
||||
MetricsConfigurator.configureMetrics(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the buscript javascript library.
|
||||
*/
|
||||
private void initializeBuscript() {
|
||||
buscript = new Buscript(this);
|
||||
// Add global variable "multiverse" to javascript environment
|
||||
buscript.setScriptVariable("multiverse", this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plotter for Environment-Values.
|
||||
*/
|
||||
private static final class EnvironmentPlotter extends Metrics.Plotter {
|
||||
private MultiverseCore core;
|
||||
private final Environment env;
|
||||
|
||||
public EnvironmentPlotter(MultiverseCore core, Environment env) {
|
||||
super(envToString(env));
|
||||
this.core = core;
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
private static String envToString(Environment env) {
|
||||
return new StringBuilder().append(env.name().toUpperCase().charAt(0))
|
||||
.append(env.name().toLowerCase().substring(1)).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getValue() {
|
||||
int count = 0;
|
||||
for (MultiverseWorld w : core.getMVWorldManager().getMVWorlds())
|
||||
if (w.getEnvironment() == env)
|
||||
count++;
|
||||
core.log(Level.FINE, String.format("Tracking %d worlds of type %s", count, env));
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Plotter for Generator-Values.
|
||||
*/
|
||||
private static final class GeneratorPlotter extends Metrics.Plotter {
|
||||
private MultiverseCore core;
|
||||
private final String gen;
|
||||
|
||||
public GeneratorPlotter(MultiverseCore core, String gen) {
|
||||
super(gen);
|
||||
this.core = core;
|
||||
this.gen = gen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getValue() {
|
||||
int count = 0;
|
||||
for (MultiverseWorld w : core.getMVWorldManager().getMVWorlds())
|
||||
if (gen.equals(w.getGenerator()))
|
||||
count++;
|
||||
core.log(Level.FINE, String.format("Tracking %d worlds of type %s", count, gen));
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
private void setupMetrics() {
|
||||
try {
|
||||
Metrics m = new Metrics(this);
|
||||
|
||||
Metrics.Graph envGraph = m.createGraph("Worlds by environment");
|
||||
for (Environment env : Environment.values())
|
||||
envGraph.addPlotter(new EnvironmentPlotter(this, env));
|
||||
|
||||
Metrics.Graph loadedWorldsGraph = m.createGraph("Worlds by environment");
|
||||
loadedWorldsGraph.addPlotter(new Metrics.Plotter("Loaded worlds") {
|
||||
@Override
|
||||
public int getValue() {
|
||||
return getMVWorldManager().getMVWorlds().size();
|
||||
}
|
||||
});
|
||||
loadedWorldsGraph.addPlotter(new Metrics.Plotter("Total number of worlds") {
|
||||
@Override
|
||||
public int getValue() {
|
||||
return getMVWorldManager().getMVWorlds().size()
|
||||
+ getMVWorldManager().getUnloadedWorlds().size();
|
||||
}
|
||||
});
|
||||
|
||||
Set<String> gens = new HashSet<String>();
|
||||
for (MultiverseWorld w : this.getMVWorldManager().getMVWorlds())
|
||||
gens.add(w.getGenerator());
|
||||
gens.remove(null);
|
||||
gens.remove("null");
|
||||
Metrics.Graph genGraph = m.createGraph("Custom Generators");
|
||||
for (String gen : gens)
|
||||
genGraph.addPlotter(new GeneratorPlotter(this, gen));
|
||||
|
||||
m.start();
|
||||
log(Level.FINE, "Metrics have run!");
|
||||
} catch (Exception e) {
|
||||
log(Level.WARNING, "There was an issue while enabling metrics: " + e.getMessage());
|
||||
buscript = new Buscript(this);
|
||||
// Add global variable "multiverse" to javascript environment
|
||||
buscript.setScriptVariable("multiverse", this);
|
||||
} catch (NullPointerException e) {
|
||||
buscript = null;
|
||||
Logging.warning("Buscript failed to load! The script command will be disabled!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,7 +383,7 @@ public class MultiverseCore extends JavaPlugin implements MVPlugin, Core {
|
||||
pm.registerEvents(this.entityListener, this);
|
||||
pm.registerEvents(this.weatherListener, this);
|
||||
pm.registerEvents(this.portalListener, this);
|
||||
log(Level.INFO, "We are aware of the warning about the deprecated event. There is no alternative that allows us to do what we need to do. The performance impact is negligible.");
|
||||
log(Level.INFO, ChatColor.GREEN + "We are aware of the warning about the deprecated event. There is no alternative that allows us to do what we need to do and performance impact is negligible. It is safe to ignore.");
|
||||
pm.registerEvents(this.worldListener, this);
|
||||
pm.registerEvents(new MVMapListener(this), this);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.onarandombox.MultiverseCore.commands;
|
||||
import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -55,7 +56,7 @@ public class GameruleCommand extends MultiverseCommand {
|
||||
return;
|
||||
}
|
||||
|
||||
final String gameRule = args.get(0);
|
||||
final GameRule gameRule = GameRule.getByName(args.get(0));
|
||||
final String value = args.get(1);
|
||||
final World world;
|
||||
if (args.size() == 2) {
|
||||
@@ -64,17 +65,52 @@ public class GameruleCommand extends MultiverseCommand {
|
||||
world = Bukkit.getWorld(args.get(2));
|
||||
if (world == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Failure!" + ChatColor.WHITE + " World " + ChatColor.AQUA + args.get(2)
|
||||
+ ChatColor.WHITE + " does not exist.");
|
||||
+ ChatColor.WHITE + " does not exist.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (world.setGameRuleValue(gameRule, value)) {
|
||||
sender.sendMessage(ChatColor.GREEN + "Success!" + ChatColor.WHITE + " Gamerule " + ChatColor.AQUA + gameRule
|
||||
+ ChatColor.WHITE + " was set to " + ChatColor.GREEN + value);
|
||||
if (gameRule == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Failure! " + ChatColor.AQUA + args.get(0) + ChatColor.WHITE
|
||||
+ " is not a valid gamerule.");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "Failure!" + ChatColor.WHITE + " Gamerule " + ChatColor.AQUA + gameRule
|
||||
+ ChatColor.WHITE + " cannot be set to " + ChatColor.RED + value);
|
||||
if (gameRule.getType() == Boolean.class) {
|
||||
boolean booleanValue;
|
||||
if (value.equalsIgnoreCase("true")) {
|
||||
booleanValue = true;
|
||||
} else if (value.equalsIgnoreCase("false")) {
|
||||
booleanValue = false;
|
||||
} else {
|
||||
sender.sendMessage(getErrorMessage(gameRule.getName(), value) + "it can only be set to true or false.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!world.setGameRule(gameRule, booleanValue)) {
|
||||
sender.sendMessage(getErrorMessage(gameRule.getName(), value) + "something went wrong.");
|
||||
return;
|
||||
}
|
||||
} else if (gameRule.getType() == Integer.class) {
|
||||
try {
|
||||
if (!world.setGameRule(gameRule, Integer.parseInt(value))) {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(getErrorMessage(gameRule.getName(), value) + "it can only be set to a positive integer.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "Failure!" + ChatColor.WHITE + " Gamerule " + ChatColor.AQUA + gameRule.getName()
|
||||
+ ChatColor.WHITE + " isn't supported yet, please let us know about it.");
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendMessage(ChatColor.GREEN + "Success!" + ChatColor.WHITE + " Gamerule " + ChatColor.AQUA + gameRule.getName()
|
||||
+ ChatColor.WHITE + " was set to " + ChatColor.GREEN + value + ChatColor.WHITE + ".");
|
||||
}
|
||||
}
|
||||
|
||||
private String getErrorMessage(String gameRule, String value) {
|
||||
return ChatColor.RED + "Failure!" + ChatColor.WHITE + " Gamerule " + ChatColor.AQUA + gameRule
|
||||
+ ChatColor.WHITE + " could not be set to " + ChatColor.RED + value + ChatColor.WHITE + ", ";
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ package com.onarandombox.MultiverseCore.commands;
|
||||
import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -60,6 +61,11 @@ public class GamerulesCommand extends MultiverseCommand {
|
||||
world = p.getWorld();
|
||||
} else {
|
||||
world = Bukkit.getWorld(args.get(0));
|
||||
if (world == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Failure!" + ChatColor.WHITE + " World " + ChatColor.AQUA + args.get(0)
|
||||
+ ChatColor.WHITE + " does not exist.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final StringBuilder gameRules = new StringBuilder();
|
||||
@@ -68,7 +74,7 @@ public class GamerulesCommand extends MultiverseCommand {
|
||||
gameRules.append(ChatColor.WHITE).append(", ");
|
||||
}
|
||||
gameRules.append(ChatColor.AQUA).append(gameRule).append(ChatColor.WHITE).append(": ");
|
||||
gameRules.append(ChatColor.GREEN).append(world.getGameRuleValue(gameRule));
|
||||
gameRules.append(ChatColor.GREEN).append(world.getGameRuleValue(GameRule.getByName(gameRule)));
|
||||
}
|
||||
sender.sendMessage("=== Gamerules for " + ChatColor.AQUA + world.getName() + ChatColor.WHITE + " ===");
|
||||
sender.sendMessage(gameRules.toString());
|
||||
|
||||
@@ -26,7 +26,7 @@ public class ListCommand extends PaginatedCoreCommand<String> {
|
||||
public ListCommand(MultiverseCore plugin) {
|
||||
super(plugin);
|
||||
this.setName("World Listing");
|
||||
this.setCommandUsage("/mv list");
|
||||
this.setCommandUsage("/mv list [page]");
|
||||
this.setArgRange(0, 2);
|
||||
this.addKey("mvlist");
|
||||
this.addKey("mvl");
|
||||
|
||||
@@ -27,6 +27,7 @@ public class ReloadCommand extends MultiverseCommand {
|
||||
this.setCommandUsage("/mv reload");
|
||||
this.setArgRange(0, 0);
|
||||
this.addKey("mvreload");
|
||||
this.addKey("mvr");
|
||||
this.addKey("mv reload");
|
||||
this.addCommandExample("/mv reload");
|
||||
this.setPermission("multiverse.core.reload", "Reloads worlds.yml and config.yml.", PermissionDefault.OP);
|
||||
|
||||
@@ -35,6 +35,10 @@ public class ScriptCommand extends MultiverseCommand {
|
||||
|
||||
@Override
|
||||
public void runCommand(CommandSender sender, List<String> args) {
|
||||
if (plugin.getScriptAPI() == null) {
|
||||
sender.sendMessage("Buscript failed to load while the server was starting. Scripts cannot be run.");
|
||||
return;
|
||||
}
|
||||
File file = new File(plugin.getScriptAPI().getScriptFolder(), args.get(0));
|
||||
if (!file.exists()) {
|
||||
sender.sendMessage("That script file does not exist in the Multiverse-Core scripts directory!");
|
||||
|
||||
@@ -30,6 +30,7 @@ public class SetSpawnCommand extends MultiverseCommand {
|
||||
this.setCommandUsage("/mv setspawn");
|
||||
this.setArgRange(0, 6);
|
||||
this.addKey("mvsetspawn");
|
||||
this.addKey("mvsets");
|
||||
this.addKey("mvss");
|
||||
this.addKey("mv set spawn");
|
||||
this.addKey("mv setspawn");
|
||||
|
||||
@@ -40,7 +40,7 @@ public class TeleportCommand extends MultiverseCommand {
|
||||
Permission menu = new Permission("multiverse.teleport.*", "Allows you to display the teleport menu.", PermissionDefault.OP);
|
||||
|
||||
this.setName("Teleport");
|
||||
this.setCommandUsage("/mv tp " + ChatColor.GOLD + "[PLAYER]" + ChatColor.GREEN + " {WORLD}");
|
||||
this.setCommandUsage("/mv tp " + ChatColor.GOLD + "[PLAYER]" + ChatColor.GREEN + " {DESTINATION}");
|
||||
this.setArgRange(1, 2);
|
||||
this.addKey("mvtp");
|
||||
this.addKey("mv tp");
|
||||
|
||||
@@ -10,12 +10,13 @@ package com.onarandombox.MultiverseCore.commands;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||
import com.onarandombox.MultiverseCore.event.MVVersionEvent;
|
||||
import com.onarandombox.MultiverseCore.utils.webpaste.BitlyURLShortener;
|
||||
import com.onarandombox.MultiverseCore.utils.webpaste.PasteFailedException;
|
||||
import com.onarandombox.MultiverseCore.utils.webpaste.PasteService;
|
||||
import com.onarandombox.MultiverseCore.utils.webpaste.PasteServiceFactory;
|
||||
import com.onarandombox.MultiverseCore.utils.webpaste.PasteServiceType;
|
||||
import com.onarandombox.MultiverseCore.utils.webpaste.URLShortener;
|
||||
import com.onarandombox.MultiverseCore.utils.webpaste.URLShortenerFactory;
|
||||
import com.onarandombox.MultiverseCore.utils.webpaste.URLShortenerType;
|
||||
import com.pneumaticraft.commandhandler.CommandHandler;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
@@ -24,10 +25,8 @@ import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.StringUtil;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -35,110 +34,91 @@ import java.util.Map;
|
||||
* Dumps version info to the console.
|
||||
*/
|
||||
public class VersionCommand extends MultiverseCommand {
|
||||
private static final URLShortener SHORTENER = new BitlyURLShortener();
|
||||
private static final URLShortener SHORTENER = URLShortenerFactory.getService(URLShortenerType.BITLY);
|
||||
|
||||
public VersionCommand(MultiverseCore plugin) {
|
||||
super(plugin);
|
||||
this.setName("Multiverse Version");
|
||||
this.setCommandUsage("/mv version " + ChatColor.GOLD + "-[bh] [--include-plugin-list]");
|
||||
this.setCommandUsage("/mv version " + ChatColor.GOLD + "[-b|-h|-p] [--include-plugin-list]");
|
||||
this.setArgRange(0, 2);
|
||||
this.addKey("mv version");
|
||||
this.addKey("mvver");
|
||||
this.addKey("mvv");
|
||||
this.addKey("mvversion");
|
||||
this.setPermission("multiverse.core.version",
|
||||
"Dumps version info to the console, optionally to pastie.org with -p or pastebin.com with a -b.", PermissionDefault.TRUE);
|
||||
"Dumps version info to the console, optionally to pastebin.com with -b, to hastebin.com using -h, or to paste.gg with -p.", PermissionDefault.TRUE);
|
||||
}
|
||||
|
||||
private String getLegacyString() {
|
||||
StringBuilder legacyFile = new StringBuilder();
|
||||
legacyFile.append("[Multiverse-Core] Multiverse-Core Version: ").append(this.plugin.getDescription().getVersion()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] Bukkit Version: ").append(this.plugin.getServer().getVersion()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] Loaded Worlds: ").append(this.plugin.getMVWorldManager().getMVWorlds()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] Multiverse Plugins Loaded: ").append(this.plugin.getPluginCount()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] Economy being used: ").append(plugin.getEconomist().getEconomyName()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] Permissions Plugin: ").append(this.plugin.getMVPerms().getType()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] Dumping Config Values: (version ")
|
||||
.append(this.plugin.getMVConfig().getVersion()).append(")").append('\n');
|
||||
legacyFile.append("[Multiverse-Core] messagecooldown: ").append(plugin.getMessaging().getCooldown()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] teleportcooldown: ").append(plugin.getMVConfig().getTeleportCooldown()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] worldnameprefix: ").append(plugin.getMVConfig().getPrefixChat()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] worldnameprefixFormat: ").append(plugin.getMVConfig().getPrefixChatFormat()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] enforceaccess: ").append(plugin.getMVConfig().getEnforceAccess()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] displaypermerrors: ").append(plugin.getMVConfig().getDisplayPermErrors()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] teleportintercept: ").append(plugin.getMVConfig().getTeleportIntercept()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] firstspawnoverride: ").append(plugin.getMVConfig().getFirstSpawnOverride()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] firstspawnworld: ").append(plugin.getMVConfig().getFirstSpawnWorld()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] debug: ").append(plugin.getMVConfig().getGlobalDebug()).append('\n');
|
||||
legacyFile.append("[Multiverse-Core] Special Code: FRN002").append('\n');
|
||||
return legacyFile.toString();
|
||||
return "[Multiverse-Core] Multiverse-Core Version: " + this.plugin.getDescription().getVersion() + '\n'
|
||||
+ "[Multiverse-Core] Bukkit Version: " + this.plugin.getServer().getVersion() + '\n'
|
||||
+ "[Multiverse-Core] Loaded Worlds: " + this.plugin.getMVWorldManager().getMVWorlds() + '\n'
|
||||
+ "[Multiverse-Core] Multiverse Plugins Loaded: " + this.plugin.getPluginCount() + '\n'
|
||||
+"[Multiverse-Core] Economy being used: " + plugin.getEconomist().getEconomyName() + '\n'
|
||||
+ "[Multiverse-Core] Permissions Plugin: " + this.plugin.getMVPerms().getType() + '\n'
|
||||
+ "[Multiverse-Core] Dumping Config Values: (version " + this.plugin.getMVConfig().getVersion() + ")" + '\n'
|
||||
+ "[Multiverse-Core] enforceaccess: " + plugin.getMVConfig().getEnforceAccess() + '\n'
|
||||
+ "[Multiverse-Core] prefixchat: " + plugin.getMVConfig().getPrefixChat() + '\n'
|
||||
+ "[Multiverse-Core] prefixchatformat: " + plugin.getMVConfig().getPrefixChatFormat() + '\n'
|
||||
+ "[Multiverse-Core] useasyncchat: " + plugin.getMVConfig().getUseAsyncChat() + '\n'
|
||||
+ "[Multiverse-Core] teleportintercept: " + plugin.getMVConfig().getTeleportIntercept() + '\n'
|
||||
+ "[Multiverse-Core] firstspawnoverride: " + plugin.getMVConfig().getFirstSpawnOverride() + '\n'
|
||||
+ "[Multiverse-Core] displaypermerrors: " + plugin.getMVConfig().getDisplayPermErrors() + '\n'
|
||||
+ "[Multiverse-Core] globaldebug: " + plugin.getMVConfig().getGlobalDebug() + '\n'
|
||||
+ "[Multiverse-Core] silentstart: " + plugin.getMVConfig().getSilentStart() + '\n'
|
||||
+ "[Multiverse-Core] messagecooldown: " + plugin.getMessaging().getCooldown() + '\n'
|
||||
+ "[Multiverse-Core] version: " + plugin.getMVConfig().getVersion() + '\n'
|
||||
+ "[Multiverse-Core] firstspawnworld: " + plugin.getMVConfig().getFirstSpawnWorld() + '\n'
|
||||
+ "[Multiverse-Core] teleportcooldown: " + plugin.getMVConfig().getTeleportCooldown() + '\n'
|
||||
+ "[Multiverse-Core] defaultportalsearch: " + plugin.getMVConfig().isUsingDefaultPortalSearch() + '\n'
|
||||
+ "[Multiverse-Core] portalsearchradius: " + plugin.getMVConfig().getPortalSearchRadius() + '\n'
|
||||
+ "[Multiverse-Core] autopurge: " + plugin.getMVConfig().isAutoPurgeEnabled() + '\n'
|
||||
+ "[Multiverse-Core] Special Code: FRN002" + '\n';
|
||||
}
|
||||
|
||||
private String getMarkdownString() {
|
||||
StringBuilder markdownString = new StringBuilder();
|
||||
markdownString.append("# Multiverse-Core\n");
|
||||
markdownString.append("## Overview\n");
|
||||
markdownString.append("| Name | Value |\n");
|
||||
markdownString.append("| --- | --- |\n");
|
||||
markdownString.append("| Multiverse-Core Version | `").append(this.plugin.getDescription().getVersion()).append("` |\n");
|
||||
markdownString.append("| Bukkit Version | `").append(this.plugin.getServer().getVersion()).append("` |\n");
|
||||
//markdownString.append("| Loaded Worlds | `").append(this.plugin.getMVWorldManager().getMVWorlds()).append("` |\n");
|
||||
markdownString.append("| Multiverse Plugins Loaded | `").append(this.plugin.getPluginCount()).append("` |\n");
|
||||
markdownString.append("| Economy being used | `").append(plugin.getEconomist().getEconomyName()).append("` |\n");
|
||||
markdownString.append("| Permissions Plugin | `").append(this.plugin.getMVPerms().getType()).append("` |\n");
|
||||
markdownString.append("## Parsed Config\n");
|
||||
markdownString.append("These are what Multiverse thought the in-memory values of the config were.\n\n");
|
||||
markdownString.append("| Config Key | Value |\n");
|
||||
markdownString.append("| --- | --- |\n");
|
||||
markdownString.append("| version | `").append(this.plugin.getMVConfig().getVersion()).append("` |\n");
|
||||
markdownString.append("| messagecooldown | `").append(plugin.getMessaging().getCooldown()).append("` |\n");
|
||||
markdownString.append("| teleportcooldown | `").append(plugin.getMVConfig().getTeleportCooldown()).append("` |\n");
|
||||
markdownString.append("| worldnameprefix | `").append(plugin.getMVConfig().getPrefixChat()).append("` |\n");
|
||||
markdownString.append("| worldnameprefixFormat | `").append(plugin.getMVConfig().getPrefixChatFormat()).append("` |\n");
|
||||
markdownString.append("| enforceaccess | `").append(plugin.getMVConfig().getEnforceAccess()).append("` |\n");
|
||||
markdownString.append("| displaypermerrors | `").append(plugin.getMVConfig().getDisplayPermErrors()).append("` |\n");
|
||||
markdownString.append("| teleportintercept | `").append(plugin.getMVConfig().getTeleportIntercept()).append("` |\n");
|
||||
markdownString.append("| firstspawnoverride | `").append(plugin.getMVConfig().getFirstSpawnOverride()).append("` |\n");
|
||||
markdownString.append("| firstspawnworld | `").append(plugin.getMVConfig().getFirstSpawnWorld()).append("` |\n");
|
||||
markdownString.append("| debug | `").append(plugin.getMVConfig().getGlobalDebug()).append("` |\n");
|
||||
return markdownString.toString();
|
||||
return "# Multiverse-Core" + '\n'
|
||||
+ "## Overview" + '\n'
|
||||
+ "| Name | Value |" + '\n'
|
||||
+ "| --- | --- |" + '\n'
|
||||
+ "| Multiverse-Core Version | `" + this.plugin.getDescription().getVersion() + "` |" + '\n'
|
||||
+ "| Bukkit Version | `" + this.plugin.getServer().getVersion() + "` |" + '\n'
|
||||
+ "| Loaded Worlds | `" + this.plugin.getMVWorldManager().getMVWorlds() + "` |" + '\n'
|
||||
+ "| Multiverse Plugins Loaded | `" + this.plugin.getPluginCount() + "` |" + '\n'
|
||||
+ "| Economy being used | `" + plugin.getEconomist().getEconomyName() + "` |" + '\n'
|
||||
+ "| Permissions Plugin | `" + this.plugin.getMVPerms().getType() + "` |" + '\n'
|
||||
+ "## Parsed Config" + '\n'
|
||||
+ "These are what Multiverse thought the in-memory values of the config were." + "\n\n"
|
||||
+ "| Config Key | Value |" + '\n'
|
||||
+ "| --- | --- |" + '\n'
|
||||
+ "| version | `" + this.plugin.getMVConfig().getVersion() + "` |" + '\n'
|
||||
+ "| messagecooldown | `" + plugin.getMessaging().getCooldown() + "` |" + '\n'
|
||||
+ "| teleportcooldown | `" + plugin.getMVConfig().getTeleportCooldown() + "` |" + '\n'
|
||||
+ "| worldnameprefix | `" + plugin.getMVConfig().getPrefixChat() + "` |" + '\n'
|
||||
+ "| worldnameprefixFormat | `" + plugin.getMVConfig().getPrefixChatFormat() + "` |" + '\n'
|
||||
+ "| enforceaccess | `" + plugin.getMVConfig().getEnforceAccess() + "` |" + '\n'
|
||||
+ "| displaypermerrors | `" + plugin.getMVConfig().getDisplayPermErrors() + "` |" + '\n'
|
||||
+ "| teleportintercept | `" + plugin.getMVConfig().getTeleportIntercept() + "` |" + '\n'
|
||||
+ "| firstspawnoverride | `" + plugin.getMVConfig().getFirstSpawnOverride() + "` |" + '\n'
|
||||
+ "| firstspawnworld | `" + plugin.getMVConfig().getFirstSpawnWorld() + "` |" + '\n'
|
||||
+ "| debug | `" + plugin.getMVConfig().getGlobalDebug() + "` |" + '\n';
|
||||
}
|
||||
|
||||
private String readFile(final String filename) {
|
||||
String result;
|
||||
try {
|
||||
FileReader reader = new FileReader(filename);
|
||||
BufferedReader bufferedReader = new BufferedReader(reader);
|
||||
String line;
|
||||
result = "";
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
result += line + '\n';
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Logging.severe("Unable to find %s. Here's the traceback: %s", filename, e.getMessage());
|
||||
e.printStackTrace();
|
||||
result = String.format("ERROR: Could not load: %s", filename);
|
||||
} catch (IOException e) {
|
||||
Logging.severe("Something bad happend when reading %s. Here's the traceback: %s", filename, e.getMessage());
|
||||
e.printStackTrace();
|
||||
result = String.format("ERROR: Could not load: %s", filename);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private void addVersionInfoToEvent(MVVersionEvent event) {
|
||||
// add the legacy version info
|
||||
event.appendVersionInfo(this.getLegacyString());
|
||||
|
||||
private Map<String, String> getVersionFiles() {
|
||||
Map<String, String> files = new HashMap<String, String>();
|
||||
// add the legacy file, but as markdown so it's readable
|
||||
// TODO Readd this in 5.0.0
|
||||
// event.putDetailedVersionInfo("version.md", this.getMarkdownString());
|
||||
|
||||
// Add the legacy file, but as markdown so it's readable
|
||||
files.put("version.md", this.getMarkdownString());
|
||||
|
||||
// Add the config.yml
|
||||
// add config.yml
|
||||
File configFile = new File(this.plugin.getDataFolder(), "config.yml");
|
||||
files.put(configFile.getName(), this.readFile(configFile.getAbsolutePath()));
|
||||
event.putDetailedVersionInfo("multiverse-core/config.yml", configFile);
|
||||
|
||||
// Add the config.yml
|
||||
File worldConfig = new File(this.plugin.getDataFolder(), "worlds.yml");
|
||||
files.put(worldConfig.getName(), this.readFile(worldConfig.getAbsolutePath()));
|
||||
return files;
|
||||
// add worlds.yml
|
||||
File worldsFile = new File(this.plugin.getDataFolder(), "worlds.yml");
|
||||
event.putDetailedVersionInfo("multiverse-core/worlds.yml", worldsFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,23 +128,26 @@ public class VersionCommand extends MultiverseCommand {
|
||||
sender.sendMessage("Version info dumped to console. Please check your server logs.");
|
||||
}
|
||||
|
||||
MVVersionEvent versionEvent = new MVVersionEvent(this.getLegacyString(), this.getVersionFiles());
|
||||
final Map<String, String> files = this.getVersionFiles();
|
||||
MVVersionEvent versionEvent = new MVVersionEvent();
|
||||
|
||||
this.addVersionInfoToEvent(versionEvent);
|
||||
this.plugin.getServer().getPluginManager().callEvent(versionEvent);
|
||||
|
||||
String versionInfo = versionEvent.getVersionInfo();
|
||||
|
||||
if (CommandHandler.hasFlag("--include-plugin-list", args)) {
|
||||
versionInfo = versionInfo + "\nPlugins: " + getPluginList();
|
||||
versionEvent.appendVersionInfo('\n' + "Plugins: " + getPluginList());
|
||||
versionEvent.putDetailedVersionInfo("plugins.txt", "Plugins: " + getPluginList());
|
||||
}
|
||||
|
||||
final String data = versionInfo;
|
||||
final String versionInfo = versionEvent.getVersionInfo();
|
||||
versionEvent.putDetailedVersionInfo("version.txt", versionInfo);
|
||||
|
||||
final Map<String, String> files = versionEvent.getDetailedVersionInfo();
|
||||
|
||||
// log to console
|
||||
String[] lines = data.split("\n");
|
||||
String[] lines = versionInfo.split("\\r?\\n");
|
||||
for (String line : lines) {
|
||||
if (!line.isEmpty()) {
|
||||
Logging.info(line);
|
||||
this.plugin.getServer().getLogger().info(line);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,10 +158,16 @@ public class VersionCommand extends MultiverseCommand {
|
||||
String pasteUrl;
|
||||
if (CommandHandler.hasFlag("-b", args)) {
|
||||
// private post to pastebin
|
||||
pasteUrl = postToService(PasteServiceType.PASTEBIN, true, data, files);
|
||||
pasteUrl = postToService(PasteServiceType.PASTEBIN, true, versionInfo, files);
|
||||
} else if (CommandHandler.hasFlag("-g", args)) {
|
||||
// private post to github
|
||||
pasteUrl = postToService(PasteServiceType.GITHUB, true, versionInfo, files);
|
||||
} else if (CommandHandler.hasFlag("-h", args)) {
|
||||
// private post to pastebin
|
||||
pasteUrl = postToService(PasteServiceType.HASTEBIN, true, data, files);
|
||||
// private post to hastebin
|
||||
pasteUrl = postToService(PasteServiceType.HASTEBIN, true, versionInfo, files);
|
||||
} else if (CommandHandler.hasFlag("-p", args)) {
|
||||
// private post to paste.gg
|
||||
pasteUrl = postToService(PasteServiceType.PASTEGG, true, versionInfo, files);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@@ -204,20 +193,25 @@ public class VersionCommand extends MultiverseCommand {
|
||||
* @param pasteFiles Map of filenames/contents of debug info.
|
||||
* @return URL of visible paste
|
||||
*/
|
||||
private static String postToService(PasteServiceType type, boolean isPrivate, String pasteData,
|
||||
Map<String, String> pasteFiles) {
|
||||
private static String postToService(PasteServiceType type, boolean isPrivate, String pasteData, Map<String, String> pasteFiles) {
|
||||
PasteService ps = PasteServiceFactory.getService(type, isPrivate);
|
||||
|
||||
try {
|
||||
String result;
|
||||
if (ps.supportsMultiFile()) {
|
||||
result = ps.postData(ps.encodeData(pasteFiles), ps.getPostURL());
|
||||
result = ps.postData(pasteFiles);
|
||||
} else {
|
||||
result = ps.postData(ps.encodeData(pasteData), ps.getPostURL());
|
||||
result = ps.postData(pasteData);
|
||||
}
|
||||
return SHORTENER.shorten(result);
|
||||
|
||||
if (SHORTENER != null) return SHORTENER.shorten(result);
|
||||
return result;
|
||||
} catch (PasteFailedException e) {
|
||||
System.out.print(e);
|
||||
return "Error posting to service";
|
||||
e.printStackTrace();
|
||||
return "Error posting to service.";
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
return "That service isn't supported yet.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.bukkit.util.Vector;
|
||||
* A bed-{@link MVDestination}.
|
||||
*/
|
||||
public class BedDestination implements MVDestination {
|
||||
public static final String OLD_BED_STRING = "b:playerbed";
|
||||
public static final String OWN_BED_STRING = "playerbed";
|
||||
private String playername = "";
|
||||
private boolean isValid;
|
||||
private Location knownBedLoc;
|
||||
@@ -46,11 +46,11 @@ public class BedDestination implements MVDestination {
|
||||
boolean validFormat = split.length >= 1 && split.length <= 2 && split[0].equals(this.getIdentifier());
|
||||
|
||||
OfflinePlayer p = Bukkit.getOfflinePlayer(split[1]);
|
||||
boolean validPlayer = (p != null);
|
||||
boolean validPlayer = p.getName() != null && !p.getName().equals(OWN_BED_STRING);
|
||||
|
||||
if (validFormat && validPlayer) this.playername = p.getName();
|
||||
|
||||
this.isValid = destination.equals(OLD_BED_STRING) || (validFormat && validPlayer);
|
||||
this.isValid = destination.equals("b:" + OWN_BED_STRING) || (validFormat && validPlayer);
|
||||
|
||||
return this.isValid;
|
||||
}
|
||||
@@ -136,6 +136,6 @@ public class BedDestination implements MVDestination {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return playername.isEmpty() ? OLD_BED_STRING : ("b:" + playername);
|
||||
return "b:" + (playername.isEmpty() ? OWN_BED_STRING : playername);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,16 @@
|
||||
package com.onarandombox.MultiverseCore.event;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -13,9 +21,9 @@ public class MVVersionEvent extends Event {
|
||||
private final StringBuilder versionInfoBuilder;
|
||||
private final Map<String, String> detailedVersionInfo;
|
||||
|
||||
public MVVersionEvent(String legacyVersionInfo, Map<String, String> files) {
|
||||
this.versionInfoBuilder = new StringBuilder(legacyVersionInfo);
|
||||
this.detailedVersionInfo = files;
|
||||
public MVVersionEvent() {
|
||||
versionInfoBuilder = new StringBuilder();
|
||||
detailedVersionInfo = new HashMap<>();
|
||||
}
|
||||
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
@@ -49,14 +57,14 @@ public class MVVersionEvent extends Event {
|
||||
*
|
||||
* This information is used for advanced paste services that would prefer
|
||||
* to get the information as several files. Examples include config.yml or
|
||||
* portals.yml.
|
||||
* portals.yml. Note that the map returned is immutable.
|
||||
*
|
||||
* The keys are filenames, the values are the contents of the files.
|
||||
*
|
||||
* @return The key value mapping of files and the contents of those files.
|
||||
* @return The immutable key value mapping of files and the contents of those files.
|
||||
*/
|
||||
public Map<String, String> getDetailedVersionInfo() {
|
||||
return this.detailedVersionInfo;
|
||||
return Collections.unmodifiableMap(this.detailedVersionInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,4 +74,46 @@ public class MVVersionEvent extends Event {
|
||||
public void appendVersionInfo(String moreVersionInfo) {
|
||||
this.versionInfoBuilder.append(moreVersionInfo);
|
||||
}
|
||||
|
||||
private String readFile(final String filename) {
|
||||
StringBuilder result;
|
||||
|
||||
try {
|
||||
FileReader reader = new FileReader(filename);
|
||||
BufferedReader bufferedReader = new BufferedReader(reader);
|
||||
String line;
|
||||
result = new StringBuilder();
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
result.append(line).append("\n");
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Logging.severe("Unable to find %s. Here's the traceback: %s", filename, e.getMessage());
|
||||
e.printStackTrace();
|
||||
result = new StringBuilder(String.format("ERROR: Could not load: %s", filename));
|
||||
} catch (IOException e) {
|
||||
Logging.severe("Something bad happend when reading %s. Here's the traceback: %s", filename, e.getMessage());
|
||||
e.printStackTrace();
|
||||
result = new StringBuilder(String.format("ERROR: Could not load: %s", filename));
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file to to the detailed version-info currently saved in this event.
|
||||
* @param fileName The name of the file.
|
||||
* @param contents The contents of the file.
|
||||
*/
|
||||
public void putDetailedVersionInfo(String fileName, String contents) {
|
||||
this.detailedVersionInfo.put(fileName, contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file to to the detailed version-info currently saved in this event.
|
||||
* @param filename The name of the file.
|
||||
* @param file The file.
|
||||
*/
|
||||
public void putDetailedVersionInfo(String filename, File file) {
|
||||
this.putDetailedVersionInfo(filename, readFile(file.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,9 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Stream;
|
||||
@@ -72,14 +74,27 @@ public class FileUtils {
|
||||
* @param target Target-File
|
||||
* @param log A logger that logs the operation
|
||||
*
|
||||
* @return if it had success
|
||||
* @return true if it had success
|
||||
*/
|
||||
public static boolean copyFolder(File source, File target, Logger log) {
|
||||
return copyFolder(source, target, null, log);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to copy the world-folder.
|
||||
* @param source Source-File
|
||||
* @param target Target-File
|
||||
* @param excludeFiles files to ignore and not copy over to Target-File
|
||||
* @param log A logger that logs the operation
|
||||
*
|
||||
* @return true if it had success
|
||||
*/
|
||||
public static boolean copyFolder(File source, File target, List<String> excludeFiles, Logger log) {
|
||||
Path sourceDir = source.toPath();
|
||||
Path targetDir = target.toPath();
|
||||
|
||||
try {
|
||||
Files.walkFileTree(sourceDir, new CopyDirFileVisitor(sourceDir, targetDir));
|
||||
Files.walkFileTree(sourceDir, new CopyDirFileVisitor(sourceDir, targetDir, excludeFiles));
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
log.log(Level.WARNING, "Unable to copy directory", e);
|
||||
@@ -91,10 +106,12 @@ public class FileUtils {
|
||||
|
||||
private final Path sourceDir;
|
||||
private final Path targetDir;
|
||||
private final List<String> excludeFiles;
|
||||
|
||||
private CopyDirFileVisitor(Path sourceDir, Path targetDir) {
|
||||
private CopyDirFileVisitor(Path sourceDir, Path targetDir, List<String> excludeFiles) {
|
||||
this.sourceDir = sourceDir;
|
||||
this.targetDir = targetDir;
|
||||
this.excludeFiles = excludeFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,9 +125,13 @@ public class FileUtils {
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
// Pass files that are set to ignore
|
||||
if (excludeFiles != null && excludeFiles.contains(file.getFileName().toString()))
|
||||
return FileVisitResult.CONTINUE;
|
||||
// Copy the files
|
||||
Path targetFile = targetDir.resolve(sourceDir.relativize(file));
|
||||
Files.copy(file, targetFile, COPY_ATTRIBUTES);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import com.onarandombox.MultiverseCore.api.LocationManipulation;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -52,7 +53,7 @@ public class SimpleLocationManipulation implements LocationManipulation {
|
||||
if (location == null) {
|
||||
return "";
|
||||
}
|
||||
return String.format("%s:%.2f,%.2f,%.2f:%.2f:%.2f", location.getWorld().getName(),
|
||||
return String.format(Locale.ENGLISH, "%s:%.2f,%.2f,%.2f:%.2f:%.2f", location.getWorld().getName(),
|
||||
location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.onarandombox.MultiverseCore.utils;
|
||||
|
||||
/**
|
||||
* A utility class that enables automated tests to flag Multiverse for testing. This allows Multiverse to not perform
|
||||
* certain behaviors such as enabled stats uploads.
|
||||
*/
|
||||
public class TestingMode {
|
||||
|
||||
private static boolean enabled = false;
|
||||
|
||||
public static void enable() {
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
public static boolean isDisabled() {
|
||||
return !enabled;
|
||||
}
|
||||
}
|
||||
@@ -43,15 +43,18 @@ import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Public facing API to add/remove Multiverse worlds.
|
||||
*/
|
||||
public class WorldManager implements MVWorldManager {
|
||||
private final MultiverseCore plugin;
|
||||
private final Pattern worldNamePattern = Pattern.compile("[a-zA-Z0-9/._-]+");
|
||||
private final WorldPurger worldPurger;
|
||||
private final Map<String, MultiverseWorld> worlds;
|
||||
private Map<String, WorldProperties> worldsFromTheConfig;
|
||||
@@ -59,6 +62,8 @@ public class WorldManager implements MVWorldManager {
|
||||
private Map<String, String> defaultGens;
|
||||
private String firstSpawn;
|
||||
|
||||
private static final List<String> CLONE_IGNORE_FILES = Arrays.asList("session.lock", "uid.dat");
|
||||
|
||||
public WorldManager(MultiverseCore core) {
|
||||
this.plugin = core;
|
||||
this.worldsFromTheConfig = new HashMap<String, WorldProperties>();
|
||||
@@ -91,6 +96,190 @@ public class WorldManager implements MVWorldManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes cloning easier to understand and manage.
|
||||
*/
|
||||
private class CloneHelper {
|
||||
private String oldName;
|
||||
private String newName;
|
||||
private File oldWorldFile;
|
||||
private File newWorldFile;
|
||||
private MultiverseWorld oldWorld;
|
||||
|
||||
public CloneHelper(String oldName, String newName) {
|
||||
this.oldName = oldName;
|
||||
this.newName = newName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The clone operation.
|
||||
*
|
||||
* @return True if clone is successful, false otherwise.
|
||||
*/
|
||||
public boolean run() {
|
||||
if (!validCloneParameters()) {
|
||||
Logging.warning("Invalid clone parameters");
|
||||
return false;
|
||||
}
|
||||
|
||||
initWorldFiles();
|
||||
if (newWorldFile.exists()) {
|
||||
Logging.warning("Folder for new world '%s' already exists", newName);
|
||||
return false;
|
||||
}
|
||||
|
||||
oldWorld = getMVWorld(oldName);
|
||||
if (!isOldWorldLoadable()) {
|
||||
Logging.severe("Old world '%s' is not loadable", oldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean wasAutoSave = manuallySaveWorld();
|
||||
|
||||
if (!copyWorldFolder()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
revertBackAutoSave(wasAutoSave);
|
||||
|
||||
return initNewCloneWorld();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that world with oldName can be clone to a world called newName.
|
||||
*
|
||||
* @return True if parameters are valid, otherwise false.
|
||||
*/
|
||||
private boolean validCloneParameters() {
|
||||
String originalOldName = oldName;
|
||||
if (!isWorldFromConfig(oldName)) {
|
||||
oldName = getWorldByAliasFromConfig(oldName);
|
||||
}
|
||||
|
||||
if (oldName == null) {
|
||||
Logging.warning("Old world '%s' does not exist", originalOldName);
|
||||
return false;
|
||||
}
|
||||
if (isWorldFromConfig(newName)) {
|
||||
Logging.warning("New world '%s' already exists", newName);
|
||||
return false;
|
||||
}
|
||||
if (!isValidWorldName(newName)) {
|
||||
Logging.warning("New world name '%s' is invalid", newName);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get world folders from world container.
|
||||
*/
|
||||
private void initWorldFiles() {
|
||||
oldWorldFile = new File(plugin.getServer().getWorldContainer(), oldName);
|
||||
newWorldFile = new File(plugin.getServer().getWorldContainer(), newName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that old world can be loaded and saved properly.
|
||||
*
|
||||
* @return True if old world can be loaded successfully, false otherwise.
|
||||
*/
|
||||
private boolean isOldWorldLoadable() {
|
||||
if (oldWorld != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Logging.fine("Old world '%s' is currently unloaded. Attempting to load it...", oldName);
|
||||
WorldProperties props = worldsFromTheConfig.get(oldName);
|
||||
boolean wasLoadSpawn = worldsFromTheConfig.get(oldName).isKeepingSpawnInMemory();
|
||||
if (wasLoadSpawn) {
|
||||
props.setKeepSpawnInMemory(false);
|
||||
}
|
||||
|
||||
if (!loadWorld(oldName)) {
|
||||
Logging.severe("Failed to load the old world '%s'", oldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
getMVWorld(oldName).getCBWorld().setAutoSave(false);
|
||||
|
||||
if (!unloadWorld(oldName, true)) {
|
||||
Logging.severe("Failed to unload the old world '%S'", oldName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wasLoadSpawn) {
|
||||
props.setKeepSpawnInMemory(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicating old world folder to the new world folder.
|
||||
*
|
||||
* @return True if copy process was successful, false otherwise.
|
||||
*/
|
||||
private boolean copyWorldFolder() {
|
||||
Logging.fine("Copying files for world '%s'", oldName);
|
||||
if (!FileUtils.copyFolder(oldWorldFile, newWorldFile, CLONE_IGNORE_FILES, Logging.getLogger()) || !newWorldFile.exists()) {
|
||||
Logging.severe("Failed to copy files for world '%s', see the log info", newName);
|
||||
return false;
|
||||
}
|
||||
Logging.fine("Succeeded at copying files");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure world is save being copying world files.
|
||||
*
|
||||
* @return Previous auto-save setting for the old world.
|
||||
*/
|
||||
private boolean manuallySaveWorld() {
|
||||
if (oldWorld != null && oldWorld.getCBWorld().isAutoSave()) {
|
||||
Logging.config("Saving world '%s'", oldName);
|
||||
oldWorld.getCBWorld().setAutoSave(false);
|
||||
oldWorld.getCBWorld().save();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void revertBackAutoSave(boolean wasAutoSave) {
|
||||
if (oldWorld != null && wasAutoSave) {
|
||||
Logging.fine("Revert back to enabling auto-save");
|
||||
oldWorld.getCBWorld().setAutoSave(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize new properties with old ones.
|
||||
*/
|
||||
private void copyPropertiesToNewWorld() {
|
||||
WorldProperties newProps = new WorldProperties();
|
||||
newProps.copyValues(worldsFromTheConfig.get(oldName));
|
||||
newProps.setAlias(""); // don't keep the alias the same -- that would be useless
|
||||
worldsFromTheConfig.put(newName, newProps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load up the newly copied clone world.
|
||||
*/
|
||||
private boolean initNewCloneWorld() {
|
||||
copyPropertiesToNewWorld();
|
||||
if (!saveWorldsConfig()) {
|
||||
Logging.severe("Failed to save worlds.yml");
|
||||
return false;
|
||||
}
|
||||
if (!doLoad(newName)) {
|
||||
Logging.severe("Failed to load the cloned world '" + newName + "'");
|
||||
return false;
|
||||
}
|
||||
Logging.fine("Succeeded at loading cloned world '" + newName + "'");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @deprecated Use {@link #cloneWorld(String, String)} instead.
|
||||
@@ -106,105 +295,7 @@ public class WorldManager implements MVWorldManager {
|
||||
*/
|
||||
@Override
|
||||
public boolean cloneWorld(String oldName, String newName) {
|
||||
// Make sure we already know about the old world and that we don't
|
||||
// already know about the new world.
|
||||
if (!this.worldsFromTheConfig.containsKey(oldName)) {
|
||||
for (Map.Entry<String, WorldProperties> entry : this.worldsFromTheConfig.entrySet()) {
|
||||
if (oldName.equals(entry.getValue().getAlias())) {
|
||||
oldName = entry.getKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!this.worldsFromTheConfig.containsKey(oldName)) {
|
||||
Logging.warning("Old world '%s' does not exist", oldName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (this.isMVWorld(newName)) {
|
||||
Logging.warning("New world '%s' already exists", newName);
|
||||
return false;
|
||||
}
|
||||
|
||||
final File oldWorldFile = new File(this.plugin.getServer().getWorldContainer(), oldName);
|
||||
final File newWorldFile = new File(this.plugin.getServer().getWorldContainer(), newName);
|
||||
|
||||
// Make sure the new world doesn't exist outside of multiverse.
|
||||
if (newWorldFile.exists()) {
|
||||
Logging.warning("File for new world '%s' already exists", newName);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load the old world... but just the metadata.
|
||||
boolean wasJustLoaded = false;
|
||||
boolean wasLoadSpawn = false;
|
||||
if (this.plugin.getServer().getWorld(oldName) == null) {
|
||||
wasJustLoaded = true;
|
||||
WorldProperties props = this.worldsFromTheConfig.get(oldName);
|
||||
wasLoadSpawn = props.isKeepingSpawnInMemory();
|
||||
if (wasLoadSpawn) {
|
||||
// No chunks please.
|
||||
props.setKeepSpawnInMemory(false);
|
||||
}
|
||||
if (!this.loadWorld(oldName)) {
|
||||
return false;
|
||||
}
|
||||
this.plugin.getServer().getWorld(oldName).setAutoSave(false);
|
||||
}
|
||||
|
||||
// Grab a bit of metadata from the old world.
|
||||
MVWorld oldWorld = (MVWorld) getMVWorld(oldName);
|
||||
Environment environment = oldWorld.getEnvironment();
|
||||
String seedString = oldWorld.getSeed() + "";
|
||||
WorldType worldType = oldWorld.getWorldType();
|
||||
Boolean generateStructures = oldWorld.getCBWorld().canGenerateStructures();
|
||||
String generator = oldWorld.getGenerator();
|
||||
boolean useSpawnAdjust = oldWorld.getAdjustSpawn();
|
||||
|
||||
// Don't need the loaded world anymore.
|
||||
if (wasJustLoaded) {
|
||||
this.unloadWorld(oldName, true);
|
||||
oldWorld = null;
|
||||
if (wasLoadSpawn) {
|
||||
this.worldsFromTheConfig.get(oldName).setKeepSpawnInMemory(true);
|
||||
}
|
||||
}
|
||||
|
||||
boolean wasAutoSave = false;
|
||||
if (oldWorld != null && oldWorld.getCBWorld().isAutoSave()) {
|
||||
wasAutoSave = true;
|
||||
Logging.config("Saving world '%s'", oldName);
|
||||
oldWorld.getCBWorld().setAutoSave(false);
|
||||
oldWorld.getCBWorld().save();
|
||||
}
|
||||
Logging.config("Copying files for world '%s'", oldName);
|
||||
if (!FileUtils.copyFolder(oldWorldFile, newWorldFile, Logging.getLogger())) {
|
||||
Logging.warning("Failed to copy files for world '%s', see the log info", newName);
|
||||
return false;
|
||||
}
|
||||
if (oldWorld != null && wasAutoSave) {
|
||||
oldWorld.getCBWorld().setAutoSave(true);
|
||||
}
|
||||
|
||||
File uidFile = new File(newWorldFile, "uid.dat");
|
||||
if (uidFile.exists() && !uidFile.delete()) {
|
||||
Logging.warning("Failed to delete unique ID file for world '%s'", newName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (newWorldFile.exists()) {
|
||||
Logging.fine("Succeeded at copying files");
|
||||
if (this.addWorld(newName, environment, seedString, worldType, generateStructures, generator, useSpawnAdjust)) {
|
||||
// getMVWorld() doesn't actually return an MVWorld
|
||||
Logging.fine("Succeeded at importing world");
|
||||
MVWorld newWorld = (MVWorld) this.getMVWorld(newName);
|
||||
newWorld.copyValues(this.worldsFromTheConfig.get(oldName));
|
||||
// don't keep the alias the same -- that would be useless
|
||||
newWorld.setAlias("");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Logging.warning("Failed to copy files for world '%s', see the log info", newName);
|
||||
return false;
|
||||
return new CloneHelper(oldName, newName).run();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,6 +316,11 @@ public class WorldManager implements MVWorldManager {
|
||||
if (name.equalsIgnoreCase("plugins") || name.equalsIgnoreCase("logs")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isValidWorldName(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Long seed = null;
|
||||
WorldCreator c = new WorldCreator(name);
|
||||
if (seedString != null && seedString.length() > 0) {
|
||||
@@ -407,6 +503,21 @@ public class WorldManager implements MVWorldManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the world name is allowed
|
||||
*
|
||||
* @param name Name of the world
|
||||
* @return True if the world world name is valid based on regex
|
||||
*/
|
||||
private boolean isValidWorldName(String name) {
|
||||
if (!worldNamePattern.matcher(name).matches()) {
|
||||
Logging.warning("Invalid world name '" + name + "'");
|
||||
Logging.warning("World name should not contain spaces or special characters!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void brokenWorld(String name) {
|
||||
this.plugin.log(Level.SEVERE, "The world '" + name + "' could NOT be loaded because it contains errors and is probably corrupt!");
|
||||
this.plugin.log(Level.SEVERE, "Try using Minecraft Region Fixer to repair your world! '" + name + "'");
|
||||
@@ -487,6 +598,13 @@ public class WorldManager implements MVWorldManager {
|
||||
*/
|
||||
@Override
|
||||
public boolean deleteWorld(String name, boolean removeFromConfig, boolean deleteWorldFolder) {
|
||||
if (this.hasUnloadedWorld(name, false)) {
|
||||
// Attempt to load if unloaded so we can actually delete the world
|
||||
if (!this.doLoad(name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
World world = this.plugin.getServer().getWorld(name);
|
||||
if (world == null) {
|
||||
// We can only delete loaded worlds
|
||||
@@ -658,6 +776,19 @@ public class WorldManager implements MVWorldManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isWorldFromConfig(String name) {
|
||||
return this.worldsFromTheConfig.containsKey(name);
|
||||
}
|
||||
|
||||
private String getWorldByAliasFromConfig(String name) {
|
||||
return this.worldsFromTheConfig.entrySet()
|
||||
.stream()
|
||||
.filter(worldEntry -> name.equals(worldEntry.getValue().getAlias()))
|
||||
.map(Map.Entry::getKey)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -899,6 +1030,9 @@ public class WorldManager implements MVWorldManager {
|
||||
return this.configWorlds;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean hasUnloadedWorld(String name, boolean includeLoaded) {
|
||||
if (getMVWorld(name) != null) {
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.onarandombox.MultiverseCore.utils.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import com.onarandombox.MultiverseCore.MultiverseCore;
|
||||
import com.onarandombox.MultiverseCore.api.MVWorldManager;
|
||||
import com.onarandombox.MultiverseCore.api.MultiverseWorld;
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bukkit.World;
|
||||
|
||||
public class MetricsConfigurator {
|
||||
|
||||
private static final int PLUGIN_ID = 7765;
|
||||
private static final String NO_GENERATOR_NAME = "N/A";
|
||||
|
||||
public static void configureMetrics(MultiverseCore plugin) {
|
||||
MetricsConfigurator configurator = new MetricsConfigurator(plugin);
|
||||
configurator.initMetrics();
|
||||
}
|
||||
|
||||
private final MultiverseCore plugin;
|
||||
private final Metrics metrics;
|
||||
|
||||
private MetricsConfigurator(MultiverseCore plugin) {
|
||||
this.plugin = plugin;
|
||||
this.metrics = new Metrics(plugin, PLUGIN_ID);
|
||||
}
|
||||
|
||||
private MVWorldManager getWorldManager() {
|
||||
return plugin.getMVWorldManager();
|
||||
}
|
||||
|
||||
private Collection<MultiverseWorld> getMVWorlds() {
|
||||
return getWorldManager().getMVWorlds();
|
||||
}
|
||||
|
||||
private void initMetrics() {
|
||||
try {
|
||||
addCustomGeneratorsMetric();
|
||||
addEnvironmentsMetric();
|
||||
addWorldCountMetric();
|
||||
|
||||
Logging.fine("Metrics enabled.");
|
||||
} catch (Exception e) {
|
||||
Logging.warning("There was an issue while enabling metrics:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void addCustomGeneratorsMetric() {
|
||||
addAdvancedPieMetric("custom_generators", map -> {
|
||||
for (MultiverseWorld w : getMVWorlds()) {
|
||||
MetricsHelper.incrementCount(map, getGeneratorName(w));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String getGeneratorName(MultiverseWorld world) {
|
||||
String gen = world.getGenerator();
|
||||
return (gen != null && !gen.equalsIgnoreCase("null")) ? gen.split(":")[0] : NO_GENERATOR_NAME;
|
||||
}
|
||||
|
||||
private void addEnvironmentsMetric() {
|
||||
addAdvancedPieMetric("environments", map -> {
|
||||
for (MultiverseWorld w : getMVWorlds()) {
|
||||
MetricsHelper.incrementCount(map, titleCaseEnv(w.getEnvironment()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String titleCaseEnv(World.Environment env) {
|
||||
String envName = env.name().replaceAll("_+", " ");
|
||||
return WordUtils.capitalizeFully(envName);
|
||||
}
|
||||
|
||||
private void addWorldCountMetric() {
|
||||
addMultiLineMetric("world_count", map -> {
|
||||
int loadedWorldsCount = getMVWorlds().size();
|
||||
map.put("Loaded worlds", loadedWorldsCount);
|
||||
map.put("Total number of worlds", loadedWorldsCount + getWorldManager().getUnloadedWorlds().size());
|
||||
});
|
||||
}
|
||||
|
||||
private void addAdvancedPieMetric(String chartId, Consumer<Map<String, Integer>> metricsFunc) {
|
||||
metrics.addCustomChart(MetricsHelper.createAdvancedPieChart(chartId, metricsFunc));
|
||||
}
|
||||
|
||||
private void addMultiLineMetric(String chartId, Consumer<Map<String, Integer>> metricsFunc) {
|
||||
metrics.addCustomChart(MetricsHelper.createMultiLineChart(chartId, metricsFunc));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.onarandombox.MultiverseCore.utils.metrics;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.bstats.bukkit.Metrics;
|
||||
|
||||
enum MetricsHelper {
|
||||
;
|
||||
|
||||
/**
|
||||
* Adds one to the value in the given map with the given key. If the key does not exist in the map, it will be added with a value of 1.
|
||||
*/
|
||||
static void incrementCount(Map<String, Integer> map, String key) {
|
||||
Integer count = map.getOrDefault(key, 0);
|
||||
map.put(key, count + 1);
|
||||
}
|
||||
|
||||
static Metrics.AdvancedPie createAdvancedPieChart(String chartId, Consumer<Map<String, Integer>> metricsFunc) {
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
metricsFunc.accept(map);
|
||||
return new Metrics.AdvancedPie(chartId, () -> map);
|
||||
}
|
||||
|
||||
static Metrics.MultiLineChart createMultiLineChart(String chartId, Consumer<Map<String, Integer>> metricsFunc) {
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
metricsFunc.accept(map);
|
||||
return new Metrics.MultiLineChart(chartId, () -> map);
|
||||
}
|
||||
|
||||
}
|
||||
+36
-14
@@ -1,19 +1,43 @@
|
||||
package com.onarandombox.MultiverseCore.utils.webpaste;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An {@link URLShortener} using {@code bit.ly}.
|
||||
* A {@link URLShortener} using {@code bit.ly}. Requires an access token.
|
||||
*/
|
||||
public class BitlyURLShortener extends HttpAPIClient implements URLShortener {
|
||||
private static final String GENERIC_BITLY_REQUEST_FORMAT = "https://api-ssl.bitly.com/v3/shorten?format=txt&apiKey=%s&login=%s&longUrl=%s";
|
||||
class BitlyURLShortener extends URLShortener {
|
||||
private static final String ACCESS_TOKEN = "Bearer bitly-access-token";
|
||||
private static final String BITLY_POST_REQUEST = "https://api-ssl.bitly.com/v4/shorten";
|
||||
|
||||
// I think it's no problem that these are public
|
||||
private static final String USERNAME = "multiverse2";
|
||||
private static final String API_KEY = "R_9dbff4862a3bc0c4218a7d78cc10d0e0";
|
||||
BitlyURLShortener() {
|
||||
super(BITLY_POST_REQUEST, ACCESS_TOKEN);
|
||||
if (ACCESS_TOKEN.endsWith("access-token")) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public BitlyURLShortener() {
|
||||
super(String.format(GENERIC_BITLY_REQUEST_FORMAT, API_KEY, USERNAME, "%s"));
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
String encodeData(String data) {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("domain", "j.mp");
|
||||
json.put("long_url", data);
|
||||
return json.toJSONString();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
String encodeData(Map<String, String> data) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -22,13 +46,11 @@ public class BitlyURLShortener extends HttpAPIClient implements URLShortener {
|
||||
@Override
|
||||
public String shorten(String longUrl) {
|
||||
try {
|
||||
String result = this.exec(longUrl);
|
||||
if (!result.startsWith("http://j.mp/")) // ... then it's failed :/
|
||||
throw new IOException(result);
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
String stringJSON = this.exec(encodeData(longUrl), ContentType.JSON);
|
||||
return (String) ((JSONObject) new JSONParser().parse(stringJSON)).get("link");
|
||||
} catch (IOException | ParseException e) {
|
||||
e.printStackTrace();
|
||||
return longUrl; // sorry ...
|
||||
return longUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.onarandombox.MultiverseCore.utils.webpaste;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Pastes to {@code gist.github.com}. Requires an access token with the {@code gist} scope.
|
||||
*/
|
||||
class GitHubPasteService extends PasteService {
|
||||
private final boolean isPrivate;
|
||||
// this access token must have the "gist" scope
|
||||
private static final String ACCESS_TOKEN = "token github-access-token";
|
||||
private static final String GITHUB_POST_REQUEST = "https://api.github.com/gists";
|
||||
|
||||
GitHubPasteService(boolean isPrivate) {
|
||||
super(GITHUB_POST_REQUEST, ACCESS_TOKEN);
|
||||
this.isPrivate = isPrivate;
|
||||
if (ACCESS_TOKEN.endsWith("access-token")) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
String encodeData(String data) {
|
||||
Map<String, String> mapData = new HashMap<String, String>();
|
||||
mapData.put("multiverse.txt", data);
|
||||
return this.encodeData(mapData);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
String encodeData(Map<String, String> files) {
|
||||
JSONObject root = new JSONObject();
|
||||
root.put("description", "Multiverse-Core Debug Info");
|
||||
root.put("public", !this.isPrivate);
|
||||
JSONObject fileList = new JSONObject();
|
||||
for (Map.Entry<String, String> entry : files.entrySet()) {
|
||||
JSONObject fileObject = new JSONObject();
|
||||
fileObject.put("content", entry.getValue());
|
||||
fileList.put(entry.getKey(), fileObject);
|
||||
}
|
||||
|
||||
root.put("files", fileList);
|
||||
return root.toJSONString();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String postData(String data) throws PasteFailedException {
|
||||
try {
|
||||
String stringJSON = this.exec(encodeData(data), ContentType.JSON);
|
||||
return (String) ((JSONObject) new JSONParser().parse(stringJSON)).get("html_url");
|
||||
} catch (IOException | ParseException e) {
|
||||
throw new PasteFailedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String postData(Map<String, String> data) throws PasteFailedException {
|
||||
try {
|
||||
String stringJSON = this.exec(encodeData(data), ContentType.JSON);
|
||||
return (String) ((JSONObject) new JSONParser().parse(stringJSON)).get("html_url");
|
||||
} catch (IOException | ParseException e) {
|
||||
throw new PasteFailedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsMultiFile() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
package com.onarandombox.MultiverseCore.utils.webpaste;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class GithubPasteService implements PasteService {
|
||||
|
||||
private final boolean isPrivate;
|
||||
|
||||
public GithubPasteService(boolean isPrivate) {
|
||||
this.isPrivate = isPrivate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeData(String data) {
|
||||
Map<String, String> mapData = new HashMap<String, String>();
|
||||
mapData.put("multiverse.txt", data);
|
||||
return this.encodeData(mapData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeData(Map<String, String> files) {
|
||||
JsonObject root = new JsonObject();
|
||||
root.add("description", new JsonPrimitive("Multiverse-Core Debug Info"));
|
||||
root.add("public", new JsonPrimitive(!this.isPrivate));
|
||||
JsonObject fileList = new JsonObject();
|
||||
for (Map.Entry<String, String> entry : files.entrySet())
|
||||
{
|
||||
JsonObject fileObject = new JsonObject();
|
||||
fileObject.add("content", new JsonPrimitive(entry.getValue()));
|
||||
fileList.add(entry.getKey(), fileObject);
|
||||
}
|
||||
root.add("files", fileList);
|
||||
return root.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getPostURL() {
|
||||
try {
|
||||
return new URL("https://api.github.com/gists");
|
||||
//return new URL("http://jsonplaceholder.typicode.com/posts");
|
||||
} catch (MalformedURLException e) {
|
||||
return null; // should never hit here
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String postData(String encodedData, URL url) throws PasteFailedException {
|
||||
OutputStreamWriter wr = null;
|
||||
BufferedReader rd = null;
|
||||
try {
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setDoOutput(true);
|
||||
wr = new OutputStreamWriter(conn.getOutputStream());
|
||||
wr.write(encodedData);
|
||||
wr.flush();
|
||||
|
||||
rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
String line;
|
||||
String pastieUrl = "";
|
||||
//Pattern pastiePattern = this.getURLMatchingPattern();
|
||||
StringBuilder responseString = new StringBuilder();
|
||||
|
||||
while ((line = rd.readLine()) != null) {
|
||||
responseString.append(line);
|
||||
}
|
||||
return new JsonParser().parse(responseString.toString()).getAsJsonObject().get("html_url").getAsString();
|
||||
} catch (Exception e) {
|
||||
throw new PasteFailedException(e);
|
||||
} finally {
|
||||
if (wr != null) {
|
||||
try {
|
||||
wr.close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
if (rd != null) {
|
||||
try {
|
||||
rd.close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsMultiFile() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+40
-52
@@ -1,79 +1,67 @@
|
||||
package com.onarandombox.MultiverseCore.utils.webpaste;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Pastes to {@code hastebin.com}.
|
||||
*/
|
||||
public class HastebinPasteService implements PasteService {
|
||||
class HastebinPasteService extends PasteService {
|
||||
private static final String HASTEBIN_POST_REQUEST = "https://hastebin.com/documents";
|
||||
|
||||
HastebinPasteService() {
|
||||
super(HASTEBIN_POST_REQUEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String encodeData(String data) {
|
||||
String encodeData(String data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String encodeData(Map<String, String> data) {
|
||||
String encodeData(Map<String, String> data) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public URL getPostURL() {
|
||||
public String postData(String data) throws PasteFailedException {
|
||||
try {
|
||||
return new URL("https://hastebin.com/documents");
|
||||
} catch (MalformedURLException e) {
|
||||
return null; // should never hit here
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String postData(String encodedData, URL url) throws PasteFailedException {
|
||||
OutputStreamWriter wr = null;
|
||||
BufferedReader rd = null;
|
||||
try {
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setDoOutput(true);
|
||||
|
||||
wr = new OutputStreamWriter(conn.getOutputStream());
|
||||
rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
|
||||
wr.write(encodedData);
|
||||
wr.flush();
|
||||
|
||||
String line;
|
||||
StringBuilder responseString = new StringBuilder();
|
||||
while ((line = rd.readLine()) != null) {
|
||||
responseString.append(line);
|
||||
}
|
||||
String key = new JsonParser().parse(responseString.toString()).getAsJsonObject().get("key").getAsString();
|
||||
|
||||
return "https://hastebin.com/" + key;
|
||||
} catch (Exception e) {
|
||||
String stringJSON = this.exec(encodeData(data), ContentType.PLAINTEXT);
|
||||
return "https://hastebin.com/" + ((JSONObject) new JSONParser().parse(stringJSON)).get("key");
|
||||
} catch (IOException | ParseException e) {
|
||||
throw new PasteFailedException(e);
|
||||
} finally {
|
||||
if (wr != null) {
|
||||
try {
|
||||
wr.close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
if (rd != null) {
|
||||
try {
|
||||
rd.close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String postData(Map<String, String> data) throws PasteFailedException {
|
||||
try {
|
||||
String stringJSON = this.exec(encodeData(data), ContentType.PLAINTEXT);
|
||||
return "https://hastebin.com/" + ((JSONObject) new JSONParser().parse(stringJSON)).get("key");
|
||||
} catch (IOException | ParseException e) {
|
||||
throw new PasteFailedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsMultiFile() {
|
||||
return false;
|
||||
|
||||
@@ -1,50 +1,129 @@
|
||||
package com.onarandombox.MultiverseCore.utils.webpaste;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* HTTP API-client.
|
||||
*/
|
||||
public abstract class HttpAPIClient {
|
||||
abstract class HttpAPIClient {
|
||||
/**
|
||||
* The URL for this API-request.
|
||||
* The URL for this API-request, and if necessary, the access token.
|
||||
* If an access token is not necessary, it should be set to null.
|
||||
*/
|
||||
protected final String urlFormat;
|
||||
private final String url;
|
||||
private final String accessToken;
|
||||
|
||||
public HttpAPIClient(String urlFormat) {
|
||||
this.urlFormat = urlFormat;
|
||||
/**
|
||||
* Types of data that can be sent.
|
||||
*/
|
||||
enum ContentType {
|
||||
JSON,
|
||||
PLAINTEXT,
|
||||
URLENCODED
|
||||
}
|
||||
|
||||
HttpAPIClient(String url) {
|
||||
this(url, null);
|
||||
}
|
||||
|
||||
HttpAPIClient(String url, String accessToken) {
|
||||
this.url = url;
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP Content-Type header that corresponds with each ContentType.
|
||||
* @param type The type of data.
|
||||
* @return The HTTP Content-Type header that corresponds with the type of data.
|
||||
*/
|
||||
private String getContentHeader(ContentType type) {
|
||||
switch (type) {
|
||||
case JSON:
|
||||
return "application/json; charset=utf-8";
|
||||
case PLAINTEXT:
|
||||
return "text/plain; charset=utf-8";
|
||||
case URLENCODED:
|
||||
return "application/x-www-form-urlencoded; charset=utf-8";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unexpected value: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the given String data into a format suitable for transmission in an HTTP request.
|
||||
*
|
||||
* @param data The raw data to encode.
|
||||
* @return A URL-encoded string.
|
||||
*/
|
||||
abstract String encodeData(String data);
|
||||
|
||||
/**
|
||||
* Encode the given Map data into a format suitable for transmission in an HTTP request.
|
||||
*
|
||||
* @param data The raw data to encode.
|
||||
* @return A URL-encoded string.
|
||||
*/
|
||||
abstract String encodeData(Map<String, String> data);
|
||||
|
||||
/**
|
||||
* Executes this API-Request.
|
||||
* @param args Format-args.
|
||||
* @param payload The data that will be sent.
|
||||
* @param type The type of data that will be sent.
|
||||
* @return The result (as text).
|
||||
* @throws IOException When the I/O-operation failed.
|
||||
*/
|
||||
protected final String exec(Object... args) throws IOException {
|
||||
final String exec(String payload, ContentType type) throws IOException {
|
||||
BufferedReader rd = null;
|
||||
OutputStreamWriter wr = null;
|
||||
|
||||
URLConnection conn = new URL(String.format(this.urlFormat, args)).openConnection();
|
||||
conn.connect();
|
||||
StringBuilder ret = new StringBuilder();
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
while (!reader.ready()); // wait until reader is ready, may not be necessary, SUPPRESS CHECKSTYLE: EmptyStatement
|
||||
HttpsURLConnection conn = (HttpsURLConnection) new URL(this.url).openConnection();
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setDoOutput(true);
|
||||
|
||||
while (reader.ready()) {
|
||||
ret.append(reader.readLine()).append('\n');
|
||||
// we can receive anything!
|
||||
conn.addRequestProperty("Accept", "*/*");
|
||||
// set a dummy User-Agent
|
||||
conn.addRequestProperty("User-Agent", "placeholder");
|
||||
// this isn't required, but is technically correct
|
||||
conn.addRequestProperty("Content-Type", getContentHeader(type));
|
||||
// only some API requests require an access token
|
||||
if (this.accessToken != null) {
|
||||
conn.addRequestProperty("Authorization", this.accessToken);
|
||||
}
|
||||
|
||||
wr = new OutputStreamWriter(conn.getOutputStream(), StandardCharsets.UTF_8.newEncoder());
|
||||
wr.write(payload);
|
||||
wr.flush();
|
||||
|
||||
String line;
|
||||
StringBuilder responseString = new StringBuilder();
|
||||
// this has to be initialized AFTER the data has been flushed!
|
||||
rd = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
|
||||
|
||||
while ((line = rd.readLine()) != null) {
|
||||
responseString.append(line);
|
||||
}
|
||||
|
||||
return responseString.toString();
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
if (wr != null) {
|
||||
try {
|
||||
reader.close();
|
||||
wr.close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
if (rd != null) {
|
||||
try {
|
||||
rd.close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.onarandombox.MultiverseCore.utils.webpaste;
|
||||
|
||||
/**
|
||||
* Thrown when pasting failed.
|
||||
* Thrown when pasting fails.
|
||||
*/
|
||||
public class PasteFailedException extends Exception {
|
||||
public PasteFailedException() {
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.onarandombox.MultiverseCore.utils.webpaste;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Pastes to {@code paste.gg}.
|
||||
*/
|
||||
class PasteGGPasteService extends PasteService {
|
||||
private final boolean isPrivate;
|
||||
private static final String PASTEGG_POST_REQUEST = "https://api.paste.gg/v1/pastes";
|
||||
|
||||
PasteGGPasteService(boolean isPrivate) {
|
||||
super(PASTEGG_POST_REQUEST);
|
||||
this.isPrivate = isPrivate;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
String encodeData(String data) {
|
||||
Map<String, String> mapData = new HashMap<String, String>();
|
||||
mapData.put("multiverse.txt", data);
|
||||
return this.encodeData(mapData);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
String encodeData(Map<String, String> files) {
|
||||
JSONObject root = new JSONObject();
|
||||
root.put("name", "Multiverse-Core Debug Info");
|
||||
root.put("visibility", this.isPrivate ? "unlisted" : "public");
|
||||
JSONArray fileList = new JSONArray();
|
||||
for (Map.Entry<String, String> entry : files.entrySet()) {
|
||||
JSONObject fileObject = new JSONObject();
|
||||
JSONObject contentObject = new JSONObject();
|
||||
fileObject.put("name", entry.getKey());
|
||||
fileObject.put("content", contentObject);
|
||||
contentObject.put("format", "text");
|
||||
contentObject.put("value", entry.getValue());
|
||||
fileList.add(fileObject);
|
||||
}
|
||||
|
||||
root.put("files", fileList);
|
||||
return root.toJSONString();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String postData(String data) throws PasteFailedException {
|
||||
try {
|
||||
String stringJSON = this.exec(encodeData(data), ContentType.JSON);
|
||||
return (String) ((JSONObject) ((JSONObject) new JSONParser().parse(stringJSON)).get("result")).get("id");
|
||||
} catch (IOException | ParseException e) {
|
||||
throw new PasteFailedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String postData(Map<String, String> data) throws PasteFailedException {
|
||||
try {
|
||||
String stringJSON = this.exec(encodeData(data), ContentType.JSON);
|
||||
return "https://paste.gg/" + ((JSONObject) ((JSONObject) new JSONParser().parse(stringJSON)).get("result")).get("id");
|
||||
} catch (IOException | ParseException e) {
|
||||
throw new PasteFailedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsMultiFile() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,63 +1,52 @@
|
||||
package com.onarandombox.MultiverseCore.utils.webpaste;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An interface to a web-based text-pasting service. Classes implementing this
|
||||
* interface should implement its methods to send data to an online text-sharing
|
||||
* service, such as pastebin.com. Conventionally, a paste is accomplished by (given
|
||||
* some PasteService instance ps):
|
||||
* An interface to a web-based text-pasting service. Classes extending this
|
||||
* should implement its methods to send data to an online text-sharing service,
|
||||
* such as pastebin.com. Given some PasteService instance ps, a paste is accomplished by:
|
||||
*
|
||||
* {@code ps.postData(ps.encodeData(someString), ps.getPostURL());}
|
||||
* {@code ps.postData(someString);}
|
||||
*
|
||||
* Services that provide a distinction between "public" and "private" pastes
|
||||
* should implement a custom constructor that specifies which kind the PasteService
|
||||
* should implement a constructor that specifies which kind the PasteService
|
||||
* instance is submitting; an example of this is the PastebinPasteService class.
|
||||
*/
|
||||
public interface PasteService {
|
||||
public abstract class PasteService extends HttpAPIClient {
|
||||
PasteService(String url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
PasteService(String url, String accessToken) {
|
||||
super(url, accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the given String data into a format suitable for transmission in an HTTP request.
|
||||
* Post data to the Web.
|
||||
*
|
||||
* @param data The raw data to encode.
|
||||
* @return A URL-encoded string.
|
||||
*/
|
||||
String encodeData(String data);
|
||||
|
||||
/**
|
||||
* Encode the given Map data into a format suitable for transmission in an HTTP request.
|
||||
*
|
||||
* @param data The raw data to encode.
|
||||
* @return A URL-encoded string.
|
||||
*/
|
||||
String encodeData(Map<String, String> data);
|
||||
|
||||
/**
|
||||
* Get the URL to which this paste service sends new pastes.
|
||||
*
|
||||
* @return The URL that will be accessed to complete the paste.
|
||||
*/
|
||||
URL getPostURL();
|
||||
|
||||
/**
|
||||
* Post encoded data to the Web.
|
||||
*
|
||||
* @param encodedData A URL-encoded String containing the full request to post to
|
||||
* the given URL. Can be the result of calling #encodeData().
|
||||
* @param url The URL to which to paste. Can be the result of calling #getPostURL().
|
||||
* @param data A String to post to the web.
|
||||
* @throws PasteFailedException When pasting/posting the data failed.
|
||||
* @return The URL at which the new paste is visible.
|
||||
*/
|
||||
String postData(String encodedData, URL url) throws PasteFailedException;
|
||||
public abstract String postData(String data) throws PasteFailedException;
|
||||
|
||||
/**
|
||||
* Post data to the Web.
|
||||
*
|
||||
* @param data A Map to post to the web.
|
||||
* @throws PasteFailedException When pasting/posting the data failed.
|
||||
* @return The URL at which the new paste is visible.
|
||||
*/
|
||||
public abstract String postData(Map<String, String> data) throws PasteFailedException;
|
||||
|
||||
/**
|
||||
* Does this service support uploading multiple files.
|
||||
*
|
||||
* Newer services like gist support multi-file which allows us to upload configs
|
||||
* in addition to the standard logs.
|
||||
* Newer services like GitHub's Gist support multi-file pastes,
|
||||
* which allows us to upload configs in addition to the standard logs.
|
||||
*
|
||||
* @return True if this service supports multiple file upload.
|
||||
*/
|
||||
boolean supportsMultiFile();
|
||||
public abstract boolean supportsMultiFile();
|
||||
}
|
||||
+3
-1
@@ -14,12 +14,14 @@ public class PasteServiceFactory {
|
||||
*/
|
||||
public static PasteService getService(PasteServiceType type, boolean isPrivate) {
|
||||
switch(type) {
|
||||
case PASTEGG:
|
||||
return new PasteGGPasteService(isPrivate);
|
||||
case PASTEBIN:
|
||||
return new PastebinPasteService(isPrivate);
|
||||
case HASTEBIN:
|
||||
return new HastebinPasteService();
|
||||
case GITHUB:
|
||||
return new GithubPasteService(isPrivate);
|
||||
return new GitHubPasteService(isPrivate);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ package com.onarandombox.MultiverseCore.utils.webpaste;
|
||||
* @see PasteServiceFactory
|
||||
*/
|
||||
public enum PasteServiceType {
|
||||
/**
|
||||
* @see PasteGGPasteService
|
||||
*/
|
||||
PASTEGG,
|
||||
/**
|
||||
* @see PastebinPasteService
|
||||
*/
|
||||
@@ -16,7 +20,7 @@ public enum PasteServiceType {
|
||||
*/
|
||||
HASTEBIN,
|
||||
/**
|
||||
* @see GithubPasteService
|
||||
* @see GitHubPasteService
|
||||
*/
|
||||
GITHUB
|
||||
}
|
||||
+35
-59
@@ -1,24 +1,19 @@
|
||||
package com.onarandombox.MultiverseCore.utils.webpaste;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Pastes to {@code pastebin.com}.
|
||||
*/
|
||||
public class PastebinPasteService implements PasteService {
|
||||
class PastebinPasteService extends PasteService {
|
||||
private final boolean isPrivate;
|
||||
private static final String PASTEBIN_POST_REQUEST = "https://pastebin.com/api/api_post.php";
|
||||
|
||||
private boolean isPrivate;
|
||||
|
||||
public PastebinPasteService(boolean isPrivate) {
|
||||
PastebinPasteService(boolean isPrivate) {
|
||||
super(PASTEBIN_POST_REQUEST);
|
||||
this.isPrivate = isPrivate;
|
||||
}
|
||||
|
||||
@@ -26,73 +21,54 @@ public class PastebinPasteService implements PasteService {
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public URL getPostURL() {
|
||||
String encodeData(String data) {
|
||||
try {
|
||||
return new URL("http://pastebin.com/api/api_post.php");
|
||||
} catch (MalformedURLException e) {
|
||||
return null; // should never hit here
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String encodeData(String data) {
|
||||
try {
|
||||
String encData = URLEncoder.encode("api_dev_key", "UTF-8") + "=" + URLEncoder.encode("d61d68d31e8e0392b59b50b277411c71", "UTF-8");
|
||||
encData += "&" + URLEncoder.encode("api_option", "UTF-8") + "=" + URLEncoder.encode("paste", "UTF-8");
|
||||
encData += "&" + URLEncoder.encode("api_paste_code", "UTF-8") + "=" + URLEncoder.encode(data, "UTF-8");
|
||||
encData += "&" + URLEncoder.encode("api_paste_private", "UTF-8") + "=" + URLEncoder.encode(this.isPrivate ? "1" : "0", "UTF-8");
|
||||
encData += "&" + URLEncoder.encode("api_paste_format", "UTF-8") + "=" + URLEncoder.encode("yaml", "UTF-8");
|
||||
return encData;
|
||||
return URLEncoder.encode("api_dev_key", "UTF-8") + "=" + URLEncoder.encode("d61d68d31e8e0392b59b50b277411c71", "UTF-8") +
|
||||
"&" + URLEncoder.encode("api_option", "UTF-8") + "=" + URLEncoder.encode("paste", "UTF-8") +
|
||||
"&" + URLEncoder.encode("api_paste_code", "UTF-8") + "=" + URLEncoder.encode(data, "UTF-8") +
|
||||
"&" + URLEncoder.encode("api_paste_private", "UTF-8") + "=" + URLEncoder.encode(this.isPrivate ? "1" : "0", "UTF-8") +
|
||||
"&" + URLEncoder.encode("api_paste_format", "UTF-8") + "=" + URLEncoder.encode("yaml", "UTF-8") +
|
||||
"&" + URLEncoder.encode("api_paste_name", "UTF-8") + "=" + URLEncoder.encode("Multiverse-Core Debug Info", "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return ""; // should never hit here
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String encodeData(Map<String, String> data) {
|
||||
return null;
|
||||
String encodeData(Map<String, String> data) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String postData(String encodedData, URL url) throws PasteFailedException {
|
||||
OutputStreamWriter wr = null;
|
||||
BufferedReader rd = null;
|
||||
public String postData(String data) throws PasteFailedException {
|
||||
try {
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setDoOutput(true);
|
||||
wr = new OutputStreamWriter(conn.getOutputStream());
|
||||
wr.write(encodedData);
|
||||
wr.flush();
|
||||
|
||||
rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
String line;
|
||||
String pastebinUrl = "";
|
||||
while ((line = rd.readLine()) != null) {
|
||||
pastebinUrl = line;
|
||||
}
|
||||
return pastebinUrl;
|
||||
} catch (Exception e) {
|
||||
return this.exec(encodeData(data), ContentType.URLENCODED);
|
||||
} catch (IOException e) {
|
||||
throw new PasteFailedException(e);
|
||||
} finally {
|
||||
if (wr != null) {
|
||||
try {
|
||||
wr.close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
if (rd != null) {
|
||||
try {
|
||||
rd.close();
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String postData(Map<String, String> data) throws PasteFailedException {
|
||||
try {
|
||||
return this.exec(encodeData(data), ContentType.URLENCODED);
|
||||
} catch (IOException e) {
|
||||
throw new PasteFailedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsMultiFile() {
|
||||
return false;
|
||||
|
||||
@@ -1,13 +1,27 @@
|
||||
package com.onarandombox.MultiverseCore.utils.webpaste;
|
||||
|
||||
/**
|
||||
* URL-Shortener.
|
||||
* An interface to a web-based URL Shortener. Classes extending this should
|
||||
* implement its methods to shorten links using the service. Given some
|
||||
* URLShortener instance us, a URL is shortened by:
|
||||
*
|
||||
* {@code us.shorten(longUrl);}
|
||||
*
|
||||
* An example of this, is the BitlyURLShortener.
|
||||
*/
|
||||
public interface URLShortener {
|
||||
public abstract class URLShortener extends HttpAPIClient {
|
||||
URLShortener(String url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
URLShortener(String url, String accessToken) {
|
||||
super(url, accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorten an URL.
|
||||
* Shorten a URL.
|
||||
* @param longUrl The long form.
|
||||
* @return The shortened URL.
|
||||
*/
|
||||
String shorten(String longUrl);
|
||||
public abstract String shorten(String longUrl);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.onarandombox.MultiverseCore.utils.webpaste;
|
||||
|
||||
/**
|
||||
* Used to construct {@link URLShortener}s.
|
||||
*/
|
||||
public class URLShortenerFactory {
|
||||
private URLShortenerFactory() { }
|
||||
|
||||
/**
|
||||
* Constructs a new {@link URLShortener}.
|
||||
* @param type The {@link URLShortenerType}.
|
||||
* @return The newly created {@link URLShortener}.
|
||||
*/
|
||||
public static URLShortener getService(URLShortenerType type) {
|
||||
if (type == URLShortenerType.BITLY) {
|
||||
try {
|
||||
return new BitlyURLShortener();
|
||||
} catch (UnsupportedOperationException ignored) {}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.onarandombox.MultiverseCore.utils.webpaste;
|
||||
|
||||
/**
|
||||
* An enum containing all known {@link URLShortener}s.
|
||||
*
|
||||
* @see URLShortener
|
||||
* @see URLShortenerFactory
|
||||
*/
|
||||
public enum URLShortenerType {
|
||||
/**
|
||||
* @see BitlyURLShortener
|
||||
*/
|
||||
BITLY
|
||||
}
|
||||
+64
-113
@@ -1,7 +1,8 @@
|
||||
name: Multiverse-Core
|
||||
main: com.onarandombox.MultiverseCore.MultiverseCore
|
||||
authors: ['Rigby', 'fernferret', 'lithium3141', 'main--', 'dumptruckman']
|
||||
authors: ['dumptruckman', 'Rigby', 'fernferret', 'lithium3141', 'main--']
|
||||
website: 'https://dev.bukkit.org/projects/multiverse-core'
|
||||
softdepend: ['Vault']
|
||||
api-version: 1.13
|
||||
version: maven-version-number
|
||||
commands:
|
||||
@@ -10,34 +11,24 @@ commands:
|
||||
usage: /<command>
|
||||
mvcreate:
|
||||
description: World create command
|
||||
usage: |
|
||||
/<command> <world> <environment>
|
||||
/<command> creative normal -- Creates a world called 'creative' with a NORMAL environment.
|
||||
/<command> hellworld nether -- Creates a world called 'hellworld' with a NETHER environment.
|
||||
mvc:
|
||||
description: World create command
|
||||
aliases: [mvc]
|
||||
usage: |
|
||||
/<command> <world> <environment>
|
||||
/<command> creative normal -- Creates a world called 'creative' with a NORMAL environment.
|
||||
/<command> hellworld nether -- Creates a world called 'hellworld' with a NETHER environment.
|
||||
mvimport:
|
||||
description: World import command
|
||||
aliases: [mvim]
|
||||
usage: |
|
||||
/<command> <world> <environment>
|
||||
/<command> creative normal -- Imports an existing world called 'creative' with a NORMAL environment.
|
||||
/<command> hellworld nether -- Imports an existing world called 'hellworld' with a NETHER environment.
|
||||
mvim:
|
||||
description: World import command
|
||||
usage: |
|
||||
/<command> <world> <environment>
|
||||
/<command> creative normal -- Imports an existing world called 'creative' with a NORMAL environment.
|
||||
/<command> hellworld nether -- Imports an existing world called 'hellworld' with a NETHER environment.
|
||||
/<command> <world> <environment> [-g generator[:id]] [-n]
|
||||
/<command> creative normal -- Imports an existing world called 'creative' with a NORMAL environment.
|
||||
/<command> hellworld nether -- Imports an existing world called 'hellworld' with a NETHER environment.
|
||||
mvremove:
|
||||
description: World remove command
|
||||
description: Remove world from multiverse command
|
||||
usage: |
|
||||
/<command> <world>
|
||||
mvdelete:
|
||||
description: World delete command
|
||||
description: Delete world from server folders command
|
||||
usage: |
|
||||
/<command> <world>
|
||||
mvunload:
|
||||
@@ -46,103 +37,75 @@ commands:
|
||||
/<command> <world>
|
||||
mvmodify:
|
||||
description: Modify the settings of an existing world
|
||||
aliases: [mvm]
|
||||
usage: |
|
||||
/<command> <world> <option>:<value>
|
||||
/<command> creative pvp:false -- Turns off PVP in the 'creative' world.
|
||||
/<command> <set|add|remove|clear> <value> <property> [world]
|
||||
/<command> set pvp false creative -- Turns off PVP in the 'creative' world.
|
||||
mvmset:
|
||||
description: Modify the settings of an existing world
|
||||
usage: |
|
||||
/<command> <world> <option>:<value>
|
||||
/<command> creative pvp:false -- Turns off PVP in the 'creative' world.
|
||||
/<command> <value> <property> [world]
|
||||
/<command> pvp false creative -- Turns off PVP in the 'creative' world.
|
||||
mvmadd:
|
||||
description: Modify the settings of an existing world
|
||||
usage: |
|
||||
/<command> <world> <option>:<value>
|
||||
/<command> creative pvp:false -- Turns off PVP in the 'creative' world.
|
||||
/<command> <value> <property> [world]
|
||||
/<command> sheep animals world_nether -- Add sheep to animal list for 'world_nether' world.
|
||||
mvmremove:
|
||||
description: Modify the settings of an existing world
|
||||
aliases: [mvmdelete]
|
||||
usage: |
|
||||
/<command> <world> <option>:<value>
|
||||
/<command> creative pvp:false -- Turns off PVP in the 'creative' world.
|
||||
/<command> <value> <property> [world]
|
||||
/<command> sheep animals world_nether -- remove sheep from animal list for 'world_nether' world.
|
||||
mvmclear:
|
||||
description: Modify the settings of an existing world
|
||||
usage: |
|
||||
/<command> <world> <option>:<value>
|
||||
/<command> creative pvp:false -- Turns off PVP in the 'creative' world.
|
||||
mvm:
|
||||
description: Modify the settings of an existing world
|
||||
usage: |
|
||||
/<command> <world> <option>:<value>
|
||||
/<command> creative pvp:false -- Turns off PVP in the 'creative' world.
|
||||
/<command> <property> [world]
|
||||
/<command> animals world_nether -- Empties animal list for 'world_nether' world.
|
||||
mvtp:
|
||||
description: Command to teleport between Worlds
|
||||
usage: |
|
||||
/<command> <world>[:spawn]
|
||||
/<command> [player] <destination>
|
||||
Example: /<command> creative - Teleports you to the relevant location in the 'creative' world.
|
||||
Example: /<command> creative:spawn - Teleports you to the spawn of the 'creative' world.
|
||||
mvlist:
|
||||
description: Print list of loaded Worlds
|
||||
aliases: [mvl]
|
||||
usage: |
|
||||
/<command> [environment]
|
||||
Example: /<command> NETHER - Shows all NETHER Worlds.
|
||||
Example: /<command> NORMAL - Shows all NORMAL Worlds.
|
||||
mvl:
|
||||
description: Print list of loaded Worlds
|
||||
usage: |
|
||||
/<command> [environment]
|
||||
/<command> [page]
|
||||
Example: /<command> NETHER - Shows all NETHER Worlds.
|
||||
Example: /<command> NORMAL - Shows all NORMAL Worlds.
|
||||
mvsetspawn:
|
||||
description: Set the spawn area for a particular world
|
||||
usage: /<command> -- Sets the spawn area of the current world to your location.
|
||||
mvset:
|
||||
description: Set the spawn area for a particular world
|
||||
usage: /<command> -- Sets the spawn area of the current world to your location.
|
||||
mvss:
|
||||
description: Set the spawn area for a particular world
|
||||
aliases: [mvsets, mvss]
|
||||
usage: /<command> -- Sets the spawn area of the current world to your location.
|
||||
mvspawn:
|
||||
description: Teleport to the spawn area
|
||||
usage: /<command> -- Teleports you to the spawn area of your current world.
|
||||
mvs:
|
||||
description: Teleport to the spawn area
|
||||
usage: /<command> -- Teleports you to the spawn area of your current world.
|
||||
aliases: [mvs]
|
||||
usage: /<command> [player] -- Teleports you to the spawn area of your current world.
|
||||
mvcoord:
|
||||
description: Display World, Coordinates, Direction & Compression for a world.
|
||||
usage: |
|
||||
/<command> [world]
|
||||
/<command> -- Shows the relevant coordinates in your current world.
|
||||
/<command> creative -- Shows the relevant coordinates if you were in the 'creative' world.
|
||||
mvc:
|
||||
description: Display World, Coordinates, Direction & Compression for a world.
|
||||
aliases: [mvco]
|
||||
usage: |
|
||||
/<command> [world]
|
||||
/<command> -- Shows the relevant coordinates in your current world.
|
||||
/<command> creative -- Shows the relevant coordinates if you were in the 'creative' world.
|
||||
mvwho:
|
||||
description: Display online users per world.
|
||||
aliases: [mvw]
|
||||
usage: |
|
||||
/<command> [world]
|
||||
/<command> -- Shows who is online in each world.
|
||||
/<command> creative -- Shows who is online in the 'creative' world.
|
||||
mvw:
|
||||
description: Display online users per world.
|
||||
usage: |
|
||||
/<command> [world]
|
||||
/<command> [world|--all]
|
||||
/<command> -- Shows who is online in each world.
|
||||
/<command> creative -- Shows who is online in the 'creative' world.
|
||||
mvreload:
|
||||
description: Reload Configuration files.
|
||||
usage: /<command>
|
||||
mvr:
|
||||
description: Reload Configuration files.
|
||||
aliases: [mvr]
|
||||
usage: /<command>
|
||||
mvpurge:
|
||||
description: Purge the targetted world of creatures.
|
||||
usage: |
|
||||
/<command> [world] [creatures]
|
||||
/<command> [WORLD|all] [all|animals|monsters|MOBNAME]
|
||||
/<command> -- Purges the players world of all creatures.
|
||||
/<command> creative * -- Purges the creative world of all Creatures.
|
||||
/<command> creative all -- Purges the creative world of all Creatures.
|
||||
/<command> creative creeper -- Purges the creative world of all CREEPERS.
|
||||
mvconfirm:
|
||||
description: Confirms sensitive decisions like deleting a world.
|
||||
@@ -150,87 +113,75 @@ commands:
|
||||
/<command>
|
||||
mvinfo:
|
||||
description: Gets world info.
|
||||
aliases: [mvi]
|
||||
usage: |
|
||||
/<command> [world]
|
||||
mvi:
|
||||
description: Gets world info.
|
||||
usage: |
|
||||
/<command> [world]
|
||||
/<command> [world] [page]
|
||||
mvenv:
|
||||
description: Tells the user all possible environment types.
|
||||
usage: |
|
||||
/<command>
|
||||
mvv:
|
||||
description: Prints out version info.
|
||||
usage: |
|
||||
/<command>
|
||||
mvversion:
|
||||
description: Prints out version info.
|
||||
aliases: [mvv, mvver]
|
||||
usage: |
|
||||
/<command>
|
||||
mvco:
|
||||
description: Displays the player's coordinates.
|
||||
usage: |
|
||||
/<command>
|
||||
mvh:
|
||||
description: Displays the Multiverse Help.
|
||||
usage: |
|
||||
/<command>
|
||||
mvsearch:
|
||||
description: Displays the Multiverse Help.
|
||||
usage: |
|
||||
/<command>
|
||||
/<command> [-b|-h|-p] [--include-plugin-list]
|
||||
mvhelp:
|
||||
description: Displays the Multiverse Help.
|
||||
aliases: [mvsearch, mvh]
|
||||
usage: |
|
||||
/<command>
|
||||
/<command> [filter] [page #]
|
||||
mvdebug:
|
||||
description: Turns on debugging.
|
||||
usage: |
|
||||
/<command>
|
||||
/<command> [1|2|3|off|silent]
|
||||
mvgenerators:
|
||||
description: Displays all found world generators.
|
||||
usage: |
|
||||
/<command>
|
||||
mvgens:
|
||||
description: Displays all found world generators.
|
||||
aliases: [mvgens]
|
||||
usage: |
|
||||
/<command>
|
||||
mvload:
|
||||
description: Loads a world into Multiverse.
|
||||
usage: |
|
||||
/<command> {WORLD}
|
||||
/<command> <world>
|
||||
mvregen:
|
||||
description: Regenerates a world Multiverse already knows about.
|
||||
usage: |
|
||||
/<command> {WORLD}
|
||||
/<command> <world> [-s seed]
|
||||
mvscript:
|
||||
description: Runs a script from the Multiverse scripts directory.
|
||||
usage: |
|
||||
/<command> {script} [target]
|
||||
/<command> <script> [target]
|
||||
mvclone:
|
||||
description: World clone command
|
||||
aliases: [mvcl]
|
||||
usage: |
|
||||
/<command> <world> <environment>
|
||||
/<command> <world> <environment> [-g generator[:id]]
|
||||
/<command> creative grieftastic -- Creates a world called 'grieftastic' exactly identical to the world 'creative'.
|
||||
mvsilent:
|
||||
description: Reduces startup messages
|
||||
usage: |
|
||||
/<command> [true|false]
|
||||
|
||||
mvgamerule:
|
||||
description: Sets a gamerule.
|
||||
aliases: [mvrule]
|
||||
usage: |
|
||||
/<command> {RULE} {VALUE} [WORLD]
|
||||
mvrule:
|
||||
description: Sets a gamerule.
|
||||
usage: |
|
||||
/<command> {RULE} {VALUE} [WORLD]
|
||||
/<command> <rule> <value> [world]
|
||||
mvgamerules:
|
||||
description: Lists the gamerules.
|
||||
description: Lists the gamerules
|
||||
aliases: [mvrules]
|
||||
usage: |
|
||||
/<command> [WORLD]
|
||||
mvrules:
|
||||
description: Lists the gamerules.
|
||||
/<command> [world]
|
||||
mvanchors:
|
||||
description: Creating and removing Anchors command
|
||||
aliases: [mvanchor]
|
||||
usage: |
|
||||
/<command> [WORLD]
|
||||
/<command> <name> [-d]
|
||||
mvcheck:
|
||||
description: Validate your multiverse settings command
|
||||
usage: |
|
||||
/<command> <name> <destination>
|
||||
mvconfig:
|
||||
description: Configuration command
|
||||
aliases: [mvconf]
|
||||
usage: |
|
||||
/<command> <property> <value>
|
||||
@@ -6,6 +6,9 @@ import static org.junit.Assert.assertTrue;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import org.junit.After;
|
||||
@@ -86,6 +89,34 @@ public class FileUtilsTest {
|
||||
assertTrue(Files.isRegularFile(targetChildDirFile));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyFolder_excludingSomeFiles() throws Exception {
|
||||
Path targetDir = tempDir.resolve("target");
|
||||
Path targetFile = targetDir.resolve("parentDirFile.txt");
|
||||
Path targetIgnoreFile = targetDir.resolve("parentIgnoreFile.txt");
|
||||
Path targetChildDir = targetDir.resolve("childDir");
|
||||
Path targetChildDirFile = targetChildDir.resolve("childDirFile.txt");
|
||||
Path targetChildIgnoreFile = targetChildDir.resolve("childIgnoreFile.txt");
|
||||
|
||||
List<String> excludeFiles = new ArrayList<>(Arrays.asList("parentIgnoreFile.txt", "childIgnoreFile.txt"));
|
||||
|
||||
assertFalse(Files.isDirectory(targetDir));
|
||||
assertFalse(Files.isRegularFile(targetFile));
|
||||
assertFalse(Files.isRegularFile(targetIgnoreFile));
|
||||
assertFalse(Files.isDirectory(targetChildDir));
|
||||
assertFalse(Files.isRegularFile(targetChildDirFile));
|
||||
assertFalse(Files.isRegularFile(targetChildIgnoreFile));
|
||||
|
||||
assertTrue(FileUtils.copyFolder(parentDir.toFile(), targetDir.toFile(), excludeFiles, Logging.getLogger()));
|
||||
|
||||
assertTrue(Files.isDirectory(targetDir));
|
||||
assertTrue(Files.isRegularFile(targetFile));
|
||||
assertFalse(Files.isRegularFile(targetIgnoreFile));
|
||||
assertTrue(Files.isDirectory(targetChildDir));
|
||||
assertTrue(Files.exists(targetChildDirFile));
|
||||
assertFalse(Files.isRegularFile(targetChildIgnoreFile));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyFolder_intoExistingFolder() throws Exception {
|
||||
Path targetDir = Files.createDirectory(tempDir.resolve("target"));
|
||||
|
||||
@@ -64,6 +64,7 @@ public class TestInstanceCreator {
|
||||
public static final File worldsDirectory = new File("bin/test/server");
|
||||
|
||||
public boolean setUp() {
|
||||
TestingMode.enable();
|
||||
try {
|
||||
pluginDirectory.mkdirs();
|
||||
assertTrue(pluginDirectory.exists());
|
||||
|
||||
Reference in new issue
Block a user