Merge upstream updates from EarthMC/QuickShop-Reremake (PR #3)

Remove Metrics, Sentry/Rollbar error reporting, FabledSkyblock integration,
environment checker, Bootstrap GUI, Spartan compatibility, and all tests.
Adopt Adventure API for item hover chat, simplify ReflectFactory methods,
cache hopper protection config. Retain 1.19.4 API compatibility
(EntityType.DROPPED_ITEM, PotionData, NMS-based item JSON serialization).
Clean up build.gradle.kts to match removed code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit was merged in pull request #3.
This commit is contained in:
NotAlexNoyleandClaude Opus 4.6 committed 2026-04-13 07:05:13 -04:00
commit afe9033684
56 files changed
+82 -5358

No files matched your search

-10
View File
@@ -1,10 +0,0 @@
component_depth: 100
languages:
- java
- script
exclude:
- /src/main/resources
- /src/test/
- /.github
- /.idea
- /lib
-20
View File
@@ -1,20 +0,0 @@
version = 1
[[analyzers]]
name = "shell"
enabled = true
[[analyzers]]
name = "sql"
enabled = true
[[analyzers]]
name = "test-coverage"
enabled = true
[[analyzers]]
name = "java"
enabled = true
[analyzers.meta]
runtime_version = "15"
-72
View File
@@ -1,72 +0,0 @@
language: java
sudo: required
cache:
directories:
- "$HOME/.m2/repository"
jdk:
- openjdk8
install: skip
#script:
# - export PROJECT_NAME=QuickShop-Reremake #Set project name
# - git clone --depth=1 https://github.com/Ghost-chu/$PROJECT_NAME.git $PROJECT_NAME #Clone project
# - cd $PROJECT_NAME #Cd into project
# - mvn clean #Clean up
# - mvn -T 4 install #Install
after_success:
- rm -rf push # GITHUB - CLEANUP
#Script to release to Github Release
- mkdir push
- cp -r ./target/*.jar ./push/
- rm -f ./push/original-*.jar
- rm -f ./push/*-shaded.jar
- rm -f ./push/*-sources.jar
- mv -f ./push/*-javadoc.jar ./push/JavaDocument.zip
# #Script to release to Bukkit Dev
# - mkdir devbukkit
# - cp -r ./target/*.jar ./devbukkit/
# - rm -f ./devbukkit/original-*.jar
# - rm -f ./devbukkit/*-javadoc.jar
# - rm -f ./devbukkit/*-shaded.jar
# - rm -f ./devbukkit/*-sources.jar
# - rm -f ./target/original-*.jar
# - ls ./devbukkit -1 | grep ".jar$" > jarname.txt
deploy:
skip_cleanup: true
provider: releases
api_key:
secure: xsJTi70QvH4lqKDhpJvqpfBBKSlxrTxkLofeJND58ZYPFhVk4egTalBYz/fT54s4G8YQHflSUNocl+W9zn/4lpdsdI1acMhCpBz014TJOMeEuwXN7yMslGO8eUKaZUiVjhygzrCp0RKwmY3TcpcFI98lbDAsVgFegzBdQpGk3gtlF3O/PAFEcHnhkEdohNJHlBrPFIdahnM8/saYbyzSzcjGRLkIOt75yzY/+AE0pQh24yI1K6xGA2FzO9LVBmNE15HvoqQhmZ8amKMbbsOJNe9OLJYHZRmWViudtaQibZtKWLLH+S+kjJ280PA96NtqCQ4xI/bDTfgxg34VWwKh3NtuAAS1mcnLpSTIQddI2D+R2pfG5igq69qXkK/Xedgv06H9y8dHw+ygBUm5J+cooktASw3WCgwncesU5oO5G2vd/NxbcpDSm5LookdpWtxHL36dg1gafPKJI2sthileN4LfIp9cBMgIN4bDdp9CLjzayzbVeRAqFrvbCV+qW5Eub5cMun0BEZpIEcAFnugMLrkMGm5wtLkFKwhE8Qy7ZmsArGOVFjaQloTWHhrae0avqbBbJPglbWeYT0Bm4M1fqNU80e8bwPaC24yJpTN+MoUZ4cvJ7c09++4b0Q4VK5ordyqipK0/2jalclGNRZAXkDr+dQO6vBCLYZPEjShW3nY=
file:
- ./push/*
file_glob: true
on:
tags: true
overwrite: true
#after_deploy:
# #Confirm release to Bukkit Dev
# - chmod +x deploy.sh
# - "./deploy.sh $Curse_token"
# #Deploy to the mvn-repo
# - echo "Deploying to the Github..."
# - git clone --depth=1 https://$Github_token@github.com/Ghost-chu/maven-repo.git maven-repo
# - mvn deploy -DaltDeploymentRepository=mvn-repo::default::file:./maven-repo
# - cd maven-repo
# - git add .
# - git commit -m "Auto update by Travis-CI bot"
# - git push --force
# - cd ..
# - echo "Finish upload to Maven Repository"
#after_script:
# #Upload data to BinaryRepository
# - git clone --depth=1 https://$Github_token@github.com/Ghost-chu/BinaryRepository.git BinaryRepository
# - mkdir -p ./BinaryRepository/$PROJECT_NAME/$TRAVIS_BUILD_NUMBER
# - mkdir -p ./BinaryRepository/$PROJECT_NAME/$TRAVIS_BUILD_NUMBER/target
# - cp -r ./target/* ./BinaryRepository/$PROJECT_NAME/$TRAVIS_BUILD_NUMBER/target
# - echo -e "== Built by Travis-CI ==\nBuild Number [$TRAVIS_BUILD_NUMBER]\nBuild Type
# [$TRAVIS_EVENT_TYPE]\nTag [$TRAVIS_TAG]\nCommit [$TRAVIS_COMMIT] - [$TRAVIS_COMMIT_MESSAGE]"
# > ./BinaryRepository/$PROJECT_NAME/$TRAVIS_BUILD_NUMBER/BUILDINFO
# - cd BinaryRepository
# - git add .
# - git commit -m "Auto update by Bot"
# - git push --force
# - cd .. #Back root
# - echo "Finish upload to BinaryRepository"
-12
View File
@@ -1,12 +0,0 @@
{
"scanSettings": {
"baseBranches": []
},
"checkRunSettings": {
"vulnerableCheckRunConclusionLevel": "failure",
"displayMode": "diff"
},
"issueSettings": {
"minSeverityLevel": "LOW"
}
}
Binary file not shown.
-18
View File
@@ -44,8 +44,6 @@ repositories {
maven(url = "https://repo.papermc.io/repository/maven-public/")
maven(url = "https://repo.bg-software.com/repository/api/")
maven(url = "https://maven.enginehub.org/repo/")
maven(url = "https://repo.songoda.com/repository/public/")
maven(url = "https://repo.craftaro.com/repository/public/")
maven(url = "https://repo.minebench.de/")
}
@@ -62,27 +60,17 @@ dependencies {
compileOnly("me.clip:placeholderapi:2.11.6")
compileOnly("com.github.angeschossen:LandsAPI:6.35.0")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0")
testImplementation("com.github.seeseemelk:MockBukkit-v1.20:3.87.0")
testImplementation("org.xerial:sqlite-jdbc:3.40.1.0")
testImplementation("mysql:mysql-connector-java:8.0.33")
implementation("org.apache.commons:commons-compress:1.22")
implementation("org.apache.commons:commons-lang3:3.12.0")
compileOnly(files("lib/SpartanAPI-9.1.jar"))
compileOnly("com.github.TownyAdvanced:Towny:0.97.0.5")
compileOnly("com.sk89q.worldguard:worldguard-bukkit:7.0.9")
compileOnly("com.plotsquared:PlotSquared-Core:6.11.1") { isTransitive = false }
compileOnly(files("lib/Residence5.0.1.0.jar"))
compileOnly("com.massivecraft:Factions:1.6.9.5-U0.6.0")
compileOnly(files("lib/BlocksHub-3.2.1.jar"))
implementation("com.rollbar:rollbar-java:1.10.0")
implementation("com.github.PotatoCraft-Studio:MineDown:1.7.1-modified")
compileOnly(files("lib/GemsEconomy-4.9.2.jar"))
compileOnly(files("lib/TNE-0.1.1.17-PRE-2.jar"))
compileOnly("com.songoda:skyblock:2.3.30")
compileOnly("com.songoda:SongodaCore:2.6.18")
implementation("commons-codec:commons-codec:1.15")
implementation("org.slf4j:slf4j-nop:1.7.32")
implementation("io.papermc:paperlib:1.0.7")
@@ -99,10 +87,7 @@ dependencies {
compileOnly("org.projectlombok:lombok:1.18.30")
annotationProcessor("org.projectlombok:lombok:1.18.30")
testCompileOnly("org.projectlombok:lombok:1.18.30")
testAnnotationProcessor("org.projectlombok:lombok:1.18.30")
compileOnly("org.jetbrains:annotations:24.0.1")
testCompileOnly("org.jetbrains:annotations:24.0.1")
}
tasks.named<ProcessResources>("processResources") {
@@ -114,8 +99,6 @@ tasks.named<ProcessResources>("processResources") {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
tasks.withType<Test>().configureEach { useJUnitPlatform() }
tasks.withType<AbstractArchiveTask>().configureEach {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
@@ -165,7 +148,6 @@ tasks.named<ShadowJar>("shadowJar") {
relocate("net.minidev.json", "org.maxgamer.quickshop.shade.net.minidev.json.minidev.json")
relocate("com.fasterxml.jackson.core", "org.maxgamer.quickshop.shade.com.fasterxml.jackson.jackson.core")
relocate("me.lucko", "org.maxgamer.quickshop.shade.me.lucko")
relocate("com.rollbar", "org.maxgamer.quickshop.shade.com.rollbar")
relocate(
"com.dumptruckman.bukkit.configuration",
"org.maxgamer.quickshop.shade.com.dumptruckman.bukkit.configuration",
-6
View File
@@ -1,6 +0,0 @@
project_id_env: CROWDIN_PROJECT_ID
api_token_env: CROWDIN_PERSONAL_TOKEN
preserve_hierarchy: true
files:
- source: /src/main/resources/lang/*.json
translation: /crowdin/lang/%locale%/%original_file_name%
-28
View File
@@ -1,28 +0,0 @@
#!/bin/sh
#
# This file is a part of project QuickShop, the name is deploy.sh
# Copyright (C) PotatoCraft Studio and contributors
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
echo "Deploy jar to dev.bukkit.org"
xToken=$1
curl -X POST -H "X-Api-Token: $xToken" -F 'metadata={"changelog":"Auto upload by Jenkins CI, see update details at https://www.spigotmc.org/resources/62575/updates","gameVersions":[8503,7915,7667,7330,7105,8849,8897,9016,9189,9261,9560,9561],"releaseType":"release"}' -F "file=@./target/QuickShop.jar" -s "https://dev.bukkit.org/api/projects/320536/upload-file" >fileid.json
cat fileid.json
echo "Finished upload to dev.bukkit.org."
exit 0
BIN
View File
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large. Load diff
@@ -113,17 +113,9 @@ import org.maxgamer.quickshop.util.compatibility.SimpleCompatibilityManager;
import org.maxgamer.quickshop.util.config.ConfigCommentUpdater;
import org.maxgamer.quickshop.util.config.ConfigProvider;
import org.maxgamer.quickshop.util.config.ConfigurationFixer;
import org.maxgamer.quickshop.util.envcheck.CheckResult;
import org.maxgamer.quickshop.util.envcheck.EnvCheckEntry;
import org.maxgamer.quickshop.util.envcheck.EnvironmentChecker;
import org.maxgamer.quickshop.util.envcheck.ResultContainer;
import org.maxgamer.quickshop.util.envcheck.ResultReport;
import org.maxgamer.quickshop.util.matcher.item.BukkitItemMatcherImpl;
import org.maxgamer.quickshop.util.matcher.item.QuickShopItemMatcherImpl;
import org.maxgamer.quickshop.util.reload.ReloadManager;
import org.maxgamer.quickshop.util.reporter.error.EmptyErrorReporter;
import org.maxgamer.quickshop.util.reporter.error.IErrorReporter;
import org.maxgamer.quickshop.util.reporter.error.RollbarErrorReporter;
import org.maxgamer.quickshop.watcher.CalendarWatcher;
import org.maxgamer.quickshop.watcher.DisplayAutoDespawnWatcher;
import org.maxgamer.quickshop.watcher.DisplayDupeRemoverWatcher;
@@ -140,7 +132,6 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -154,7 +145,6 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
@@ -244,10 +234,6 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
@Nullable
@Getter
private LogWatcher logWatcher;
/**
* bStats, good helper for metrics.
*/
private Metrics metrics;
/**
* The plugin OpenInv (null if not present)
*/
@@ -263,11 +249,6 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
*/
@Getter
private PermissionChecker permissionChecker;
/**
* The error reporter to help devs report errors to Sentry.io
*/
@Getter
private IErrorReporter sentryErrorReporter = new EmptyErrorReporter();
/**
* The server UniqueID, use to the ErrorReporter
*/
@@ -303,8 +284,6 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
@Getter
private boolean includeOfflinePlayer;
@Getter
private EnvironmentChecker environmentChecker;
@Getter
@Nullable
private UpdateWatcher updateWatcher;
@Getter
@@ -816,7 +795,6 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
} catch (Throwable e) {
this.getSentryErrorReporter().ignoreThrow();
getLogger().log(Level.WARNING, "Something going wrong when loading up economy system", e);
getLogger().severe("QuickShop could not hook into a economy/Not found Vault or Reserve!");
getLogger().severe("QuickShop CANNOT start!");
@@ -918,7 +896,6 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
getLogger().info("QuickShop " + getFork() + " - Early boot step - Booting up");
// BEWARE THESE ONLY RUN ONCE
this.buildInfo = new BuildInfo(getResource("BUILDINFO"));
runtimeCheck(EnvCheckEntry.Stage.ON_LOAD);
getLogger().info("Reading the configuration...");
this.initConfiguration();
this.bootError = null;
@@ -949,11 +926,6 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
public final void onDisable() {
getLogger().info("QuickShop is finishing remaining work, this may need a while...");
if (sentryErrorReporter != null) {
sentryErrorReporter.unregister();
}
if (this.integrationHelper != null) {
@@ -999,7 +971,9 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
}
if (AbstractDisplayItem.getNowUsing() == DisplayType.VIRTUALITEM) {
if (AbstractDisplayItem.getNowUsing() == DisplayType.VIRTUALITEM && this.display
&& Bukkit.getPluginManager().getPlugin("ProtocolLib") != null)
{
VirtualDisplayItem.VirtualDisplayItemManager.unload();
@@ -1170,126 +1144,6 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
}
private void runtimeCheck(@NotNull EnvCheckEntry.Stage stage) {
testing = true;
environmentChecker = new org.maxgamer.quickshop.util.envcheck.EnvironmentChecker(this);
ResultReport resultReport = environmentChecker.run(stage);
StringJoiner joiner = new StringJoiner("\n", "", "");
if (resultReport.getFinalResult().ordinal() > CheckResult.WARNING.ordinal()) {
for (Entry<EnvCheckEntry, ResultContainer> result : resultReport.getResults().entrySet()) {
if (result.getValue().getResult().ordinal() > CheckResult.WARNING.ordinal()) {
joiner.add(String.format("- [%s/%s] %s", result.getValue().getResult().getDisplay(),
result.getKey().name(), result.getValue().getResultMessage()));
}
}
}
// Check If we need kill the server or disable plugin
switch (resultReport.getFinalResult()) {
case DISABLE_PLUGIN:
Bukkit.getPluginManager().disablePlugin(this);
break;
case STOP_WORKING:
setupBootError(new BootError(this.getLogger(), joiner.toString()), true);
PluginCommand command = getCommand("qs");
if (command != null) {
command.setTabCompleter(this); // Disable tab completer
}
break;
case KILL_SERVER:
getLogger().severe(
"[Security Risk Detected] QuickShop forcing crash the server for security, contact the developer for details.");
String result = environmentChecker.getReportMaker().bake();
File reportFile = writeSecurityReportToFile();
URI uri = null;
if (reportFile != null) {
uri = reportFile.toURI();
}
if (uri != null) {
getLogger().warning("[Security Risk Detected] To get more details, please check: " + uri);
try {
if (java.awt.Desktop.isDesktopSupported()) {
java.awt.Desktop dp = java.awt.Desktop.getDesktop();
if (dp.isSupported(java.awt.Desktop.Action.BROWSE)) {
dp.browse(uri);
getLogger().warning("[Security Risk Detected] A browser already open for you. ");
}
}
} catch (Throwable ignored) {
// If failed, write directly to console
getLogger().severe(result);
}
} else {
// If write failed, write directly to console
getLogger().severe(result);
}
// Wait for a while for user and logger outputting
try {
// 10 seconds
Thread.yield();
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Halt the process, kill the server
Runtime.getRuntime().halt(-1);
default:
break;
}
testing = false;
}
private File writeSecurityReportToFile() {
File file = new File(getDataFolder(), UUID.randomUUID() + ".security.letter.txt");
try {
Files.write(new File(getDataFolder(), UUID.randomUUID() + ".security.letter.txt").toPath(),
environmentChecker.getReportMaker().bake().getBytes(StandardCharsets.UTF_8));
file = file.getCanonicalFile();
} catch (IOException e) {
getLogger().log(Level.SEVERE, "Failed to write security report!", e);
return null;
}
return file;
}
@Override
public final void onEnable() {
@@ -1310,42 +1164,9 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
Timer enableTimer = new Timer(true);
this.integrationHelper.callIntegrationsLoad(IntegrateStage.onEnableBegin);
getLogger().info("QuickShop " + getFork());
/* Check the running envs is support or not. */
getLogger().info("Starting plugin self-test, please wait...");
runtimeCheck(EnvCheckEntry.Stage.ON_ENABLE);
getLogger().info("Reading the configuration...");
this.initConfiguration();
getLogger().info("Developers: " + Util.list2String(this.getDescription().getAuthors()));
getLogger().info("Original author: Netherfoam, Timtower, KaiNoMood");
getLogger().info("Let's start loading the plugin");
getLogger().info("Chat processor selected: Hardcoded BungeeChat Lib");
/* Process Metrics and Sentry error reporter. */
metrics = new Metrics(this, 3320);
try {
if (!getConfig().getBoolean("auto-report-errors")) {
Util.debugLog("Error reporter was disabled!");
} else {
sentryErrorReporter = new RollbarErrorReporter(this);
}
} catch (Throwable th) {
getLogger().warning("Cannot load the Sentry Error Reporter: " + th.getMessage());
getLogger().warning(
"Because our error reporter doesn't work, please report this error to developer, thank you!");
}
/* Initalize the Utils */
this.loadItemMatcher();
Util.initialize();
@@ -1386,7 +1207,6 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
}
getLogger().info("Registering commands...");
/* PreInit for BootError feature */
commandManager = new SimpleCommandManager(this);
// noinspection ConstantConditions
@@ -1445,7 +1265,6 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
shopLoader = new ShopLoader(this);
shopLoader.loadShops();
getLogger().info("Registering listeners...");
// Register events
// Listeners (These don't)
new BlockListener(this, this.shopCache).register();
@@ -1569,8 +1388,6 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
integrationHelper.searchAndRegisterPlugins();
this.integrationHelper.callIntegrationsLoad(IntegrateStage.onEnableAfter);
getLogger().info("Registering bStats metrics...");
submitMetrics();
if (loaded) {
getServer().getPluginManager().callEvent(new QSConfigurationReloadEvent(this));
@@ -1712,82 +1529,6 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
}
private void submitMetrics() {
if (!getConfig().getBoolean("disabled-metrics")) {
String vaultVer;
Plugin vault = Bukkit.getPluginManager().getPlugin("Vault");
if (vault != null) {
vaultVer = vault.getDescription().getVersion();
} else {
vaultVer = "Vault not found";
}
// Use internal Metric class not Maven for solve plugin name issues
String economyType = AbstractEconomy.getNowUsing().name();
if (getEconomy() != null) {
economyType = this.getEconomy().getName();
}
String eventAdapter;
if (getConfig().getInt("shop.protection-checking-handler") == 1) {
eventAdapter = "QUICKSHOP";
} else {
eventAdapter = "BUKKIT";
}
// Version
metrics.addCustomChart(new Metrics.SimplePie("server_version", Bukkit::getVersion));
metrics.addCustomChart(new Metrics.SimplePie("bukkit_version", Bukkit::getBukkitVersion));
metrics.addCustomChart(new Metrics.SimplePie("vault_version", () -> vaultVer));
metrics.addCustomChart(new Metrics.SimplePie("use_display_items",
() -> Util.boolean2Status(getConfig().getBoolean("shop.display-items"))));
metrics.addCustomChart(
new Metrics.SimplePie("use_locks", () -> Util.boolean2Status(getConfig().getBoolean("shop.lock"))));
metrics.addCustomChart(new Metrics.SimplePie("use_sneak_action",
() -> Util.boolean2Status(getConfig().getBoolean("shop.interact.sneak-to-create")
|| getConfig().getBoolean("shop.interact.sneak-to-trade")
|| getConfig().getBoolean("shop.interact.sneak-to-control"))));
String finalEconomyType = economyType;
metrics.addCustomChart(new Metrics.SimplePie("economy_type", () -> finalEconomyType));
metrics.addCustomChart(new Metrics.SimplePie("use_display_auto_despawn",
() -> String.valueOf(getConfig().getBoolean("shop.display-auto-despawn"))));
metrics.addCustomChart(new Metrics.SimplePie("use_enhance_display_protect",
() -> String.valueOf(getConfig().getBoolean("shop.enchance-display-protect"))));
metrics.addCustomChart(new Metrics.SimplePie("use_enhance_shop_protect",
() -> String.valueOf(getConfig().getBoolean("shop.enchance-shop-protect"))));
metrics.addCustomChart(new Metrics.SimplePie("use_ongoing_fee",
() -> String.valueOf(getConfig().getBoolean("shop.ongoing-fee.enable"))));
metrics.addCustomChart(
new Metrics.SimplePie("database_type", () -> this.getDatabaseManager().getDatabase().getName()));
metrics.addCustomChart(
new Metrics.SimplePie("display_type", () -> AbstractDisplayItem.getNowUsing().name()));
metrics.addCustomChart(new Metrics.SimplePie("itemmatcher_type", () -> this.getItemMatcher().getName()));
metrics.addCustomChart(new Metrics.SimplePie("use_stack_item", () -> String.valueOf(this.isAllowStack())));
metrics.addCustomChart(new Metrics.SimplePie("chat_adapter", () -> "Hardcoded Adventure"));
metrics.addCustomChart(new Metrics.SimplePie("event_adapter", () -> eventAdapter));
metrics.addCustomChart(new Metrics.SingleLineChart("shops_created_on_all_servers",
() -> this.getShopManager().getAllShops().size()));
} else {
getLogger().info("You have disabled mertics, Skipping...");
}
}
// TODO: Refactor it
private void updateConfig(int selectedVersion) throws IOException {
@@ -3369,7 +3110,6 @@ public class QuickShop extends JavaPlugin implements QuickShopAPI {
try {
ReflectFactory.getCommandMap().register("qs", quickShopCommand);
ReflectFactory.syncCommands();
} catch (Exception e) {
@@ -20,12 +20,13 @@
package org.maxgamer.quickshop.chat.platform.minedown;
import lombok.AllArgsConstructor;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.chat.ComponentSerializer;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@@ -38,13 +39,8 @@ import org.maxgamer.quickshop.api.chat.QuickChat;
import org.maxgamer.quickshop.api.chat.QuickComponent;
import org.maxgamer.quickshop.api.shop.Shop;
import org.maxgamer.quickshop.chat.QuickComponentImpl;
import org.maxgamer.quickshop.util.MsgUtil;
import org.maxgamer.quickshop.util.ReflectFactory;
import org.maxgamer.quickshop.util.TextSplitter;
import org.maxgamer.quickshop.util.Util;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
@@ -128,6 +124,13 @@ public class BungeeQuickChat implements QuickChat {
}
if (component.get() instanceof Component adventureComponent) {
receiver.sendMessage(adventureComponent);
return;
}
Util.debugLog("Illegal component " + component.get().getClass().getName() + " sending to "
+ this.getClass().getName() + " processor, trying force sending.");
@@ -149,109 +152,7 @@ public class BungeeQuickChat implements QuickChat {
@Override
public void sendItemHologramChat(@NotNull Player player, @NotNull String text, @NotNull ItemStack itemStack) {
sendItemHologramChat(player, text, itemStack, false);
}
private BungeeComponentBuilder appendItemHoloChat(@Nullable String itemJson, @NotNull String message) {
BungeeComponentBuilder builder = new BungeeComponentBuilder();
TextSplitter.SpilledString spilledString = TextSplitter.deBakeItem(message);
if (itemJson == null) {
if (spilledString == null) {
builder.appendLegacy(message);
} else {
builder.appendLegacyAndItem(spilledString.getLeft(), spilledString.getComponents(),
spilledString.getRight());
}
} else {
HoverEvent itemHoverEvent = new HoverEvent(HoverEvent.Action.SHOW_ITEM,
new ComponentBuilder(itemJson).create());
if (spilledString == null) {
builder.event(itemHoverEvent);
builder.appendLegacy(message);
// Dummy for not included hover event
builder.append(new TextComponent());
builder.event((HoverEvent) null);
} else {
// Only show item on item name side
for (BaseComponent component : spilledString.getComponents()) {
component.setHoverEvent(itemHoverEvent);
}
builder.appendLegacyAndItem(spilledString.getLeft(), spilledString.getComponents(),
spilledString.getRight());
}
}
return builder;
}
private void sendItemHologramChat(@NotNull Player player, @NotNull String text, @NotNull ItemStack itemStack,
boolean skipItemHoloChat)
{
TextComponent errorComponent = new TextComponent(
plugin.text().of(player, "menu.item-holochat-error").forLocale());
try {
BungeeComponentBuilder builder;
if (skipItemHoloChat) {
builder = appendItemHoloChat(null, text);
} else {
builder = appendItemHoloChat(ReflectFactory.convertBukkitItemStackToJson(itemStack), text);
}
BaseComponent[] result = builder.create();
String resultStr = ComponentSerializer.toString(result);
Util.debugLog("Sending debug: " + resultStr);
// The limit in vanilla server is 32767
if (resultStr.getBytes(StandardCharsets.UTF_8).length > 32767) {
if (skipItemHoloChat) {
// If still too large after skipItemHoloChat, just send the error message
plugin.text().of(player, "menu.item-holochat-data-too-large").send();
} else {
sendItemHologramChat(player, text, itemStack, true);
}
} else {
player.spigot().sendMessage(result);
}
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException
| InstantiationException e)
{
plugin.getLogger().log(Level.WARNING, "Failed to process chat component", e);
player.spigot().sendMessage(errorComponent);
}
player.sendMessage(LegacyComponentSerializer.legacySection().deserialize(text).hoverEvent(itemStack));
}
@@ -260,65 +161,26 @@ public class BungeeQuickChat implements QuickChat {
@NotNull Player player, @NotNull String message)
{
return getItemHologramChat(shop, itemStack, player, message, false);
}
private @NotNull QuickComponent getItemHologramChat(@NotNull Shop shop, @NotNull ItemStack itemStack,
@NotNull Player player, @NotNull String message, boolean skipItemHoloChat)
{
TextComponent errorComponent = new TextComponent(
plugin.text().of(player, "menu.item-holochat-error").forLocale());
try {
BungeeComponentBuilder builder;
if (skipItemHoloChat) {
builder = appendItemHoloChat(null, message);
} else {
builder = appendItemHoloChat(ReflectFactory.convertBukkitItemStackToJson(itemStack), message);
}
final net.kyori.adventure.text.TextComponent.Builder builder = LegacyComponentSerializer.legacySection()
.deserialize(message).hoverEvent(itemStack).toBuilder();
if (QuickShop.getPermissionManager().hasPermission(player, "quickshop.preview")) {
// Skip the previous component, avoid it was applied with click event
builder.append(" ");
builder.event(new ClickEvent(ClickEvent.Action.RUN_COMMAND,
MsgUtil.fillArgs("/qs silentpreview {0}", shop.getRuntimeRandomUniqueId().toString())));
builder.appendLegacy(plugin.text().of(player, "menu.preview").forLocale());
builder.clickEvent(net.kyori.adventure.text.event.ClickEvent
.runCommand("/qs silentpreview " + shop.getRuntimeRandomUniqueId()));
builder.append(LegacyComponentSerializer.legacySection()
.deserialize(plugin.text().of(player, "menu.preview").forLocale()));
}
BaseComponent[] result = builder.create();
// The limit in vanilla server is 32767
if (ComponentSerializer.toString(result).getBytes(StandardCharsets.UTF_8).length > 32767) {
if (skipItemHoloChat) {
// If still too large after skipItemHoloChat, just send the error message
return new QuickComponentImpl(
plugin.text().of(player, "menu.item-holochat-data-too-large").forLocale());
} else {
return getItemHologramChat(shop, itemStack, player, message, true);
}
} else {
return new QuickComponentImpl(result);
}
return new QuickComponentImpl(builder.build());
} catch (Exception t) {
plugin.getLogger().log(Level.WARNING, "Failed to process chat component", t);
return new QuickComponentImpl(errorComponent);
return new QuickComponentImpl(
new TextComponent(plugin.text().of(player, "menu.item-holochat-error").forLocale()));
}
@@ -329,31 +191,10 @@ public class BungeeQuickChat implements QuickChat {
@NotNull String normalText)
{
TextComponent errorComponent = new TextComponent(
plugin.text().of(player, "menu.item-holochat-error").forLocale());
final Component component = LegacyComponentSerializer.legacySection()
.deserialize(normalText + " " + plugin.text().of(player, "menu.preview").forLocale())
.hoverEvent(itemStack);
String json;
try {
json = ReflectFactory.convertBukkitItemStackToJson(itemStack);
} catch (Exception throwable) {
plugin.getLogger().log(Level.SEVERE, "Failed to saving item to json for holochat", throwable);
return new QuickComponentImpl(errorComponent);
}
if (json == null) {
return new QuickComponentImpl(errorComponent);
}
TextComponent component = new TextComponent(
normalText + " " + plugin.text().of(player, "menu.preview").forLocale());
ComponentBuilder cBuilder = new ComponentBuilder(json);
component.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, cBuilder.create()));
return new QuickComponentImpl(component);
}
@@ -125,7 +125,6 @@ public class SubCommand_Paste implements CommandHandler<CommandSender> {
} catch (IOException e) {
plugin.getSentryErrorReporter().ignoreThrow();
plugin.getLogger().log(Level.WARNING,
"Failed to save paste locally! The content will be send to the console", e);
sender.sendMessage("Paste save failed! Sending paste to the console...");
@@ -80,7 +80,6 @@ public class SubCommand_Update implements CommandHandler<CommandSender> {
MsgUtil.sendDirectMessage(sender,
ChatColor.RED + "Update failed! Please check your console for more information.");
plugin.getSentryErrorReporter().ignoreThrow();
plugin.getLogger().log(Level.WARNING, "Failed to update QuickShop because of the following error:", e);
return;
@@ -271,7 +271,6 @@ public class DatabaseManager implements Reloadable {
} catch (SQLException sqle) {
plugin.getSentryErrorReporter().ignoreThrow();
this.plugin.getLogger().log(Level.WARNING,
"Database connection may lost, we are trying reconnecting, if this message appear too many times, you should check your database file(sqlite) and internet connection(mysql).",
sqle);
@@ -110,7 +110,6 @@ public class Economy_Reserve extends AbstractEconomy {
} catch (Exception throwable) {
plugin.getSentryErrorReporter().ignoreThrow();
plugin.getLogger().log(Level.WARNING, errorMsg, throwable);
return false;
@@ -145,7 +144,6 @@ public class Economy_Reserve extends AbstractEconomy {
} catch (Exception throwable) {
plugin.getSentryErrorReporter().ignoreThrow();
plugin.getLogger().log(Level.WARNING, errorMsg, throwable);
return formatInternal(balance);
@@ -182,7 +180,6 @@ public class Economy_Reserve extends AbstractEconomy {
} catch (Exception throwable) {
plugin.getSentryErrorReporter().ignoreThrow();
plugin.getLogger().log(Level.WARNING, errorMsg, throwable);
return 0.0;
@@ -220,7 +217,6 @@ public class Economy_Reserve extends AbstractEconomy {
} catch (Exception throwable) {
plugin.getSentryErrorReporter().ignoreThrow();
plugin.getLogger().log(Level.WARNING, errorMsg, throwable);
return false;
@@ -245,7 +241,6 @@ public class Economy_Reserve extends AbstractEconomy {
} catch (Exception throwable) {
plugin.getSentryErrorReporter().ignoreThrow();
plugin.getLogger().log(Level.WARNING, errorMsg, throwable);
return false;
@@ -190,7 +190,6 @@ public class Economy_Vault extends AbstractEconomy implements Listener {
} catch (Exception t) {
plugin.getSentryErrorReporter().ignoreThrow();
if (trader.getName() == null) {
plugin.getLogger().warning("Deposit failed and player name is NULL, Player uuid: "
@@ -281,7 +280,6 @@ public class Economy_Vault extends AbstractEconomy implements Listener {
} catch (Exception t) {
plugin.getSentryErrorReporter().ignoreThrow();
plugin.getLogger().log(Level.WARNING, String.format(ERROR_MESSAGE, getProviderName()), t);
return 0.0;
@@ -331,7 +329,6 @@ public class Economy_Vault extends AbstractEconomy implements Listener {
} catch (Exception t) {
plugin.getSentryErrorReporter().ignoreThrow();
if (trader.getName() == null) {
plugin.getLogger().warning("Withdraw failed and player name is NULL, Player uuid: "
@@ -26,7 +26,6 @@ import org.jetbrains.annotations.NotNull;
import org.maxgamer.quickshop.QuickShop;
import org.maxgamer.quickshop.api.integration.*;
import org.maxgamer.quickshop.integration.advancedregionmarket.AdvancedShopRegionMarketIntegration;
import org.maxgamer.quickshop.integration.fabledskyblock.FabledIntegration;
import org.maxgamer.quickshop.integration.factionsuuid.FactionsUUIDIntegration;
import org.maxgamer.quickshop.integration.griefprevention.GriefPreventionIntegration;
import org.maxgamer.quickshop.integration.iridiumskyblock.IridiumSkyblockIntegration;
@@ -46,7 +45,7 @@ import java.util.logging.Level;
public class SimpleIntegrationManager extends QuickShopInstanceHolder implements IntegrationManager {
private static final Map<String, Class<? extends IntegratedPlugin>> INTEGRATION_MAPPING = new HashMap<>(7);
private static final Map<String, Class<? extends IntegratedPlugin>> INTEGRATION_MAPPING = new HashMap<>();
static {
@@ -57,7 +56,6 @@ public class SimpleIntegrationManager extends QuickShopInstanceHolder implements
INTEGRATION_MAPPING.put("Residence", ResidenceIntegration.class);
INTEGRATION_MAPPING.put("Towny", TownyIntegration.class);
INTEGRATION_MAPPING.put("WorldGuard", WorldGuardIntegration.class);
INTEGRATION_MAPPING.put("FabledSkyblock", FabledIntegration.class);
INTEGRATION_MAPPING.put("IridiumSkyblock", IridiumSkyblockIntegration.class);
INTEGRATION_MAPPING.put("SuperiorSkyblock", SuperiorSkyblock2Integration.class);
INTEGRATION_MAPPING.put("AdvancedRegionMarket", AdvancedShopRegionMarketIntegration.class);
@@ -1,167 +0,0 @@
/*
* This file is a part of project QuickShop, the name is FabledIntegration.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.integration.fabledskyblock;
import com.songoda.skyblock.api.SkyBlockAPI;
import com.songoda.skyblock.api.island.Island;
import com.songoda.skyblock.api.island.IslandRole;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.maxgamer.quickshop.QuickShop;
import org.maxgamer.quickshop.api.integration.IntegrateStage;
import org.maxgamer.quickshop.api.integration.IntegrationStage;
import org.maxgamer.quickshop.integration.AbstractQSIntegratedPlugin;
import org.maxgamer.quickshop.util.reload.ReloadResult;
import org.maxgamer.quickshop.util.reload.ReloadStatus;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@IntegrationStage(loadStage = IntegrateStage.onEnableAfter)
public class FabledIntegration extends AbstractQSIntegratedPlugin {
private boolean ignoreDisabledWorlds;
private boolean whitelist;
private List<IslandRole> islandRoleList = new ArrayList<>();
public FabledIntegration(QuickShop plugin) {
super(plugin);
plugin.getReloadManager().register(this);
loadConfiguration();
registerListener();
}
private void loadConfiguration() {
ignoreDisabledWorlds = plugin.getConfig().getBoolean("integration.fabledskyblock.ignore-disabled-worlds");
whitelist = plugin.getConfig().getBoolean("integration.fabledskyblock.whitelist-mode");
this.islandRoleList = new ArrayList<>();
for (String roleStr : plugin.getConfig().getStringList("integration.fabledskyblock.create")) {
try {
IslandRole role = IslandRole.valueOf(roleStr.toUpperCase(Locale.ENGLISH));
this.islandRoleList.add(role);
} catch (IllegalArgumentException e) {
plugin.getLogger().warning("Invalid FabledSkyBlock setting role in config: " + roleStr);
}
}
}
/**
* Return the integrated plugin name. For example, Residence
*
* @return integrated plugin
*/
@Override
public @NotNull String getName() {
return "FabledSkyblock";
}
/**
* Check if a player can create shop here
*
* @param player the player want to create shop
* @param location shop location
* @return If you can create shop here
*/
@Override
public boolean canCreateShopHere(@NotNull Player player, @NotNull Location location) {
Island island = SkyBlockAPI.getIslandManager().getIslandAtLocation(location);
if (island == null)
return whitelist;
return this.islandRoleList.contains(island.getRole(player));
}
/**
* Check if a player can trade with shop here
*
* @param player the player want to trade with shop
* @param location shop location
* @return If you can trade with shop here
*/
@Override
public boolean canTradeShopHere(@NotNull Player player, @NotNull Location location) {
if (SkyBlockAPI.getIslandManager().getIslandAtLocation(location) == null) {
return ignoreDisabledWorlds;
}
return true;
}
/**
* Check if a player can delete a shop here
*
* @param player the player want to delete the shop
* @param location shop location
* @return If you can delete the shop here
*/
@Override
public boolean canDeleteShopHere(@NotNull Player player, @NotNull Location location) {
Island island = SkyBlockAPI.getIslandManager().getIslandAtLocation(location);
if (island == null)
return whitelist;
return this.islandRoleList.contains(island.getRole(player));
}
/**
* Loading logic Execute Stage defined by IntegrationStage
*/
@Override
public void load() {
}
/**
* Unloding logic Will execute when Quickshop unloading
*/
@Override
public void unload() {
}
@Override
public ReloadResult reloadModule() throws Exception {
loadConfiguration();
return ReloadResult.builder().status(ReloadStatus.SUCCESS).build();
}
}
@@ -1,100 +0,0 @@
/*
* This file is a part of project QuickShop, the name is Bootstrap.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.javaw.bootstrap;
import javax.swing.*;
/**
* Java default bootstrap if user trying launch QuickShop directly
*
* @author Ghost_chu
*/
public class Bootstrap {
public static void main(String[] args) {
System.out.println("QuickShop is a Spigot plugin.");
System.out.println(
"You cannot directly execute this jar file, please install it as server plugin following the tutorials.");
System.out.println("https://www.spigotmc.org/wiki/spigot-installation.");
if (java.awt.Desktop.isDesktopSupported()) {
try {
java.net.URI uri = java.net.URI.create("https://www.spigotmc.org/wiki/spigot-installation/#plugins");
java.awt.Desktop dp = java.awt.Desktop.getDesktop();
if (dp.isSupported(java.awt.Desktop.Action.BROWSE)) {
createAndShowGUI(true);
dp.browse(uri);
} else {
createAndShowGUI(false);
}
} catch (java.io.IOException e) {
e.printStackTrace();
}
} else {
createAndShowGUI(false);
}
}
private static void createAndShowGUI(boolean supportBrowse) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | UnsupportedLookAndFeelException | IllegalAccessException
| InstantiationException e)
{
e.printStackTrace();
}
if (supportBrowse) {
JOptionPane.showMessageDialog(new JPanel(), "<html><body><p>QuickShop is a Spigot plugin.</p>"
+ "<p>You cannot directly execute this jar file, please install it as server plugin following the <a href=\"https://www.spigotmc.org/wiki/spigot-installation/\">tutorials</a>."
+ "<p>Press \"OK\" button to open Spigot's plugin installation tutorial.</p>" + "</body></html>",
"QuickShop Alert", JOptionPane.ERROR_MESSAGE);
} else {
JOptionPane.showMessageDialog(new JPanel(), "<html><body><p>QuickShop is a Spigot plugin.</p>"
+ "<p>You cannot directly execute this jar file, please install it as server plugin following the tutorials."
+ "<p>Please open the link https://www.spigotmc.org/wiki/spigot-installation/ in your browser to view.</p>"
+ "</body></html>", "QuickShop Alert", JOptionPane.ERROR_MESSAGE);
}
}
}
@@ -455,7 +455,7 @@ public class ShopProtectionListener extends AbstractProtectionListener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
public void onInventoryMove(InventoryMoveItemEvent event) {
if (!plugin.getConfig().getBoolean("protect.hopper")) {
if (!protectHoppers) {
return;
@@ -268,9 +268,6 @@ public class MojangGameLanguageImpl extends BukkitGameLanguageImpl implements Ga
}
private static final boolean isPotionSupportMinecraftKey = Util
.isMethodAvailable("org.bukkit.potion.PotionEffectType", "getKey");
@Override
public @NotNull String getPotion(@NotNull PotionEffectType potionEffectType) {
@@ -281,14 +278,11 @@ public class MojangGameLanguageImpl extends BukkitGameLanguageImpl implements Ga
}
JsonElement jsonElement;
if (isPotionSupportMinecraftKey) {
JsonElement jsonElement = lang.get().get("item.minecraft.potion.effect." + potionEffectType.getKey().getKey());
jsonElement = lang.get().get("effect.minecraft." + potionEffectType.getKey().getKey().toLowerCase());
if (jsonElement == null) {
} else {
jsonElement = lang.get().get("effect.minecraft." + potionEffectType.getName().toLowerCase());
jsonElement = lang.get().get("effect.minecraft." + potionEffectType.getKey().getKey());
}
@@ -553,7 +547,6 @@ public class MojangGameLanguageImpl extends BukkitGameLanguageImpl implements Ga
} catch (Exception e) {
plugin.getSentryErrorReporter().ignoreThrow();
plugin.getLogger().log(Level.WARNING, "Something going wrong when loading game translation assets", e);
} finally {
@@ -219,8 +219,8 @@ public class ContainerShop implements Shop {
this.taxAccount = taxAccount;
initDisplayItem();
this.dirty = false;
// updateShopData();
// updateShopData();
}
private void updateShopData() {
@@ -1788,6 +1788,8 @@ public class SimpleShopManager implements ShopManager, Reloadable {
for (PotionEffect potionEffect : effectsToPrint) {
// Internal api notes: amplifier starts from zero, so plus one to get the
// correct result
int level = potionEffect.getAmplifier() + 1;
chatSheetPrinter.printLine(ChatColor.YELLOW + MsgUtil.getPotioni18n(potionEffect.getType()) + " "
+ (level <= 10 ? RomanNumber.toRoman(potionEffect.getAmplifier()) : level));
@@ -51,6 +51,7 @@ public enum GameVersion {
v1_19_R1(true, false, true, true, true, true), v1_19_R2(true, false, true, true, true, true),
v1_19_R3(true, false, true, true, true, true), v1_20_R1(true, false, true, true, true, true),
v1_20_R2(true, false, true, true, true, true), v1_20_R3(true, false, true, true, true, true),
v1_21_4(true, false, true, true, true, true),
UNKNOWN(true, false, false, true, true, true);
@@ -888,7 +888,6 @@ public class MsgUtil {
Util.debugLog("Content is null");
Throwable throwable = new Throwable("Known issue: Global Alert accepted null string, what the fuck");
plugin.getSentryErrorReporter().sendError(throwable, "NullCheck");
return;
}
@@ -19,7 +19,14 @@
package org.maxgamer.quickshop.util;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.command.CommandMap;
@@ -28,17 +35,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.maxgamer.quickshop.QuickShop;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.stream.Collectors;
/**
* ReflectFactory is library builtin QuickShop to get/execute stuff that cannot
* be access with BukkitAPI with reflect way.
@@ -47,17 +43,10 @@ import java.util.stream.Collectors;
*/
public class ReflectFactory {
private static String cachedVersion = null;
private static Method craftItemStack_asNMSCopyMethod;
private static Method itemStack_saveMethod;
private static Class<?> nbtTagCompoundClass;
private static Class<?> craftServerClass;
private static Class<?> cachedNMSClass;
private static String nmsVersion;
private static Method getMinecraftKeyNameMethod;
private static final boolean isMinecraftKeyNameMethodUnavailable = false;
// private static Object serverInstance;
// private static Field tpsField;
static {
@@ -81,8 +70,6 @@ public class ReflectFactory {
Class<?> returnType = method.getReturnType();
Parameter[] parameters = method.getParameters();
// Save method sign is
// foo(net/minecraft/nbt/NBTTagCompound)L(net/minecraft/nbt/NBTTagCompound)
return !method.isSynthetic() && !method.isBridge() && parameters.length == 1
&& returnType.equals(nbtTagCompoundClass)
&& parameters[0].getType().equals(nbtTagCompoundClass);
@@ -108,8 +95,6 @@ public class ReflectFactory {
}
craftServerClass = Class.forName("org.bukkit.craftbukkit." + nmsVersion + ".CraftServer");
} catch (Exception t) {
QuickShop.getInstance().getLogger().log(Level.WARNING,
@@ -144,100 +129,12 @@ public class ReflectFactory {
return QuickShop.getInstance().getTpsWatcher().getAverageTPS();
// if (serverInstance == null || tpsField == null) {
// try {
// serverInstance = getNMSClass("MinecraftServer").getMethod("getServer").invoke(null);
// tpsField = serverInstance.getClass().getField("recentTps");
// } catch (NoSuchFieldException
// | SecurityException
// | IllegalAccessException
// | IllegalArgumentException
// | InvocationTargetException
// | NoSuchMethodException e) {
// serverInstance = null;
// tpsField = null;
// Util.debugLog("Failed to get TPS " + e.getMessage());
// try {
//
// }catch (Exception exception){
// return 20.0;
// }
// }
// }
// try {
// double[] tps = ((double[]) tpsField.get(serverInstance));
// return tps[0];
// } catch (IllegalAccessException ignored) {
// return 20.0;
// }
}
@NotNull
public static Class<?> getNMSClass(@Nullable String className) {
if (cachedNMSClass != null) {
return cachedNMSClass;
}
if (className == null) {
className = "MinecraftServer";
}
String name = Bukkit.getServer().getClass().getPackage().getName();
String version = name.substring(name.lastIndexOf('.') + 1);
try {
cachedNMSClass = Class.forName("net.minecraft.server." + version + "." + className);
return cachedNMSClass;
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
@NotNull
public static String getServerVersion() {
if (cachedVersion != null) {
return cachedVersion;
}
try {
Field consoleField = Bukkit.getServer().getClass().getDeclaredField("console");
// protected
consoleField.setAccessible(true);
// dedicated server
Object console = consoleField.get(Bukkit.getServer());
cachedVersion = String.valueOf(console.getClass().getSuperclass().getMethod("getVersion").invoke(console));
return cachedVersion;
} catch (Exception e) {
// Fallback to common substring
String[] strings = StringUtils.substringsBetween(Bukkit.getServer().getVersion(), "(MC: ", ")");
if (strings != null && strings.length == 1) {
cachedVersion = strings[0];
} else {
cachedVersion = "Unknown";
}
return cachedVersion;
}
return Bukkit.getServer().getMinecraftVersion();
}
@@ -246,10 +143,6 @@ public class ReflectFactory {
*
* @param bStack ItemStack
* @return The json for ItemStack.
* @throws InvocationTargetException throws
* @throws IllegalAccessException throws
* @throws NoSuchMethodException throws
* @throws InstantiationException throws
*/
@Nullable
public static String convertBukkitItemStackToJson(@NotNull ItemStack bStack)
@@ -272,164 +165,16 @@ public class ReflectFactory {
}
/**
* Save ItemStack to Json through the NMS.
*
* @param bStack ItemStack
* @return The json for ItemStack.
* @throws InvocationTargetException throws
* @throws IllegalAccessException throws
* @throws NoSuchMethodException throws
* @throws InstantiationException throws
*/
@Nullable
public static Object convertBukkitItemStackToMojangItemStack(@NotNull ItemStack bStack)
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException
{
public static CommandMap getCommandMap() {
if (bStack.getType() == Material.AIR) {
return null;
}
Object mcStack = craftItemStack_asNMSCopyMethod.invoke(null, bStack);
Object nbtTagCompound = nbtTagCompoundClass.getDeclaredConstructor().newInstance();
itemStack_saveMethod.invoke(mcStack, nbtTagCompound);
return nbtTagCompound.toString();
}
public static CommandMap getCommandMap() throws NoSuchFieldException, IllegalAccessException {
Field commandMapField = Bukkit.getServer().getClass().getDeclaredField("commandMap");
commandMapField.setAccessible(true);
return (CommandMap) commandMapField.get(Bukkit.getServer());
}
public static void syncCommands() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method method = craftServerClass.getDeclaredMethod("syncCommands");
try {
method.setAccessible(true);
} catch (Exception ignored) {
}
method.invoke(Bukkit.getServer(), (Object[]) null);
}
private static Method findMethod(Class<?> targetClass, Class<?> returnType, Predicate<Method> filter,
Class<?>... args)
{
FindProcess: for (Method method : targetClass.getMethods()) {
if (method.isBridge() && method.isSynthetic()) {
continue;
}
if (method.getReturnType() == returnType) {
if (method.getParameterCount() == args.length) {
Parameter[] parameters = method.getParameters();
for (int i = 0; i < args.length; i++) {
if (parameters[i].getType() != args[i]) {
continue FindProcess;
}
}
if (filter.test(method)) {
return method;
}
}
}
}
return null;
return Bukkit.getServer().getCommandMap();
}
@Nullable
public static String getMaterialMinecraftNamespacedKey(Material material) {
Object nmsItem;
try {
nmsItem = Class.forName("org.bukkit.craftbukkit." + getNMSVersion() + ".util.CraftMagicNumbers")
.getMethod("getItem", Material.class).invoke(null, material);
if (nmsItem == null) {
Util.debugLog("nmsItem null");
return null;
}
try {
getMinecraftKeyNameMethod = nmsItem.getClass().getMethod("getName");
} catch (NoSuchMethodException exception) {
Util.debugLog("Mapping changed during minecraft update, dynamic searching...");
getMinecraftKeyNameMethod = findMethod(nmsItem.getClass(), String.class, method -> {
try {
return !"toString".equals(method.getName()) && ((String) method.invoke(nmsItem)).toLowerCase()
.contains(material.getKey().getKey().toLowerCase(Locale.ROOT));
} catch (Throwable throwable) {
return false;
}
});
}
if (getMinecraftKeyNameMethod == null) {
Util.debugLog("getMinecraftKeyNameMethod is null");
return null;
} else {
return (String) getMinecraftKeyNameMethod.invoke(nmsItem);
}
} catch (IllegalAccessException | ClassNotFoundException | NoSuchMethodException
| InvocationTargetException e)
{
Util.debugLog("getMinecraftKeyNameMethod, error: " + e);
return null;
} catch (Throwable throwable) {
Util.debugLog("getMinecraftKeyNameMethod, Unknown error: " + throwable);
return null;
}
return material.isItem() ? material.getItemTranslationKey() : material.getBlockTranslationKey();
}
@@ -29,7 +29,6 @@ import org.maxgamer.quickshop.api.shop.Shop;
import org.maxgamer.quickshop.economy.Economy_Vault;
import org.maxgamer.quickshop.shop.ShopLoader;
import org.maxgamer.quickshop.util.MsgUtil;
import org.maxgamer.quickshop.util.ReflectFactory;
import org.maxgamer.quickshop.util.Util;
import org.maxgamer.quickshop.util.collector.CollectResolver;
import org.maxgamer.quickshop.util.collector.CollectType;
@@ -108,7 +107,6 @@ public class CollectorAdapter {
data.put("name", plugin.getServer().getName());
data.put("software", plugin.getServer().getVersion());
data.put("version", plugin.getServer().getVersion());
data.put("version_internal", ReflectFactory.getNMSVersion());
data.put("version_data", plugin.getServer().getUnsafe().getDataVersion());
data.put("online_mode", plugin.getServer().getOnlineMode());
data.put("view_distance", plugin.getServer().getViewDistance());
@@ -43,7 +43,6 @@ public class SimpleCompatibilityManager extends QuickShopInstanceHolder implemen
static {
MODULE_MAP.put("NoCheatPlus", NCPCompatibilityModule.class);
MODULE_MAP.put("Spartan", SpartanCompatibilityModule.class);
}
@@ -1,109 +0,0 @@
/*
* This file is a part of project QuickShop, the name is SpartanCompatibilityModule.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util.compatibility;
import me.vagdedes.spartan.api.API;
import me.vagdedes.spartan.api.PlayerViolationEvent;
import me.vagdedes.spartan.system.Enums;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
import org.maxgamer.quickshop.QuickShop;
import org.maxgamer.quickshop.api.compatibility.AbstractQSCompatibilityModule;
import org.maxgamer.quickshop.util.Util;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentSkipListSet;
public class SpartanCompatibilityModule extends AbstractQSCompatibilityModule implements Listener {
public SpartanCompatibilityModule(QuickShop plugin) {
super(plugin);
}
private final Set<UUID> ignoreList = new ConcurrentSkipListSet<>();
@Override
public void register() {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@Override
public void unregister() {
HandlerList.unregisterAll(this);
}
@Override
public @NotNull String getName() {
return "Spartan";
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPlayerViolation(PlayerViolationEvent event) {
if (ignoreList.contains(event.getPlayer().getUniqueId())) {
event.setCancelled(true);
}
}
@Override
public void toggle(@NotNull Player player, boolean status) {
if (status) {
Util.debugLog("Calling Spartan continue follow " + player.getName() + " cheats detection.");
ignoreList.remove(player.getUniqueId());
for (Enums.HackType value : Enums.HackType.values()) {
API.startCheck(player, value);
}
} else {
ignoreList.add(player.getUniqueId());
Util.debugLog("Calling Spartan ignore " + player.getName()
+ " cheats detection until we finished permission checks.");
for (Enums.HackType value : Enums.HackType.values()) {
API.stopCheck(player, value);
}
}
}
}
@@ -1,41 +0,0 @@
/*
* This file is a part of project QuickShop, the name is CheckResult.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util.envcheck;
public enum CheckResult {
SKIPPED("Skip"), PASSED("Pass"), WARNING("Warning"), STOP_WORKING("Error"), DISABLE_PLUGIN("Fatal"),
KILL_SERVER("Kill");
private final String display;
CheckResult(String display) {
this.display = display;
}
public String getDisplay() {
return display;
}
}
@@ -1,40 +0,0 @@
/*
* This file is a part of project QuickShop, the name is EnvCheckEntry.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util.envcheck;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface EnvCheckEntry {
String name() default "Unknown EnvCheck Test";
int priority() default 50;
Stage[] stage() default Stage.ON_ENABLE;
enum Stage {
CONSTRUCTOR, ON_LOAD, ON_ENABLE
}
}
@@ -1,709 +0,0 @@
/*
* This file is a part of project QuickShop, the name is EnvironmentChecker.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util.envcheck;
import lombok.Getter;
import lombok.SneakyThrows;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import org.maxgamer.quickshop.QuickShop;
import org.maxgamer.quickshop.api.shop.AbstractDisplayItem;
import org.maxgamer.quickshop.api.shop.DisplayType;
import org.maxgamer.quickshop.shop.VirtualDisplayItem;
import org.maxgamer.quickshop.util.GameVersion;
import org.maxgamer.quickshop.util.JsonUtil;
import org.maxgamer.quickshop.util.MsgUtil;
import org.maxgamer.quickshop.util.ReflectFactory;
import org.maxgamer.quickshop.util.Util;
import org.maxgamer.quickshop.util.security.JarVerifyTool;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public final class EnvironmentChecker {
private final QuickShop plugin;
private final List<Method> tests = new ArrayList<>();
@Getter
private final SecurityReport reportMaker = new SecurityReport();
public EnvironmentChecker(QuickShop plugin) {
this.plugin = plugin;
this.registerTests(this.getClass()); // register self
}
/**
* Register tests to QuickShop EnvChecker
*
* @param clazz The class contains test
*/
public void registerTests(@NotNull Class<?> clazz) {
for (Method declaredMethod : clazz.getDeclaredMethods()) {
registerTest(declaredMethod);
}
}
/**
* Register test to QuickShop EnvChecker
*
* @param method The test method
*/
public void registerTest(@NotNull Method method) {
EnvCheckEntry envCheckEntry = method.getAnnotation(EnvCheckEntry.class);
if (envCheckEntry == null) {
return;
}
if (method.getReturnType() != ResultContainer.class) {
plugin.getLogger().warning("Failed loading EncCheckEntry [" + method.getName() + "]: Illegal test returns");
return;
}
tests.add(method);
}
private void sortTests() {
tests.sort((o1, o2) -> {
EnvCheckEntry e1 = o1.getAnnotation(EnvCheckEntry.class);
EnvCheckEntry e2 = o2.getAnnotation(EnvCheckEntry.class);
return Integer.compare(e1.priority(), e2.priority());
});
}
public ResultReport run(EnvCheckEntry.Stage stage) {
sortTests();
Map<EnvCheckEntry, ResultContainer> results = new LinkedHashMap<>();
boolean skipAllTest = false;
ResultContainer executeResult = null;
Properties properties = System.getProperties();
CheckResult gResult = CheckResult.PASSED;
for (Method declaredMethod : this.tests) {
if (skipAllTest) {
break;
}
CheckResult result = CheckResult.PASSED;
try {
EnvCheckEntry envCheckEntry = declaredMethod.getAnnotation(EnvCheckEntry.class);
if (Arrays.stream(envCheckEntry.stage()).noneMatch(entry -> entry == stage)) {
Util.debugLog("Skip test: " + envCheckEntry.name() + ": Except stage: "
+ Arrays.toString(envCheckEntry.stage()) + " Current stage: " + stage);
continue;
}
if (false && !properties.containsKey("org.maxgamer.quickshop.util.envcheck.skip."
+ envCheckEntry.name().toUpperCase(Locale.ROOT).replace(" ", "_")))
{
executeResult = (ResultContainer) declaredMethod.invoke(this);
if (executeResult.getResult().ordinal() > result.ordinal()) { // set bad result if its worse than
// the latest one.
result = executeResult.getResult();
}
} else {
result = CheckResult.SKIPPED;
}
switch (result) {
case SKIPPED:
plugin.getLogger().info("[SKIP] " + envCheckEntry.name());
Util.debugLog("Runtime check [" + envCheckEntry.name() + "] has been skipped (Startup Flag).");
break;
case PASSED:
if (Util.isDevEdition() || Util.isDevMode()) {
plugin.getLogger().info("[OK] " + envCheckEntry.name());
Util.debugLog("[Pass] " + envCheckEntry.name() + ": " + executeResult.getResultMessage());
}
break;
case WARNING:
plugin.getLogger()
.warning("[WARN] " + envCheckEntry.name() + ": " + executeResult.getResultMessage());
Util.debugLog("[Warning] " + envCheckEntry.name() + ": " + executeResult.getResultMessage());
break;
case STOP_WORKING:
plugin.getLogger()
.warning("[STOP] " + envCheckEntry.name() + ": " + executeResult.getResultMessage());
Util.debugLog(
"[Stop-Freeze] " + envCheckEntry.name() + ": " + executeResult.getResultMessage());
// It's okay, QuickShop should continue executing checks to collect more data.
// And show user all errors at once.
break;
case DISABLE_PLUGIN:
plugin.getLogger()
.warning("[FATAL] " + envCheckEntry.name() + ": " + executeResult.getResultMessage());
Util.debugLog(
"[Fatal-Disable] " + envCheckEntry.name() + ": " + executeResult.getResultMessage());
skipAllTest = true; // We need to disable the plugin NOW! Some HUGE exception is happening here,
// hurry up!
break;
case KILL_SERVER:
plugin.getLogger()
.warning("[FATAL] " + envCheckEntry.name() + ": " + executeResult.getResultMessage());
Util.debugLog("[Fatal-Kill] " + envCheckEntry.name() + ": " + executeResult.getResultMessage());
skipAllTest = true; // We need to disable the plugin NOW! Some HUGE exception is happening here,
// hurry up!
break;
default:
plugin.getLogger().warning(
"[UNDEFINED] " + envCheckEntry.name() + ": " + executeResult.getResultMessage());
}
if (executeResult != null) {
results.put(envCheckEntry, executeResult);
} else {
results.put(envCheckEntry, new ResultContainer(CheckResult.SKIPPED,
"Startup flag mark this check should be skipped."));
}
if (result.ordinal() > gResult.ordinal()) { // set bad result if its worse than the latest one.
gResult = result;
}
} catch (Exception e) {
plugin.getLogger().log(Level.WARNING, "Failed to execute EnvCheckEntry [" + declaredMethod.getName()
+ "]: Exception thrown out without getting caught. Something went wrong!", e);
plugin.getLogger().warning("[FAIL] " + declaredMethod.getName());
}
}
return new ResultReport(gResult, results);
}
public boolean isOutdatedJvm() {
String jvmVersion = System.getProperty("java.version"); // Use java version not jvm version.
String[] splitVersion = jvmVersion.split("\\.");
if (splitVersion.length < 1) {
Util.debugLog("Failed to parse jvm version to check: " + jvmVersion);
return false;
}
try {
int majorVersion = Integer.parseInt(splitVersion[0]);
return majorVersion < 16; // Target JDK/JRE version
} catch (NumberFormatException ignored) {
Util.debugLog("Failed to parse jvm major version to check: " + splitVersion[0]);
return false;
}
}
@SneakyThrows
@EnvCheckEntry(name = "Signature Verify", priority = 0, stage =
{ EnvCheckEntry.Stage.ON_LOAD, EnvCheckEntry.Stage.ON_ENABLE })
public ResultContainer securityVerify() {
JarVerifyTool tool = new JarVerifyTool();
JarFile jarFile = null;
try {
ClassLoader loader = this.getClass().getClassLoader();
try (InputStream stream1 = loader.getResourceAsStream("META-INF/MANIFEST.MF");
InputStream stream2 = loader.getResourceAsStream("META-INF/SELFSIGN.DSA");
InputStream stream3 = loader.getResourceAsStream("META-INF/SELFSIGN.SF"))
{
if (stream1 == null || stream2 == null || stream3 == null) {
if (stream1 == null) {
this.reportMaker.signatureFileMissing("META-INF/MANIFEST.MF");
}
if (stream2 == null) {
this.reportMaker.signatureFileMissing("META-INF/SELFSIGN.DSA");
}
if (stream3 == null) {
this.reportMaker.signatureFileMissing("META-INF/SELFSIGN.SF");
}
plugin.getLogger().warning(
"The signature could not be found! The QuickShop jar has been modified or you're running a custom build.");
return new ResultContainer(CheckResult.KILL_SERVER,
"Security risk detected, QuickShop jar has been modified.");
}
}
String jarPath = this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile();
jarPath = URLDecoder.decode(jarPath, "UTF-8");
Util.debugLog("JarPath selected: " + jarPath);
jarFile = new JarFile(jarPath);
List<JarEntry> modifiedEntry = tool.verify(jarFile);
if (modifiedEntry.isEmpty()) {
return new ResultContainer(CheckResult.PASSED, "The jar is valid. No issues detected.");
} else {
modifiedEntry.forEach(jarEntry -> {
this.reportMaker.signatureVerifyFail(jarEntry);
plugin.getLogger().warning(">> Modified Class Detected <<");
plugin.getLogger().warning("Name: " + jarEntry.getName());
plugin.getLogger().warning("CRC: " + jarEntry.getCrc());
plugin.getLogger().warning(JsonUtil.getGson().toJson(jarEntry));
});
plugin.getLogger().severe(
"QuickShop detected that the jar has been modified! This is usually caused by the file being corrupted or virus infected.");
plugin.getLogger().severe("To prevent severe server failure, QuickShop has been disabled.");
plugin.getLogger().severe(
"For further information, Please join our support Discord server: https://discord.com/invite/bfefw2E.");
return new ResultContainer(CheckResult.KILL_SERVER,
"Security risk detected, QuickShop jar has been modified.");
}
} catch (Exception ioException) {
plugin.getLogger().log(Level.WARNING,
"ALERT: QuickShop cannot validate itself. This may be caused by you having deleted QuickShop's jar while the server is running.",
ioException);
return new ResultContainer(CheckResult.KILL_SERVER,
"Failed to validate digital signature! Security may be compromised!");
} finally {
if (jarFile != null) {
try {
jarFile.close();
} catch (IOException ignored) {
}
}
}
}
@EnvCheckEntry(name = "Plugin Manifest Check", priority = 1, stage = { EnvCheckEntry.Stage.ON_LOAD,
EnvCheckEntry.Stage.ON_ENABLE })
public ResultContainer manifestCheck() {
String mainClass = plugin.getDescription().getMain();
if (!mainClass.equals("org.maxgamer.quickshop.QuickShop")) {
this.reportMaker.manifestModified(plugin.getDescription());
plugin.getLogger().warning("ALERT: Detected main class has been modified!");
plugin.getLogger().warning("Should be: org.maxgamer.quickshop.QuickShop");
plugin.getLogger().warning("Actually: " + mainClass);
return new ResultContainer(CheckResult.KILL_SERVER,
"Failed to validate main class! Security may be compromised!");
}
return new ResultContainer(CheckResult.PASSED, "Check passed.");
}
@EnvCheckEntry(name = "Potential Infection Characteristics Check", priority = 1, stage = {
EnvCheckEntry.Stage.ON_LOAD, EnvCheckEntry.Stage.ON_ENABLE })
public ResultContainer potentialCheck() {
String jarPath = this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile();
try {
jarPath = URLDecoder.decode(jarPath, "UTF-8");
Util.debugLog("JarPath selected: " + jarPath);
ZipFile zipFile = new ZipFile(jarPath);
Enumeration<? extends ZipEntry> zipEntryEnumeration = zipFile.entries();
boolean found = false;
while (zipEntryEnumeration.hasMoreElements()) {
ZipEntry entry = zipEntryEnumeration.nextElement();
if (entry.getName().startsWith("javassist") || entry.getName().startsWith(".")) {
found = true;
this.reportMaker.potentialInfected(entry);
plugin.getLogger().log(Level.WARNING, "Potential Infection Detected:");
plugin.getLogger().log(Level.WARNING, "File: " + entry.getName());
plugin.getLogger().log(Level.WARNING, "CRC: " + entry.getCrc());
plugin.getLogger().log(Level.WARNING, "Time: " + entry.getTime());
}
}
if (found) {
plugin.getLogger().log(Level.WARNING,
"ALERT: QuickShop detected Potential Infection, this jar may already infected by malware, stop the server and create full server backup immediately, run virus scan and contact the QuickShop support if you need!");
return new ResultContainer(CheckResult.KILL_SERVER,
"Potential Infection detected, Killing server process...");
}
} catch (IOException e) {
plugin.getLogger().log(Level.WARNING,
"ALERT: QuickShop cannot validate itself. This may be caused by you having deleted QuickShop's jar while the server is running.",
e);
return new ResultContainer(CheckResult.KILL_SERVER,
"Failed to validate files in jar! Security may be compromised!");
}
return new ResultContainer(CheckResult.PASSED, "Check passed.");
}
@SneakyThrows
@EnvCheckEntry(name = "Java Runtime Environment Version Test", priority = 1, stage = EnvCheckEntry.Stage.ON_ENABLE)
public ResultContainer jrevTest() {
if (isOutdatedJvm()) {
String jvmWarning = "\n" + "============================================================\n"
+ " Warning! You're running an outdated version of Java!\n"
+ "============================================================\n"
+ "* QuickShop will stop being compatible with your current Java version in the future!\n" + "*\n"
+ "* You should schedule a Java upgrade on your server,\n"
+ "* because we will drop support for any Java versions lower than Java 16.\n" + "*\n"
+ "* That means:\n" + "* 1) Future QuickShop builds will no longer work on your server.\n"
+ "* 2) No support for QuickShop builds that run on outdated Java versions will be given.\n"
+ "* \n" + "* Why:\n" + "* 1) We don't want to keep compatibility with outdated software\n"
+ "* and systems. As Paper upgraded, we did too.\n"
+ "* 2) Java is downward compatible, so most legacy (Java 8+) Plugins should still work.\n"
+ "* 3) Newer Java APIs allow accessing resources and processing them\n"
+ "* faster than before, meaning a performance improvement.\n" + "* \n" + "* What should I do?\n"
+ "* You should update your server's Java version\n"
+ "* as soon as you can to Java 16 or higher.\n" + "*\n"
+ "* Most plugins can run on Java 16+ without problems\n"
+ "* unless their code is really outdated.\n"
+ "* If a Plugin is not compatible with Java 16 and the developer\n"
+ "* doesn't update it, then you should replace them.\n" + "*\n" + "* You can get Java 16 here:\n"
+ "* https://www.oracle.com/java/technologies/javase-downloads.html\n" + "*\n"
+ String.format("* Current Java version: %s", System.getProperty("java.version"));
plugin.getLogger().warning(jvmWarning);
Thread.sleep(5000);
return new ResultContainer(CheckResult.WARNING, "Unsupported outdated JRE version detected.");
}
return new ResultContainer(CheckResult.PASSED, "Java is up-to-date: " + System.getProperty("java.version"));
}
@EnvCheckEntry(name = "Spigot Based Server Test", priority = 2)
public ResultContainer spigotBasedServer() {
ResultContainer success = new ResultContainer(CheckResult.PASSED, "Server");
ResultContainer failed = new ResultContainer(CheckResult.STOP_WORKING,
"Server must be Spigot based, Don't use CraftBukkit!");
try {
// API test
try {
plugin.getServer().spigot();
String nmsVersion = ReflectFactory.getNMSVersion();
plugin.getLogger().info("Running QuickShop-" + QuickShop.getFork() + " on NMS version " + nmsVersion
+ " For Minecraft version " + ReflectFactory.getServerVersion());
} catch (Throwable e) {
return failed;
}
return success;
} catch (Exception e) {
plugin.getLogger().log(Level.WARNING, "Failed to check Spigot API!" + plugin.getServer().getBukkitVersion()
+ " may not be Spigot based.");
return failed;
}
}
@EnvCheckEntry(name = "Old QuickShop Test", priority = 3)
public ResultContainer oldQuickShopTest() {
if (Util.isClassAvailable("org.maxgamer.quickshop.Util.NMS")) {
return new ResultContainer(CheckResult.STOP_WORKING,
"FATAL: Old QuickShop build is installed! You must remove old QuickShop jar from the plugins folder!");
}
return new ResultContainer(CheckResult.PASSED, "No old QuickShop jar installled on this server");
}
public boolean isForgeBasedServer() {
// Forge server detect - Arclight
if (Util.isClassAvailable("net.minecraftforge.server.ServerMain")) {
return true;
}
return Util.isClassAvailable("net.minecraftforge.fml.loading.ModInfo");
}
public boolean isFabricBasedServer() {
// Nobody really make it right!?
return Util.isClassAvailable("net.fabricmc.loader.launch.knot.KnotClient"); // OMG
}
@EnvCheckEntry(name = "ModdedServer Based Test", priority = 4)
public ResultContainer moddedBasedTest() {
boolean trigged = false;
if (isForgeBasedServer()) {
plugin.getLogger().warning("WARN: QuickShop is not designed and tested for Forge!");
plugin.getLogger().warning("WARN: Use at you own risk!.");
plugin.getLogger().warning("WARN: No support will be given!");
trigged = true;
}
if (isFabricBasedServer()) {
plugin.getLogger().warning("WARN: QuickShop is not designed and tested for Fabric!");
plugin.getLogger().warning("WARN: Use at you own risk!.");
plugin.getLogger().warning("WARN: No support will be given!");
trigged = true;
}
if (trigged) {
return new ResultContainer(CheckResult.WARNING, "No support will be given to modded servers.");
}
return new ResultContainer(CheckResult.PASSED, "Server is unmodified.");
}
@EnvCheckEntry(name = "CoreSupport Test", priority = 6)
public ResultContainer coreSupportTest() {
String nmsVersion = ReflectFactory.getNMSVersion();
GameVersion gameVersion = GameVersion.get(nmsVersion);
if (!gameVersion.isCoreSupports()) {
return new ResultContainer(CheckResult.STOP_WORKING, "Your Minecraft version is no longer supported: "
+ ReflectFactory.getServerVersion() + " (" + nmsVersion + ")");
}
if (gameVersion == GameVersion.UNKNOWN) {
return new ResultContainer(CheckResult.WARNING, "QuickShop may not fully support version " + nmsVersion
+ "/" + ReflectFactory.getServerVersion() + ", Some features may not work.");
}
return new ResultContainer(CheckResult.PASSED, "Passed checks");
}
@EnvCheckEntry(name = "Virtual DisplayItem Support Test", priority = 7)
public ResultContainer virtualDisplaySupportTest() {
String nmsVersion = ReflectFactory.getNMSVersion();
GameVersion gameVersion = GameVersion.get(nmsVersion);
Throwable throwable;
if (!gameVersion.isVirtualDisplaySupports()) {
throwable = new IllegalStateException(
"This game version " + gameVersion + " not supports Virtual DisplayItem.");
} else {
if (plugin.getServer().getPluginManager().getPlugin("ProtocolLib") != null) {
throwable = VirtualDisplayItem.PacketFactory.testFakeItem();
} else {
AbstractDisplayItem.setNotSupportVirtualItem(true);
return new ResultContainer(CheckResult.WARNING,
"ProtocolLib is not installed, virtual DisplayItem seems will not work on your server.");
}
}
if (throwable != null) {
Util.debugLog(throwable.getMessage());
MsgUtil.debugStackTrace(throwable.getStackTrace());
AbstractDisplayItem.setNotSupportVirtualItem(true);
// do not throw
plugin.getLogger().log(Level.SEVERE,
"Virtual DisplayItem Support Test: Failed to initialize VirtualDisplayItem", throwable);
return new ResultContainer(CheckResult.WARNING,
"Virtual DisplayItem seems to not work on this Minecraft server, Make sure QuickShop, ProtocolLib and server builds are up to date.");
} else {
return new ResultContainer(CheckResult.PASSED, "Passed checks");
}
}
@EnvCheckEntry(name = "GameVersion supporting Test", priority = 9)
public ResultContainer gamerVersionSupportTest() {
String nmsVersion = ReflectFactory.getNMSVersion();
GameVersion gameVersion = GameVersion.get(nmsVersion);
if (gameVersion == GameVersion.UNKNOWN) {
return new ResultContainer(CheckResult.WARNING,
"Your Minecraft server version not tested by developers, QuickShop may ran into issues on this version.");
}
return new ResultContainer(CheckResult.PASSED, "Passed checks");
}
@EnvCheckEntry(name = "PacketListenerAPI Conflict Test", priority = 10)
public ResultContainer plapiConflictTest() {
if (plugin.isDisplayEnabled() && AbstractDisplayItem.getNowUsing() == DisplayType.VIRTUALITEM
&& Bukkit.getPluginManager().isPluginEnabled("ProtocolLib")
&& Bukkit.getPluginManager().isPluginEnabled("PacketListenerAPI"))
{
return new ResultContainer(CheckResult.WARNING,
"Virtual DisplayItem may stop working on your server. We are already aware that [PacketListenerAPI] and [ProtocolLib] are conflicting. (QuickShops requirement to send fake items). If your display is not showing, please uninstall [PacketListenerAPI].");
}
return new ResultContainer(CheckResult.PASSED, "Passed checks");
}
/*
* No idea why ghost adding this check, groupmanager should work along with QS
*
* @EnvCheckEntry(name = "Permission Manager Test", priority = 10, stage =
* EnvCheckEntry.Stage.ON_ENABLE) public ResultContainer
* permManagerConflictTest() { if
* (plugin.getServer().getPluginManager().isPluginEnabled("GroupManager")) {
* return new ResultContainer(CheckResult.WARNING,
* "WARNING: Unsupported plugin management plugin [GroupManager] installed, the permissions may not working."
* ); } return new ResultContainer(CheckResult.PASSED, "Passed checks"); }
*/
@EnvCheckEntry(name = "End of life Test", priority = Integer.MAX_VALUE, stage = EnvCheckEntry.Stage.ON_ENABLE)
public ResultContainer eolTest() {
if (plugin.getGameVersion().isEndOfLife()) {
return new ResultContainer(CheckResult.WARNING,
"End Of Life! This Minecraft version no-longer receive QuickShop future updates! You won't receive any updates from QuickShop, think about upgrading!");
}
return new ResultContainer(CheckResult.PASSED, "Passed checks");
}
}
@@ -1,55 +0,0 @@
/*
* This file is a part of project QuickShop, the name is ResultContainer.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util.envcheck;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ResultContainer {
private final CheckResult result;
private String resultMessage;
public ResultContainer(@NotNull CheckResult result, @Nullable String resultMessage) {
this.result = result;
this.resultMessage = resultMessage;
if (StringUtils.isEmpty(this.resultMessage)) {
this.resultMessage = "null";
}
}
public CheckResult getResult() {
return result;
}
public String getResultMessage() {
return resultMessage;
}
}
@@ -1,34 +0,0 @@
/*
* This file is a part of project QuickShop, the name is ResultReport.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util.envcheck;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Map;
@AllArgsConstructor
@Data
public class ResultReport {
private final CheckResult finalResult;
private final Map<EnvCheckEntry, ResultContainer> results;
}
@@ -1,68 +0,0 @@
package org.maxgamer.quickshop.util.envcheck;
import org.bukkit.plugin.PluginDescriptionFile;
import org.maxgamer.quickshop.util.Util;
import java.util.zip.ZipEntry;
public class SecurityReport {
private final StringBuffer buffer = new StringBuffer();
public void signatureFileMissing(String name) {
buffer.append("META-INF signature missing: ").append("name=").append(name).append("\n");
}
public void signatureVerifyFail(ZipEntry zipEntry) {
buffer.append("Signature Fail: ").append("name=").append(zipEntry.getName()).append(", ").append("crc=")
.append(zipEntry.getCrc()).append(", ").append("time=").append(zipEntry.getTime()).append(", ")
.append("method=").append(zipEntry.getMethod()).append("\n");
}
public void potentialInfected(ZipEntry zipEntry) {
buffer.append("Potential Infected: ").append("name=").append(zipEntry.getName()).append(", ").append("crc=")
.append(zipEntry.getCrc()).append(", ").append("time=").append(zipEntry.getTime()).append(", ")
.append("method=").append(zipEntry.getMethod()).append("\n");
}
public void manifestModified(PluginDescriptionFile desc) {
buffer.append("Invalid Plugin Description: ").append("name=").append(desc.getName()).append(", ")
.append("main=").append(desc.getMain()).append(", ").append("libraries=[")
.append(Util.list2String(desc.getLibraries())).append("], ").append("provides=[")
.append(Util.list2String(desc.getProvides())).append("]\n");
}
public String bake() {
return "=============================\n" + " QuickShop Security Report\n" + "=============================\n"
+ "Description:\n" + " QuickShop detected self jar has been modified.\n"
+ " Learn more: https://github.com/PotatoCraft-Studio/QuickShop-Reremake/wiki/QuickShop-halt-my-server\n"
+ "\n" + "What that mean: \n"
+ " It usually mean the jar has been infected by malware and cannot be trusted.\n"
+ " Make sure you downloading jar from our SpigotMC and CodeMC pages.\n"
+ " Any other sources is untrusted and may provide a infected jar.\n" + "\n"
+ "I download QuickShop from SpigotMC, why I still see this:\n"
+ " As far as we know, some malware like \"L10\" have ability to infect other jars that installed on your server.\n"
+ " So clean jar can be infect when you installed on infected server.\n" + "\n"
+ "What should I do:\n"
+ " Backup your server immediately, execute virus scan with regular anti-malware software and Spigot Anti-Malware tool.\n"
+ " You can download SAMT here: https://www.spigotmc.org/resources/spigot-anti-malware.64982/\n"
+ "\n" + "Could this be a false positive:\n" + " Basically not.\n" + "\n"
+ "I need some help to handle this issue:\n"
+ " Our community and developer can help you and give you action suggestion.\n"
+ " Join our discord support server: https://discord.gg/bfefw2E\n" + "\n"
+ "Can I disable this noisy check:\n" + " No, you can't.\n" + "\n"
+ "----------------------------------\n" + "Important information related to this issue.\n"
+ "When you ask for support, please provide this paste to the support staffs:\n" + "\n" + buffer;
}
}
@@ -1,59 +0,0 @@
//package org.maxgamer.quickshop.util.hack.packet;
//
//import com.bergerkiller.bukkit.common.nbt.CommonTagCompound;
//import com.bergerkiller.bukkit.common.protocol.CommonPacket;
//import com.bergerkiller.bukkit.common.protocol.PacketType;
//import com.bergerkiller.bukkit.common.utils.BlockUtil;
//import com.bergerkiller.bukkit.common.utils.PacketUtil;
//import net.md_5.bungee.chat.ComponentSerializer;
//import org.apache.commons.lang3.Validate;
//import org.bukkit.Bukkit;
//import org.bukkit.block.Sign;
//import org.bukkit.entity.Player;
//import org.jetbrains.annotations.NotNull;
//import org.maxgamer.quickshop.QuickShop;
//import org.maxgamer.quickshop.api.chat.ComponentPackage;
//
//import java.util.List;
//
///**
// * Little treat, we modify the sign component to translatable component if possible...
// */
//public class SignPacketHack {
//
// private final QuickShop plugin;
//
// public SignPacketHack(QuickShop plugin) {
// this.plugin = plugin;
// Validate.isTrue(Bukkit.getPluginManager().isPluginEnabled("BKCommonLib"), "Require BKCommonLib installed!");
// }
//
// public void sendLines(@NotNull Sign sign, @NotNull List<ComponentPackage> lines, Player player) {
// if (player != null) {
// CommonPacket updatePacket = BlockUtil.getUpdatePacket(sign);
// if (updatePacket != null) {
// applyToSign(updatePacket, lines);
// PacketUtil.sendPacket(player, updatePacket);
// }
// }
// }
//
// public void applyToSign(@NotNull CommonPacket updatePacket, @NotNull List<ComponentPackage> lines) {
// if (updatePacket.getType() == PacketType.OUT_TILE_ENTITY_DATA) {
// // >= MC 1.10.2
//
// CommonTagCompound compound = updatePacket.read(PacketType.OUT_TILE_ENTITY_DATA.data);
// // ====================================================================
//
// for (int i = 0; i < lines.size(); i++) {
// String key = "Text" + (i + 1);
// String text = ComponentSerializer.toString(lines.get(i).getComponents());
// compound.putValue(key, text);
// }
//
// // ====================================================================
// updatePacket.write(PacketType.OUT_TILE_ENTITY_DATA.data, compound);
// }
// }
//
//}
@@ -36,7 +36,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.maxgamer.quickshop.QuickShop;
import org.maxgamer.quickshop.api.shop.ItemMatcher;
import org.maxgamer.quickshop.util.ReflectFactory;
import org.maxgamer.quickshop.util.Util;
import org.maxgamer.quickshop.util.reload.ReloadResult;
import org.maxgamer.quickshop.util.reload.ReloadStatus;
@@ -787,62 +786,54 @@ public class QuickShopItemMatcherImpl implements ItemMatcher, Reloadable {
return true;
}));
if (!"v1_13_R1".equals(ReflectFactory.getNMSVersion())
&& !"v1_13_R2".equals(ReflectFactory.getNMSVersion()))
{
addIfEnable(itemMatcherConfig, "custommodeldata", ((meta1, meta2) -> {
addIfEnable(itemMatcherConfig, "custommodeldata", ((meta1, meta2) -> {
if (meta1.hasCustomModelData() != meta2.hasCustomModelData()) {
if (meta1.hasCustomModelData() != meta2.hasCustomModelData()) {
return false;
}
if (meta1.hasCustomModelData()) {
return meta1.getCustomModelData() == meta2.getCustomModelData();
}
return true;
}));
addIfEnable(itemMatcherConfig, "suspiciousStew", ((meta1, meta2) -> {
if ((meta1 instanceof SuspiciousStewMeta) != (meta2 instanceof SuspiciousStewMeta)) {
return false;
}
if (meta1 instanceof SuspiciousStewMeta) {
SuspiciousStewMeta stewMeta1 = ((SuspiciousStewMeta) meta1);
SuspiciousStewMeta stewMeta2 = ((SuspiciousStewMeta) meta2);
if (stewMeta1.hasCustomEffects() != stewMeta2.hasCustomEffects()) {
return false;
}
if (meta1.hasCustomModelData()) {
if (stewMeta1.hasCustomEffects()) {
return meta1.getCustomModelData() == meta2.getCustomModelData();
return stewMeta1.getCustomEffects().equals(stewMeta2.getCustomEffects());
}
return true;
}));
if (!"v1_14_R1".equals(ReflectFactory.getNMSVersion())) {
addIfEnable(itemMatcherConfig, "suspiciousStew", ((meta1, meta2) -> {
if ((meta1 instanceof SuspiciousStewMeta) != (meta2 instanceof SuspiciousStewMeta)) {
return false;
}
if (meta1 instanceof SuspiciousStewMeta) {
SuspiciousStewMeta stewMeta1 = ((SuspiciousStewMeta) meta1);
SuspiciousStewMeta stewMeta2 = ((SuspiciousStewMeta) meta2);
if (stewMeta1.hasCustomEffects() != stewMeta2.hasCustomEffects()) {
return false;
}
if (stewMeta1.hasCustomEffects()) {
return stewMeta1.getCustomEffects().equals(stewMeta2.getCustomEffects());
}
}
return true;
}));
}
}
return true;
}));
}
@@ -33,7 +33,6 @@ import org.maxgamer.quickshop.api.economy.AbstractEconomy;
import org.maxgamer.quickshop.api.economy.EconomyCore;
import org.maxgamer.quickshop.economy.Economy_Vault;
import org.maxgamer.quickshop.util.MsgUtil;
import org.maxgamer.quickshop.util.ReflectFactory;
import org.maxgamer.quickshop.util.Util;
import java.io.File;
@@ -124,27 +123,9 @@ public class Paste {
finalReport.append("\tName: ").append(plugin.getServer().getName()).append("\n");
finalReport.append("\tServer Name: ").append(plugin.getServer().getName()).append("\n");
finalReport.append("\tBuild: ").append(plugin.getServer().getVersion()).append("\n");
finalReport.append("\tNMSV: ").append(ReflectFactory.getNMSVersion()).append("\n");
finalReport.append("\tVersion: ").append(plugin.getServer().getMinecraftVersion()).append("\n");
// noinspection deprecation
finalReport.append("\tData Version: ").append(plugin.getServer().getUnsafe().getDataVersion()).append("\n");
if (plugin.getEnvironmentChecker().isFabricBasedServer()
|| plugin.getEnvironmentChecker().isForgeBasedServer())
{
if (plugin.getEnvironmentChecker().isForgeBasedServer()) {
finalReport.append("\tModded Server: Forge (No support offer on this platform)\n");
}
if (plugin.getEnvironmentChecker().isFabricBasedServer()) {
finalReport.append("\tModded Server: Fabric (No support offer on this platform)\n");
}
}
finalReport.append("\tJava: ").append(System.getProperty("java.version")).append("\n");
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
List<String> arguments = runtimeMxBean.getInputArguments();
@@ -1,65 +0,0 @@
/*
* This file is a part of project QuickShop, the name is EmptyErrorReporter.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util.reporter.error;
import org.jetbrains.annotations.NotNull;
public class EmptyErrorReporter implements IErrorReporter {
@Override
public void unregister() {
}
@Override
public void sendError(@NotNull Throwable throwable, @NotNull String... context) {
}
@Override
public boolean canReport(@NotNull Throwable throwable) {
return false;
}
@Override
public void ignoreThrow() {
}
@Override
public void ignoreThrows() {
}
@Override
public void resetIgnores() {
}
@Override
public boolean isEnabled() {
return true;
}
}
@@ -1,117 +0,0 @@
/*
* This file is a part of project QuickShop, the name is IErrorReporter.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util.reporter.error;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
public interface IErrorReporter {
void unregister();
void sendError(@NotNull Throwable throwable, @NotNull String... context);
boolean canReport(@NotNull Throwable throwable);
/**
* Check a throw is cause by QS
*
* @param throwable Throws
* @return Cause or not
*/
default RollbarErrorReporter.PossiblyLevel checkWasCauseByQS(@Nullable Throwable throwable) {
if (throwable == null) {
return RollbarErrorReporter.PossiblyLevel.IMPOSSIBLE;
}
if (throwable.getMessage() == null) {
return RollbarErrorReporter.PossiblyLevel.IMPOSSIBLE;
}
if (throwable.getMessage().contains("Could not pass event")) {
if (throwable.getMessage().contains("QuickShop")) {
return RollbarErrorReporter.PossiblyLevel.CONFIRM;
} else {
return RollbarErrorReporter.PossiblyLevel.IMPOSSIBLE;
}
}
while (throwable.getCause() != null) {
throwable = throwable.getCause();
}
StackTraceElement[] stackTraceElements = throwable.getStackTrace();
if (stackTraceElements.length == 0) {
return RollbarErrorReporter.PossiblyLevel.IMPOSSIBLE;
}
if (stackTraceElements[0].getClassName().contains("org.maxgamer.quickshop")
&& stackTraceElements[1].getClassName().contains("org.maxgamer.quickshop"))
{
return RollbarErrorReporter.PossiblyLevel.CONFIRM;
}
long errorCount = Arrays.stream(stackTraceElements).limit(3)
.filter(stackTraceElement -> stackTraceElement.getClassName().contains("org.maxgamer.quickshop"))
.count();
if (errorCount > 0) {
return RollbarErrorReporter.PossiblyLevel.MAYBE;
} else if (throwable.getCause() != null) {
return checkWasCauseByQS(throwable.getCause());
}
return RollbarErrorReporter.PossiblyLevel.IMPOSSIBLE;
}
void ignoreThrow();
void ignoreThrows();
void resetIgnores();
boolean isEnabled();
}
@@ -1,537 +0,0 @@
/*
* This file is a part of project QuickShop, the name is RollbarErrorReporter.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util.reporter.error;
import com.google.common.collect.Lists;
import com.rollbar.notifier.Rollbar;
import com.rollbar.notifier.config.Config;
import com.rollbar.notifier.config.ConfigBuilder;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.plugin.InvalidPluginException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.maxgamer.quickshop.QuickShop;
import org.maxgamer.quickshop.util.GameVersion;
import org.maxgamer.quickshop.util.ReflectFactory;
import org.maxgamer.quickshop.util.Util;
import org.maxgamer.quickshop.util.paste.Paste;
import java.io.IOException;
import java.net.ProtocolException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Filter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
public class RollbarErrorReporter implements IErrorReporter {
// private volatile static String bootPaste = null;
private final Rollbar rollbar;
private final List<String> reported = new ArrayList<>(5);
private final List<Class<?>> ignoredException = Lists.newArrayList(IOException.class, OutOfMemoryError.class,
ProtocolException.class, InvalidPluginException.class, UnsupportedClassVersionError.class,
LinkageError.class);
private final QuickShop plugin;
private final QuickShopExceptionFilter quickShopExceptionFilter;
private final GlobalExceptionFilter serverExceptionFilter;
private boolean disable;
private boolean tempDisable;
private String lastPaste = null;
// private final GlobalExceptionFilter globalExceptionFilter;
@Getter
private volatile boolean enabled;
public RollbarErrorReporter(@NotNull QuickShop plugin) {
this.plugin = plugin;
Config config = ConfigBuilder.withAccessToken("c386df69d08440d9a3d982cf98b53ed6")
.environment(Util.isDevEdition() ? "development" : "production")
.platform(plugin.getServer().getVersion()).codeVersion(QuickShop.getVersion())
.handleUncaughtErrors(false).build();
this.rollbar = Rollbar.init(config);
quickShopExceptionFilter = new QuickShopExceptionFilter(plugin.getLogger().getFilter());
plugin.getLogger().setFilter(quickShopExceptionFilter); // Redirect log request passthrough our error catcher.
serverExceptionFilter = new GlobalExceptionFilter(plugin.getLogger().getFilter());
plugin.getServer().getLogger().setFilter(serverExceptionFilter);
Util.debugLog("Rollbar error reporter success loaded.");
enabled = true;
}
@Override
public void unregister() {
enabled = false;
plugin.getLogger().setFilter(quickShopExceptionFilter.preFilter);
plugin.getServer().getLogger().setFilter(serverExceptionFilter.preFilter);
// Logger.getGlobal().setFilter(globalExceptionFilter.preFilter);
}
private Map<String, Object> makeMapping() {
Map<String, Object> dataMapping = new LinkedHashMap<>();
dataMapping.put("paste", this.lastPaste);
dataMapping.put("system_os", System.getProperty("os.name"));
dataMapping.put("system_arch", System.getProperty("os.arch"));
dataMapping.put("system_version", System.getProperty("os.version"));
dataMapping.put("system_cores", String.valueOf(Runtime.getRuntime().availableProcessors()));
dataMapping.put("server_build", plugin.getServer().getVersion());
dataMapping.put("server_java", String.valueOf(System.getProperty("java.version")));
dataMapping.put("server_players",
plugin.getServer().getOnlinePlayers().size() + "/" + plugin.getServer().getMaxPlayers());
dataMapping.put("server_onlinemode", String.valueOf(plugin.getServer().getOnlineMode()));
dataMapping.put("server_bukkitversion", plugin.getServer().getVersion());
dataMapping.put("user", QuickShop.getInstance().getServerUniqueID().toString());
return dataMapping;
}
private void sendError0(@NotNull Throwable throwable, @NotNull String... context) {
try {
if (plugin.getBootError() != null) {
return; // Don't report any errors if boot failed.
}
if (tempDisable) {
this.tempDisable = false;
return;
}
if (disable) {
return;
}
if (!enabled) {
return;
}
if (!canReport(throwable)) {
return;
}
if (ignoredException.contains(throwable.getClass())) {
return;
}
if (throwable.getCause() != null) {
if (ignoredException.contains(throwable.getCause().getClass())) {
return;
}
}
if (lastPaste == null) {
String pasteURL;
try {
Paste paste = new Paste(plugin);
pasteURL = paste.paste(paste.genNewPaste(), Paste.PasteType.UBUNTU);
if (pasteURL != null && !pasteURL.isEmpty()) {
lastPaste = pasteURL;
} else {
lastPaste = paste.paste(paste.genNewPaste());
}
} catch (Exception ignored) {
}
}
this.rollbar.error(throwable, this.makeMapping(), throwable.getMessage());
plugin.getLogger().warning(
"A exception was thrown, QuickShop already caught this exception and reported it. This error will only shown once before next restart.");
plugin.getLogger().warning("====QuickShop Error Report BEGIN===");
plugin.getLogger().warning("Description: " + throwable.getMessage());
plugin.getLogger().warning("Server ID: " + plugin.getServerUniqueID());
plugin.getLogger().warning("Exception : ");
ignoreThrows();
throwable.printStackTrace();
resetIgnores();
plugin.getLogger().warning("====QuickShop Error Report E N D===");
Util.debugLog(throwable.getMessage());
Arrays.stream(throwable.getStackTrace())
.forEach(a -> Util.debugLog(a.getClassName() + "." + a.getMethodName() + ":" + a.getLineNumber()));
if (Util.isDevMode()) {
throwable.printStackTrace();
}
} catch (Exception th) {
ignoreThrow();
plugin.getLogger().log(Level.WARNING,
"Something going wrong when automatic report errors, please submit this error on Issue Tracker",
th);
}
}
/**
* Send a error to Sentry
*
* @param throwable Throws
* @param context BreadCrumb
*/
@Override
public void sendError(@NotNull Throwable throwable, @NotNull String... context) {
if (Bukkit.isPrimaryThread()) {
Bukkit.getAsyncScheduler().runNow(plugin, task -> sendError0(throwable, context));
// ignore async response
} else {
sendError0(throwable, context);
}
}
/**
* Dupe report check
*
* @param throwable Throws
* @return dupecated
*/
@Override
public boolean canReport(@NotNull Throwable throwable) {
if (!enabled) {
return false;
}
if (plugin.getUpdateWatcher() == null) {
return false;
}
if (!plugin.getUpdateWatcher().getUpdater().isLatest()) { // We only receive latest reports.
return false;
}
if (!plugin.getBuildInfo().getBuildUrl().startsWith("https://ci.codemc.io/job/PotatoCraft-Studio/")) { // Ignored
// custom
// build
// or 3rd
// fork
return false;
}
if (!GameVersion.get(ReflectFactory.getServerVersion()).isCoreSupports()) { // Ignore errors if user install
// quickshop on unsupported
// version.
return false;
}
PossiblyLevel possiblyLevel = checkWasCauseByQS(throwable);
if (possiblyLevel != PossiblyLevel.CONFIRM) {
return false;
}
if (throwable.getMessage().startsWith("#")) {
return false;
}
StackTraceElement stackTraceElement;
if (throwable.getStackTrace().length < 3) {
stackTraceElement = throwable.getStackTrace()[1];
} else {
stackTraceElement = throwable.getStackTrace()[2];
}
if (stackTraceElement.getClassName().contains("org.maxgamer.quickshop.util.reporter.error")) {
ignoreThrows();
plugin.getLogger().log(Level.WARNING, "Uncaught exception in ErrorRollbar", throwable);
resetIgnores();
return false;
}
String text = stackTraceElement.getClassName() + "#" + stackTraceElement.getMethodName() + "#"
+ stackTraceElement.getLineNumber();
if (!reported.contains(text)) {
reported.add(text);
return true;
} else {
return false;
}
}
/**
* Set ignore throw. It will unlocked after accept a throw
*/
@Override
public void ignoreThrow() {
tempDisable = true;
}
/**
* Set ignore throws. It will unlocked after called method resetIgnores.
*/
@Override
public void ignoreThrows() {
disable = true;
}
/**
* Reset ignore throw(s).
*/
@Override
public void resetIgnores() {
tempDisable = false;
disable = false;
}
// private String getPluginInfo() {
// StringBuilder buffer = new StringBuilder();
// for (Plugin bPlugin : plugin.getServer().getPluginManager().getPlugins()) {
// buffer
// .append("\t")
// .append(bPlugin.getName())
// .append("@")
// .append(bPlugin.isEnabled() ? "Enabled" : "Disabled")
// .append("\n");
// }
// return buffer.toString();
// }
enum PossiblyLevel {
CONFIRM, MAYBE, IMPOSSIBLE
}
class GlobalExceptionFilter implements Filter {
@Nullable
@Getter
private final Filter preFilter;
GlobalExceptionFilter(@Nullable Filter preFilter) {
this.preFilter = preFilter;
}
private boolean defaultValue(LogRecord rec) {
return preFilter == null || preFilter.isLoggable(rec);
}
/**
* Check if a given log record should be published.
*
* @param rec a LogRecord
* @return true if the log record should be published.
*/
@Override
public boolean isLoggable(@NotNull LogRecord rec) {
if (!enabled) {
return defaultValue(rec);
}
Level level = rec.getLevel();
if (level != Level.WARNING && level != Level.SEVERE) {
return defaultValue(rec);
}
if (rec.getThrown() == null) {
return defaultValue(rec);
}
if (Util.isDevMode()) {
sendError(rec.getThrown(), rec.getMessage());
return defaultValue(rec);
} else {
sendError(rec.getThrown(), rec.getMessage());
PossiblyLevel possiblyLevel = checkWasCauseByQS(rec.getThrown());
if (possiblyLevel == PossiblyLevel.IMPOSSIBLE) {
return true;
}
if (possiblyLevel == PossiblyLevel.MAYBE) {
plugin.getLogger().warning(
"This seems not a QuickShop error. If you have any question, you should ask QuickShop developer.");
return true;
}
return false;
}
}
}
class QuickShopExceptionFilter implements Filter {
@Nullable
@Getter
private final Filter preFilter;
QuickShopExceptionFilter(@Nullable Filter preFilter) {
this.preFilter = preFilter;
}
private boolean defaultValue(LogRecord rec) {
return preFilter == null || preFilter.isLoggable(rec);
}
/**
* Check if a given log record should be published.
*
* @param rec a LogRecord
* @return true if the log record should be published.
*/
@Override
public boolean isLoggable(@NotNull LogRecord rec) {
if (!enabled) {
return defaultValue(rec);
}
Level level = rec.getLevel();
if (level != Level.WARNING && level != Level.SEVERE) {
return defaultValue(rec);
}
if (rec.getThrown() == null) {
return defaultValue(rec);
}
if (Util.isDevMode()) {
sendError(rec.getThrown(), rec.getMessage());
return defaultValue(rec);
} else {
sendError(rec.getThrown(), rec.getMessage());
PossiblyLevel possiblyLevel = checkWasCauseByQS(rec.getThrown());
if (possiblyLevel == PossiblyLevel.IMPOSSIBLE) {
return true;
}
if (possiblyLevel == PossiblyLevel.MAYBE) {
plugin.getLogger().warning(
"This seems not a QuickShop error. If you have any question, you may can ask QuickShop developer but don't except any solution.");
return true;
}
return false;
}
}
}
}
@@ -1,80 +0,0 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.maxgamer.quickshop.util.security;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* <p>
* Taken from the jarsigner utility.
* <p>
* see
* https://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/security/tools/jarsigner/Main.java#l570
*
* @author Roland Schemers
* @author Jan Luehe
*/
public class JarVerifyTool {
@NotNull
public List<JarEntry> verify(@NotNull JarFile jar) throws IOException {
List<JarEntry> modified = new ArrayList<>();
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
try (InputStream is = jar.getInputStream(entry)) {
byte[] buffer = new byte[8192];
// noinspection StatementWithEmptyBody
while ((is.read(buffer, 0, buffer.length)) != -1) {
// We just read. This will throw a SecurityException
// if a signature/digest check fails.
}
} catch (SecurityException se) {
modified.add(entry);
}
}
return modified;
}
}
-3
View File
@@ -45,7 +45,6 @@ softdepend:
- Reserve
- PlaceholderAPI
- NoCheatPlus
- Spartan
- LuckPerms
- PermissionEx
- GroupManager
@@ -63,12 +62,10 @@ softdepend:
- Lands
- GriefPrevention
- JulySafe
- FabledSkyblock
- OpenInv
- WorldEdit
- AdvancedRegionMarket
- IridiumSkyblock
- FabledSkyblock
- NBTAPI
api-version: '${apiVersion}'
@@ -1,49 +0,0 @@
package org.maxgamer.quickshop;
import be.seeseemelk.mockbukkit.MockBukkit;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import java.lang.reflect.Field;
/**
* Use for testing related to bukkit api
* <p>
* If you are writing test which using runtime stuff, just extend it
*/
public abstract class TestBukkitBase {
@BeforeAll
public static void setUp() {
MockBukkit.getOrCreateMock();
System.getProperties().setProperty("org.maxgamer.quickshop.util.envcheck.skip.SIGNATURE_VERIFY", "true");
System.getProperties().setProperty(
"org.maxgamer.quickshop.util.envcheck.skip.POTENTIAL_INFECTION_CHARACTERISTICS_CHECK", "true");
// Prevent network flow to OTA
try {
Field CROWDIN_OTA_HOST = Class
.forName("org.maxgamer.quickshop.localization.text.distributions.crowdin.CrowdinOTA")
.getDeclaredField("CROWDIN_OTA_HOST");
CROWDIN_OTA_HOST.setAccessible(true);
CROWDIN_OTA_HOST.set(null, "http://0.0.0.0");
} catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
MockBukkit.load(QuickShop.class);
}
@AfterAll
public static void tearDown() {
MockBukkit.unmock();
}
}
@@ -1,328 +0,0 @@
/*
* This file is a part of project QuickShop, the name is EconomyTransactionTest.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http:www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.economy;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.maxgamer.quickshop.QuickShop;
import org.maxgamer.quickshop.TestBukkitBase;
import org.maxgamer.quickshop.api.economy.EconomyCore;
import org.maxgamer.quickshop.api.economy.EconomyTransaction;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class EconomyTransactionTest extends TestBukkitBase {
static EconomyCore economy = new TestEconomy();
static Trader taxAccount;
public static Trader getTaxAccount() {
if (taxAccount == null) {
taxAccount = Trader.adapt(QuickShop.getInstance().getServer().getOfflinePlayer("Tax"));
economy.getBalance(taxAccount, null, null);
}
return taxAccount;
}
private static EconomyTransaction genTransaction(UUID from, UUID to, double amount, double taxModifier,
boolean allowLoan)
{
return EconomyTransaction.builder().core(economy).from(from).to(to).amount(amount).taxAccount(getTaxAccount())
.taxModifier(taxModifier).allowLoan(allowLoan).build();
}
@Test
public void testTransaction() {
List<UUID> UUIDList = Stream.generate(UUID::randomUUID).limit(20).collect(Collectors.toList());
for (UUID account : UUIDList) {
genTransaction(null, account, 1000, 0.06, false).commit(new EconomyTransaction.TransactionCallback() {
@Override
public void onTaxFailed(@NotNull EconomyTransaction economyTransaction) {
}
@Override
public boolean onCommit(@NotNull EconomyTransaction economyTransaction) {
return true;
}
@Override
public void onSuccess(@NotNull EconomyTransaction economyTransaction) {
}
@Override
public void onFailed(@NotNull EconomyTransaction economyTransaction) {
throw new RuntimeException("Deposit Test Failed");
}
});
}
assertEquals((Double) (20 * 1000 * 0.06D), (Double) economy.getBalance(taxAccount, null, null));
assertEquals((Double) (1000 * 0.94D), (Double) economy.getBalance(UUIDList.get(0), null, null));
genTransaction(UUIDList.get(5), null, 1000, 0.0, true).commit(new EconomyTransaction.TransactionCallback() {
@Override
public void onSuccess(@NotNull EconomyTransaction economyTransaction) {
assertEquals(-1000 * 0.06D, economy.getBalance(economyTransaction.getFrom(), null, null));
}
@Override
public void onFailed(@NotNull EconomyTransaction economyTransaction) {
throw new RuntimeException("Loan Test Failed");
}
});
genTransaction(UUIDList.get(4), UUIDList.get(5), 1000, 0.06, true)
.commit(new EconomyTransaction.TransactionCallback()
{
@Override
public void onSuccess(@NotNull EconomyTransaction economyTransaction) {
assertEquals(-1000 * 0.06D, economy.getBalance(economyTransaction.getFrom(), null, null));
assertEquals(-1000 * 0.06D + 1000 * 0.94D,
economy.getBalance(economyTransaction.getTo(), null, null));
assertEquals(20 * 1000 * 0.06D + (1000 * 0.06D), economy.getBalance(taxAccount, null, null));
}
@Override
public void onFailed(@NotNull EconomyTransaction economyTransaction) {
throw new RuntimeException("Transfer Test Failed");
}
});
}
@Test
public void testRollback() {
UUID from = UUID.randomUUID();
UUID to = UUID.randomUUID();
economy.deposit(from, 99, null, null);
assertEquals(99, economy.getBalance(from, null, null));
assertEquals(0, economy.getBalance(to, null, null));
EconomyTransaction.builder().core(economy).from(from).to(to).amount(100).core(economy).taxAccount(taxAccount)
.taxModifier(0.0).build().failSafeCommit();
assertEquals(99, economy.getBalance(from, null, null));
assertEquals(0, economy.getBalance(to, null, null));
EconomyTransaction.builder().core(economy).from(from).to(to).amount(100).core(economy).taxAccount(taxAccount)
.taxModifier(0.2).build().failSafeCommit();
assertEquals(99, economy.getBalance(from, null, null));
assertEquals(0, economy.getBalance(to, null, null));
}
@Test
public void testNull() {
try {
EconomyTransaction.builder().core(economy).from(null).to(null).amount(100).core(economy)
.taxAccount(taxAccount).taxModifier(0.0).build().failSafeCommit();
} catch (IllegalArgumentException ignored) {
return;
}
throw new RuntimeException("Null Test Failed!");
}
static class TestEconomy implements EconomyCore {
final Map<UUID, Double> playerBalanceMap = new HashMap<>(10);
private Double getOrCreateAccount(UUID uuid) {
if (!playerBalanceMap.containsKey(uuid)) {
playerBalanceMap.put(uuid, 0.0);
return 0.0;
}
return playerBalanceMap.get(uuid);
}
@Override
public boolean deposit(@NotNull UUID name, double amount, @NotNull World world, @Nullable String currency) {
playerBalanceMap.put(name, amount + getBalance(name, null, null));
return true;
}
@Override
public boolean deposit(@NotNull OfflinePlayer trader, double amount, @NotNull World world,
@Nullable String currency)
{
return deposit(trader.getUniqueId(), amount, null, null);
}
@Override
public String format(double balance, @NotNull World world, @Nullable String currency) {
return Double.toString(balance);
}
@Override
public double getBalance(@NotNull UUID name, @NotNull World world, @Nullable String currency) {
return getOrCreateAccount(name);
}
@Override
public double getBalance(@NotNull OfflinePlayer player, @NotNull World world, @Nullable String currency) {
return getBalance(player.getUniqueId(), null, null);
}
@Override
public boolean transfer(@NotNull UUID from, @NotNull UUID to, double amount, @NotNull World world,
@Nullable String currency)
{
double formBalance = getBalance(from, null, null);
playerBalanceMap.put(from, 0.0);
playerBalanceMap.put(to, getBalance(from, null, null) + formBalance);
return true;
}
@Override
public boolean withdraw(@NotNull UUID name, double amount, @NotNull World world, @Nullable String currency) {
playerBalanceMap.put(name, getBalance(name, null, null) - amount);
return true;
}
@Override
public boolean withdraw(@NotNull OfflinePlayer trader, double amount, @NotNull World world,
@Nullable String currency)
{
return withdraw(trader.getUniqueId(), amount, null, null);
}
/**
* Gets the currency does exists
*
* @param currency Currency name
* @return exists
*/
@Override
public boolean hasCurrency(@NotNull World world, @NotNull String currency) {
return false;
}
/**
* Gets currency supports status
*
* @return true if supports
*/
@Override
public boolean supportCurrency() {
return false;
}
@Override
public @Nullable String getLastError() {
return "ErrorTracing: Unit Test";
}
@Override
public boolean isValid() {
return true;
}
@Override
public @NotNull String getName() {
return "TestEconomy";
}
@Override
public @NotNull Plugin getPlugin() {
throw new UnsupportedOperationException();
}
}
}
@@ -1,232 +0,0 @@
/*
* This file is a part of project QuickShop, the name is ListenerContainerTest.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.eventmanager;
import io.papermc.paper.plugin.configuration.PluginMeta;
import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginLoader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.logging.Logger;
public class ListenerContainerTest {
@Test
public void testMatches() {
Plugin testPlugin = new Plugin() {
@NotNull
@Override
public File getDataFolder() {
return null;
}
@NotNull
@Override
public PluginDescriptionFile getDescription() {
return null;
}
@NotNull
@Override
public FileConfiguration getConfig() {
return null;
}
@NotNull
public FileConfiguration getConfiguration() {
return null;
}
@Nullable
@Override
public InputStream getResource(@NotNull String s) {
return null;
}
@Override
public void saveConfig() {
}
@Override
public void saveDefaultConfig() {
}
@Override
public void saveResource(@NotNull String s, boolean b) {
}
@Override
public void reloadConfig() {
}
@NotNull
@Override
public PluginLoader getPluginLoader() {
return null;
}
@NotNull
@Override
public Server getServer() {
return null;
}
@Override
public boolean isEnabled() {
return false;
}
@Override
public void onDisable() {
}
@Override
public void onLoad() {
}
@Override
public void onEnable() {
}
@Override
public boolean isNaggable() {
return false;
}
@Override
public void setNaggable(boolean b) {
}
@Nullable
@Override
public ChunkGenerator getDefaultWorldGenerator(@NotNull String s, @Nullable String s1) {
return null;
}
@Nullable
@Override
public BiomeProvider getDefaultBiomeProvider(@NotNull String s, @Nullable String s1) {
return null;
}
@NotNull
@Override
public Logger getLogger() {
return null;
}
@NotNull
@Override
public String getName() {
return "QuickTest";
}
@Override
public @NotNull LifecycleEventManager<Plugin> getLifecycleManager() {
return null;
}
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] strings)
{
return false;
}
@Override
public @NotNull PluginMeta getPluginMeta() {
return null;
}
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command,
@NotNull String s, @NotNull String[] strings)
{
return null;
}
};
ListenerContainer listenerContainerA = new ListenerContainer(null, "@QuickTest");
ListenerContainer listenerContainerB = new ListenerContainer(null, "@QuickTestBad");
Assertions.assertTrue(listenerContainerA.matches(this.getClass(), testPlugin));
Assertions.assertFalse(listenerContainerB.matches(this.getClass(), testPlugin));
}
}
@@ -1,116 +0,0 @@
/*
* This file is a part of project QuickShop, the name is ShopTransactionMessageTest.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.shop;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.maxgamer.quickshop.TestBukkitBase;
import org.maxgamer.quickshop.localization.LocalizedMessagePair;
public class ShopTransactionMessageTest extends TestBukkitBase {
@Test
public void testV1PlainMessage() {
ShopTransactionMessageContainer container = ShopTransactionMessageContainer.fromJson("233333");
container = ShopTransactionMessageContainer.fromJson(container.toJson());
Assertions.assertEquals("233333", container.getMessage(null));
Assertions.assertNull(container.getHoverItemStr());
Assertions.assertNull(container.getHoverText(null));
}
@Test
public void testV2PlainMessage() {
ShopTransactionMessageContainer container = ShopTransactionMessageContainer
.fromJson(ShopTransactionMessageContainer.fromJson(
"{\"message\":\"233333\",\"hoverItem\":\"item:\\n \\u003d\\u003d: org.bukkit.inventory.ItemStack\\n v: 2730\\n type: JUNGLE_LOG\\n\",\"hoverText\":\"233333\"}")
.toJson());
Assertions.assertEquals("233333", container.getMessage(null));
Assertions.assertEquals(
"item:\n \u003d\u003d: org.bukkit.inventory.ItemStack\n v: 2730\n type: JUNGLE_LOG\n",
container.getHoverItemStr());
Assertions.assertEquals("233333", container.getHoverText(null));
container = ShopTransactionMessageContainer.fromJson(ShopTransactionMessageContainer.fromJson(
"{\"message\":\"233333\",\"hoverItem\":\"item:\\n \\u003d\\u003d: org.bukkit.inventory.ItemStack\\n v: 2730\\n type: JUNGLE_LOG\\n\"}")
.toJson());
Assertions.assertEquals("233333", container.getMessage(null));
Assertions.assertEquals(
"item:\n \u003d\u003d: org.bukkit.inventory.ItemStack\n v: 2730\n type: JUNGLE_LOG\n",
container.getHoverItemStr());
Assertions.assertNull(container.getHoverText(null));
container = ShopTransactionMessageContainer
.fromJson(ShopTransactionMessageContainer.fromJson("{\"message\":\"233333\"}").toJson());
Assertions.assertEquals("233333", container.getMessage(null));
Assertions.assertNull(container.getHoverItemStr());
Assertions.assertNull(container.getHoverText(null));
}
@Test
public void testModernMessage() {
// V1
ShopTransactionMessageContainer container = ShopTransactionMessageContainer
.fromJson(ShopTransactionMessageContainer.ofPlainStr("ghost_chu is an lucky guy").toJson());
Assertions.assertEquals("ghost_chu is an lucky guy", container.getMessage(null));
Assertions.assertNull(container.getHoverItemStr());
Assertions.assertNull(container.getHoverText(null));
// V2
container = ShopTransactionMessageContainer
.fromJson(ShopTransactionMessageContainer.ofStrWithItem("ghost_chu", null, null).toJson());
Assertions.assertEquals("ghost_chu", container.getMessage(null));
Assertions.assertNull(container.getHoverItemStr());
Assertions.assertNull(container.getHoverText(null));
container = ShopTransactionMessageContainer
.fromJson(ShopTransactionMessageContainer.ofStrWithItem("ghost_chu", "is", null).toJson());
Assertions.assertEquals("ghost_chu", container.getMessage(null));
Assertions.assertEquals("is", container.getHoverItemStr());
Assertions.assertNull(container.getHoverText(null));
container = ShopTransactionMessageContainer
.fromJson(ShopTransactionMessageContainer.ofStrWithItem("ghost_chu", "is", "an lucky guy").toJson());
Assertions.assertEquals("ghost_chu", container.getMessage(null));
Assertions.assertEquals("is", container.getHoverItemStr());
Assertions.assertEquals("an lucky guy", container.getHoverText(null));
// V3
container = ShopTransactionMessageContainer.fromJson(ShopTransactionMessageContainer
.ofLocalizedMessageWithItem(LocalizedMessagePair.of("nearby-shop-this-way", "ghost_chu"), "is",
LocalizedMessagePair.of("nearby-shop-this-way", "ghost_chu"))
.toJson());
Assertions.assertTrue(container.getMessage(null).contains("ghost_chu"));
Assertions.assertEquals("is", container.getHoverItemStr());
Assertions.assertTrue(container.getHoverText(null).contains("ghost_chu"));
container = ShopTransactionMessageContainer.fromJson(ShopTransactionMessageContainer
.ofLocalizedMessageWithItem(LocalizedMessagePair.of("nearby-shop-this-way", "ghost_chu"), "is", null)
.toJson());
Assertions.assertTrue(container.getMessage(null).contains("ghost_chu"));
Assertions.assertEquals("is", container.getHoverItemStr());
Assertions.assertNull(container.getHoverText(null));
container = ShopTransactionMessageContainer.fromJson(ShopTransactionMessageContainer
.ofLocalizedMessageWithItem(LocalizedMessagePair.of("nearby-shop-this-way", "ghost_chu"), null, null)
.toJson());
Assertions.assertTrue(container.getMessage(null).contains("ghost_chu"));
Assertions.assertNull(container.getHoverItemStr());
Assertions.assertNull(container.getHoverText(null));
}
}
@@ -1,65 +0,0 @@
/*
* This file is a part of project QuickShop, the name is InteractUtilTest.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.MemoryConfiguration;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class InteractUtilTest {
private ConfigurationSection genConfig(int mode, boolean allowSneaking) {
ConfigurationSection configurationSection = new MemoryConfiguration();
configurationSection.set("shop.interact.interact-mode", mode);
configurationSection.set("shop.interact.sneak-to-create", allowSneaking);
return configurationSection.getConfigurationSection("shop.interact");
}
@Test
public void testInteractBoolean() {
// ONLY
InteractUtil.init(genConfig(0, true));
Assertions.assertTrue(InteractUtil.check(InteractUtil.Action.CREATE, true));
Assertions.assertFalse(InteractUtil.check(InteractUtil.Action.CREATE, false));
InteractUtil.init(genConfig(0, false));
Assertions.assertFalse(InteractUtil.check(InteractUtil.Action.CREATE, true));
Assertions.assertTrue(InteractUtil.check(InteractUtil.Action.CREATE, false));
// BOTH
InteractUtil.init(genConfig(1, false));
Assertions.assertFalse(InteractUtil.check(InteractUtil.Action.CREATE, true));
Assertions.assertTrue(InteractUtil.check(InteractUtil.Action.CREATE, false));
InteractUtil.init(genConfig(1, true));
Assertions.assertTrue(InteractUtil.check(InteractUtil.Action.CREATE, true));
Assertions.assertTrue(InteractUtil.check(InteractUtil.Action.CREATE, false));
// REVERSED
InteractUtil.init(genConfig(2, false));
Assertions.assertTrue(InteractUtil.check(InteractUtil.Action.CREATE, true));
Assertions.assertTrue(InteractUtil.check(InteractUtil.Action.CREATE, false));
InteractUtil.init(genConfig(2, true));
Assertions.assertFalse(InteractUtil.check(InteractUtil.Action.CREATE, true));
Assertions.assertTrue(InteractUtil.check(InteractUtil.Action.CREATE, false));
}
}
@@ -1,35 +0,0 @@
/*
* This file is a part of project QuickShop, the name is UpdaterTest.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util;
public class UpdaterTest {
// @Test
// //TODO: Apply to new updater.
// public void TestUpdateVer() {
//// Assertions.assertTrue(Updater.hasUpdate("3", "4"));
//// Assertions.assertFalse(Updater.hasUpdate("3.2.3", "3.2.3"));
//// Assertions.assertTrue(Updater.hasUpdate("3.2.0", "3.2.3"));
//// Assertions.assertTrue(Updater.hasUpdate("3.2.3", "3.2.3.1"));
//// Assertions.assertTrue(Updater.hasUpdate("3.2.3", "3.2.3.0"));
//// Assertions.assertTrue(Updater.hasUpdate("3.2.3.0", "3.2.3.1"));
//// Assertions.assertFalse(Updater.hasUpdate("3.2.3.1.3", "3.2.3.1"));
// }
}
@@ -1,149 +0,0 @@
/*
* This file is a part of project QuickShop, the name is UtilTest.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.UUID;
public class UtilTest {
@Test
public void array2String() {
String sample = "A, B, C";
Assertions.assertEquals(sample, Util.array2String(new String[] { "A", "B", "C" }));
}
@Test
public void boolean2Status() {
Assertions.assertEquals(Util.boolean2Status(true), "Enabled");
Assertions.assertEquals(Util.boolean2Status(false), "Disabled");
}
@Test
public void isClassAvailable() {
Assertions.assertTrue(Util.isClassAvailable(getClass().getName()));
Assertions.assertFalse(Util.isClassAvailable("random.Class"));
}
@Test
public void isUUID() {
Assertions.assertTrue(Util.isUUID("b188beda-8bfb-ed66-65e5-25147a4617cf"));
Assertions.assertFalse(Util.isUUID("b188beda8bfbed6665e525147a4617cf"));
Assertions.assertFalse(Util.isUUID("?"));
}
@Test
public void list2String() {
String sample = "1, 2, 3, 4, 5";
Assertions.assertEquals(sample, Util.list2String(Arrays.asList("1", "2", "3", "4", "5")));
}
@Test
public void firstUppercase() {
Assertions.assertEquals("Quickshop", Util.firstUppercase("quickshop"));
}
@Test
public void mergeArgs() {
String[] args = new String[3];
args[0] = "yaa";
args[1] = "hoo";
args[2] = "woo";
Assertions.assertEquals("yaa hoo woo", Util.mergeArgs(args));
}
@Test
public void testArray2String() {
String[] array = new String[] { "aaa", "bbb", "ccc", "ddd" };
Assertions.assertEquals("aaa, bbb, ccc, ddd", Util.array2String(array));
}
@Test
public void testIsClassAvailable() {
Assertions.assertTrue(Util.isClassAvailable("java.lang.String"));
Assertions.assertFalse(Util.isClassAvailable("java.lang.NotExistedClassLoL"));
}
@Test
public void isMethodAvailable() {
Assertions.assertTrue(Util.isMethodAvailable(String.class.getName(), "toLowerCase"));
Assertions.assertFalse(Util.isMethodAvailable(String.class.getName(), "P90 RUSH B"));
}
@Test
public void testIsUUID() {
UUID uuid = UUID.randomUUID();
Assertions.assertTrue(Util.isUUID(uuid.toString()));
Assertions.assertTrue(Util.isUUID(Util.getNilUniqueId().toString()));
Assertions.assertFalse(Util.isUUID(uuid.toString().replace("-", "")));
}
@Test
public void prettifyText() {
Assertions.assertEquals("Diamond", Util.prettifyText("DIAMOND"));
}
@Test
public void testFirstUppercase() {
Assertions.assertEquals("Foobar", Util.firstUppercase("foobar"));
}
@Test
public void testMergeArgs() {
}
@Test
public void getNilUniqueId() {
Assertions.assertEquals(new UUID(0, 0), Util.getNilUniqueId());
}
}
@@ -1,54 +0,0 @@
/*
* This file is a part of project QuickShop, the name is MojangAPITest.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util.mojangapi;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.maxgamer.quickshop.TestBukkitBase;
import java.util.Optional;
public class MojangAPITest extends TestBukkitBase {
@Test
public void testMojangMetaApi() {
MojangAPI api = new MojangAPI(new MojangApiOfficialMirror());
Optional<String> metaData = api.getMetaAPI("1.16.5").get();
Assertions.assertTrue(metaData.isPresent());
Assertions.assertFalse(metaData.get().isEmpty());
}
@Test
public void testMojangAssetsApi() {
MojangAPI api = new MojangAPI(new MojangApiOfficialMirror());
MojangAPI.AssetsAPI assetsAPI = api.getAssetsAPI("1.16.5");
Assertions.assertTrue(assetsAPI.isAvailable());
Optional<MojangAPI.AssetsFileData> assetsFileData = assetsAPI.getGameAssetsFile();
Assertions.assertTrue(assetsFileData.isPresent());
Assertions.assertFalse(assetsFileData.get().getContent().isEmpty());
Assertions.assertFalse(assetsFileData.get().getId().isEmpty());
Assertions.assertFalse(assetsFileData.get().getSha1().isEmpty());
}
}
@@ -1,54 +0,0 @@
/*
* This file is a part of project QuickShop, the name is MojangAPITest.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util.mojangapi;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.maxgamer.quickshop.TestBukkitBase;
import java.util.Optional;
public class MojangAPITest_BMCLAPI extends TestBukkitBase {
@Test
public void testMojangMetaApi() {
MojangAPI api = new MojangAPI(new MojangApiBmclApiMirror());
Optional<String> metaData = api.getMetaAPI("1.16.5").get();
Assertions.assertTrue(metaData.isPresent());
Assertions.assertFalse(metaData.get().isEmpty());
}
@Test
public void testMojangAssetsApi() {
MojangAPI api = new MojangAPI(new MojangApiBmclApiMirror());
MojangAPI.AssetsAPI assetsAPI = api.getAssetsAPI("1.16.5");
Assertions.assertTrue(assetsAPI.isAvailable());
Optional<MojangAPI.AssetsFileData> assetsFileData = assetsAPI.getGameAssetsFile();
Assertions.assertTrue(assetsFileData.isPresent());
Assertions.assertFalse(assetsFileData.get().getContent().isEmpty());
Assertions.assertFalse(assetsFileData.get().getId().isEmpty());
Assertions.assertFalse(assetsFileData.get().getSha1().isEmpty());
}
}
@@ -1,54 +0,0 @@
/*
* This file is a part of project QuickShop, the name is MojangAPITest.java
* Copyright (C) PotatoCraft Studio and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.maxgamer.quickshop.util.mojangapi;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.maxgamer.quickshop.TestBukkitBase;
import java.util.Optional;
public class MojangAPITest_MCBBSAPI extends TestBukkitBase {
@Test
public void testMojangMetaApi() {
MojangAPI api = new MojangAPI(new MojangApiMcbbsApiMirror());
Optional<String> metaData = api.getMetaAPI("1.16.5").get();
Assertions.assertTrue(metaData.isPresent());
Assertions.assertFalse(metaData.get().isEmpty());
}
@Test
public void testMojangAssetsApi() {
MojangAPI api = new MojangAPI(new MojangApiMcbbsApiMirror());
MojangAPI.AssetsAPI assetsAPI = api.getAssetsAPI("1.16.5");
Assertions.assertTrue(assetsAPI.isAvailable());
Optional<MojangAPI.AssetsFileData> assetsFileData = assetsAPI.getGameAssetsFile();
Assertions.assertTrue(assetsFileData.isPresent());
Assertions.assertFalse(assetsFileData.get().getContent().isEmpty());
Assertions.assertFalse(assetsFileData.get().getId().isEmpty());
Assertions.assertFalse(assetsFileData.get().getSha1().isEmpty());
}
}
-41
View File
@@ -1,41 +0,0 @@
{
"username": "Jenkins Webhook",
"avatar_url": "https://i.loli.net/2020/07/31/8Z2sEvD137uUlRf.jpg",
"content": "New build available!",
"embeds": [
{
"author": {
"name": "Jenkins CI",
"url": "https://ci.codemc.io",
"icon_url": "https://i.loli.net/2020/07/31/8Z2sEvD137uUlRf.jpg"
},
"title": "New SNAPSHOT #$BUILD_ID available",
"url": "$BUILD_URL",
"description": "New snapshot of $POM_ARTIFACTID now is available!",
"color": 15258703,
"fields": [
{
"name": "Author",
"value": "$GIT_AUTHOR_NAME",
"inline": true
},
{
"name": "Branch",
"value": "$GIT_BRANCH",
"inline": true
},
{
"name": "Commit Message",
"value": "$GIT_COMMIT_MESSAGE"
},
{
"name": "Download Snapshot",
"value": "[Click Here]($BUILD_URL) to download"
}
],
"footer": {
"text": "Jenkins CI - Discord Webhook"
}
}
]
}