Compare commits

...
8 Commits
16 changed files with 590 additions and 162 deletions
Vendored
+7 -1
View File
@@ -3,7 +3,13 @@ pipeline {
stages {
stage('Gradle') {
steps {
sh './gradlew build'
withCredentials([usernamePassword(credentialsId: 'alttd-snapshot-user', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
sh '''
set +x
chmod +x gradlew
./gradlew build -PalttdSnapshotUsername=$USERNAME -PalttdSnapshotPassword=$PASSWORD
'''
}
}
}
stage('Archive') {
+36 -18
View File
@@ -1,17 +1,19 @@
import java.io.ByteArrayOutputStream
import java.io.FileOutputStream
import java.net.URL
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription
import net.minecrell.pluginyml.paper.PaperPluginDescription
plugins {
`java-library`
`maven-publish`
id("xyz.jpenilla.run-paper") version "2.3.0"
id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
id("de.eldoria.plugin-yml.paper") version "0.8.0"
}
dependencies {
compileOnly("com.alttd.cosmos:cosmos-api:26.2.build.17-stable")
compileOnly("com.alttd.altitudeapi:AltitudeAPI:0.0.3")
// compileOnly("com.alttd.altitudeapi:AltitudeAPI:0.0.3")
compileOnly("com.github.decentsoftware-eu:decentholograms:2.8.9")
compileOnly("org.jetbrains:annotations:16.0.2")
testImplementation("org.powermock:powermock-module-junit4:1.7.4")
@@ -19,7 +21,7 @@ dependencies {
}
group = "com.alttd.altitudetag"
version = System.getenv("BUILD_NUMBER") ?: gitCommit()
version = System.getenv("BUILD_NUMBER") ?: "DEV-BUILD"
description = "AltitudeTag"
publishing {
@@ -60,17 +62,17 @@ tasks {
}
runDirectory.set(dir)
val fileName = "/galaxy.jar"
val fileName = "/cosmos.jar"
val file = File(dir.path + fileName)
if (!file.parentFile.exists()) {
file.parentFile.mkdirs()
}
if (!file.exists()) {
download("https://repo.destro.xyz/private/com/alttd/Galaxy-Server/Galaxy-paperclip-1.20.4-R0.1-SNAPSHOT-reobf.jar", file)
download("https://jenkins.destro.xyz/job/Cosmos/lastSuccessfulBuild/artifact/cosmos-server/build/libs/cosmos-paperclip-26.2.build.17-stable.jar", file)
}
serverJar(file)
minecraftVersion("1.20.4")
minecraftVersion("26.2")
}
}
@@ -82,21 +84,37 @@ fun download(link: String, path: File) {
}
}
fun gitCommit(): String {
// val os = ByteArrayOutputStream()
// project.exec {
// commandLine = "git rev-parse --short HEAD".split(" ")
// standardOutput = os
// }
// return String(os.toByteArray()).trim()
return "FIXME"
}
bukkit {
paper {
name = rootProject.name
main = "$group.${rootProject.name}"
bootstrapper = "$group.${rootProject.name}Bootstrap"
version = "${rootProject.version}"
apiVersion = "1.21"
authors = listOf("Michael Ziluck", "destro174")
depend = listOf("DecentHolograms")
serverDependencies {
register("DecentHolograms") {
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
}
}
permissions {
register("tag.play") {
description = "Base permission for the ${rootProject.name} plugin."
default = BukkitPluginDescription.Permission.Default.FALSE
}
register("tag.commands.admin") {
description = "Admin permission for the ${rootProject.name} plugin."
default = BukkitPluginDescription.Permission.Default.FALSE
children = listOf(
"tag.play"
)
}
register("tag.commands.admin.location") {
description = "Admin permission for setting the scoreboard location."
default = BukkitPluginDescription.Permission.Default.FALSE
children = listOf(
"tag.play",
"tag.commands.admin"
)
}
}
}
@@ -1,20 +1,23 @@
package com.alttd.altitudetag;
import java.io.File;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Consumer;
import com.alttd.altitudeapi.commands.CommandHandler;
import com.alttd.altitudeapi.commands.CommandLang;
import com.alttd.altitudetag.commands.TagCommand;
import com.alttd.altitudetag.configuration.Config;
import com.alttd.altitudetag.configuration.Lang;
import com.alttd.altitudetag.listeners.ConnectionListener;
import com.alttd.altitudetag.listeners.InteractListener;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import org.bukkit.Bukkit;
import org.bukkit.boss.BossBar;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull;
@@ -48,13 +51,6 @@ public class AltitudeTag extends JavaPlugin
reloadConfiguration();
// update the CommandLang values
CommandLang.NO_PERMISSION.setValue(Lang.NO_PERMS.getRawMessage()[0]);
CommandLang.HEADER_FOOTER.setValue(Lang.HEADER_FOOTER.getRawMessage()[0]);
CommandLang.NO_SUBS.setValue(Lang.NO_SUBS.getRawMessage()[0]);
CommandLang.ONLY_PLAYERS.setValue(Lang.ONLY_PLAYERS.getRawMessage()[0]);
CommandLang.USAGE_FORMAT.setValue(Lang.USAGE.getRawMessage()[0]);
try
{
TagConnection.initialize();
@@ -71,11 +67,18 @@ public class AltitudeTag extends JavaPlugin
NotificationHandler.loadBossBar();
CommandHandler.initialize();
CommandHandler.getInstance().registerCommand(new TagCommand(), this);
Bukkit.getPluginManager().registerEvents(new ConnectionListener(), this);
Bukkit.getPluginManager().registerEvents(new InteractListener(), this);
registerCommands();
}
private void registerCommands() {
LifecycleEventManager<Plugin> manager = this.getLifecycleManager();
manager.registerEventHandler(LifecycleEvents.COMMANDS, event -> {
final Commands commands = event.registrar();
commands.register(new TagCommand().command(), "Tag, you're it!", List.of("tags", "tagging", "tagger"));
});
}
private static void reloadConfiguration()
@@ -0,0 +1,13 @@
package com.alttd.altitudetag;
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
@SuppressWarnings("UnstableApiUsage")
public class AltitudeTagBootstrap implements PluginBootstrap {
@Override
public void bootstrap(BootstrapContext context) {}
}
@@ -1,20 +0,0 @@
package com.alttd.altitudetag;
public enum Permission
{
COMMAND_ADMIN("tag.commands.admin"),
COMMAND_ADMIN_LOCATION("tag.commands.admin.location");
private String permission;
private Permission(String permission)
{
this.permission = permission;
}
public String getPermission()
{
return permission;
}
}
@@ -1,15 +0,0 @@
package com.alttd.altitudetag.commands;
import com.alttd.altitudeapi.commands.ValidBaseCommand;
import com.alttd.altitudetag.Permission;
import com.alttd.altitudetag.commands.admin.TagAdminLocationCommand;
public class TagAdminCommand extends ValidBaseCommand
{
protected TagAdminCommand()
{
super("admin", "Management commands", Permission.COMMAND_ADMIN.getPermission(), new String[]{ "a" });
addSubCommand(new TagAdminLocationCommand());
}
}
@@ -1,32 +1,55 @@
package com.alttd.altitudetag.commands;
import com.alttd.altitudeapi.commands.ValidBaseCommand;
import com.alttd.altitudetag.AltitudeTag;
import com.alttd.altitudetag.Leaderboard;
import com.alttd.altitudetag.configuration.Config;
import com.alttd.altitudetag.configuration.Lang;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.tree.LiteralCommandNode;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class TagCommand extends ValidBaseCommand
public class TagCommand
{
public TagCommand()
{
super("tag", "Tag, you're it!", "tag.play", new String[]{ "tags", "tagging", "tagger" });
public @NotNull LiteralCommandNode<CommandSourceStack> command() {
final LiteralArgumentBuilder<CommandSourceStack> builder =
Commands.literal("tag")
.requires(commandSourceStack ->
commandSourceStack.getSender() instanceof Player player &&
player.hasPermission("tag.play")
)
.then(Commands.literal("admin")
.requires(commandSourceStack ->
commandSourceStack.getSender() instanceof Player player &&
player.hasPermission("tag.commands.admin")
)
.then(Commands.literal("location")
.requires(commandSourceStack ->
commandSourceStack.getSender() instanceof Player player &&
player.hasPermission("tag.commands.admin.location")
)
.executes((source) -> {
if (!(source.getSource().getSender() instanceof Player player))
return Command.SINGLE_SUCCESS;
addSubCommand(new TagAdminCommand());
}
Leaderboard.setLocation(player.getLocation());
Lang.SET_LEADERBOARD_LOCATION.send(player);
@Override
public void help(CommandSender sender, String[] label)
{
if (sender.hasPermission(getSubCommand("admin").getPermission()))
{
sender.sendMessage(Lang.renderString(Config.NOTIFICATION_GLOBAL_BOSS_BAR_MESSAGE.getValue(),
"{player}", Bukkit.getOfflinePlayer(AltitudeTag.getTagger()).getName()));
}
else
{
super.help(sender, label);
}
return Command.SINGLE_SUCCESS;
})
)
)
.executes((source) -> {
source.getSource().getSender()
.sendMessage(Lang.renderString(Config.NOTIFICATION_GLOBAL_BOSS_BAR_MESSAGE.getValue(),
"{player}", Bukkit.getOfflinePlayer(AltitudeTag.getTagger()).getName()));
return Command.SINGLE_SUCCESS;
})
;
return builder.build();
}
}
}
@@ -1,33 +0,0 @@
package com.alttd.altitudetag.commands.admin;
import java.util.List;
import com.alttd.altitudeapi.commands.CommandArgument;
import com.alttd.altitudeapi.commands.ValidCommand;
import com.alttd.altitudetag.Leaderboard;
import com.alttd.altitudetag.Permission;
import com.alttd.altitudetag.configuration.Lang;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class TagAdminLocationCommand extends ValidCommand
{
public TagAdminLocationCommand()
{
super("location",
"Sets the leaderboard location",
Permission.COMMAND_ADMIN_LOCATION.getPermission(),
true,
new String[]{ "loc", "setloc", "setlocation", "leaderboard", "board" });
}
@Override
public void validRun(CommandSender commandSender, String[] strings, List<CommandArgument<?>> list)
{
Player player = (Player) commandSender;
Leaderboard.setLocation(player.getLocation());
Lang.SET_LEADERBOARD_LOCATION.send(player);
}
}
@@ -1,22 +0,0 @@
package com.alttd.altitudetag.commands.parsers;
import java.util.List;
import com.alttd.altitudeapi.commands.CommandHandler;
import com.alttd.altitudeapi.commands.Parser;
import org.bukkit.command.CommandSender;
public class StringParser implements Parser<String>
{
@Override
public String parseArgument(CommandSender sender, String[] label, String rawArgument)
{
return rawArgument;
}
@Override
public List<String> getRecommendations(CommandSender sender, String lastWord)
{
return CommandHandler.defaultTabComplete(sender, lastWord);
}
}
@@ -2,8 +2,8 @@ package com.alttd.altitudetag.configuration;
import java.util.Objects;
import com.alttd.altitudeapi.utils.MutableValue;
import com.alttd.altitudetag.AltitudeTag;
import com.alttd.altitudetag.utils.MutableValue;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.FileConfiguration;
@@ -3,9 +3,9 @@ package com.alttd.altitudetag.configuration;
import java.io.File;
import java.util.Arrays;
import com.alttd.altitudeapi.utils.CollectionUtils;
import com.alttd.altitudeapi.utils.StringUtils;
import com.alttd.altitudetag.AltitudeTag;
import com.alttd.altitudetag.utils.CollectionUtils;
import com.alttd.altitudetag.utils.StringUtils;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
@@ -17,19 +17,16 @@ public class InteractListener implements Listener
@EventHandler
public void onHit(EntityDamageByEntityEvent event)
{
if (!(event.getDamager() instanceof Player) || !(event.getEntity() instanceof Player))
if (!(event.getDamager() instanceof Player tagger) || !(event.getEntity() instanceof Player tagged))
{
return;
}
final Player tagger = (Player) event.getDamager();
if (!AltitudeTag.getTagger().equals(tagger.getUniqueId()))
{
return;
}
final Player tagged = (Player) event.getEntity();
// check for time since last tag
if (lastTagTime != -1 && Config.TAG_DELAY_ENABLED.getValue() && (System.currentTimeMillis() - lastTagTime) / 50 < Config.TAG_DELAY_DURATION.getValue())
@@ -16,19 +16,13 @@ public class BarUtils
*/
public static BarStyle parseBarStyle(int style)
{
switch (style)
{
case 6:
return BarStyle.SEGMENTED_6;
case 10:
return BarStyle.SEGMENTED_10;
case 12:
return BarStyle.SEGMENTED_12;
case 20:
return BarStyle.SEGMENTED_20;
default:
return BarStyle.SOLID;
}
return switch (style) {
case 6 -> BarStyle.SEGMENTED_6;
case 10 -> BarStyle.SEGMENTED_10;
case 12 -> BarStyle.SEGMENTED_12;
case 20 -> BarStyle.SEGMENTED_20;
default -> BarStyle.SOLID;
};
}
/**
@@ -0,0 +1,250 @@
package com.alttd.altitudetag.utils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
public class CollectionUtils
{
private final static Map<Class<?>, Method> nameMethods = new HashMap<>();
/**
* Retrieves the last value of the given list. If the list is null or it has no elements, this will always return
* null. If the List is also a Deque, this will return the last element using {@link Deque#peekLast()}.
*
* @param list the list to get the last value of.
* @param <T> the type of the list.
*
* @return the last value.
*/
@SuppressWarnings("unchecked")
public static <T> T getLast(List<T> list)
{
if (list == null || list.size() == 0)
{
return null;
}
if (list instanceof Deque)
{
return ((Deque<T>) list).peekLast();
}
return list.get(list.size() - 1);
}
/**
* Safely checks if the given collection is immutable. If the collection is mutable, the data will not be affected
* unless the collection in question keeps track of total number of operations. The test is done by calling
* {@link Collection#removeIf(java.util.function.Predicate)} with the predicate of {@code false}.
*
* @param values the collection to check.
*
* @return {@code true} if the collection is immutable.
*/
public static boolean isImmutable(Collection<?> values)
{
try
{
values.removeIf(x -> false);
return true;
}
catch (UnsupportedOperationException ex)
{
return false;
}
}
/**
* Converts the given values into their string counterpart. This is done by calling {@link Object#toString()} on
* every object. More specific use cases like {@link org.bukkit.entity.Player#getName()} etc are not compatible.
*
* @param values the values to convert.
* @param <T> the type of the collection.
*
* @return the generated list of Strings.
*/
public static <T> List<String> getStringList(Collection<T> values)
{
if (values == null || values.size() == 0)
{
return Collections.emptyList();
}
List<String> list = new LinkedList<>();
for (Object o : values)
{
if (o != null)
{
list.add(o.toString());
}
else
{
list.add(null);
}
}
return list;
}
/**
* Get the names of every single object passed in the values parameter. This method requires the method "getName()"
* to exist within whatever type is passed. If it does not exist, an empty list is returned. However, in the future
* there is a potential that it will be changed to throwing an {@link IllegalArgumentException}.
*
* @param values the values to get the name of.
* @param type the type of the object.
* @param <T> the type of the list.
*
* @return the list of names.
*/
public static <T> List<String> getNames(Collection<T> values, Class<T> type)
{
if (values == null || values.size() == 0)
{
return Collections.emptyList();
}
List<String> list = new LinkedList<>();
Method method = getNameMethod(type);
if (method == null)
{
return Collections.emptyList();
}
for (Object obj : values)
{
try
{
list.add((String) method.invoke(obj));
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex)
{
// this exception is actually going to be printed as it should never happen.
// the method was set to accessible previously, and it should also never have any arguments.
ex.printStackTrace();
}
}
return list;
}
private static Method getNameMethod(Class<?> clazz)
{
Method method = nameMethods.get(clazz);
if (method == null)
{
try
{
method = clazz.getDeclaredMethod("getName");
method.setAccessible(true);
nameMethods.put(clazz, method);
}
catch (NoSuchMethodException | SecurityException ex)
{
// ignored
}
}
return method;
}
/**
* Searches through the given values for the first non-null value.
*
* @param values the values to find.
* @param <T> the type of the array.
*
* @return the first non-null value.
*/
@SafeVarargs
public static <T> T firstNonNull(T... values)
{
for (T value : values)
{
if (value != null)
{
return value;
}
}
return null;
}
/**
* Converts the given String collection into a String array.
*
* @param collection the collection to convert.
*
* @return the newly created array.
*/
public static String[] toArray(Collection<String> collection)
{
return collection.toArray(new String[0]);
}
/**
* Returns a random value from the collection. If the collection is null or empty, this will return null.
*
* @param collection the collection to poll.
* @param <T> the type of the collection.
*
* @return a random value from the collection.
*/
public static <T> T randomValue(Collection<T> collection)
{
return randomValue(collection, (T) null);
}
/**
* Returns a random value from the collection. If the collection is null or empty, this will return null.
*
* @param collection the collection to poll.
* @param ignored any values not suitable to be included
* @param <T> the type of the collection.
*
* @return a random value from the collection.
*/
@SafeVarargs
public static <T> T randomValue(Collection<T> collection, T... ignored)
{
// if it's null or empty, we don't care
if (collection == null || collection.size() == 0)
{
return null;
}
// if the ignored values aren't null, we need to make them not an option
if (ignored != null)
{
collection = new ArrayList<>(collection);
collection.removeAll(Arrays.asList(ignored));
}
Random random = new Random();
// the index to get a value from
int index = random.nextInt(collection.size());
// if it's a list, we can just get it at that index, no need to iterate
if (collection instanceof List)
{
return ((List<T>) collection).get(index);
}
// it's not a list, time to iterate
Iterator<? extends T> iterator = collection.iterator();
for (int i = 0; iterator.hasNext(); i++)
{
if (i == index)
{
return iterator.next();
}
iterator.next();
}
return null;
}
}
@@ -0,0 +1,60 @@
package com.alttd.altitudetag.utils;
/**
* Represents a mutable data type for a type that may not normally be mutable, either because it is final, primitive, or sealed.
*
* @param <T> the type of this mutable value.
*/
public class MutableValue<T>
{
private T value;
/**
* Constructs a new MutableValue with the given object.
*
* @param t the value to be stored.
*/
public MutableValue(T t)
{
if (t == null)
{
throw new IllegalArgumentException("Value can't be null.");
}
this.value = t;
}
/**
* Returns the value that is currently stored. If there is no value, returns null.
*
* @return the value that is currently stored.
*/
public T getValue()
{
return value;
}
/**
* Sets the value that is currently stored.
*
* @param t the new value to be stored.
*/
public void setValue(T t)
{
if (t == null)
{
throw new IllegalArgumentException("Value can't be null.");
}
this.value = t;
}
public Class<T> getType()
{
if (value == null)
{
throw new IllegalStateException("Value can't be null.");
}
return (Class<T>) value.getClass();
}
}
@@ -0,0 +1,154 @@
package com.alttd.altitudetag.utils;
import java.text.DecimalFormat;
public class StringUtils
{
public static String implode(String[] strings, int start, int end)
{
StringBuilder sb = new StringBuilder();
for (int i = start; i < end; i++)
{
sb.append(strings[i]).append(" ");
}
return sb.toString().trim();
}
public static String[] add(String[] array, String add)
{
String[] values = new String[array.length + 1];
System.arraycopy(array, 0, values, 0, array.length);
values[array.length] = add;
return values;
}
public static String compile(String[] strings)
{
return implode(strings, 0, strings.length);
}
public static String capitalize(final String str)
{
int strLen;
if (str == null || (strLen = str.length()) == 0)
{
return str;
}
final int firstCodepoint = str.codePointAt(0);
final int newCodePoint = Character.toTitleCase(firstCodepoint);
if (firstCodepoint == newCodePoint)
{
// already capitalized
return str;
}
final int[] newCodePoints = new int[strLen]; // cannot be longer than
// the char array
int outOffset = 0;
newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; )
{
final int codepoint = str.codePointAt(inOffset);
newCodePoints[outOffset++] = codepoint; // copy the remaining ones
inOffset += Character.charCount(codepoint);
}
return new String(newCodePoints, 0, outOffset);
}
public static boolean contains(String[] values, String search)
{
for (String val : values)
{
if (val.equalsIgnoreCase(search))
{
return true;
}
}
return false;
}
public static boolean isNullOrEmpty(String str)
{
return str == null || str.length() == 0;
}
public static boolean isWhitespace(String str)
{
if (str == null)
{
return false;
}
final int sz = str.length();
for (int i = 0; i < sz; i++)
{
if (!Character.isWhitespace(str.charAt(i)))
{
return false;
}
}
return true;
}
public static boolean containsAny(String search, String... strings)
{
if (isNullOrEmpty(search))
{
return false;
}
for (String searchCharSequence : strings)
{
if (indexOf(search, searchCharSequence, 0) >= 0)
{
return true;
}
}
return false;
}
private static int indexOf(CharSequence cs, CharSequence searchChar, int start)
{
return cs.toString().indexOf(searchChar.toString(), start);
}
public static String formatNumber(Number number, int decimalPlaces, boolean useCommas)
{
StringBuilder sb = new StringBuilder();
if (useCommas)
{
sb.append("#,##0");
}
else
{
sb.append("0");
}
if (decimalPlaces > 0)
{
sb.append('.');
for (int i = 0; i < decimalPlaces; i++)
{
sb.append('0');
}
}
return new DecimalFormat(sb.toString()).format(number);
}
public static String doubleFormat(double number)
{
String formatted;
if (number % 1 == 0)
{
formatted = Integer.toString((int) number);
}
else
{
formatted = Double.toString(number);
}
return formatted;
}
}