mirror of
https://github.com/BlazingGames/blazing-games-plugin.git
synced 2025-02-03 21:26:41 -05:00
Merge remote-tracking branch 'origin/main' into textures
This commit is contained in:
commit
fdc4fa6a7d
46 changed files with 1506 additions and 271 deletions
|
@ -1,11 +1,51 @@
|
|||
name: Build and Publish
|
||||
name: Build, Test and Publish
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
test:
|
||||
runs-on: docker
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '21'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: actions/gradle/setup-gradle@v4
|
||||
with:
|
||||
gradle-version: '8.12'
|
||||
|
||||
- name: Setup Paper
|
||||
run: |
|
||||
mkdir testsrv
|
||||
curl -o testsrv/server.jar https://api.papermc.io/v2/projects/paper/versions/1.21.4/builds/118/downloads/paper-1.21.4-118.jar
|
||||
echo "eula=true" > testsrv/eula.txt
|
||||
|
||||
- name: Build test jar with Gradle
|
||||
run: gradle -Pversion=test-${{ github.run_number }} -Ptest=true build
|
||||
|
||||
- name: Install plugin
|
||||
run: |
|
||||
mkdir testsrv/plugins
|
||||
cp build/libs/blazinggames-test-${{ github.run_number }}.jar testsrv/plugins/blazinggames.jar
|
||||
|
||||
- name: Run unit tests
|
||||
timeout-minutes: 30
|
||||
run: |
|
||||
cd testsrv && java -Xms2048M -Xmx2048M -jar server.jar nogui --nogui
|
||||
|
||||
- name: Ensure tests passed
|
||||
run: |
|
||||
if [ "$(cat testsrv/TESTS_RESULT)" = "true" ]; then exit 0; else exit 1; fi
|
||||
build-and-publish:
|
||||
runs-on: docker
|
||||
needs: test
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
# blazing-games-plugin
|
||||
|
||||
![Latest Release](https://git.ivycollective.dev/BlazingGames/blazing-games-plugin/badges/release.svg)
|
||||
![Build Status](https://git.ivycollective.dev/BlazingGames/blazing-games-plugin/badges/workflows/build.yml/badge.svg?label=build+status)
|
||||
|
||||
The plugin powering the Blazing Games minecraft server, with computers, enchanting altars, spawner modification, and more!
|
||||
|
||||
## Usage
|
||||
|
@ -16,6 +19,10 @@ This is a standard Paper plugin using Gradle.
|
|||
|
||||
To build, use: `./gradlew build`
|
||||
|
||||
## Testing
|
||||
|
||||
This plugins supports testing. To run tests, use: `./gradlew build -Ptest=true`, and load the plugin normally. Once tests are done running, the file `TESTS_RESULT` in the server files directory will contain `true` if tests passed or `false` if tests failed.
|
||||
|
||||
## License
|
||||
|
||||
This plugin is licensed under the Apache License (version 2.0). For more information, please read the NOTICE and LICENSE files.
|
||||
|
|
|
@ -70,7 +70,10 @@ tasks.withType(JavaCompile).configureEach {
|
|||
}
|
||||
|
||||
processResources {
|
||||
def props = [version: version]
|
||||
def props = [
|
||||
version: version,
|
||||
launchClass: ("true".equals(project.test)) ? project.testClass : project.mainClass
|
||||
]
|
||||
inputs.properties props
|
||||
filteringCharset 'UTF-8'
|
||||
filesMatching('plugin.yml') {
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
version = STAGING
|
||||
version = STAGING
|
||||
|
||||
test = false
|
||||
mainClass = de.blazemcworld.blazinggames.BlazingGames
|
||||
testClass = de.blazemcworld.blazinggames.testing.TestBlazingGames
|
|
@ -62,8 +62,7 @@ import java.util.UUID;
|
|||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class BlazingGames extends JavaPlugin {
|
||||
public class BlazingGames extends JavaPlugin {
|
||||
public boolean API_AVAILABLE = false;
|
||||
|
||||
// Gson
|
||||
|
@ -207,7 +206,7 @@ public final class BlazingGames extends JavaPlugin {
|
|||
registerCommand("customgive", new CustomGiveCommand());
|
||||
registerCommand("killme", new KillMeCommand());
|
||||
registerCommand("playtime", new PlaytimeCommand());
|
||||
registerCommand("config", new ConfigCommand());
|
||||
registerCommand("display", new DisplayCommand());
|
||||
registerCommand("setaltar", new SetAltar());
|
||||
|
||||
// Events
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Copyright 2025 The Blazing Games Maintainers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.blazemcworld.blazinggames.commands;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import de.blazemcworld.blazinggames.utils.PlayerConfig;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
|
||||
public class ConfigCommand implements CommandExecutor, TabCompleter {
|
||||
String[] values = {"display", "pronouns", "color"};
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
if (!(sender instanceof Player p)) {
|
||||
sender.sendMessage(Component.text("Only players can use this command!")
|
||||
.color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.length < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String param = args[0];
|
||||
String value = (args.length > 1) ? Arrays.stream(args).skip(1).collect(Collectors.joining(" "))
|
||||
: null;
|
||||
|
||||
PlayerConfig config = PlayerConfig.forPlayer(p.getUniqueId());
|
||||
switch (param) {
|
||||
case "display":
|
||||
if (!enforceParam(sender, param, value, 1, 36)) return false;
|
||||
config.setDisplayName(value);
|
||||
break;
|
||||
case "pronouns":
|
||||
if (!enforceParam(sender, param, value, 1, 16)) return false;
|
||||
config.setPronouns(value);
|
||||
break;
|
||||
case "color":
|
||||
if (!enforceParam(sender, param, value, 6, 6)) return false;
|
||||
if (value == null || value.isBlank()) {
|
||||
config.setNameColor(null);
|
||||
} else {
|
||||
int realValue;
|
||||
try {
|
||||
realValue = Integer.parseInt(value, 16);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(Component.text("Invalid color: #" + value).color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
config.setNameColor(TextColor.color(realValue));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sender.sendMessage(Component.text("Unknown parameter: " + param).color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
sendSuccess(sender, param, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||
@NotNull String label, @NotNull String[] args) {
|
||||
if (args.length == 1) {
|
||||
return Arrays.asList(values);
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
private static void sendSuccess(CommandSender sender, String param, String value) {
|
||||
if (value == null || value.isBlank()) {
|
||||
sender.sendMessage(Component.text("Cleared " + param).color(NamedTextColor.GREEN));
|
||||
} else {
|
||||
sender.sendMessage(Component.text("Set " + param + " to " + value).color(NamedTextColor.GREEN));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean enforceParam(CommandSender sender, String param, String value, int minChars, int maxChars) {
|
||||
if (value == null || value.isBlank()) {
|
||||
// return for unset
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value.length() < minChars || value.length() > maxChars) {
|
||||
if (minChars == maxChars) {
|
||||
sender.sendMessage(Component.text("Parameter " + param + " must be exactly " + minChars + " chars long!").color(NamedTextColor.RED));
|
||||
} else {
|
||||
sender.sendMessage(Component.text("Parameter " + param + " must be between " + minChars + " and " + maxChars + " chars long!").color(NamedTextColor.RED));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
package de.blazemcworld.blazinggames.commands;
|
||||
|
||||
import de.blazemcworld.blazinggames.BlazingGames;
|
||||
import de.blazemcworld.blazinggames.items.ContextlessItem;
|
||||
import de.blazemcworld.blazinggames.items.CustomItem;
|
||||
import de.blazemcworld.blazinggames.items.CustomItems;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
@ -30,6 +29,7 @@ import org.bukkit.inventory.ItemStack;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -49,15 +49,10 @@ public class CustomGiveCommand implements CommandExecutor, TabCompleter {
|
|||
return true;
|
||||
}
|
||||
|
||||
if(strings.length > 2) {
|
||||
CommandHelper.sendUsage(commandSender, command);
|
||||
return true;
|
||||
}
|
||||
|
||||
CustomItem<?> itemType = CustomItems.getByKey(BlazingGames.get().key(strings[0]));
|
||||
int count = 1;
|
||||
|
||||
if(!(itemType instanceof ContextlessItem contextlessItemType))
|
||||
if(itemType == null)
|
||||
{
|
||||
commandSender.sendMessage(Component.text("Unknown custom item: " + strings[0] + "!").color(NamedTextColor.RED));
|
||||
return true;
|
||||
|
@ -67,10 +62,36 @@ public class CustomGiveCommand implements CommandExecutor, TabCompleter {
|
|||
count = Integer.parseInt(strings[1]);
|
||||
}
|
||||
|
||||
ItemStack item = contextlessItemType.create();
|
||||
item.setAmount(count);
|
||||
String rawContext = "";
|
||||
|
||||
p.getInventory().addItem(item);
|
||||
if(strings.length > 2)
|
||||
{
|
||||
List<String> contextStrings = new ArrayList<>(List.of(strings));
|
||||
contextStrings.removeFirst();
|
||||
contextStrings.removeFirst();
|
||||
|
||||
rawContext = String.join(" ", contextStrings);
|
||||
}
|
||||
|
||||
try {
|
||||
ItemStack item = itemType.createWithRawContext(p, rawContext);
|
||||
item.setAmount(count);
|
||||
|
||||
p.getInventory().addItem(item);
|
||||
}
|
||||
catch(ParseException parsingException) {
|
||||
commandSender.sendMessage(Component.text("Parsing Exception: "
|
||||
+ parsingException.getMessage()
|
||||
+ " at " + parsingException.getErrorOffset())
|
||||
.color(NamedTextColor.RED));
|
||||
BlazingGames.get().debugLog(parsingException);
|
||||
}
|
||||
catch(Exception exception) {
|
||||
commandSender.sendMessage(Component.text(exception.getClass().getName() + ": "
|
||||
+ exception.getMessage())
|
||||
.color(NamedTextColor.RED));
|
||||
BlazingGames.get().debugLog(exception);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -81,12 +102,7 @@ public class CustomGiveCommand implements CommandExecutor, TabCompleter {
|
|||
List<String> tabs = new ArrayList<>();
|
||||
|
||||
if(strings.length == 1) {
|
||||
CustomItems.getAllItems().forEach(itemType -> {
|
||||
if(itemType instanceof ContextlessItem)
|
||||
{
|
||||
tabs.add(itemType.getKey().getKey());
|
||||
}
|
||||
});
|
||||
CustomItems.getAllItems().forEach(itemType -> tabs.add(itemType.getKey().getKey()));
|
||||
}
|
||||
|
||||
return tabs;
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright 2025 The Blazing Games Maintainers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.blazemcworld.blazinggames.commands;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import de.blazemcworld.blazinggames.utils.PlayerConfig;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
|
||||
public class DisplayCommand implements CommandExecutor, TabCompleter {
|
||||
public static final TextColor colorSuccess = TextColor.color(0xD1FCDF);
|
||||
public static final TextColor colorFailure = TextColor.color(0xFC9588);
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage(Component.text("Only players can use this command!")
|
||||
.color(NamedTextColor.RED));
|
||||
return false;
|
||||
}
|
||||
PlayerConfig config = PlayerConfig.forPlayer(player.getUniqueId());
|
||||
player.sendMessage("");
|
||||
|
||||
if (args.length < 1) {
|
||||
// show help text
|
||||
player.sendMessage(Component.text("Usage: " + command.getUsage()).color(colorSuccess));
|
||||
sendNameplates(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
String param = args[0];
|
||||
String valueStr = (args.length > 1) ? Arrays.stream(args).skip(1).collect(Collectors.joining(" ")) : null;
|
||||
String value = (valueStr == null || valueStr.isBlank()) ? null : valueStr;
|
||||
String pretty;
|
||||
switch (param) {
|
||||
case "name":
|
||||
if (value != null && (value.length() < 2 || value.length() > 40)) {
|
||||
player.sendMessage(Component.text("Display name must be between 2 and 40 characters long.").color(colorFailure));
|
||||
return true;
|
||||
}
|
||||
config.setDisplayName(value);
|
||||
pretty = "display name";
|
||||
break;
|
||||
case "pronouns":
|
||||
if (value != null && (value.length() < 2 || value.length() > 20)) {
|
||||
player.sendMessage(Component.text("Pronouns must be between 2 and 20 characters long.").color(colorFailure));
|
||||
return true;
|
||||
}
|
||||
config.setPronouns(value);
|
||||
pretty = "pronouns";
|
||||
break;
|
||||
case "color":
|
||||
if (value == null) {
|
||||
config.setNameColor(null);
|
||||
player.sendMessage(Component.text("Unset name color.").color(colorSuccess));
|
||||
sendNameplates(player);
|
||||
return true;
|
||||
} else if (value.length() != 6) {
|
||||
player.sendMessage(Component.text("Colors must be a hex color without the first #. For example, \"ffffff\".").color(colorFailure));
|
||||
return true;
|
||||
} else {
|
||||
int realValue;
|
||||
try {
|
||||
realValue = Integer.parseInt(value, 16);
|
||||
} catch (NumberFormatException e) {
|
||||
player.sendMessage(Component.text("This isn't a valid color: #" + value).color(colorFailure));
|
||||
return true;
|
||||
}
|
||||
config.setNameColor(TextColor.color(realValue));
|
||||
}
|
||||
pretty = "name color";
|
||||
break;
|
||||
case "reset":
|
||||
if ("confirm".equals(value)) {
|
||||
config.setDisplayName(null);
|
||||
config.setPronouns(null);
|
||||
config.setNameColor(null);
|
||||
player.sendMessage(Component.text("Reset all settings successfully.").color(colorSuccess));
|
||||
sendNameplates(player);
|
||||
} else {
|
||||
player.sendMessage(Component.text("To reset all display settings, run ").color(colorSuccess)
|
||||
.append(Component.text("/display reset confirm").color(colorFailure)));
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
player.sendMessage(Component.text("Unknown parameter: " + param).color(colorFailure));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
player.sendMessage(Component.text("Unset " + pretty + " successfully.").color(colorSuccess));
|
||||
} else {
|
||||
player.sendMessage(Component.text("Set " + pretty + " to ").color(colorSuccess)
|
||||
.append(Component.text(value).color(NamedTextColor.WHITE))
|
||||
.append(Component.text(" successfully.").color(colorSuccess)));
|
||||
}
|
||||
sendNameplates(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||
@NotNull String label, @NotNull String[] args) {
|
||||
if (args.length == 1) {
|
||||
return List.of("name", "pronouns", "color");
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
private static void sendNameplates(Player player) {
|
||||
PlayerConfig config = PlayerConfig.forPlayer(player.getUniqueId());
|
||||
player.sendMessage(Component.text("Preview:").color(colorSuccess));
|
||||
player.sendMessage(Component.text("- Current nameplate: ").color(colorSuccess)
|
||||
.append(config.buildNameComponent(player.getName(), player.isOp())));
|
||||
player.sendMessage(Component.text("- Current nameplate (short): ").color(colorSuccess)
|
||||
.append(config.buildNameComponentShort(player.getName(), player.isOp())));
|
||||
player.sendMessage(Component.text("- Current discord name: ").color(colorSuccess)
|
||||
.append(Component.text(config.buildNameString(player.getName(), player.isOp())).color(NamedTextColor.WHITE)));
|
||||
player.sendMessage(Component.text("- Current discord name (short): ").color(colorSuccess)
|
||||
.append(Component.text(config.buildNameStringShort(player.getName())).color(NamedTextColor.WHITE)));
|
||||
config.updatePlayer(player);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ package de.blazemcworld.blazinggames.computing;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
|
@ -54,17 +55,17 @@ public class ComputerMetadata {
|
|||
}
|
||||
|
||||
public ComputerMetadata(JsonObject json) {
|
||||
IllegalArgumentException e = new IllegalArgumentException("Invalid computer metadata");
|
||||
this.id = GetGson.getString(json, "id", e);
|
||||
this.name = GetGson.getString(json, "name", e);
|
||||
this.address = UUID.fromString(GetGson.getString(json, "address", e));
|
||||
this.type = ComputerTypes.valueOf(GetGson.getString(json, "type", e));
|
||||
this.upgrades = GetGson.getString(json, "upgrades", e).split(",");
|
||||
this.location = TextLocation.deserialize(GetGson.getString(json, "location", e));
|
||||
this.owner = UUID.fromString(GetGson.getString(json, "owner", e));
|
||||
this.collaborators = Arrays.stream(GetGson.getString(json, "collaborators", e).split(",")).filter(s -> !s.isEmpty()).map(UUID::fromString).toArray(UUID[]::new);
|
||||
this.shouldRun = GetGson.getBoolean(json, "shouldRun", e);
|
||||
this.frozenTicks = GetGson.getNumber(json, "frozenTicks", e).intValue();
|
||||
Function<String, IllegalArgumentException> e = (msg) -> new IllegalArgumentException("Invalid computer metadata: missing property " + msg);
|
||||
this.id = GetGson.getString(json, "id", e.apply("id"));
|
||||
this.name = GetGson.getString(json, "name", e.apply("name"));
|
||||
this.address = UUID.fromString(GetGson.getString(json, "address", e.apply("address")));
|
||||
this.type = ComputerTypes.valueOf(GetGson.getString(json, "type", e.apply("type")));
|
||||
this.upgrades = GetGson.getString(json, "upgrades", e.apply("upgrades")).split(",");
|
||||
this.location = TextLocation.deserialize(json.get("location").isJsonNull() ? null : json.get("location").getAsString());
|
||||
this.owner = UUID.fromString(GetGson.getString(json, "owner", e.apply("owner")));
|
||||
this.collaborators = Arrays.stream(GetGson.getString(json, "collaborators", e.apply("collaborators")).split(",")).filter(s -> !s.isEmpty()).map(UUID::fromString).toArray(UUID[]::new);
|
||||
this.shouldRun = GetGson.getBoolean(json, "shouldRun", e.apply("shouldRun"));
|
||||
this.frozenTicks = GetGson.getNumber(json, "frozenTicks", e.apply("frozenTicks")).intValue();
|
||||
}
|
||||
|
||||
public JsonObject serialize() {
|
||||
|
|
|
@ -24,6 +24,9 @@ import com.google.gson.JsonParser;
|
|||
import de.blazemcworld.blazinggames.BlazingGames;
|
||||
import de.blazemcworld.blazinggames.computing.api.APIDocs;
|
||||
import de.blazemcworld.blazinggames.computing.api.TokenManager;
|
||||
import de.blazemcworld.blazinggames.testing.CoveredByTests;
|
||||
import de.blazemcworld.blazinggames.testing.tests.LoginFlowTest;
|
||||
import de.blazemcworld.blazinggames.testing.tests.UnlinkFlowTest;
|
||||
import de.blazemcworld.blazinggames.computing.api.BlazingAPI;
|
||||
import de.blazemcworld.blazinggames.computing.api.EarlyResponse;
|
||||
import de.blazemcworld.blazinggames.computing.api.Endpoint;
|
||||
|
@ -41,6 +44,7 @@ import okhttp3.RequestBody;
|
|||
import okhttp3.Response;
|
||||
import okhttp3.FormBody.Builder;
|
||||
|
||||
@CoveredByTests({LoginFlowTest.class, UnlinkFlowTest.class})
|
||||
public class AuthCallbackEndpoint implements Endpoint {
|
||||
public static final String PATH = "/auth/callback";
|
||||
private final OkHttpClient client = new OkHttpClient();
|
||||
|
|
|
@ -17,6 +17,8 @@ package de.blazemcworld.blazinggames.computing.api.impl.auth;
|
|||
|
||||
import de.blazemcworld.blazinggames.computing.api.APIDocs;
|
||||
import de.blazemcworld.blazinggames.computing.api.TokenManager;
|
||||
import de.blazemcworld.blazinggames.testing.CoveredByTests;
|
||||
import de.blazemcworld.blazinggames.testing.tests.LoginFlowTest;
|
||||
import de.blazemcworld.blazinggames.computing.api.EarlyResponse;
|
||||
import de.blazemcworld.blazinggames.computing.api.Endpoint;
|
||||
import de.blazemcworld.blazinggames.computing.api.EndpointResponse;
|
||||
|
@ -28,6 +30,7 @@ import java.time.Instant;
|
|||
import java.util.HashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@CoveredByTests(LoginFlowTest.class)
|
||||
public class AuthConsentEndpoint implements Endpoint {
|
||||
@Override
|
||||
public String path() {
|
||||
|
|
|
@ -17,6 +17,8 @@ package de.blazemcworld.blazinggames.computing.api.impl.auth;
|
|||
|
||||
import de.blazemcworld.blazinggames.computing.api.APIDocs;
|
||||
import de.blazemcworld.blazinggames.computing.api.TokenManager;
|
||||
import de.blazemcworld.blazinggames.testing.CoveredByTests;
|
||||
import de.blazemcworld.blazinggames.testing.tests.LoginFlowTest;
|
||||
import de.blazemcworld.blazinggames.computing.api.BlazingAPI;
|
||||
import de.blazemcworld.blazinggames.computing.api.EarlyResponse;
|
||||
import de.blazemcworld.blazinggames.computing.api.Endpoint;
|
||||
|
@ -27,6 +29,7 @@ import java.net.URLEncoder;
|
|||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
|
||||
@CoveredByTests(LoginFlowTest.class)
|
||||
public class AuthLinkEndpoint implements Endpoint {
|
||||
private static final String BASE_URL = "https://login.live.com/oauth20_authorize.srf";
|
||||
private static final String SCOPES = "Xboxlive.signin";
|
||||
|
|
|
@ -23,6 +23,8 @@ import de.blazemcworld.blazinggames.BlazingGames;
|
|||
import de.blazemcworld.blazinggames.computing.api.APIDocs;
|
||||
import de.blazemcworld.blazinggames.computing.api.BlazingAPI;
|
||||
import de.blazemcworld.blazinggames.computing.api.TokenManager;
|
||||
import de.blazemcworld.blazinggames.testing.CoveredByTests;
|
||||
import de.blazemcworld.blazinggames.testing.tests.LoginFlowTest;
|
||||
import de.blazemcworld.blazinggames.computing.api.EarlyResponse;
|
||||
import de.blazemcworld.blazinggames.computing.api.Endpoint;
|
||||
import de.blazemcworld.blazinggames.computing.api.EndpointResponse;
|
||||
|
@ -33,6 +35,7 @@ import de.blazemcworld.blazinggames.utils.GetGson;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@CoveredByTests(LoginFlowTest.class)
|
||||
public class AuthPrepareEndpoint implements Endpoint {
|
||||
@Override
|
||||
public String path() {
|
||||
|
|
|
@ -18,6 +18,8 @@ package de.blazemcworld.blazinggames.computing.api.impl.auth;
|
|||
import com.google.gson.JsonObject;
|
||||
import de.blazemcworld.blazinggames.computing.api.APIDocs;
|
||||
import de.blazemcworld.blazinggames.computing.api.TokenManager;
|
||||
import de.blazemcworld.blazinggames.testing.CoveredByTests;
|
||||
import de.blazemcworld.blazinggames.testing.tests.LoginFlowTest;
|
||||
import de.blazemcworld.blazinggames.computing.api.EarlyResponse;
|
||||
import de.blazemcworld.blazinggames.computing.api.Endpoint;
|
||||
import de.blazemcworld.blazinggames.computing.api.EndpointResponse;
|
||||
|
@ -25,6 +27,7 @@ import de.blazemcworld.blazinggames.computing.api.LinkedUser;
|
|||
import de.blazemcworld.blazinggames.computing.api.RequestContext;
|
||||
import de.blazemcworld.blazinggames.computing.api.RequestMethod;
|
||||
|
||||
@CoveredByTests(LoginFlowTest.class)
|
||||
public class AuthRedeemEndpoint implements Endpoint {
|
||||
@Override
|
||||
public EndpointResponse POST(RequestContext context) throws EarlyResponse {
|
||||
|
|
|
@ -22,7 +22,11 @@ import de.blazemcworld.blazinggames.computing.api.Endpoint;
|
|||
import de.blazemcworld.blazinggames.computing.api.EndpointResponse;
|
||||
import de.blazemcworld.blazinggames.computing.api.RequestContext;
|
||||
import de.blazemcworld.blazinggames.computing.api.RequestMethod;
|
||||
import de.blazemcworld.blazinggames.testing.CoveredByTests;
|
||||
import de.blazemcworld.blazinggames.testing.tests.LoginFlowTest;
|
||||
import de.blazemcworld.blazinggames.testing.tests.UnlinkFlowTest;
|
||||
|
||||
@CoveredByTests({LoginFlowTest.class, UnlinkFlowTest.class})
|
||||
public class AuthTestEndpoint implements Endpoint {
|
||||
@Override
|
||||
public String path() {
|
||||
|
|
|
@ -17,12 +17,15 @@ package de.blazemcworld.blazinggames.computing.api.impl.auth;
|
|||
|
||||
import de.blazemcworld.blazinggames.computing.api.APIDocs;
|
||||
import de.blazemcworld.blazinggames.computing.api.TokenManager;
|
||||
import de.blazemcworld.blazinggames.testing.CoveredByTests;
|
||||
import de.blazemcworld.blazinggames.testing.tests.UnlinkFlowTest;
|
||||
import de.blazemcworld.blazinggames.computing.api.EarlyResponse;
|
||||
import de.blazemcworld.blazinggames.computing.api.Endpoint;
|
||||
import de.blazemcworld.blazinggames.computing.api.EndpointResponse;
|
||||
import de.blazemcworld.blazinggames.computing.api.RequestContext;
|
||||
import java.util.HashMap;
|
||||
|
||||
@CoveredByTests(UnlinkFlowTest.class)
|
||||
public class AuthUnlinkConfirmEndpoint implements Endpoint {
|
||||
@Override
|
||||
public APIDocs[] docs() {
|
||||
|
|
|
@ -26,7 +26,10 @@ import de.blazemcworld.blazinggames.computing.api.LinkedUser;
|
|||
import de.blazemcworld.blazinggames.computing.api.Permission;
|
||||
import de.blazemcworld.blazinggames.computing.api.RequestContext;
|
||||
import de.blazemcworld.blazinggames.computing.api.RequestMethod;
|
||||
import de.blazemcworld.blazinggames.testing.CoveredByTests;
|
||||
import de.blazemcworld.blazinggames.testing.tests.RenameEndpointTest;
|
||||
|
||||
@CoveredByTests(RenameEndpointTest.class)
|
||||
public class RenameEndpoint implements Endpoint {
|
||||
@Override
|
||||
public String path() {
|
||||
|
|
|
@ -20,16 +20,20 @@ import de.blazemcworld.blazinggames.BlazingGames;
|
|||
import de.blazemcworld.blazinggames.items.CustomItem;
|
||||
import de.blazemcworld.blazinggames.items.CustomItems;
|
||||
import de.blazemcworld.blazinggames.items.contexts.ItemContext;
|
||||
import de.blazemcworld.blazinggames.utils.TextLocation;
|
||||
import io.azam.ulidj.ULID;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.List;
|
||||
|
||||
public class DeathCrateKey extends CustomItem<DeathCrateKey.DeathCrateKeyContext> {
|
||||
|
@ -79,6 +83,11 @@ public class DeathCrateKey extends CustomItem<DeathCrateKey.DeathCrateKeyContext
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DeathCrateKeyContext parseRawContext(Player player, String raw) throws ParseException {
|
||||
return DeathCrateKeyContext.parse(player, raw);
|
||||
}
|
||||
|
||||
public static String getKeyULID(ItemStack item) {
|
||||
if(CustomItems.DEATH_CRATE_KEY.matchItem(item))
|
||||
{
|
||||
|
@ -89,5 +98,41 @@ public class DeathCrateKey extends CustomItem<DeathCrateKey.DeathCrateKeyContext
|
|||
}
|
||||
|
||||
public record DeathCrateKeyContext(String crateId) implements ItemContext {
|
||||
public static DeathCrateKeyContext parse(Player player, String raw) throws ParseException {
|
||||
if (!raw.contains(":")) {
|
||||
raw = "ulid:" + raw;
|
||||
}
|
||||
|
||||
String[] split = raw.split(":", 2);
|
||||
|
||||
switch (split[0].toLowerCase()) {
|
||||
case "ulid" -> {
|
||||
if (!ULID.isValid(split[1])) {
|
||||
throw new ParseException("Invalid ULID!", raw.length());
|
||||
}
|
||||
if(CrateManager.readCrate(split[1]) == null) {
|
||||
throw new ParseException("Crate does not exist!", raw.length());
|
||||
}
|
||||
return new DeathCrateKeyContext(split[1]);
|
||||
}
|
||||
case "loc" -> {
|
||||
Location loc = TextLocation.deserializeUserInput(player.getWorld(), split[1]);
|
||||
|
||||
if(loc == null) {
|
||||
throw new ParseException("Location could not be parsed!", raw.length());
|
||||
}
|
||||
|
||||
String ulid = CrateManager.getKeyULID(loc);
|
||||
|
||||
if(ulid == null) {
|
||||
throw new ParseException("A crate does not exist at this location!", raw.length());
|
||||
}
|
||||
|
||||
return new DeathCrateKeyContext(ulid);
|
||||
}
|
||||
}
|
||||
|
||||
throw new ParseException("Invalid type '" + split[0] + "'", split[0].length() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -174,22 +174,9 @@ public class DiscordApp extends ListenerAdapter {
|
|||
|
||||
private void sendDiscordMessage(Player player, String content) {
|
||||
PlayerConfig config = PlayerConfig.forPlayer(player.getUniqueId());
|
||||
StringBuilder username = new StringBuilder();
|
||||
if (config.getDisplayName() != null && !config.getDisplayName().equals(player.getName())) {
|
||||
username.append(config.getDisplayName()).append(" [aka ").append(player.getName()).append("]");
|
||||
} else {
|
||||
username.append(player.getName());
|
||||
}
|
||||
if (config.getPronouns() != null) {
|
||||
username.append(" (").append(config.getPronouns()).append(")");
|
||||
}
|
||||
if (player.isOp()) {
|
||||
username.append(" \u266E");
|
||||
}
|
||||
|
||||
String out;
|
||||
if (ChatEventListener.meFormat(content) != null) {
|
||||
out = ((config.getDisplayName() != null) ? config.getDisplayName() : player.getName()) + " " + ChatEventListener.meFormat(content);
|
||||
out = config.buildNameStringShort(player.getName()) + " " + ChatEventListener.meFormat(content);
|
||||
} else if (ChatEventListener.greentextFormat(content) != null) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String[] parts = ChatEventListener.greentextFormat(content);
|
||||
|
@ -202,7 +189,7 @@ public class DiscordApp extends ListenerAdapter {
|
|||
}
|
||||
|
||||
WebhookMessage message = new WebhookMessageBuilder()
|
||||
.setUsername(username.toString())
|
||||
.setUsername(config.buildNameString(player.getName(), player.isOp()))
|
||||
.setAvatarUrl("https://cravatar.eu/helmavatar/" + player.getUniqueId() + "/128.png")
|
||||
.setContent(out)
|
||||
.build();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package de.blazemcworld.blazinggames.discord;
|
||||
|
||||
import de.blazemcworld.blazinggames.utils.PlayerConfig;
|
||||
import de.blazemcworld.blazinggames.utils.TextUtils;
|
||||
import io.papermc.paper.advancement.AdvancementDisplay;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
|
@ -88,10 +89,13 @@ public record DiscordNotification(
|
|||
builder.setTitle("Notification");
|
||||
builder.setColor(Color.ORANGE);
|
||||
|
||||
if (player != null) builder.setAuthor(
|
||||
player.getName(), null,
|
||||
"http://cravatar.eu/helmhead/" + player.getUniqueId() + "/128.png"
|
||||
);
|
||||
if (player != null) {
|
||||
PlayerConfig config = PlayerConfig.forPlayer(player.getUniqueId());
|
||||
builder.setAuthor(
|
||||
config.buildNameString(player.getName(), player.isOp()), null,
|
||||
"http://cravatar.eu/helmhead/" + player.getUniqueId() + "/128.png"
|
||||
);
|
||||
}
|
||||
if (title != null) builder.setTitle(title);
|
||||
if (description != null) builder.setDescription(description);
|
||||
if (color != null) builder.setColor(color);
|
||||
|
|
|
@ -20,7 +20,6 @@ import net.kyori.adventure.text.Component;
|
|||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -46,17 +45,6 @@ public class EnchantmentTome extends ContextlessItem {
|
|||
return Component.text(tomeName).color(NamedTextColor.LIGHT_PURPLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull ItemStack modifyMaterial(ItemStack stack) {
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
|
||||
meta.setEnchantmentGlintOverride(true);
|
||||
|
||||
stack.setItemMeta(meta);
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<Component> lore(ItemStack stack) {
|
||||
return List.of(getComponent());
|
||||
|
|
|
@ -23,16 +23,26 @@ import de.blazemcworld.blazinggames.enchantments.sys.CustomEnchantments;
|
|||
import de.blazemcworld.blazinggames.enchantments.sys.EnchantmentHelper;
|
||||
import de.blazemcworld.blazinggames.items.recipes.RecipeHelper;
|
||||
import de.blazemcworld.blazinggames.teleportanchor.LodestoneStorage;
|
||||
import de.blazemcworld.blazinggames.utils.Drops;
|
||||
import de.blazemcworld.blazinggames.utils.InventoryUtils;
|
||||
import de.blazemcworld.blazinggames.utils.ItemUtils;
|
||||
import de.blazemcworld.blazinggames.utils.Pair;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Effect;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.*;
|
||||
import org.bukkit.block.data.Waterlogged;
|
||||
import org.bukkit.block.data.type.Leaves;
|
||||
import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.ExperienceOrb;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
|
@ -57,7 +67,8 @@ public class BreakBlockEventListener implements Listener {
|
|||
Material.SPRUCE_LOG,
|
||||
Material.CHERRY_LOG,
|
||||
Material.WARPED_STEM,
|
||||
Material.CRIMSON_STEM
|
||||
Material.CRIMSON_STEM,
|
||||
Material.PALE_OAK_LOG
|
||||
);
|
||||
|
||||
private final Set<Material> leaves = Set.of(
|
||||
|
@ -72,7 +83,8 @@ public class BreakBlockEventListener implements Listener {
|
|||
Material.AZALEA_LEAVES,
|
||||
Material.FLOWERING_AZALEA_LEAVES,
|
||||
Material.WARPED_WART_BLOCK,
|
||||
Material.NETHER_WART_BLOCK
|
||||
Material.NETHER_WART_BLOCK,
|
||||
Material.PALE_OAK_LEAVES
|
||||
);
|
||||
|
||||
|
||||
|
@ -95,11 +107,7 @@ public class BreakBlockEventListener implements Listener {
|
|||
}
|
||||
}
|
||||
|
||||
Collection<ItemStack> drops = getBlockDrops(player, event.getBlock());
|
||||
|
||||
onAnyBlockBreak(event.getBlock());
|
||||
|
||||
InventoryUtils.collectableDrop(player, event.getBlock().getLocation(), drops);
|
||||
fakeBreakBlock(player, event.getBlock(), false);
|
||||
|
||||
if (EnchantmentHelper.hasActiveCustomEnchantment(mainHand, CustomEnchantments.TREE_FELLER)) {
|
||||
if (logs.contains(event.getBlock().getType())) {
|
||||
|
@ -219,15 +227,17 @@ public class BreakBlockEventListener implements Listener {
|
|||
Bukkit.getScheduler().runTaskLater(BlazingGames.get(), () -> treeFeller(player, blocksToBreak), 1);
|
||||
}
|
||||
|
||||
public static Collection<ItemStack> getBlockDrops(Player player, Block block) {
|
||||
public static Drops getBlockDrops(Player player, Block block) {
|
||||
ItemStack mainHand = player.getInventory().getItemInMainHand();
|
||||
|
||||
return getBlockDrops(mainHand, block);
|
||||
}
|
||||
|
||||
public static Collection<ItemStack> getBlockDrops(ItemStack mainHand, Block block) {
|
||||
public static Drops getBlockDrops(ItemStack mainHand, Block block) {
|
||||
BlockState state = block.getState();
|
||||
Collection<ItemStack> drops = block.getDrops(mainHand);
|
||||
Drops drops = new Drops(block.getDrops(mainHand));
|
||||
|
||||
drops.addExperience(getDroppedExp(block, mainHand));
|
||||
|
||||
if (block.getType() == Material.CHISELED_BOOKSHELF) {
|
||||
if (mainHand.getEnchantmentLevel(Enchantment.SILK_TOUCH) <= 0) {
|
||||
|
@ -244,6 +254,7 @@ public class BreakBlockEventListener implements Listener {
|
|||
mainHand.getType() == Material.DIAMOND_PICKAXE ||
|
||||
mainHand.getType() == Material.NETHERITE_PICKAXE
|
||||
)) {
|
||||
drops.setExperience(0);
|
||||
CreatureSpawner spawner = (CreatureSpawner) block.getState();
|
||||
ItemStack item = new ItemStack(Material.SPAWNER);
|
||||
BlockStateMeta meta = (BlockStateMeta) item.getItemMeta();
|
||||
|
@ -297,22 +308,26 @@ public class BreakBlockEventListener implements Listener {
|
|||
|
||||
if (ComputerRegistry.getComputerByLocationRounded(block.getLocation()) != null) {
|
||||
BootedComputer computer = ComputerRegistry.getComputerByLocationRounded(block.getLocation());
|
||||
return List.of(ComputerRegistry.addAttributes(computer.getType().getType().getDisplayItem(computer), computer));
|
||||
return new Drops(ComputerRegistry.addAttributes(computer.getType().getType().getDisplayItem(computer), computer));
|
||||
} else {
|
||||
return drops;
|
||||
}
|
||||
}
|
||||
|
||||
public static void fakeBreakBlock(Player player, Block block) {
|
||||
fakeBreakBlock(player, block, true);
|
||||
}
|
||||
|
||||
public static void fakeBreakBlock(Player player, Block block, boolean playEffects) {
|
||||
if (block.isEmpty() || block.getType().getHardness() < 0 || block.isLiquid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Collection<ItemStack> drops = getBlockDrops(player, block);
|
||||
Drops drops = getBlockDrops(player, block);
|
||||
|
||||
onAnyBlockBreak(block);
|
||||
|
||||
block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getBlockData());
|
||||
if(playEffects) block.getWorld().playEffect(block.getLocation(), Effect.STEP_SOUND, block.getBlockData());
|
||||
|
||||
boolean waterlogged = false;
|
||||
|
||||
|
@ -336,4 +351,23 @@ public class BreakBlockEventListener implements Listener {
|
|||
ComputerRegistry.unload(computer.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private static int getDroppedExp(Block block, ItemStack tool) {
|
||||
if (!(block instanceof CraftBlock craftBlock)) return 0;
|
||||
|
||||
net.minecraft.world.level.block.state.BlockState nmsBlockState = craftBlock.getNMS();
|
||||
BlockPos pos = craftBlock.getPosition();
|
||||
ServerLevel level = craftBlock.getCraftWorld().getHandle();
|
||||
|
||||
return nmsBlockState.getBlock().getExpDrop(nmsBlockState, level, pos, CraftItemStack.asNMSCopy(tool), true);
|
||||
}
|
||||
|
||||
public static void awardBlock(Location location, int amount, Player trigger) {
|
||||
if(!(location.getWorld() instanceof CraftWorld world)) { return; }
|
||||
if(!(trigger instanceof CraftPlayer player)) { return; }
|
||||
|
||||
net.minecraft.world.entity.ExperienceOrb.award(
|
||||
world.getHandle(), new Vec3(location.x(), location.y(), location.z()), amount,
|
||||
ExperienceOrb.SpawnReason.BLOCK_BREAK, player.getHandleRaw());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import io.papermc.paper.chat.ChatRenderer;
|
|||
import io.papermc.paper.event.player.AsyncChatEvent;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -43,43 +42,14 @@ public class ChatEventListener implements Listener, ChatRenderer {
|
|||
|
||||
@Override
|
||||
public @NotNull Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message, @NotNull Audience viewer) {
|
||||
// format username
|
||||
Component username;
|
||||
PlayerConfig config = PlayerConfig.forPlayer(source.getUniqueId());
|
||||
if (config.getDisplayName() != null && !config.getDisplayName().equals(source.getName())) {
|
||||
username = Component.text(config.getDisplayName()).hoverEvent(HoverEvent.showText(Component.text("Real name: " + source.getName())));
|
||||
} else {
|
||||
username = Component.text(source.getName()).hoverEvent(HoverEvent.showText(Component.text("Real name: " + source.getName())));
|
||||
}
|
||||
|
||||
if (config.getNameColor() != null) {
|
||||
username = username.color(config.getNameColor());
|
||||
}
|
||||
|
||||
|
||||
if (config.getPronouns() != null) {
|
||||
username = username.appendSpace().append(Component.text("(" + config.getPronouns() + ")")
|
||||
.color(NamedTextColor.GRAY).hoverEvent(HoverEvent.showText(Component.text("Pronouns"))));
|
||||
}
|
||||
|
||||
if (source.isOp()) {
|
||||
username = username.appendSpace().append(Component.text("\u266E").color(NamedTextColor.RED)
|
||||
.hoverEvent(HoverEvent.showText(Component.text("Server Operator"))));
|
||||
}
|
||||
|
||||
// custom formatting
|
||||
Component username = config.buildNameComponent(source.getName(), source.isOp());
|
||||
String rawMessage = TextUtils.componentToString(message);
|
||||
if (meFormat(rawMessage) != null) {
|
||||
// me when a oneliner needs to be multiline
|
||||
Component minimalUsername = Component.text(config.getDisplayName() != null ? config.getDisplayName() : source.getName())
|
||||
.color(config.getNameColor() != null ? config.getNameColor() : NamedTextColor.WHITE)
|
||||
.hoverEvent(HoverEvent.showText(Component.text("Real name: " + source.getName())
|
||||
.appendNewline().append(Component.text("Pronouns: " + config.getPronouns() != null ? config.getPronouns() : "None specified"))
|
||||
.appendNewline().append(Component.text("Server Operator: " + (source.isOp() ? "Yes" : "No")))));
|
||||
|
||||
return Component.text("*").color(NamedTextColor.WHITE)
|
||||
.appendSpace()
|
||||
.append(minimalUsername)
|
||||
.append(config.buildNameComponentShort(source.getName(), source.isOp()))
|
||||
.appendSpace()
|
||||
.append(TextUtils.colorCodeParser(TextUtils.stringToComponent(meFormat(rawMessage))).color(NamedTextColor.WHITE));
|
||||
} else if (greentextFormat(rawMessage) != null) {
|
||||
|
|
|
@ -20,14 +20,18 @@ import de.blazemcworld.blazinggames.computing.api.BlazingAPI;
|
|||
import de.blazemcworld.blazinggames.discord.DiscordApp;
|
||||
import de.blazemcworld.blazinggames.discord.DiscordNotification;
|
||||
import de.blazemcworld.blazinggames.packs.ResourcePackManager.PackConfig;
|
||||
import de.blazemcworld.blazinggames.utils.PlayerConfig;
|
||||
import de.blazemcworld.blazinggames.items.recipes.CustomRecipes;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
public class JoinEventListener implements Listener {
|
||||
public static final TextColor color = TextColor.color(0xD1F990);
|
||||
|
||||
@EventHandler
|
||||
public void join(PlayerJoinEvent event) {
|
||||
event.getPlayer().discoverRecipes(CustomRecipes.getAllRecipes().keySet());
|
||||
|
@ -44,5 +48,10 @@ public class JoinEventListener implements Listener {
|
|||
true
|
||||
);
|
||||
}
|
||||
|
||||
PlayerConfig config = PlayerConfig.forPlayer(event.getPlayer().getUniqueId());
|
||||
config.updatePlayer(event.getPlayer());
|
||||
Component name = config.buildNameComponent(event.getPlayer().getName(), event.getPlayer().isOp());
|
||||
event.joinMessage(Component.empty().append(name).append(Component.text(" joined the game").color(color)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@ package de.blazemcworld.blazinggames.events;
|
|||
import de.blazemcworld.blazinggames.BlazingGames;
|
||||
import de.blazemcworld.blazinggames.discord.DiscordApp;
|
||||
import de.blazemcworld.blazinggames.discord.DiscordNotification;
|
||||
import de.blazemcworld.blazinggames.utils.PlayerConfig;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.EventHandler;
|
||||
|
@ -25,12 +28,18 @@ import org.bukkit.event.Listener;
|
|||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
public class QuitEventListener implements Listener {
|
||||
public static final TextColor color = TextColor.color(0xF99490);
|
||||
|
||||
@EventHandler
|
||||
public void join(PlayerQuitEvent event) {
|
||||
DiscordApp.send(DiscordNotification.playerLeave(event.getPlayer()));
|
||||
|
||||
if (Bukkit.getOnlinePlayers().size() == 1) {
|
||||
if (Bukkit.getOnlinePlayers().size() == 1 && BlazingGames.get().getPackConfig() != null) {
|
||||
BlazingGames.get().rebuildPack();
|
||||
}
|
||||
|
||||
Component name = PlayerConfig.forPlayer(event.getPlayer().getUniqueId())
|
||||
.buildNameComponent(event.getPlayer().getName(), event.getPlayer().isOp());
|
||||
event.quitMessage(Component.empty().append(name).append(Component.text(" left the game").color(color)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package de.blazemcworld.blazinggames.items;
|
||||
|
||||
import de.blazemcworld.blazinggames.items.contexts.EmptyItemContext;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
public abstract class ContextlessItem extends CustomItem<EmptyItemContext> {
|
||||
public final @NotNull ItemStack create() {
|
||||
return create(EmptyItemContext.instance);
|
||||
|
@ -13,6 +16,11 @@ public abstract class ContextlessItem extends CustomItem<EmptyItemContext> {
|
|||
return modifyMaterial(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EmptyItemContext parseRawContext(Player player, String raw) throws ParseException {
|
||||
return EmptyItemContext.parse(player, raw);
|
||||
}
|
||||
|
||||
protected @NotNull ItemStack modifyMaterial(ItemStack stack) {
|
||||
return stack;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import net.kyori.adventure.text.Component;
|
|||
import org.bukkit.Keyed;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemRarity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
@ -32,6 +33,7 @@ import org.bukkit.inventory.meta.components.UseCooldownComponent;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.text.ParseException;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class CustomItem<T extends ItemContext> implements RecipeProvider, Keyed, ItemPredicate {
|
||||
|
@ -94,6 +96,10 @@ public abstract class CustomItem<T extends ItemContext> implements RecipeProvide
|
|||
return ItemChangeProviders.update(result);
|
||||
}
|
||||
|
||||
public final @NotNull ItemStack createWithRawContext(Player player, String raw) throws ParseException {
|
||||
return create(parseRawContext(player, raw));
|
||||
}
|
||||
|
||||
public ItemStack update(ItemStack stack) {
|
||||
return stack.clone();
|
||||
}
|
||||
|
@ -129,4 +135,6 @@ public abstract class CustomItem<T extends ItemContext> implements RecipeProvide
|
|||
public List<Component> lore(ItemStack stack) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
protected abstract T parseRawContext(Player player, String raw) throws ParseException;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,19 @@
|
|||
|
||||
package de.blazemcworld.blazinggames.items.contexts;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
public class EmptyItemContext implements ItemContext {
|
||||
public static EmptyItemContext instance = new EmptyItemContext();
|
||||
|
||||
public static EmptyItemContext parse(Player player, String raw) throws ParseException {
|
||||
if(raw.isBlank())
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
throw new ParseException("Do mention that this item's context is empty.", raw.length());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,5 +17,4 @@
|
|||
package de.blazemcworld.blazinggames.items.contexts;
|
||||
|
||||
public interface ItemContext {
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import java.io.File;
|
|||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
|
@ -34,30 +33,33 @@ import java.util.logging.Logger;
|
|||
import com.google.gson.JsonObject;
|
||||
|
||||
import de.blazemcworld.blazinggames.BlazingGames;
|
||||
import io.azam.ulidj.MonotonicULID;
|
||||
|
||||
public class ResourcePackManager {
|
||||
private static final MonotonicULID ulid = new MonotonicULID();
|
||||
private static final File workingDirectory = new File(".packwork");
|
||||
static {
|
||||
workingDirectory.mkdirs();
|
||||
}
|
||||
|
||||
public static record PackConfig(
|
||||
String description,
|
||||
UUID uuid
|
||||
) {}
|
||||
|
||||
public static File build(Logger log, PackConfig config) {
|
||||
File outputFile = new File(workingDirectory, ulid.generate() + ".zip");
|
||||
Map<String, String> environment = new HashMap<>();
|
||||
Map<String, Object> environment = new HashMap<>();
|
||||
environment.put("create", "true");
|
||||
URI uri = URI.create("jar:file:" + outputFile.getAbsolutePath());
|
||||
environment.put("useTempFile", Boolean.TRUE);
|
||||
|
||||
log.info("Building resource pack...");
|
||||
|
||||
Path path;
|
||||
try {
|
||||
// this is in a seperate code block because it throws and IOException
|
||||
// but it's not AutoCloseable, meaning it cannot be put in the try-with-resources :3
|
||||
path = Files.createTempFile("blazinggames-packwork", ".zip");
|
||||
path.toFile().delete(); // otherwise zipfs complains about no zip header
|
||||
} catch (IOException e) {
|
||||
BlazingGames.get().log(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
try (
|
||||
FileSystem zip = FileSystems.newFileSystem(uri, environment);
|
||||
FileSystem zip = FileSystems.newFileSystem(path, environment);
|
||||
) {
|
||||
// create pack meta
|
||||
JsonObject root = new JsonObject();
|
||||
|
@ -80,7 +82,8 @@ public class ResourcePackManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
return outputFile;
|
||||
path.toFile().deleteOnExit();
|
||||
return path.toFile();
|
||||
}
|
||||
|
||||
public static void write(Path path, byte[] data) throws IOException {
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright 2025 The Blazing Games Maintainers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.blazemcworld.blazinggames.testing;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import de.blazemcworld.blazinggames.BlazingGames;
|
||||
import de.blazemcworld.blazinggames.computing.ComputerMetadata;
|
||||
import de.blazemcworld.blazinggames.computing.ComputerRegistry;
|
||||
import de.blazemcworld.blazinggames.computing.api.LinkedUser;
|
||||
import de.blazemcworld.blazinggames.computing.api.Permission;
|
||||
import de.blazemcworld.blazinggames.computing.api.TokenManager;
|
||||
import de.blazemcworld.blazinggames.computing.types.ComputerTypes;
|
||||
import de.blazemcworld.blazinggames.utils.NameGenerator;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public abstract class BlazingTest {
|
||||
public abstract boolean runAsync();
|
||||
public boolean run() {
|
||||
try {
|
||||
runTest();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract void runTest() throws Exception;
|
||||
public void preRunSync() throws Exception {}
|
||||
|
||||
// methods for test runner
|
||||
protected void assertBoolean(String condition, boolean assertion) throws TestFailedException {
|
||||
if (!assertion) {
|
||||
throw new TestFailedException(getClass(), "assertBoolean failed: \"" + condition + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertEquals(Object expected, Object actual) throws TestFailedException {
|
||||
if (expected == null && actual == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (expected == null || actual == null || !expected.equals(actual)) {
|
||||
throw new TestFailedException(getClass(), "assertEquals expected \"" + expected + "\" but got \"" + actual + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertNotNull(Object... objects) throws TestFailedException {
|
||||
for (Object object : objects) {
|
||||
if (object == null) {
|
||||
throw new TestFailedException(getClass(), "assertNotNull failed: object is null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertNotEmpty(Object[] array) throws TestFailedException {
|
||||
if (array.length == 0) {
|
||||
throw new TestFailedException(getClass(), "assertNotEmpty failed: array is empty");
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertNotEmpty(List<Object> list) throws TestFailedException {
|
||||
if (list.size() == 0) {
|
||||
throw new TestFailedException(getClass(), "assertNotEmpty failed: list is empty");
|
||||
}
|
||||
}
|
||||
|
||||
protected void debugLog(String... contents) {
|
||||
String message = String.join(" ", contents);
|
||||
BlazingGames.get().debugLog(getClass().getSimpleName() + ": " + message);
|
||||
}
|
||||
|
||||
private static int id = 0;
|
||||
protected synchronized LinkedUser createLinkedUser(boolean expired, UUID uuid, Permission... permissions) {
|
||||
id++;
|
||||
List<Permission> perms = List.of(permissions);
|
||||
long expAt = expired ? 0L : Instant.now().plusSeconds(TimeUnit.HOURS.toSeconds(6L)).getEpochSecond();
|
||||
return new LinkedUser("UnitTest" + id, uuid, 0, TokenManager.getInstant(), perms, expAt);
|
||||
}
|
||||
|
||||
protected LinkedUser createLinkedUser(boolean expired, Permission... permissions) {
|
||||
return createLinkedUser(expired, UUID.randomUUID(), permissions);
|
||||
}
|
||||
|
||||
protected String createSignedJWT(boolean expired, UUID uuid, Permission... permissions) {
|
||||
LinkedUser user = createLinkedUser(expired, uuid, permissions);
|
||||
return LinkedUser.signLinkedUser(user);
|
||||
}
|
||||
|
||||
protected String createSignedJWT(boolean expired, Permission... permissions) {
|
||||
return createSignedJWT(expired, UUID.randomUUID(), permissions);
|
||||
}
|
||||
|
||||
public static final OkHttpClient client = new OkHttpClient.Builder()
|
||||
.followRedirects(false)
|
||||
.followSslRedirects(false)
|
||||
.build();
|
||||
public static final MediaType json = MediaType.parse("application/json");
|
||||
protected JsonObject sendRequest(Request request) throws IOException {
|
||||
Response response = client.newCall(request).execute();
|
||||
JsonElement json = BlazingGames.gson.fromJson(response.body().charStream(), JsonElement.class);
|
||||
debugLog(request.url() + ": " + json.toString());
|
||||
return json.getAsJsonObject();
|
||||
}
|
||||
|
||||
protected JsonObject sendGetRequestUnauthenticated(String url) throws IOException {
|
||||
return sendRequest(new Request.Builder()
|
||||
.url("http://localhost:8080" + url)
|
||||
.build());
|
||||
}
|
||||
|
||||
protected JsonObject sendGetRequest(String url, String authorization) throws IOException {
|
||||
return sendRequest(new Request.Builder()
|
||||
.url("http://localhost:8080" + url)
|
||||
.header("Authorization", "Bearer " + authorization)
|
||||
.build());
|
||||
}
|
||||
|
||||
protected JsonObject sendPostRequestUnauthenticated(String url, JsonObject body) throws IOException {
|
||||
return sendRequest(new Request.Builder()
|
||||
.url("http://localhost:8080" + url)
|
||||
.post(RequestBody.create(BlazingGames.gson.toJson(body), json))
|
||||
.build());
|
||||
}
|
||||
|
||||
protected JsonObject sendPostRequest(String url, JsonObject body, String authorization) throws IOException {
|
||||
return sendRequest(new Request.Builder()
|
||||
.url("http://localhost:8080" + url)
|
||||
.post(RequestBody.create(BlazingGames.gson.toJson(body), json))
|
||||
.header("Authorization", "Bearer " + authorization)
|
||||
.build());
|
||||
}
|
||||
|
||||
protected JsonObject sendPutRequest(String url, JsonObject body, String authorization) throws IOException {
|
||||
return sendRequest(new Request.Builder()
|
||||
.url("http://localhost:8080" + url)
|
||||
.put(RequestBody.create(BlazingGames.gson.toJson(body), json))
|
||||
.header("Authorization", "Bearer " + authorization)
|
||||
.build());
|
||||
}
|
||||
|
||||
protected JsonObject sendPatchRequest(String url, JsonObject body, String authorization) throws IOException {
|
||||
return sendRequest(new Request.Builder()
|
||||
.url("http://localhost:8080" + url)
|
||||
.patch(RequestBody.create(BlazingGames.gson.toJson(body), json))
|
||||
.header("Authorization", "Bearer " + authorization)
|
||||
.build());
|
||||
}
|
||||
|
||||
protected JsonObject sendDeleteRequest(String url, String authorization) throws IOException {
|
||||
return sendRequest(new Request.Builder()
|
||||
.url("http://localhost:8080" + url)
|
||||
.delete()
|
||||
.header("Authorization", "Bearer " + authorization)
|
||||
.build());
|
||||
}
|
||||
|
||||
private static int xSafeValue = 0;
|
||||
protected synchronized void createComputerInWorld(final ComputerTypes type, final UUID owner, final Consumer<String> ulidCallback) {
|
||||
final World world = Bukkit.getWorlds().get(0);
|
||||
final Location location = new Location(world, xSafeValue, 10, 0);
|
||||
xSafeValue += 10;
|
||||
location.getBlock().setType(Material.AIR);
|
||||
|
||||
ComputerRegistry.placeNewComputer(
|
||||
location, type, owner, (c) -> {
|
||||
ulidCallback.accept(c.getId());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
protected synchronized ComputerMetadata createComputerInItem(final String ulid, final ComputerTypes type, final UUID owner) {
|
||||
var metadata = new ComputerMetadata(
|
||||
ulid,
|
||||
NameGenerator.generateName(),
|
||||
UUID.randomUUID(),
|
||||
type,
|
||||
new String[0],
|
||||
null,
|
||||
owner,
|
||||
new UUID[0],
|
||||
false,
|
||||
0
|
||||
);
|
||||
ComputerRegistry.metadataStorage.storeData(ulid, metadata);
|
||||
return metadata;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2025 The Blazing Games Maintainers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.blazemcworld.blazinggames.testing;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Documented
|
||||
/**
|
||||
* Classes or methods annotated with this annotation are covered by the tests listed in the value.
|
||||
*
|
||||
* Useful if you're editing an annotated element to adjust tests acordingly.
|
||||
*/
|
||||
public @interface CoveredByTests {
|
||||
Class<? extends BlazingTest>[] value();
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright 2025 The Blazing Games Maintainers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.blazemcworld.blazinggames.testing;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import de.blazemcworld.blazinggames.BlazingGames;
|
||||
|
||||
public class TestBlazingGames extends BlazingGames {
|
||||
public static final int TEST_RUNNERS = 5;
|
||||
private static final ArrayList<TestList> tests = new ArrayList<>(List.of(TestList.values()));
|
||||
private static final ArrayList<TestList> failedTests = new ArrayList<>();
|
||||
private static boolean started = false;
|
||||
private static int remainingRunners = TEST_RUNNERS;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
try {
|
||||
super.onEnable();
|
||||
|
||||
if (!started) {
|
||||
started = true;
|
||||
|
||||
if (tests.isEmpty()) {
|
||||
getLogger().severe("No tests found!");
|
||||
exit(false);
|
||||
return;
|
||||
}
|
||||
|
||||
getLogger().info("Starting " + tests.size() + " tests with " + TEST_RUNNERS + " runners...");
|
||||
|
||||
int runners = TEST_RUNNERS > tests.size() ? tests.size() : TEST_RUNNERS;
|
||||
if (runners != TEST_RUNNERS) {
|
||||
getLogger().warning("Not enough tests to run with " + TEST_RUNNERS + " runners! Running with " + runners + " instead");
|
||||
remainingRunners = tests.size();
|
||||
}
|
||||
|
||||
for (int i = 0; i < runners; i++) {
|
||||
scheduleNextTest(null, false);
|
||||
}
|
||||
|
||||
getLogger().info("Tests starting soon...");
|
||||
} else {
|
||||
getLogger().severe("Plugin was loaded twice. Exiting.");
|
||||
exit(false);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
getLogger().severe("An unhandled exception occurred in onEnable. Exiting.");
|
||||
exit(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
try {
|
||||
super.onDisable();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
getLogger().severe("An unhandled exception occurred in onDisable. Exiting.");
|
||||
exit(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig() {}
|
||||
|
||||
@Override
|
||||
public void saveDefaultConfig() {}
|
||||
|
||||
@Override
|
||||
public @NotNull FileConfiguration getConfig() {
|
||||
var config = new YamlConfiguration();
|
||||
|
||||
// defaults (config.yml)
|
||||
try (
|
||||
InputStream stream = getClass().getResourceAsStream("/config.yml");
|
||||
Reader reader = new InputStreamReader(stream);
|
||||
) {
|
||||
config.setDefaults(YamlConfiguration.loadConfiguration(reader));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
// overrides (config.testing.yml)
|
||||
try (
|
||||
InputStream stream = getClass().getResourceAsStream("/config.testing.yml");
|
||||
Reader reader = new InputStreamReader(stream);
|
||||
) {
|
||||
config.load(reader);
|
||||
} catch (IOException | InvalidConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public static void exit(boolean success) {
|
||||
File file = new File("TESTS_RESULT");
|
||||
file.delete();
|
||||
try (FileWriter writer = new FileWriter(file)) {
|
||||
writer.write(success ? "true" : "false");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
Bukkit.getServer().shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void scheduleNextTest(final TestList currentTest, final boolean passed) {
|
||||
final TestList test = nextTest(currentTest, passed);
|
||||
if (test != null) {
|
||||
final int taskId = test.test.runAsync()
|
||||
? Bukkit.getScheduler().runTaskLaterAsynchronously(get(), new TestRunner(test, get().getLogger()), 10).getTaskId()
|
||||
: Bukkit.getScheduler().runTaskLater(get(), new TestRunner(test, get().getLogger()), 10).getTaskId();
|
||||
Bukkit.getScheduler().runTaskLater(get(), () -> runPreTestSync(test, taskId), 5);
|
||||
} else {
|
||||
remainingRunners--;
|
||||
if (remainingRunners <= 0) {
|
||||
final boolean isSuccess = failedTests.isEmpty();
|
||||
get().getLogger().info("All tests are done.");
|
||||
if (isSuccess) {
|
||||
get().getLogger().info("All tests passed! Exiting cleanly.");
|
||||
} else {
|
||||
get().getLogger().severe("Some tests failed:");
|
||||
for (TestList testList : failedTests) {
|
||||
get().getLogger().severe("* " + testList.name());
|
||||
}
|
||||
}
|
||||
Bukkit.getScheduler().runTaskLater(get(), () -> exit(isSuccess), 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void runPreTestSync(final TestList test, final int taskId) {
|
||||
try {
|
||||
test.test.preRunSync();
|
||||
} catch (Exception e) {
|
||||
BlazingGames.get().getLogger().severe("Failed to run preRunSync for " + test.name());
|
||||
Bukkit.getScheduler().cancelTask(taskId);
|
||||
scheduleNextTest(test, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized TestList nextTest(final TestList currentTest, final boolean passed) {
|
||||
if (currentTest != null) {
|
||||
if (!passed) {
|
||||
failedTests.add(currentTest);
|
||||
}
|
||||
}
|
||||
if (tests.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return tests.remove(0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2025 The Blazing Games Maintainers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.blazemcworld.blazinggames.testing;
|
||||
|
||||
public class TestFailedException extends Exception {
|
||||
public TestFailedException(Class<?> clazz, String message) {
|
||||
super("Test failed: " + clazz.getName() + ": " + message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2025 The Blazing Games Maintainers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.blazemcworld.blazinggames.testing;
|
||||
|
||||
import de.blazemcworld.blazinggames.testing.tests.*;
|
||||
|
||||
public enum TestList {
|
||||
LOGIN_FLOW(new LoginFlowTest()),
|
||||
UNLINK_FLOW(new UnlinkFlowTest()),
|
||||
RENAME_ENDPOINT(new RenameEndpointTest()),
|
||||
;
|
||||
|
||||
public final BlazingTest test;
|
||||
TestList(BlazingTest test) {
|
||||
this.test = test;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2025 The Blazing Games Maintainers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.blazemcworld.blazinggames.testing;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class TestRunner implements Runnable {
|
||||
private final TestList test;
|
||||
private final Logger logger;
|
||||
|
||||
public TestRunner(TestList test, Logger logger) {
|
||||
this.test = test;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
logger.info("Running test: " + test.name());
|
||||
boolean passed = test.test.run();
|
||||
if (!passed) {
|
||||
logger.severe("Test failed: " + test.name());
|
||||
} else {
|
||||
logger.info("Test passed: " + test.name());
|
||||
}
|
||||
TestBlazingGames.scheduleNextTest(test, passed);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright 2025 The Blazing Games Maintainers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.blazemcworld.blazinggames.testing.tests;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import de.blazemcworld.blazinggames.testing.BlazingTest;
|
||||
import de.blazemcworld.blazinggames.utils.GetGson;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class LoginFlowTest extends BlazingTest {
|
||||
@Override
|
||||
public boolean runAsync() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTest() throws Exception {
|
||||
// implementation note:
|
||||
// the server really doesn't care too much and allows you to submit
|
||||
// requests that aren't the same as in the html, such as json instead of form body or
|
||||
// giving the boolean as a literal instead of a string, and this test does use those.
|
||||
//
|
||||
// if we really wanted a test to make sure it worked perfectly, it may be better to set
|
||||
// up something that emulates a web browser and actually followed the redirects, which is
|
||||
// outside the scope of these tests.
|
||||
|
||||
String username = "LoginFlowTest";
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
||||
// server: send prepare code request
|
||||
JsonObject prepareBody = new JsonObject();
|
||||
prepareBody.addProperty("name", "login flow test");
|
||||
prepareBody.addProperty("contact", ".....");
|
||||
prepareBody.addProperty("purpose", "testing xd");
|
||||
prepareBody.add("permissions", new JsonArray());
|
||||
JsonObject prepareResponse = sendPostRequestUnauthenticated("/auth/prepare", prepareBody);
|
||||
assertBoolean("/auth/prepare", GetGson.getBoolean(prepareResponse, "success", new IllegalStateException()));
|
||||
String code = GetGson.getString(prepareResponse, "code", new IllegalArgumentException("Prepare endpoint missing code"));
|
||||
String key = GetGson.getString(prepareResponse, "key", new IllegalStateException("Prepare endpoint missing key"));
|
||||
|
||||
// client: send link request
|
||||
StringBuilder linkUrl = new StringBuilder("http://localhost:8080/auth/link");
|
||||
linkUrl.append("?code=").append(code);
|
||||
linkUrl.append("&mcname=").append(username);
|
||||
linkUrl.append("&mcuuid=").append(uuid.toString());
|
||||
Request linkRequest = new Request.Builder()
|
||||
.url(linkUrl.toString())
|
||||
.build();
|
||||
Response linkResponse = client.newCall(linkRequest).execute();
|
||||
assertEquals(302, linkResponse.code());
|
||||
|
||||
// client: send callback request
|
||||
StringBuilder callbackUrl = new StringBuilder("http://localhost:8080/auth/callback");
|
||||
callbackUrl.append("?code=").append(username).append(".").append(uuid.toString());
|
||||
callbackUrl.append("&state=").append(code);
|
||||
Request callbackRequest = new Request.Builder()
|
||||
.url(callbackUrl.toString())
|
||||
.build();
|
||||
Response callbackResponse = client.newCall(callbackRequest).execute();
|
||||
assertEquals(302, callbackResponse.code());
|
||||
String locationHeader = callbackResponse.header("Location");
|
||||
assertNotNull(locationHeader);
|
||||
|
||||
// parse for confirmation token
|
||||
String[] parts = locationHeader.split("\\?");
|
||||
assertBoolean("parts.length == 2", parts.length == 2);
|
||||
String[] params = parts[1].split("&");
|
||||
String confirmationToken = null;
|
||||
for (String param : params) {
|
||||
if (param.startsWith("token=")) {
|
||||
confirmationToken = param.split("=")[1];
|
||||
}
|
||||
}
|
||||
assertNotNull(confirmationToken);
|
||||
|
||||
// client: send pre consent request
|
||||
StringBuilder preConsentUrl = new StringBuilder("http://localhost:8080/auth/consent");
|
||||
preConsentUrl.append("?code=").append(code);
|
||||
preConsentUrl.append("&token=").append(confirmationToken);
|
||||
Request preConsentRequest = new Request.Builder()
|
||||
.url(preConsentUrl.toString())
|
||||
.get()
|
||||
.build();
|
||||
Response preConsentResponse = client.newCall(preConsentRequest).execute();
|
||||
assertEquals(200, preConsentResponse.code());
|
||||
// note: this is needed due to internal flow state checks
|
||||
|
||||
// client: send consent request
|
||||
JsonObject consentBody = new JsonObject();
|
||||
consentBody.addProperty("code", code);
|
||||
consentBody.addProperty("token", confirmationToken);
|
||||
consentBody.addProperty("verdict", true);
|
||||
Request consentRequest = new Request.Builder()
|
||||
.url("http://localhost:8080/auth/consent")
|
||||
.post(RequestBody.create(consentBody.toString(), json))
|
||||
.build();
|
||||
Response consentResponse = client.newCall(consentRequest).execute();
|
||||
assertEquals(200, consentResponse.code());
|
||||
|
||||
// server: send redeem request
|
||||
JsonObject redeemBody = new JsonObject();
|
||||
redeemBody.addProperty("key", key);
|
||||
JsonObject redeemResponse = sendPostRequestUnauthenticated("/auth/redeem", redeemBody);
|
||||
assertBoolean("/auth/redeem", GetGson.getBoolean(redeemResponse, "success", new IllegalStateException()));
|
||||
String token = GetGson.getString(redeemResponse, "token", new IllegalStateException("Redeem endpoint missing token"));
|
||||
|
||||
// server: send test request
|
||||
JsonObject testResponse = sendGetRequest("/auth/test", token);
|
||||
assertBoolean("/auth/test", GetGson.getBoolean(testResponse, "success", new IllegalStateException()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright 2025 The Blazing Games Maintainers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package de.blazemcworld.blazinggames.testing.tests;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import de.blazemcworld.blazinggames.computing.ComputerEditor;
|
||||
import de.blazemcworld.blazinggames.computing.ComputerMetadata;
|
||||
import de.blazemcworld.blazinggames.computing.ComputerRegistry;
|
||||
import de.blazemcworld.blazinggames.computing.api.Permission;
|
||||
import de.blazemcworld.blazinggames.computing.api.TokenManager;
|
||||
import de.blazemcworld.blazinggames.computing.types.ComputerTypes;
|
||||
import de.blazemcworld.blazinggames.testing.BlazingTest;
|
||||
import io.azam.ulidj.ULID;
|
||||
|
||||
public class RenameEndpointTest extends BlazingTest {
|
||||
private UUID owner;
|
||||
private String ulidWorld;
|
||||
|
||||
@Override
|
||||
public void preRunSync() throws Exception {
|
||||
owner = UUID.randomUUID();
|
||||
createComputerInWorld(ComputerTypes.CONSOLE, owner, (c) -> {
|
||||
ulidWorld = c;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean runAsync() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runTest() throws Exception {
|
||||
String newName = TokenManager.generateRandomString(8);
|
||||
String jwt = createSignedJWT(false, owner, Permission.READ_COMPUTERS, Permission.WRITE_COMPUTERS);
|
||||
|
||||
// world computer
|
||||
assertNotNull(owner, ulidWorld);
|
||||
JsonObject renameRequest1 = new JsonObject();
|
||||
renameRequest1.addProperty("id", ulidWorld);
|
||||
renameRequest1.addProperty("name", newName);
|
||||
JsonObject renameResponse1 = sendPatchRequest("/computers/rename", renameRequest1, jwt);
|
||||
assertBoolean("renaming world computer", renameResponse1.get("success").getAsBoolean());
|
||||
assertEquals(newName, ComputerRegistry.getComputerById(ulidWorld).getMetadata().name);
|
||||
assertEquals(newName, ComputerEditor.getMetadata(ulidWorld).name);
|
||||
|
||||
// item computer
|
||||
String ulidItem = ULID.random();
|
||||
createComputerInItem(ulidItem, ComputerTypes.CONSOLE, owner);
|
||||
|
||||
JsonObject renameRequest2 = new JsonObject();
|
||||
renameRequest2.addProperty("id", ulidItem);
|
||||
renameRequest2.addProperty("name", newName);
|
||||
JsonObject renameResponse2 = sendPatchRequest("/computers/rename", renameRequest2, jwt);
|
||||
assertBoolean("renaming item computer", renameResponse2.get("success").getAsBoolean());
|
||||
assertEquals(newName, ComputerEditor.getMetadata(ulidItem).name);
|
||||
|
||||
// unauthorized renaming
|
||||
String ulidNoAuth = ULID.random();
|
||||
String jwtNoAuth = createSignedJWT(false);
|
||||
ComputerMetadata metadataNoAuth = createComputerInItem(ulidNoAuth, ComputerTypes.CONSOLE, owner);
|
||||
String oldNameNoAuth = metadataNoAuth.name;
|
||||
|
||||
JsonObject renameRequest3 = new JsonObject();
|
||||
renameRequest3.addProperty("id", ulidNoAuth);
|
||||
renameRequest3.addProperty("name", newName);
|
||||
JsonObject renameResponse3 = sendPatchRequest("/computers/rename", renameRequest3, jwtNoAuth);
|
||||
assertBoolean("renaming with bad jwt", !renameResponse3.get("success").getAsBoolean());
|
||||
assertEquals(oldNameNoAuth, ComputerEditor.getMetadata(ulidNoAuth).name);
|
||||
|
||||
// permissionless renaming
|
||||
String ulidNoPerms = ULID.random();
|
||||
String jwtNoPerms = createSignedJWT(false);
|
||||
ComputerMetadata metadataNoPerms = createComputerInItem(ulidNoPerms, ComputerTypes.CONSOLE, owner);
|
||||
String oldNameNoPerms = metadataNoPerms.name;
|
||||
|
||||
JsonObject renameRequest4 = new JsonObject();
|
||||
renameRequest4.addProperty("id", ulidNoPerms);
|
||||
renameRequest4.addProperty("name", newName);
|
||||
JsonObject renameResponse4 = sendPatchRequest("/computers/rename", renameRequest4, jwtNoPerms);
|
||||
assertBoolean("renaming with missing permission", !renameResponse4.get("success").getAsBoolean());
|
||||
assertEquals(oldNameNoPerms, ComputerEditor.getMetadata(ulidNoPerms).name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2025 The Blazing Games Maintainers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package de.blazemcworld.blazinggames.testing.tests;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import de.blazemcworld.blazinggames.computing.api.LinkedUser;
|
||||
import de.blazemcworld.blazinggames.computing.api.impl.auth.AuthUnlinkEndpoint;
|
||||
import de.blazemcworld.blazinggames.testing.BlazingTest;
|
||||
import de.blazemcworld.blazinggames.utils.GetGson;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class UnlinkFlowTest extends BlazingTest {
|
||||
|
||||
@Override
|
||||
public boolean runAsync() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTest() throws Exception {
|
||||
LinkedUser linkedUser = createLinkedUser(false);
|
||||
String signed = LinkedUser.signLinkedUser(linkedUser);
|
||||
|
||||
// send test request 1
|
||||
JsonObject testResponse1 = sendGetRequest("/auth/test", signed);
|
||||
assertBoolean("/auth/test linked", GetGson.getBoolean(testResponse1, "success", new IllegalStateException()));
|
||||
|
||||
// send callback request
|
||||
StringBuilder callbackUrl = new StringBuilder("http://localhost:8080/auth/callback");
|
||||
callbackUrl.append("?code=").append(linkedUser.username()).append(".").append(linkedUser.uuid().toString());
|
||||
callbackUrl.append("&state=").append(AuthUnlinkEndpoint.MAGIC_UNLINK_STATE);
|
||||
Request callbackRequest = new Request.Builder()
|
||||
.url(callbackUrl.toString())
|
||||
.build();
|
||||
Response callbackResponse = client.newCall(callbackRequest).execute();
|
||||
assertEquals(302, callbackResponse.code());
|
||||
String locationHeader = callbackResponse.header("Location");
|
||||
assertNotNull(locationHeader);
|
||||
|
||||
// parse for confirmation token
|
||||
String[] parts = locationHeader.split("\\?");
|
||||
assertBoolean("parts.length == 2", parts.length == 2);
|
||||
String[] params = parts[1].split("&");
|
||||
String confirmationToken = null;
|
||||
for (String param : params) {
|
||||
if (param.startsWith("token=")) {
|
||||
confirmationToken = param.split("=")[1];
|
||||
}
|
||||
}
|
||||
assertNotNull(confirmationToken);
|
||||
|
||||
// send unlink confirm request
|
||||
JsonObject unlinkConfirmBody = new JsonObject();
|
||||
unlinkConfirmBody.addProperty("token", confirmationToken);
|
||||
unlinkConfirmBody.addProperty("verdict", true);
|
||||
Request unlinkConfirmRequest = new Request.Builder()
|
||||
.url("http://localhost:8080/auth/unlink-confirm")
|
||||
.post(RequestBody.create(unlinkConfirmBody.toString(), json))
|
||||
.build();
|
||||
Response unlinkConfirmResponse = client.newCall(unlinkConfirmRequest).execute();
|
||||
assertEquals(200, unlinkConfirmResponse.code());
|
||||
|
||||
// send test request 2
|
||||
JsonObject testResponse2 = sendGetRequest("/auth/test", signed);
|
||||
assertBoolean("/auth/test unlinked", !GetGson.getBoolean(testResponse2, "success", new IllegalStateException()));
|
||||
}
|
||||
}
|
52
src/main/java/de/blazemcworld/blazinggames/utils/Drops.java
Normal file
52
src/main/java/de/blazemcworld/blazinggames/utils/Drops.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2025 The Blazing Games Maintainers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package de.blazemcworld.blazinggames.utils;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class Drops extends ArrayList<ItemStack> {
|
||||
private int expToGive = 0;
|
||||
|
||||
public Drops() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Drops(Collection<ItemStack> drops) {
|
||||
this();
|
||||
this.addAll(drops);
|
||||
}
|
||||
|
||||
public Drops(ItemStack... drops) {
|
||||
this(List.of(drops));
|
||||
}
|
||||
|
||||
public int getExperienceDropped() {
|
||||
return expToGive;
|
||||
}
|
||||
|
||||
public void addExperience(int expAmount) {
|
||||
expToGive += expAmount;
|
||||
}
|
||||
|
||||
public void setExperience(int expAmount) {
|
||||
expToGive = expAmount;
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ package de.blazemcworld.blazinggames.utils;
|
|||
import de.blazemcworld.blazinggames.computing.ComputerRegistry;
|
||||
import de.blazemcworld.blazinggames.enchantments.sys.CustomEnchantments;
|
||||
import de.blazemcworld.blazinggames.enchantments.sys.EnchantmentHelper;
|
||||
import de.blazemcworld.blazinggames.events.BreakBlockEventListener;
|
||||
import de.blazemcworld.blazinggames.items.CustomItem;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
|
@ -26,8 +27,6 @@ import org.bukkit.entity.Player;
|
|||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
public class InventoryUtils {
|
||||
|
@ -69,17 +68,21 @@ public class InventoryUtils {
|
|||
}
|
||||
|
||||
public static void collectableDrop(Player player, Location location, ItemStack... drops) {
|
||||
collectableDrop(player, location, Arrays.asList(drops));
|
||||
collectableDrop(player, location, new Drops(drops));
|
||||
}
|
||||
|
||||
public static void collectableDrop(Player player, Location location, Collection<ItemStack> drops) {
|
||||
public static void collectableDrop(Player player, Location location, Drops drops) {
|
||||
if (EnchantmentHelper.hasActiveCustomEnchantment(player.getInventory().getItemInMainHand(), CustomEnchantments.COLLECTABLE)) {
|
||||
player.giveExp(drops.getExperienceDropped(), true);
|
||||
|
||||
for (ItemStack drop : drops) {
|
||||
for (Map.Entry<Integer, ItemStack> overflow : player.getInventory().addItem(drop).entrySet()) {
|
||||
drop(player, location, overflow.getValue());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BreakBlockEventListener.awardBlock(location, drops.getExperienceDropped(), player);
|
||||
|
||||
for (ItemStack drop : drops) {
|
||||
drop(player, location, drop);
|
||||
}
|
||||
|
|
|
@ -68,54 +68,54 @@ public class ItemUtils {
|
|||
case WHITE_WOOL, LIGHT_GRAY_WOOL, GRAY_WOOL, BLACK_WOOL, BROWN_WOOL, RED_WOOL, ORANGE_WOOL, YELLOW_WOOL,
|
||||
LIME_WOOL, GREEN_WOOL, CYAN_WOOL, LIGHT_BLUE_WOOL, BLUE_WOOL, PURPLE_WOOL, MAGENTA_WOOL, PINK_WOOL
|
||||
-> Material.WHITE_WOOL;
|
||||
case OAK_CHEST_BOAT, SPRUCE_CHEST_BOAT, BIRCH_CHEST_BOAT, JUNGLE_CHEST_BOAT, ACACIA_CHEST_BOAT, DARK_OAK_CHEST_BOAT, MANGROVE_CHEST_BOAT, CHERRY_CHEST_BOAT, BAMBOO_CHEST_RAFT
|
||||
case OAK_CHEST_BOAT, SPRUCE_CHEST_BOAT, BIRCH_CHEST_BOAT, JUNGLE_CHEST_BOAT, ACACIA_CHEST_BOAT, DARK_OAK_CHEST_BOAT, MANGROVE_CHEST_BOAT, CHERRY_CHEST_BOAT, BAMBOO_CHEST_RAFT, PALE_OAK_CHEST_BOAT
|
||||
-> Material.OAK_CHEST_BOAT;
|
||||
case OAK_BOAT, SPRUCE_BOAT, BIRCH_BOAT, JUNGLE_BOAT, ACACIA_BOAT, DARK_OAK_BOAT, MANGROVE_BOAT, CHERRY_BOAT, BAMBOO_RAFT
|
||||
case OAK_BOAT, SPRUCE_BOAT, BIRCH_BOAT, JUNGLE_BOAT, ACACIA_BOAT, DARK_OAK_BOAT, MANGROVE_BOAT, CHERRY_BOAT, BAMBOO_RAFT, PALE_OAK_BOAT
|
||||
-> Material.OAK_BOAT;
|
||||
case OAK_WOOD, SPRUCE_WOOD, BIRCH_WOOD, JUNGLE_WOOD, ACACIA_WOOD, DARK_OAK_WOOD, MANGROVE_WOOD, CHERRY_WOOD,
|
||||
case OAK_WOOD, SPRUCE_WOOD, BIRCH_WOOD, JUNGLE_WOOD, ACACIA_WOOD, DARK_OAK_WOOD, MANGROVE_WOOD, CHERRY_WOOD, PALE_OAK_WOOD,
|
||||
WARPED_HYPHAE, CRIMSON_HYPHAE
|
||||
-> Material.OAK_WOOD;
|
||||
case STRIPPED_OAK_WOOD, STRIPPED_SPRUCE_WOOD, STRIPPED_BIRCH_WOOD, STRIPPED_JUNGLE_WOOD, STRIPPED_ACACIA_WOOD, STRIPPED_DARK_OAK_WOOD, STRIPPED_MANGROVE_WOOD, STRIPPED_CHERRY_WOOD,
|
||||
case STRIPPED_OAK_WOOD, STRIPPED_SPRUCE_WOOD, STRIPPED_BIRCH_WOOD, STRIPPED_JUNGLE_WOOD, STRIPPED_ACACIA_WOOD, STRIPPED_DARK_OAK_WOOD, STRIPPED_MANGROVE_WOOD, STRIPPED_CHERRY_WOOD, STRIPPED_PALE_OAK_WOOD,
|
||||
STRIPPED_WARPED_HYPHAE, STRIPPED_CRIMSON_HYPHAE
|
||||
-> Material.STRIPPED_OAK_WOOD;
|
||||
case OAK_LOG, SPRUCE_LOG, BIRCH_LOG, JUNGLE_LOG, ACACIA_LOG, DARK_OAK_LOG, MANGROVE_LOG, CHERRY_LOG,
|
||||
case OAK_LOG, SPRUCE_LOG, BIRCH_LOG, JUNGLE_LOG, ACACIA_LOG, DARK_OAK_LOG, MANGROVE_LOG, CHERRY_LOG, PALE_OAK_LOG,
|
||||
WARPED_STEM, CRIMSON_STEM, BAMBOO_BLOCK
|
||||
-> Material.OAK_LOG;
|
||||
case STRIPPED_OAK_LOG, STRIPPED_SPRUCE_LOG, STRIPPED_BIRCH_LOG, STRIPPED_JUNGLE_LOG, STRIPPED_ACACIA_LOG, STRIPPED_DARK_OAK_LOG, STRIPPED_MANGROVE_LOG, STRIPPED_CHERRY_LOG,
|
||||
case STRIPPED_OAK_LOG, STRIPPED_SPRUCE_LOG, STRIPPED_BIRCH_LOG, STRIPPED_JUNGLE_LOG, STRIPPED_ACACIA_LOG, STRIPPED_DARK_OAK_LOG, STRIPPED_MANGROVE_LOG, STRIPPED_CHERRY_LOG, STRIPPED_PALE_OAK_LOG,
|
||||
STRIPPED_WARPED_STEM, STRIPPED_CRIMSON_STEM, STRIPPED_BAMBOO_BLOCK
|
||||
-> Material.STRIPPED_OAK_LOG;
|
||||
case OAK_FENCE_GATE, SPRUCE_FENCE_GATE, BIRCH_FENCE_GATE, JUNGLE_FENCE_GATE, ACACIA_FENCE_GATE, DARK_OAK_FENCE_GATE, MANGROVE_FENCE_GATE, CHERRY_FENCE_GATE,
|
||||
WARPED_FENCE_GATE, CRIMSON_FENCE_GATE, BAMBOO_FENCE_GATE
|
||||
WARPED_FENCE_GATE, CRIMSON_FENCE_GATE, BAMBOO_FENCE_GATE, PALE_OAK_FENCE_GATE
|
||||
-> Material.OAK_FENCE_GATE;
|
||||
case OAK_FENCE, SPRUCE_FENCE, BIRCH_FENCE, JUNGLE_FENCE, ACACIA_FENCE, DARK_OAK_FENCE, MANGROVE_FENCE, CHERRY_FENCE,
|
||||
WARPED_FENCE, CRIMSON_FENCE, BAMBOO_FENCE
|
||||
WARPED_FENCE, CRIMSON_FENCE, BAMBOO_FENCE, PALE_OAK_FENCE
|
||||
-> Material.OAK_FENCE;
|
||||
case OAK_SIGN, SPRUCE_SIGN, BIRCH_SIGN, JUNGLE_SIGN, ACACIA_SIGN, DARK_OAK_SIGN, MANGROVE_SIGN, CHERRY_SIGN,
|
||||
WARPED_SIGN, CRIMSON_SIGN, BAMBOO_SIGN
|
||||
WARPED_SIGN, CRIMSON_SIGN, BAMBOO_SIGN, PALE_OAK_SIGN
|
||||
-> Material.OAK_SIGN;
|
||||
case OAK_HANGING_SIGN, SPRUCE_HANGING_SIGN, BIRCH_HANGING_SIGN, JUNGLE_HANGING_SIGN, ACACIA_HANGING_SIGN, DARK_OAK_HANGING_SIGN, MANGROVE_HANGING_SIGN, CHERRY_HANGING_SIGN,
|
||||
WARPED_HANGING_SIGN, CRIMSON_HANGING_SIGN, BAMBOO_HANGING_SIGN
|
||||
WARPED_HANGING_SIGN, CRIMSON_HANGING_SIGN, BAMBOO_HANGING_SIGN, PALE_OAK_HANGING_SIGN
|
||||
-> Material.OAK_HANGING_SIGN;
|
||||
case OAK_BUTTON, SPRUCE_BUTTON, BIRCH_BUTTON, JUNGLE_BUTTON, ACACIA_BUTTON, DARK_OAK_BUTTON, MANGROVE_BUTTON, CHERRY_BUTTON,
|
||||
WARPED_BUTTON, CRIMSON_BUTTON, BAMBOO_BUTTON
|
||||
WARPED_BUTTON, CRIMSON_BUTTON, BAMBOO_BUTTON, PALE_OAK_BUTTON
|
||||
-> Material.OAK_BUTTON;
|
||||
case OAK_DOOR, SPRUCE_DOOR, BIRCH_DOOR, JUNGLE_DOOR, ACACIA_DOOR, DARK_OAK_DOOR, MANGROVE_DOOR, CHERRY_DOOR,
|
||||
WARPED_DOOR, CRIMSON_DOOR, BAMBOO_DOOR
|
||||
WARPED_DOOR, CRIMSON_DOOR, BAMBOO_DOOR, PALE_OAK_DOOR
|
||||
-> Material.OAK_DOOR;
|
||||
case OAK_PRESSURE_PLATE, SPRUCE_PRESSURE_PLATE, BIRCH_PRESSURE_PLATE, JUNGLE_PRESSURE_PLATE, ACACIA_PRESSURE_PLATE, DARK_OAK_PRESSURE_PLATE, MANGROVE_PRESSURE_PLATE, CHERRY_PRESSURE_PLATE,
|
||||
WARPED_PRESSURE_PLATE, CRIMSON_PRESSURE_PLATE, BAMBOO_PRESSURE_PLATE
|
||||
WARPED_PRESSURE_PLATE, CRIMSON_PRESSURE_PLATE, BAMBOO_PRESSURE_PLATE, PALE_OAK_PRESSURE_PLATE
|
||||
-> Material.OAK_PRESSURE_PLATE;
|
||||
case OAK_SLAB, SPRUCE_SLAB, BIRCH_SLAB, JUNGLE_SLAB, ACACIA_SLAB, DARK_OAK_SLAB, MANGROVE_SLAB, CHERRY_SLAB,
|
||||
WARPED_SLAB, CRIMSON_SLAB, BAMBOO_SLAB, PETRIFIED_OAK_SLAB, BAMBOO_MOSAIC_SLAB
|
||||
WARPED_SLAB, CRIMSON_SLAB, BAMBOO_SLAB, PETRIFIED_OAK_SLAB, BAMBOO_MOSAIC_SLAB, PALE_OAK_SLAB
|
||||
-> Material.OAK_SLAB;
|
||||
case OAK_STAIRS, SPRUCE_STAIRS, BIRCH_STAIRS, JUNGLE_STAIRS, ACACIA_STAIRS, DARK_OAK_STAIRS, MANGROVE_STAIRS, CHERRY_STAIRS,
|
||||
WARPED_STAIRS, CRIMSON_STAIRS, BAMBOO_STAIRS, BAMBOO_MOSAIC_STAIRS
|
||||
WARPED_STAIRS, CRIMSON_STAIRS, BAMBOO_STAIRS, BAMBOO_MOSAIC_STAIRS, PALE_OAK_STAIRS
|
||||
-> Material.OAK_STAIRS;
|
||||
case OAK_TRAPDOOR, SPRUCE_TRAPDOOR, BIRCH_TRAPDOOR, JUNGLE_TRAPDOOR, ACACIA_TRAPDOOR, DARK_OAK_TRAPDOOR, MANGROVE_TRAPDOOR, CHERRY_TRAPDOOR,
|
||||
WARPED_TRAPDOOR, CRIMSON_TRAPDOOR, BAMBOO_TRAPDOOR
|
||||
WARPED_TRAPDOOR, CRIMSON_TRAPDOOR, BAMBOO_TRAPDOOR, PALE_OAK_TRAPDOOR
|
||||
-> Material.OAK_TRAPDOOR;
|
||||
case OAK_PLANKS, SPRUCE_PLANKS, BIRCH_PLANKS, JUNGLE_PLANKS, ACACIA_PLANKS, DARK_OAK_PLANKS, MANGROVE_PLANKS, CHERRY_PLANKS,
|
||||
WARPED_PLANKS, CRIMSON_PLANKS, BAMBOO_PLANKS, BAMBOO_MOSAIC
|
||||
WARPED_PLANKS, CRIMSON_PLANKS, BAMBOO_PLANKS, BAMBOO_MOSAIC, PALE_OAK_PLANKS
|
||||
-> Material.OAK_PLANKS;
|
||||
default -> mat;
|
||||
};
|
||||
|
|
|
@ -18,10 +18,15 @@ package de.blazemcworld.blazinggames.utils;
|
|||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import de.blazemcworld.blazinggames.data.DataStorage;
|
||||
import de.blazemcworld.blazinggames.data.compression.GZipCompressionProvider;
|
||||
import de.blazemcworld.blazinggames.data.name.UUIDNameProvider;
|
||||
import de.blazemcworld.blazinggames.data.storage.PropertiesStorageProvider;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
|
||||
public class PlayerConfig {
|
||||
|
@ -48,6 +53,68 @@ public class PlayerConfig {
|
|||
|
||||
|
||||
|
||||
public void updatePlayer(Player player) {
|
||||
Component name = buildNameComponent(player.getName(), player.isOp());
|
||||
player.displayName(name);
|
||||
player.playerListName(name);
|
||||
}
|
||||
|
||||
public Component buildNameComponent(String playerName, boolean isOp) {
|
||||
Component username;
|
||||
if (getDisplayName() != null && !getDisplayName().equals(playerName)) {
|
||||
username = Component.text(getDisplayName()).hoverEvent(HoverEvent.showText(Component.text("Real name: " + playerName)));
|
||||
} else {
|
||||
username = Component.text(playerName).hoverEvent(HoverEvent.showText(Component.text("Real name: " + playerName)));
|
||||
}
|
||||
|
||||
if (getNameColor() != null) {
|
||||
username = username.color(getNameColor());
|
||||
}
|
||||
|
||||
if (getPronouns() != null) {
|
||||
username = username.appendSpace().append(Component.text("(" + getPronouns() + ")")
|
||||
.color(NamedTextColor.GRAY).hoverEvent(HoverEvent.showText(Component.text("Pronouns"))));
|
||||
}
|
||||
|
||||
if (isOp) {
|
||||
username = username.appendSpace().append(Component.text("\u266E").color(NamedTextColor.RED)
|
||||
.hoverEvent(HoverEvent.showText(Component.text("Server Operator"))));
|
||||
}
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
public Component buildNameComponentShort(String playerName, boolean isOp) {
|
||||
return Component.text(getDisplayName() != null ? getDisplayName() : playerName)
|
||||
.color(getNameColor() != null ? getNameColor() : NamedTextColor.WHITE)
|
||||
.hoverEvent(HoverEvent.showText(Component.text("Real name: " + playerName)
|
||||
.appendNewline().append(Component.text("Pronouns: " + (getPronouns() != null ? getPronouns() : "None specified")))
|
||||
.appendNewline().append(Component.text("Server Operator: " + (isOp ? "Yes" : "No")))));
|
||||
}
|
||||
|
||||
public String buildNameString(String playerName, boolean isOp) {
|
||||
StringBuilder username = new StringBuilder();
|
||||
if (getDisplayName() != null && !getDisplayName().equals(playerName)) {
|
||||
username.append(getDisplayName()).append(" [aka ").append(playerName).append("]");
|
||||
} else {
|
||||
username.append(playerName);
|
||||
}
|
||||
if (getPronouns() != null) {
|
||||
username.append(" (").append(getPronouns()).append(")");
|
||||
}
|
||||
if (isOp) {
|
||||
username.append(" \u266E");
|
||||
}
|
||||
|
||||
return username.toString();
|
||||
}
|
||||
|
||||
public String buildNameStringShort(String playerName) {
|
||||
return getDisplayName() != null ? getDisplayName() : playerName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getDisplayName() {
|
||||
String value = props.getProperty("displayname", null);
|
||||
if (value == null || value.isBlank()) return null;
|
||||
|
|
|
@ -24,6 +24,7 @@ import com.google.gson.TypeAdapter;
|
|||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import org.bukkit.World;
|
||||
|
||||
/**
|
||||
* Location represented as a string
|
||||
|
@ -74,6 +75,41 @@ public class TextLocation {
|
|||
}
|
||||
}
|
||||
|
||||
public static Location deserializeUserInput(World world, String serialized) {
|
||||
if (serialized != null && !serialized.isEmpty()) {
|
||||
String[] split = serialized.split(" ");
|
||||
switch (split.length) {
|
||||
case 6: { // world, x, y, z, yaw, pitch
|
||||
String worldName = split[0];
|
||||
double x = Double.parseDouble(split[1]);
|
||||
double y = Double.parseDouble(split[2]);
|
||||
double z = Double.parseDouble(split[3]);
|
||||
float yaw = Float.parseFloat(split[4]);
|
||||
float pitch = Float.parseFloat(split[5]);
|
||||
return new Location(Bukkit.getWorld(worldName), x, y, z, yaw, pitch);
|
||||
}
|
||||
case 4: { // world, x, y, z
|
||||
String worldName = split[0];
|
||||
double x = Double.parseDouble(split[1]);
|
||||
double y = Double.parseDouble(split[2]);
|
||||
double z = Double.parseDouble(split[3]);
|
||||
return new Location(Bukkit.getWorld(worldName), x, y, z);
|
||||
}
|
||||
case 3: { // x, y, z
|
||||
double x = Double.parseDouble(split[0]);
|
||||
double y = Double.parseDouble(split[1]);
|
||||
double z = Double.parseDouble(split[2]);
|
||||
return new Location(world, x, y, z);
|
||||
}
|
||||
default: {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class LocationTypeAdapter extends TypeAdapter<Location> {
|
||||
@Override
|
||||
public void write(JsonWriter out, Location value) throws IOException {
|
||||
|
|
32
src/main/resources/config.testing.yml
Normal file
32
src/main/resources/config.testing.yml
Normal file
|
@ -0,0 +1,32 @@
|
|||
# overrides of config.yml for when unit testing is enabled
|
||||
|
||||
jda:
|
||||
enabled: false
|
||||
|
||||
logging:
|
||||
log-error: true
|
||||
log-info: true
|
||||
log-debug: true
|
||||
notify-ops-on-error: false
|
||||
|
||||
computing:
|
||||
disable-computers: false
|
||||
privileges:
|
||||
chunkloading: true
|
||||
net: true
|
||||
|
||||
resource-packs:
|
||||
enabled: true
|
||||
|
||||
authorization:
|
||||
microsoft:
|
||||
spoof-ms-server: true
|
||||
jwt:
|
||||
secret-key: randomize-on-server-start
|
||||
secret-key-is-password: false
|
||||
|
||||
services:
|
||||
blazing-api:
|
||||
enabled: true
|
||||
blazing-wss:
|
||||
enabled: true
|
|
@ -1,6 +1,6 @@
|
|||
name: blazinggames
|
||||
version: '${version}'
|
||||
main: de.blazemcworld.blazinggames.BlazingGames
|
||||
main: '${launchClass}'
|
||||
api-version: '1.21.4'
|
||||
prefix: BlazingGames
|
||||
authors: [BlazeMCworld, sbot50, 'Ivy Collective (ivyc.)', XTerPL]
|
||||
|
@ -41,7 +41,7 @@ commands:
|
|||
permission: blazinggames.customenchant
|
||||
customgive:
|
||||
description: "Gives you a specific custom item with a specified count"
|
||||
usage: /customgive <custom item> [count]
|
||||
usage: /customgive <custom item> [count] [context]
|
||||
permission: blazinggames.customgive
|
||||
killme:
|
||||
description: "Kills you. Painfully."
|
||||
|
@ -50,9 +50,10 @@ commands:
|
|||
playtime:
|
||||
description: "See how much time you and your friends have wasted on this stupid server."
|
||||
usage: /playtime [player]
|
||||
config:
|
||||
description: "Change display settings for your player. Tab complete for available options."
|
||||
usage: /config <param> [...value]
|
||||
display:
|
||||
description: "Change nameplate display settings for your player."
|
||||
usage: /display [name|pronouns|color] [value]
|
||||
aliases: [config, nick]
|
||||
setaltar:
|
||||
description: "Set altar with specific level at current location"
|
||||
usage: /setaltar <level>
|
||||
|
|
Loading…
Reference in a new issue