Transitioned from Main to ContextAware.

This commit is contained in:
wolf
2025-07-03 21:50:58 -04:00
parent d52dd511df
commit 1191b9c7cf
44 changed files with 1464 additions and 964 deletions

View File

@@ -1,54 +0,0 @@
package me.trouper.alias;
import me.trouper.alias.data.Common;
import me.trouper.alias.server.AutoRegistrar;
import me.trouper.alias.server.commands.QuickCommand;
import me.trouper.alias.server.events.GuiListener;
import me.trouper.alias.server.events.QuickListener;
import me.trouper.alias.update.AutoUpdater;
import org.bukkit.plugin.java.JavaPlugin;
public final class Alias extends JavaPlugin {
private static Class<? extends JavaPlugin> host;
private static AutoRegistrar autoRegistrar;
private static Common common;
private static boolean enabled;
public static synchronized void register(JavaPlugin plugin, Common common) {
if (plugin == null || enabled) return;
Alias.host = plugin.getClass();
Alias.common = common;
AutoUpdater.checkUpdate(plugin,common);
autoRegistrar = new AutoRegistrar(plugin);
autoRegistrar.getQuickListeners().add(new GuiListener());
autoRegistrar.loadAll(common.getPackageName());
enabled = true;
}
public static synchronized void stop(JavaPlugin plugin, Common common) {
autoRegistrar.getQuickListeners().forEach(QuickListener::unregister);
autoRegistrar.getQuickCommands().forEach(QuickCommand::disable);
AutoUpdater.checkUpdate(plugin,common);
}
public static Class<? extends JavaPlugin> getHost() {
return host;
}
public static AutoRegistrar getAutoRegistrar() {
return autoRegistrar;
}
public static Common getCommon() {
return common;
}
public static void updateCommon(Common common) {
Alias.common = common;
}
}

View File

@@ -0,0 +1,99 @@
package me.trouper.alias;
import me.trouper.alias.data.Common;
import me.trouper.alias.data.DataManager;
import me.trouper.alias.data.JsonSerializable;
import me.trouper.alias.server.AutoRegistrar;
import me.trouper.alias.server.events.listeners.GuiListener;
import me.trouper.alias.server.events.listeners.SpawnListener;
import me.trouper.alias.server.events.listeners.WandListener;
import me.trouper.alias.server.systems.TaskManager;
import me.trouper.alias.server.systems.Text;
import me.trouper.alias.server.systems.Verbose;
import me.trouper.alias.server.systems.display.DisplayManager;
import me.trouper.alias.server.update.AutoUpdater;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.ArrayList;
import java.util.List;
public class AliasContext {
private final JavaPlugin plugin;
private final Common common;
private final AutoRegistrar autoRegistrar;
private final AutoUpdater autoUpdater;
private final DataManager dataManager;
private final Text text;
private final Verbose verbose;
private final DisplayManager displayManager;
private boolean enabled = false;
public AliasContext(JavaPlugin plugin, Common common) {
this.plugin = plugin;
this.common = common;
this.autoRegistrar = new AutoRegistrar(this);
this.autoUpdater = new AutoUpdater(this);
this.dataManager = new DataManager(this);
this.text = new Text(this);
this.verbose = new Verbose(this);
this.displayManager = new DisplayManager(this);
}
/**
* Initialize the Alias context and register all components.
* This must be called before using any Alias features.
* Alias should be registered first.
* See {@link AliasContextProvider#registerContext(JavaPlugin, AliasContext)}
*/
public synchronized void initialize() {
if (enabled) return;
plugin.getLogger().info("Initializing Alias context for " + plugin.getName());
autoUpdater.checkUpdate();
autoRegistrar.loadAll(common.getPackageName());
Bukkit.getPluginManager().registerEvents(new GuiListener(),getPlugin());
Bukkit.getPluginManager().registerEvents(new SpawnListener(this),getPlugin());
Bukkit.getPluginManager().registerEvents(new WandListener(this),getPlugin());
List<JsonSerializable<?>> copy = new ArrayList<>(autoRegistrar.getSerializables());
for (JsonSerializable<?> serializable : copy) {
dataManager.load(serializable.getClass());
}
enabled = true;
plugin.getLogger().info("Alias context initialized successfully");
}
/**
* Shutdown the Alias context, save any {@link me.trouper.alias.data.JsonSerializable} and release resources.
* This should be called when the plugin is shutting down.
*/
public synchronized void shutdown() {
if (!enabled) return;
plugin.getLogger().info("Shutting down Alias context for " + plugin.getName());
autoRegistrar.getSerializables().forEach(jsonSerializable -> {
dataManager.save(jsonSerializable.getClass());
});
autoRegistrar.unregisterAll();
autoUpdater.checkUpdate();
enabled = false;
plugin.getLogger().info("Alias context shutdown complete");
}
public JavaPlugin getPlugin() { return plugin; }
public Common getCommon() { return common; }
public AutoRegistrar getAutoRegistrar() { return autoRegistrar; }
public Text getText() { return text; }
public boolean isEnabled() { return enabled; }
public TaskManager createTaskManager() { return new TaskManager(this); }
public Verbose getVerbose() { return verbose; }
public DisplayManager getDisplayManager() { return displayManager; }
public DataManager getDataManager() { return dataManager; }
public AutoUpdater getAutoUpdater() { return autoUpdater; }
}

View File

@@ -0,0 +1,44 @@
package me.trouper.alias;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class AliasContextProvider {
private static final Map<Class<? extends JavaPlugin>, AliasContext> contexts = new ConcurrentHashMap<>();
/**
* Register a context for a plugin
* This must be called BEFORE {@link AliasContext#initialize()}.
*/
public static void registerContext(JavaPlugin plugin, AliasContext context) {
contexts.put(plugin.getClass(), context);
}
/**
* Get context for a plugin class
*/
public static AliasContext getContext(Class<? extends JavaPlugin> pluginClass) {
AliasContext context = contexts.get(pluginClass);
if (context == null) {
throw new RuntimeException("No Alias context registered for " + pluginClass.getSimpleName() +
". Make sure to call AliasContext.initialize() in your plugin's onEnable() method!");
}
return context;
}
/**
* Remove context for a plugin
*/
public static void removeContext(Class<? extends JavaPlugin> pluginClass) {
contexts.remove(pluginClass);
}
/**
* Check if context exists for a plugin
*/
public static boolean hasContext(Class<? extends JavaPlugin> pluginClass) {
return contexts.containsKey(pluginClass);
}
}

View File

@@ -0,0 +1,72 @@
package me.trouper.alias.data;
import me.trouper.alias.AliasContext;
import me.trouper.alias.server.AutoRegistrar;
import java.util.List;
import java.util.Optional;
/**
* Manages loading, retrieving, and saving of JsonSerializable instances
* registered via AutoRegistrar.
*/
public class DataManager {
private final AutoRegistrar registrar;
public DataManager(AliasContext context) {
this.registrar = context.getAutoRegistrar();
}
/**
* Loads the data for the given JsonSerializable type from file, updates the registry,
* and returns the loaded instance (or fallback if loading failed).
*
* @param clazz the class type to load
* @param <T> type extending JsonSerializable
* @return loaded or fallback instance
*/
public <T extends JsonSerializable<?>> T load(Class<T> clazz) {
Optional<T> opt = getOptional(clazz);
if (opt.isEmpty()) {
return null;
}
T instance = opt.get();
T loaded = JsonSerializable.load(instance.getFile(), clazz, instance);
if (loaded != instance) {
List<JsonSerializable<?>> list = registrar.getSerializables();
list.remove(instance);
list.add(loaded);
}
return loaded;
}
/**
* Retrieves the registered JsonSerializable instance without loading.
*
* @param clazz the class type to retrieve
* @param <T> type extending JsonSerializable
* @return instance or null if not found
*/
public <T extends JsonSerializable<?>> T get(Class<T> clazz) {
return getOptional(clazz).orElse(null);
}
private <T extends JsonSerializable<?>> Optional<T> getOptional(Class<T> clazz) {
return registrar.getSerializables().stream()
.filter(clazz::isInstance)
.map(clazz::cast)
.findFirst();
}
/**
* Saves the registered JsonSerializable instance to its file.
* Does nothing if the type is not registered.
*
* @param clazz the class type to save
* @param <T> type extending JsonSerializable
*/
public <T extends JsonSerializable<?>> void save(Class<T> clazz) {
getOptional(clazz).ifPresent(JsonSerializable::save);
}
}

View File

@@ -1,6 +1,9 @@
package me.trouper.alias.data;
import com.google.gson.*;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import me.trouper.alias.utils.misc.FileValidationUtils;
import java.io.*;

View File

@@ -1,5 +1,8 @@
package me.trouper.alias.server;
import me.trouper.alias.AliasContext;
import me.trouper.alias.data.DataManager;
import me.trouper.alias.data.JsonSerializable;
import me.trouper.alias.server.commands.QuickCommand;
import me.trouper.alias.server.events.QuickListener;
import me.trouper.alias.server.systems.AbstractWand;
@@ -13,66 +16,77 @@ import java.util.Set;
import java.util.logging.Level;
public class AutoRegistrar {
private final JavaPlugin plugin;
private final List<QuickCommand> quickCommands = new ArrayList<>();
private final List<QuickListener> quickListeners = new ArrayList<>();
private final List<AbstractWand> wands = new ArrayList<>();
private final List<JsonSerializable<?>> serializables = new ArrayList<>();
public AutoRegistrar(JavaPlugin plugin) {
this.plugin = plugin;
public AutoRegistrar(AliasContext context) {
this.plugin = context.getPlugin();
}
public void loadAll(String basePackage) {
Set<Class<?>> classes = ReflectionUtils.getClassesInPackage(plugin, basePackage);
for (Class<?> clazz : classes) {
if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()) || clazz.isEnum() || clazz.isAnnotation()) {
continue;
}
if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()) ||
clazz.isEnum() || clazz.isAnnotation()) continue;
boolean isCommand = QuickCommand.class.isAssignableFrom(clazz);
boolean isWand = AbstractWand.class.isAssignableFrom(clazz);
boolean isListener = QuickListener.class.isAssignableFrom(clazz);
boolean isSerializable = JsonSerializable.class.isAssignableFrom(clazz);
if (!isCommand && !isWand && !isListener) continue;
if (!isCommand && !isWand && !isListener && !isSerializable) continue;
Registrar registrarFlags = clazz.getAnnotation(Registrar.class);
if (registrarFlags != null && registrarFlags.exclude()) {
plugin.getLogger().info("Excluding " + clazz.getSimpleName() + " from the Registrar.");
continue;
}
try {
Object instance = clazz.getDeclaredConstructor().newInstance();
if (instance instanceof QuickCommand command) {
command.register();
quickCommands.add(command);
plugin.getLogger().info("Registered QuickCommand: " + clazz.getSimpleName());
plugin.getLogger().info("Found QuickCommand: " + clazz.getSimpleName());
}
if (instance instanceof QuickListener listener && !(instance instanceof AbstractWand)) {
quickListeners.add(listener);
plugin.getLogger().info("Found QuickListener: " + clazz.getSimpleName());
}
if (instance instanceof AbstractWand wand) {
wand.register();
wands.add(wand);
plugin.getLogger().info("Registered AbstractWand: " + clazz.getSimpleName());
plugin.getLogger().info("Found AbstractWand: " + clazz.getSimpleName());
}
else if (instance instanceof QuickListener listener) {
listener.register();
quickListeners.add(listener);
plugin.getLogger().info("Registered QuickListener: " + clazz.getSimpleName());
if (instance instanceof JsonSerializable<?> js) {
serializables.add(js);
plugin.getLogger().info("Found JsonSerializable: " + clazz.getSimpleName());
}
} catch (Throwable t) {
plugin.getLogger().log(Level.WARNING, "Failed to instantiate: " + clazz.getName(), t);
}
}
quickListeners.forEach(QuickListener::register);
quickCommands.forEach(QuickCommand::register);
}
public List<QuickCommand> getQuickCommands() {
return quickCommands;
public void unregisterAll() {
quickListeners.forEach(QuickListener::unregister);
quickListeners.clear();
quickCommands.forEach(QuickCommand::disable);
quickCommands.clear();
}
public List<QuickListener> getQuickListeners() {
return quickListeners;
}
public List<AbstractWand> getWands() {
return wands;
}
public List<QuickCommand> getQuickCommands() { return quickCommands; }
public List<QuickListener> getQuickListeners() { return quickListeners; }
public List<AbstractWand> getWands() { return wands; }
public List<JsonSerializable<?>> getSerializables() { return serializables; }
}

View File

@@ -0,0 +1,104 @@
package me.trouper.alias.server;
import me.trouper.alias.AliasContext;
import me.trouper.alias.AliasContextProvider;
import me.trouper.alias.data.Common;
import me.trouper.alias.data.DataManager;
import me.trouper.alias.server.systems.Text;
import me.trouper.alias.server.systems.Verbose;
import me.trouper.alias.server.systems.display.DisplayManager;
import me.trouper.alias.utils.misc.Randomizer;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.Random;
public interface ContextAware {
/**
* Get the plugin class this component belongs to.
* Easiest thing to avoid repeating this method is to make a "PluginContext" interface and fill out this method.
*/
Class<? extends JavaPlugin> getPluginClass();
default AliasContext getContext() {
return AliasContextProvider.getContext(getPluginClass());
}
default JavaPlugin getPlugin() {
return getContext().getPlugin();
}
default Common getCommon() {
return getContext().getCommon();
}
default Text getTextSystem() {
return getContext().getText();
}
default DisplayManager getDisplayManager() {
return getContext().getDisplayManager();
}
default Verbose getVerbose() {
return getContext().getVerbose();
}
default AutoRegistrar getAutoRegistrar() {
return getContext().getAutoRegistrar();
}
default DataManager getDataManager() {
return getContext().getDataManager();
}
default void info(Audience audience, Component message, Component... args) {
getTextSystem().message(Text.Pallet.INFO, audience, message, args);
}
default void error(Audience audience, Component message, Component... args) {
getTextSystem().message(Text.Pallet.ERROR, audience, message, args);
}
default void warning(Audience audience, Component message, Component... args) {
getTextSystem().message(Text.Pallet.WARNING, audience, message, args);
}
default void success(Audience audience, Component message, Component... args) {
getTextSystem().message(Text.Pallet.SUCCESS, audience, message, args);
}
default void message(Audience audience, Component message, Component... args) {
getTextSystem().message(Text.Pallet.NEUTRAL, audience, message, args);
}
default void infoAny(Audience audience, String message, Object... args) {
getTextSystem().messageAny(Text.Pallet.INFO, audience, message, args);
}
default void errorAny(Audience audience, String message, Object... args) {
getTextSystem().messageAny(Text.Pallet.ERROR, audience, message, args);
}
default void warningAny(Audience audience, String message, Object... args) {
getTextSystem().messageAny(Text.Pallet.WARNING, audience, message, args);
}
default void successAny(Audience audience, String message, Object... args) {
getTextSystem().messageAny(Text.Pallet.SUCCESS, audience, message, args);
}
default void messageAny(Audience audience, String message, Object... args) {
getTextSystem().messageAny(Text.Pallet.NEUTRAL, audience, message, args);
}
default Random random() {
return new Random();
}
default Randomizer randomizer() {
return new Randomizer();
}
}

View File

@@ -1,83 +0,0 @@
package me.trouper.alias.server;
import io.papermc.paper.registry.RegistryAccess;
import me.trouper.alias.Alias;
import me.trouper.alias.data.Common;
import me.trouper.alias.server.systems.Text;
import me.trouper.alias.utils.misc.Randomizer;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.Random;
public interface Main {
Main main = new Main() {};
default RegistryAccess getRegistryAccess() {
return RegistryAccess.registryAccess();
}
default JavaPlugin getPlugin() {
Class<? extends JavaPlugin> host = Alias.getHost();
if (host == null) throw new RuntimeException("Alias is not enabled. Make sure to call Alias#register() in your JavaPlugin#onLoad() method!");
return getPlugin(host);
}
default <T extends JavaPlugin> T getPlugin(Class<T> pluginClass) {
return JavaPlugin.getPlugin(pluginClass);
}
default Common getCommon() {
return Alias.getCommon();
}
default void infoAny(Audience player, String message, Object... args) {
Text.messageAny(Text.Pallet.INFO, player, message, args);
}
default void errorAny(Audience player, String message, Object... args) {
Text.messageAny(Text.Pallet.ERROR,player, message, args);
}
default void warningAny(Audience player, String message, Object... args) {
Text.messageAny(Text.Pallet.WARNING, player, message, args);
}
default void successAny(Audience player, String message, Object... args) {
Text.messageAny(Text.Pallet.SUCCESS, player, message, args);
}
default void messageAny(Audience player, String message, Object... args) {
Text.messageAny(Text.Pallet.NEUTRAL, player, message, args);
}
default void info(Audience player, Component message, Component... args) {
Text.message(Text.Pallet.INFO, player, message, args);
}
default void error(Audience player, Component message, Component... args) {
Text.message(Text.Pallet.ERROR,player, message, args);
}
default void warning(Audience player, Component message, Component... args) {
Text.message(Text.Pallet.WARNING, player, message, args);
}
default void success(Audience player, Component message, Component... args) {
Text.message(Text.Pallet.SUCCESS, player, message, args);
}
default void message(Audience player, Component message, Component... args) {
Text.message(Text.Pallet.NEUTRAL, player, message, args);
}
default Random random() {
return new Random();
}
default Randomizer randomizer() {
return new Randomizer();
}
}

View File

@@ -0,0 +1,12 @@
package me.trouper.alias.server;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Registrar {
boolean exclude() default false;
}

View File

@@ -1,6 +1,6 @@
package me.trouper.alias.server.commands;
import me.trouper.alias.server.Main;
import me.trouper.alias.server.ContextAware;
import me.trouper.alias.server.commands.completions.CompletionBuilder;
import me.trouper.alias.server.commands.completions.CompletionNode;
import net.kyori.adventure.text.Component;
@@ -12,8 +12,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public interface QuickCommand extends TabExecutor, Main {
public interface QuickCommand extends TabExecutor, ContextAware {
void handleCommand(CommandSender sender, Command command, String label, Args args);
void handleCompletion(CommandSender sender, Command command, String label, Args args, CompletionBuilder b);
@@ -23,6 +22,7 @@ public interface QuickCommand extends TabExecutor, Main {
PluginCommand command = getPlugin().getCommand(registry.value());
if (command != null) {
getPlugin().getLogger().info("Registering Command from " + this.getClass().getSimpleName());
command.setExecutor(this);
command.setTabCompleter(this);
}

View File

@@ -3,6 +3,7 @@ package me.trouper.alias.server.commands;
import me.trouper.alias.server.events.QuickListener;
public interface QuickCommandListener extends QuickCommand, QuickListener {
@Override
default void register() {
QuickCommand.super.register();

View File

@@ -1,13 +1,15 @@
package me.trouper.alias.server.events;
import me.trouper.alias.server.Main;
import me.trouper.alias.server.ContextAware;
import org.bukkit.Bukkit;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
public interface QuickListener extends Listener, Main {
public interface QuickListener extends Listener, ContextAware {
default void register() {
Bukkit.getPluginManager().registerEvents(this,main.getPlugin());
getPlugin().getLogger().info("Registering Listeners from " + this.getClass().getSimpleName());
Bukkit.getPluginManager().registerEvents(this,getPlugin());
}
default void unregister() {

View File

@@ -0,0 +1,46 @@
package me.trouper.alias.server.events.custom;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class PlayerSpawnEntityEvent extends Event implements Cancellable {
private static final HandlerList HANDLERS = new HandlerList();
private final Player player;
private final Entity spawnedEntity;
private boolean cancelled = false;
public PlayerSpawnEntityEvent(Player player, Entity spawnedEntity) {
this.player = player;
this.spawnedEntity = spawnedEntity;
}
public Player getPlayer() {
return player;
}
public Entity getSpawnedEntity() {
return spawnedEntity;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public HandlerList getHandlers() {
return HANDLERS;
}
public static HandlerList getHandlerList() {
return HANDLERS;
}
}

View File

@@ -1,14 +1,17 @@
package me.trouper.alias.server.events;
package me.trouper.alias.server.events.listeners;
import me.trouper.alias.server.events.QuickListener;
import me.trouper.alias.server.systems.gui.QuickGui;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.java.JavaPlugin;
public class GuiListener implements QuickListener {
public class GuiListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL)
public void onInventoryClick(InventoryClickEvent event) {
@@ -31,5 +34,4 @@ public class GuiListener implements QuickListener {
gui.getViewers().remove(event.getPlayer());
});
}
}

View File

@@ -0,0 +1,102 @@
package me.trouper.alias.server.events.listeners;
import me.trouper.alias.AliasContext;
import me.trouper.alias.server.events.custom.PlayerSpawnEntityEvent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.EnderPearl;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public class SpawnListener implements Listener {
private final AliasContext context;
private final ConcurrentLinkedQueue<Placed> recentBlocks = new ConcurrentLinkedQueue<>();
private final Map<UUID, UUID> pearlOwners = new ConcurrentHashMap<>();
public SpawnListener(AliasContext context) {
this.context = context;
Bukkit.getScheduler().runTaskTimer(context.getPlugin(), this::cleanup, 20, 20);
}
private void cleanup() {
long cutoff = System.currentTimeMillis() - 2000;
Iterator<Placed> it = recentBlocks.iterator();
while (it.hasNext() && it.next().time < cutoff) {
it.remove();
}
}
@EventHandler
public void onBlockPlace(BlockPlaceEvent e) {
recentBlocks.add(new Placed(e.getPlayer().getUniqueId(), e.getBlockPlaced().getLocation(), System.currentTimeMillis()));
}
@EventHandler
public void onProjectileLaunch(ProjectileLaunchEvent e) {
if (!(e.getEntity() instanceof EnderPearl)) return;
if (!(e.getEntity().getShooter() instanceof Player p)) return;
pearlOwners.put(e.getEntity().getUniqueId(), p.getUniqueId());
Bukkit.getScheduler().runTaskLaterAsynchronously(
context.getPlugin(),
() -> pearlOwners.remove(e.getEntity().getUniqueId()),
100L
);
}
@EventHandler
public void onCreatureSpawn(CreatureSpawnEvent e) {
SpawnReason reason = e.getSpawnReason();
Player spawner = null;
if (reason == SpawnReason.BUILD_IRONGOLEM
|| reason == SpawnReason.BUILD_SNOWMAN
|| reason == SpawnReason.BUILD_WITHER) {
Location spawnLoc = e.getEntity().getLocation();
long now = System.currentTimeMillis();
for (Placed p : recentBlocks) {
if (p.time > now - 2000 && p.loc.getWorld().equals(spawnLoc.getWorld())
&& p.loc.distanceSquared(spawnLoc) < 4) {
spawner = Bukkit.getPlayer(p.playerId);
break;
}
}
} else if (reason == SpawnReason.ENDER_PEARL) {
for (Map.Entry<UUID, UUID> en : pearlOwners.entrySet()) {
Entity pearl = Bukkit.getEntity(en.getKey());
if (pearl != null && pearl.getLocation().distanceSquared(e.getEntity().getLocation()) < 4) {
spawner = Bukkit.getPlayer(en.getValue());
break;
}
}
}
if (spawner == null) return;
PlayerSpawnEntityEvent pse = new PlayerSpawnEntityEvent(spawner, e.getEntity());
Bukkit.getPluginManager().callEvent(pse);
if (pse.isCancelled()) {
e.setCancelled(true);
}
}
private static class Placed {
final UUID playerId;
final Location loc;
final long time;
Placed(UUID p, Location l, long t) { playerId = p; loc = l; time = t; }
}
}

View File

@@ -0,0 +1,168 @@
package me.trouper.alias.server.events.listeners;
import me.trouper.alias.AliasContext;
import me.trouper.alias.server.systems.AbstractWand;
import me.trouper.alias.utils.misc.Cooldown;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.player.*;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.UUID;
public class WandListener implements Listener {
private final AliasContext context;
private final Cooldown<UUID> debounce = new Cooldown<>();
public WandListener(AliasContext context) {
this.context = context;
}
private List<AbstractWand> getWands() {
return context.getAutoRegistrar().getWands();
}
private AbstractWand getWandForItem(ItemStack item) {
if (item == null) return null;
for (AbstractWand wand : getWands()) {
if (item.isSimilar(wand.getWandItem())) {
return wand;
}
}
return null;
}
private AbstractWand getWandForPlayer(Player p) {
ItemStack inMain = p.getInventory().getItemInMainHand();
ItemStack inOff = p.getInventory().getItemInOffHand();
AbstractWand wand = getWandForItem(inMain);
if (wand != null) return wand;
return getWandForItem(inOff);
}
@EventHandler
public final void onSwapHands(PlayerSwapHandItemsEvent e) {
Player p = e.getPlayer();
AbstractWand wand = getWandForPlayer(p);
if (wand == null || !p.hasPermission(wand.getUsePermission())) return;
e.setCancelled(true);
wand.swapHand(p);
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onInteract(PlayerInteractEvent e) {
Player p = e.getPlayer();
AbstractWand wand = getWandForPlayer(p);
if (wand == null || !p.hasPermission(wand.getUsePermission())) return;
Action action = e.getAction();
switch (action) {
case RIGHT_CLICK_AIR, RIGHT_CLICK_BLOCK -> {
e.setCancelled(true);
if (debounce.isOnCooldown(p.getUniqueId())) return;
debounce.setCooldown(p.getUniqueId(), 100);
wand.rightClick(p);
}
case LEFT_CLICK_AIR, LEFT_CLICK_BLOCK -> {
e.setCancelled(true);
wand.leftClick(p);
}
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onEntityDamage(EntityDamageByEntityEvent e) {
if (!(e.getDamager() instanceof Player p)) return;
AbstractWand wand = getWandForPlayer(p);
if (wand == null || !p.hasPermission(wand.getUsePermission())) return;
e.setCancelled(true);
wand.leftClick(p);
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onEntityInteract(PlayerInteractEntityEvent e) {
Player p = e.getPlayer();
AbstractWand wand = getWandForPlayer(p);
if (wand == null || !p.hasPermission(wand.getUsePermission())) return;
e.setCancelled(true);
if (debounce.isOnCooldown(p.getUniqueId())) return;
debounce.setCooldown(p.getUniqueId(), 100);
wand.rightClick(p);
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onEntityInteractAt(PlayerInteractAtEntityEvent e) {
Player p = e.getPlayer();
AbstractWand wand = getWandForPlayer(p);
if (wand == null || !p.hasPermission(wand.getUsePermission())) return;
if (debounce.isOnCooldown(p.getUniqueId())) return;
debounce.setCooldown(p.getUniqueId(), 100);
e.setCancelled(true);
wand.rightClick(p);
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onBlockBreak(BlockBreakEvent e) {
Player p = e.getPlayer();
AbstractWand wand = getWandForPlayer(p);
if (wand == null || !p.hasPermission(wand.getUsePermission())) return;
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onBlockPlace(BlockPlaceEvent e) {
Player p = e.getPlayer();
AbstractWand wand = getWandForItem(e.getItemInHand());
if (wand == null || !p.hasPermission(wand.getUsePermission())) return;
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onItemDrop(PlayerDropItemEvent e) {
Player p = e.getPlayer();
AbstractWand wand = getWandForItem(e.getItemDrop().getItemStack());
if (wand == null || !p.hasPermission(wand.getUsePermission())) return;
e.setCancelled(true);
}
@EventHandler
public final void onScroll(PlayerItemHeldEvent e) {
Player p = e.getPlayer();
AbstractWand wand = getWandForPlayer(p);
if (wand == null || !p.hasPermission(wand.getUsePermission())) return;
int prev = e.getPreviousSlot();
int curr = e.getNewSlot();
if (!p.isSneaking() || getWandForItem(p.getInventory().getItem(prev)) == null) return;
e.setCancelled(true);
if (curr == 8 && prev == 0) wand.onScrollUp(p);
else if (curr == 0 && prev == 8) wand.onScrollDown(p);
else if (curr < prev) wand.onScrollUp(p);
else if (curr > prev) wand.onScrollDown(p);
}
}

View File

@@ -1,27 +1,12 @@
package me.trouper.alias.server.systems;
import me.trouper.alias.server.Main;
import me.trouper.alias.server.events.QuickListener;
import me.trouper.alias.utils.misc.Cooldown;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.player.*;
import org.bukkit.inventory.ItemStack;
import java.util.UUID;
public abstract class AbstractWand implements QuickListener, Main {
public abstract class AbstractWand {
private final String usePermission;
private final ItemStack wandItem;
private final Cooldown<UUID> debounce = new Cooldown<>();
public AbstractWand(String usePermission, ItemStack wandItem) {
this.wandItem = wandItem.clone();
@@ -31,126 +16,11 @@ public abstract class AbstractWand implements QuickListener, Main {
public String getUsePermission() {
return usePermission;
}
public ItemStack getWandItem() {
return wandItem.clone();
}
private boolean isWand(ItemStack item) {
return item != null && item.isSimilar(wandItem);
}
private boolean isHoldingWand(Player p) {
ItemStack inMain = p.getInventory().getItemInMainHand();
ItemStack inOff = p.getInventory().getItemInOffHand();
return isWand(inMain) || isWand(inOff);
}
@EventHandler
public final void onSwapHands(PlayerSwapHandItemsEvent e) {
Player p = e.getPlayer();
if (!isHoldingWand(p) || !p.hasPermission(getUsePermission())) return;
e.setCancelled(true);
swapHand(p);
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onInteract(PlayerInteractEvent e) {
Player p = e.getPlayer();
if (!isHoldingWand(p) || !p.hasPermission(getUsePermission())) return;
Action action = e.getAction();
switch (action) {
case RIGHT_CLICK_AIR, RIGHT_CLICK_BLOCK -> {
e.setCancelled(true);
if (debounce.isOnCooldown(p.getUniqueId())) return;
debounce.setCooldown(p.getUniqueId(),100);
rightClick(p);
}
case LEFT_CLICK_AIR, LEFT_CLICK_BLOCK -> {
e.setCancelled(true);
leftClick(p);
}
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onEntityDamage(EntityDamageByEntityEvent e) {
if (!(e.getDamager() instanceof Player p)) return;
if (!isHoldingWand(p) || !p.hasPermission(getUsePermission())) return;
e.setCancelled(true);
leftClick(p);
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onEntityInteract(PlayerInteractEntityEvent e) {
Player p = e.getPlayer();
if (!isHoldingWand(p) || !p.hasPermission(getUsePermission())) return;
e.setCancelled(true);
if (debounce.isOnCooldown(p.getUniqueId())) return;
debounce.setCooldown(p.getUniqueId(),100);
rightClick(p);
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onEntityInteractAt(PlayerInteractAtEntityEvent e) {
Player p = e.getPlayer();
if (!isHoldingWand(p) || !p.hasPermission(getUsePermission())) return;
if (debounce.isOnCooldown(p.getUniqueId())) return;
debounce.setCooldown(p.getUniqueId(),100);
e.setCancelled(true);
rightClick(p);
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onBlockBreak(BlockBreakEvent e) {
Player p = e.getPlayer();
if (!isHoldingWand(p) || !p.hasPermission(getUsePermission())) return;
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onBlockPlace(BlockPlaceEvent e) {
Player p = e.getPlayer();
if (!isWand(e.getItemInHand()) || !p.hasPermission(getUsePermission())) return;
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onItemDrop(PlayerDropItemEvent e) {
Player p = e.getPlayer();
if (!isWand(e.getItemDrop().getItemStack()) || !p.hasPermission(getUsePermission())) return;
e.setCancelled(true);
}
@EventHandler
public final void onScroll(PlayerItemHeldEvent e) {
Player p = e.getPlayer();
if (!isHoldingWand(p) || !p.hasPermission(getUsePermission())) return;
int prev = e.getPreviousSlot();
int curr = e.getNewSlot();
if (!p.isSneaking() || !isWand(p.getInventory().getItem(prev))) return;
e.setCancelled(true);
if (curr == 8 && prev == 0) onScrollUp(p);
else if (curr == 0 && prev == 8) onScrollDown(p);
else if (curr < prev) onScrollUp(p);
else if (curr > prev) onScrollDown(p);
}
public final void swapHand(Player p) {
if (p.isSneaking()) onSwapHandSneak(p);
else onSwapHand(p);
@@ -166,20 +36,20 @@ public abstract class AbstractWand implements QuickListener, Main {
else onRightClick(p);
}
protected void onSwapHand(Player player) {}
protected void onSwapHandSneak(Player player) {}
protected void onRightClick(Player player) {}
protected void onRightClickSneak(Player player) {}
protected void onLeftClick(Player player) {}
protected void onLeftClickSneak(Player player) {}
public void onSwapHand(Player player) {}
public void onSwapHandSneak(Player player) {}
public void onRightClick(Player player) {}
public void onRightClickSneak(Player player) {}
public void onLeftClick(Player player) {}
public void onLeftClickSneak(Player player) {}
/**
* The player must be sneaking to scroll the wand.
*/
protected void onScrollUp(Player player) {}
public void onScrollUp(Player player) {}
/**
* The player must be sneaking to scroll the wand.
*/
protected void onScrollDown(Player player) {}
public void onScrollDown(Player player) {}
}

View File

@@ -1,20 +1,25 @@
package me.trouper.alias.server.systems;
import me.trouper.alias.server.Main;
import me.trouper.alias.AliasContext;
import org.bukkit.Bukkit;
import java.io.Closeable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap;
import java.util.Map;
public class TaskManager implements Closeable, Main {
public class TaskManager implements Closeable {
private final AliasContext context;
private final Map<Integer, Boolean> tasks = new HashMap<>();
private volatile boolean closed = false;
public TaskManager(AliasContext context) {
this.context = context;
}
public int scheduleTask(Runnable task, long delay) {
if (closed) return -1;
int taskId = Bukkit.getScheduler().runTaskLater(main.getPlugin(), () -> {
int taskId = Bukkit.getScheduler().runTaskLater(context.getPlugin(), () -> {
if (!closed) {
task.run();
}

View File

@@ -1,7 +1,6 @@
package me.trouper.alias.server.systems;
import me.trouper.alias.Alias;
import me.trouper.alias.server.Main;
import me.trouper.alias.AliasContext;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
@@ -18,8 +17,12 @@ import org.bukkit.entity.Player;
import java.util.*;
public class Text implements Main {
public class Text {
private final AliasContext context;
public Text(AliasContext context) {
this.context = context;
}
/**
* Messages an audience applying pallet formatting to the text and placeholders. Placeholders are zero-indexed and curly braced. {0}, {1}, {2}...
* Supports both flat messages and fancy wrapped messages based on Alias configuration.
@@ -29,7 +32,7 @@ public class Text implements Main {
* @param text The message to format
* @param args Qualified placeholders to color.
*/
public static void messageAny(Pallet pallet, boolean playSound, Audience audience, String text, Object... args) {
public void messageAny(Pallet pallet, boolean playSound, Audience audience, String text, Object... args) {
message(
pallet,
playSound,
@@ -49,7 +52,7 @@ public class Text implements Main {
* @param text The message to format
* @param args Qualified placeholders to color.
*/
public static void messageAny(Pallet pallet, Audience audience, String text, Object... args) {
public void messageAny(Pallet pallet, Audience audience, String text, Object... args) {
messageAny(pallet,true,audience,text,args);
}
@@ -63,7 +66,7 @@ public class Text implements Main {
* @param text The component message to format
* @param args Qualified placeholders to color.
*/
public static void message(Pallet pallet, boolean playSound, Audience audience, ComponentLike text, ComponentLike... args) {
public void message(Pallet pallet, boolean playSound, Audience audience, ComponentLike text, ComponentLike... args) {
Component message = getMessage(pallet, text, args);
audience.sendMessage(message);
if (playSound && audience instanceof Player p) p.playSound(p.getLocation(), pallet.sound.sound, SoundCategory.VOICE, 10f, pallet.sound.pitch);
@@ -78,7 +81,7 @@ public class Text implements Main {
* @param text The component message to format
* @param args Qualified placeholders to color.
*/
public static void message(Pallet pallet, Audience audience, ComponentLike text, ComponentLike... args) {
public void message(Pallet pallet, Audience audience, ComponentLike text, ComponentLike... args) {
message(pallet,true,audience,text,args);
}
@@ -89,7 +92,7 @@ public class Text implements Main {
* @param args Qualified placeholders to color.
* @return The final component, formatted according to flat/fancy setting.
*/
public static Component getMessageAny(Pallet pallet, String text, Object... args) {
public Component getMessageAny(Pallet pallet, String text, Object... args) {
return getMessage(
pallet,
color(text),
@@ -108,10 +111,10 @@ public class Text implements Main {
* @param args Qualified placeholders to color.
* @return The final component, formatted according to flat/fancy setting.
*/
public static Component getMessage(Pallet pallet, ComponentLike text, ComponentLike... args) {
public Component getMessage(Pallet pallet, ComponentLike text, ComponentLike... args) {
Component formattedMessage = format(pallet, text, args);
if (main.getCommon().useFlat()) {
if (context.getCommon().useFlat()) {
return formatFlatMessage(formattedMessage);
} else {
return formatFancyMessage(formattedMessage);
@@ -123,8 +126,8 @@ public class Text implements Main {
* @param message The formatted message component
* @return The message with flat prefix applied
*/
private static Component formatFlatMessage(Component message) {
Component prefix = color(main.getCommon().getFlatPrefix());
private Component formatFlatMessage(Component message) {
Component prefix = color(context.getCommon().getFlatPrefix());
return prefix.append(message);
}
@@ -134,8 +137,8 @@ public class Text implements Main {
* @param message The formatted message component
* @return The message with fancy formatting and line wrapping
*/
private static Component formatFancyMessage(Component message) {
List<Component> wrappedLines = wrapComponent(message, 50, (int) Math.round((main.getCommon().getPluginName().length() + 3) * 1.3));
private Component formatFancyMessage(Component message) {
List<Component> wrappedLines = wrapComponent(message, 50, (int) Math.round((context.getCommon().getPluginName().length() + 3) * 1.3));
// 50 is slightly below the average character width of someone's minecraft chat. The 3 is to account for the bolded "| " and the 1.3 is to account for bolding the plugin name.
if (wrappedLines.isEmpty()) {
wrappedLines.add(Component.empty());
@@ -144,15 +147,15 @@ public class Text implements Main {
Component result = Component.empty().appendNewline();
Component firstLine = Component.empty()
.append(Component.text("| ", TextColor.color(main.getCommon().getSecondaryColor())).decorate(TextDecoration.BOLD))
.append(Component.text(main.getCommon().getPluginName() + " ", TextColor.color(main.getCommon().getMainColor()), TextDecoration.BOLD))
.append(Component.text("| ", TextColor.color(context.getCommon().getSecondaryColor())).decorate(TextDecoration.BOLD))
.append(Component.text(context.getCommon().getPluginName() + " ", TextColor.color(context.getCommon().getMainColor()), TextDecoration.BOLD))
.append(wrappedLines.get(0));
result = result.append(firstLine);
for (int i = 1; i < wrappedLines.size(); i++) {
Component line = Component.empty()
.append(Component.text("| ", TextColor.color(main.getCommon().getSecondaryColor())).decorate(TextDecoration.BOLD))
.append(Component.text("| ", TextColor.color(context.getCommon().getSecondaryColor())).decorate(TextDecoration.BOLD))
.append(wrappedLines.get(i));
result = result.appendNewline().append(line);
@@ -170,7 +173,7 @@ public class Text implements Main {
* @param firstLineOffset Offset for the first line (plugin name length)
* @return List of wrapped component lines
*/
private static List<Component> wrapComponent(Component component, int maxLineLength, int firstLineOffset) {
private List<Component> wrapComponent(Component component, int maxLineLength, int firstLineOffset) {
List<Component> lines = new ArrayList<>();
List<ComponentWord> words = extractWords(component);
@@ -218,7 +221,7 @@ public class Text implements Main {
* @param word The word to check
* @return true if the word starts with punctuation
*/
private static boolean startsWithPunctuation(ComponentWord word) {
private boolean startsWithPunctuation(ComponentWord word) {
String text = PlainTextComponentSerializer.plainText().serialize(word.component());
return !text.isEmpty() && ".,!?;:)]}".indexOf(text.charAt(0)) != -1;
}
@@ -228,7 +231,7 @@ public class Text implements Main {
* @param component The component to extract words from
* @return List of ComponentWord objects
*/
private static List<ComponentWord> extractWords(Component component) {
private List<ComponentWord> extractWords(Component component) {
List<ComponentWord> words = new ArrayList<>();
extractWordsRecursive(component, Style.empty(), words);
return words;
@@ -240,7 +243,7 @@ public class Text implements Main {
* @param inheritedStyle The style inherited from parent components
* @param words The list to add words to
*/
private static void extractWordsRecursive(Component component, Style inheritedStyle, List<ComponentWord> words) {
private void extractWordsRecursive(Component component, Style inheritedStyle, List<ComponentWord> words) {
Style currentStyle = inheritedStyle.merge(component.style());
if (component instanceof TextComponent textComponent) {
@@ -267,7 +270,7 @@ public class Text implements Main {
* @param text The text to measure
* @return The visible character count
*/
private static int getVisibleLength(String text) {
private int getVisibleLength(String text) {
return PlainTextComponentSerializer.plainText().serialize(Component.text(text)).length();
}
@@ -276,7 +279,7 @@ public class Text implements Main {
* @param msg the legacy text
* @return The deserialized component
*/
public static Component color(String msg) {
public Component color(String msg) {
if (msg.contains("§")) return LegacyComponentSerializer.legacySection().deserialize(msg);
return LegacyComponentSerializer.legacyAmpersand().deserialize(msg);
}
@@ -286,7 +289,7 @@ public class Text implements Main {
* @param ampersands String with ampersand codes
* @return String with section codes
*/
public static String legacyAmpersandColor(String ampersands) {
public String legacyAmpersandColor(String ampersands) {
return ampersands.replaceAll("&","§");
}
@@ -297,7 +300,7 @@ public class Text implements Main {
* @param args Arguments to replace placeholders
* @return Formatted component
*/
public static Component format(Pallet pallet, String text, Object... args) {
public Component format(Pallet pallet, String text, Object... args) {
return format(pallet, Component.text(text), Arrays.stream(args).map(arg->Component.text(arg.toString())).toArray(Component[]::new));
}
@@ -309,7 +312,7 @@ public class Text implements Main {
* @param args Argument components to replace placeholders
* @return Formatted component with colors applied
*/
public static Component format(Pallet pallet, ComponentLike text, ComponentLike... args) {
public Component format(Pallet pallet, ComponentLike text, ComponentLike... args) {
Component resultComponent = text.asComponent().color(pallet.mainText);
if (args == null || args.length == 0) {
@@ -339,7 +342,7 @@ public class Text implements Main {
* @param component The component to check.
* @return Currently always returns true, indicating recoloring should occur.
*/
private static boolean shouldRecolor(Component component) {
private boolean shouldRecolor(Component component) {
Set<TextColor> colors = new HashSet<>();
collectColors(component,colors);
return colors.size() <= 1;
@@ -350,7 +353,7 @@ public class Text implements Main {
* @param component The component to collect.
* @param colors A mutable HashSet of colors.
*/
private static void collectColors(Component component, Set<TextColor> colors) {
private void collectColors(Component component, Set<TextColor> colors) {
if (component.color() != null) {
colors.add(component.color());
}
@@ -364,7 +367,7 @@ public class Text implements Main {
* @param input The input string
* @return String with color codes removed
*/
public static String removeColors(String input) {
public String removeColors(String input) {
if (input == null) return null;
input = input.replaceAll("(?i)[&§][0-9a-fk-or]", ""); // Legacy colors
@@ -379,7 +382,7 @@ public class Text implements Main {
* @param input The input component
* @return Component with plain text only
*/
public static Component removeColors(ComponentLike input) {
public Component removeColors(ComponentLike input) {
if (input == null) return Component.text("");
String plainText = PlainTextComponentSerializer.plainText().serialize(input.asComponent());
@@ -392,7 +395,7 @@ public class Text implements Main {
* @param argIndex The argument index (0-indexed)
* @return The appropriate TextColor for the argument
*/
private static TextColor getArgColor(Pallet pallet, int argIndex) {
private TextColor getArgColor(Pallet pallet, int argIndex) {
return switch (argIndex) {
case 1 -> pallet.arg2;
case 2 -> pallet.arg3;
@@ -403,52 +406,49 @@ public class Text implements Main {
/**
* Represents a word extracted from a component with its formatting preserved.
*/
private static record ComponentWord(Component component, int visibleLength) {}
private record ComponentWord(Component component, int visibleLength) {}
/**
* Color pallets for different message types with appropriate colors and sounds.
*/
public enum Pallet {
ERROR(
TextColor.color(0xD3A6A4), // Soft red for main text
TextColor.color(0xFFF1AE), // Light yellow for default args
TextColor.color(0xFF796D), // Coral for second arg
TextColor.color(0xC62828), // Dark red for third arg
TextColor.color(0xD3A6A4),
TextColor.color(0xFFF1AE),
TextColor.color(0xFF796D),
TextColor.color(0xC62828),
new SoundData(Sound.BLOCK_NOTE_BLOCK_BASS, 1)
),
WARNING(
TextColor.color(0xFFF3CD), // Light yellow for main text
TextColor.color(0xFFF9F5), // Very light cream for default args
TextColor.color(0xFFD54F), // Gold for second arg
TextColor.color(0xFFA000), // Orange for third arg
TextColor.color(0xFFF3CD),
TextColor.color(0xFFF9F5),
TextColor.color(0xFFD54F),
TextColor.color(0xFFA000),
new SoundData(Sound.BLOCK_NOTE_BLOCK_BIT, 0.5F)
),
INFO(
TextColor.color(0xBBDEFB), // Light blue for main text
TextColor.color(0xD2D0EA), // Light lavender for default args
TextColor.color(0x64B5F6), // Medium blue for second arg
TextColor.color(0x1976D2), // Dark blue for third arg
TextColor.color(0xBBDEFB),
TextColor.color(0xD2D0EA),
TextColor.color(0x64B5F6),
TextColor.color(0x1976D2),
new SoundData(Sound.BLOCK_NOTE_BLOCK_CHIME, 0.7F)
),
SUCCESS(
TextColor.color(0xCDFFC7), // Light green for main text
TextColor.color(0xFFFFFF), // White for default args
TextColor.color(0xB0FFE3), // Light mint for second arg
TextColor.color(0x63CD83), // Medium green for third arg
TextColor.color(0xCDFFC7),
TextColor.color(0xFFFFFF),
TextColor.color(0xB0FFE3),
TextColor.color(0x63CD83),
new SoundData(Sound.BLOCK_NOTE_BLOCK_PLING, 1.5F)
),
NEUTRAL(
TextColor.color(0xD3D3D3), // Light gray for main text
TextColor.color(0xFFFFFF), // White for default args
TextColor.color(0xFFB3F8), // Light pink for second arg
TextColor.color(0xE280FF), // Purple for third arg
TextColor.color(0xD3D3D3),
TextColor.color(0xFFFFFF),
TextColor.color(0xFFB3F8),
TextColor.color(0xE280FF),
new SoundData(Sound.BLOCK_NOTE_BLOCK_BELL, 1)
),
LOCATION(
TextColor.color(0xAAAAAA), // Gray for main text
TextColor.color(0xFFB0C1), // Light pink for default args
TextColor.color(0xB6F5B6), // Light green for second arg
TextColor.color(0xB0C1FF), // Light blue for third arg
TextColor.color(0xAAAAAA),
TextColor.color(0xFFB0C1),
TextColor.color(0xB6F5B6),
TextColor.color(0xB0C1FF),
new SoundData(Sound.UI_TOAST_IN, 2)
);

View File

@@ -1,22 +1,28 @@
package me.trouper.alias.server.systems;
import me.trouper.alias.server.Main;
import me.trouper.alias.AliasContext;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
public class Verbose implements Main {
public class Verbose {
private final AliasContext context;
public Verbose(AliasContext context) {
this.context = context;
}
/**
* A dynamic verbose system which uses the format from the {@link Text} system.
* A Uses the format from the {@link Text} system.
* @param backtrace The number of calls up the stacktrace to go.
* @param verbose A message with 0 indexed curly brace placeholders. {0}, {1}, {2}...
* @param args Qualified placeholder values.
*/
public static void send(int backtrace, String verbose, Object... args) {
if (!main.getCommon().getDebugMode()) return;
public void send(int backtrace, String verbose, Object... args) {
if (!context.getCommon().getDebugMode()) return;
String callerInfo = "Unknown Caller";
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
@@ -28,20 +34,20 @@ public class Verbose implements Main {
if (className.contains("-")) callerInfo = "Protected";
else callerInfo = className + "." + caller.getMethodName();
if (main.getCommon().getDebuggerExclusions().contains(callerInfo)) return;
if (context.getCommon().getDebuggerExclusions().contains(callerInfo)) return;
}
Object[] processedArgs = processArgs(args);
Component message = Text.format(Text.Pallet.INFO, verbose, processedArgs);
message = Text.format(Text.Pallet.INFO,
Component message = context.getText().format(Text.Pallet.INFO, verbose, processedArgs);
message = context.getText().format(Text.Pallet.INFO,
Component.text("{0} [DEBUG ^ {1}] [{2}] » {3}"),
Component.text(main.getCommon().getPluginName()),
Component.text(context.getCommon().getPluginName()),
Component.text(backtrace),
Component.text(callerInfo),
message
);
main.getPlugin().getComponentLogger().info(message);
context.getPlugin().getComponentLogger().info(message);
for (Player operator : Bukkit.getOnlinePlayers()) {
if (!operator.isOp()) continue;
@@ -50,15 +56,15 @@ public class Verbose implements Main {
}
/**
* A dynamic verbose system which uses the format from the {@link Text} system.
* Uses the format from the {@link Text} system.
* @param verbose A message with 0 indexed curly brace placeholders. {0}, {1}, {2}...
* @param args Qualified placeholder values.
*/
public static void send(String verbose, Object... args) {
public void send(String verbose, Object... args) {
send(1,verbose,args);
}
private static Object[] processArgs(Object... args) {
private Object[] processArgs(Object... args) {
Object[] processed = new Object[args.length];
for (int i = 0; i < args.length; i++) {

View File

@@ -0,0 +1,26 @@
package me.trouper.alias.server.systems.display;
import me.trouper.alias.AliasContext;
import me.trouper.alias.server.systems.display.tracing.BlockDisplayRaytracer;
import me.trouper.alias.server.systems.display.tracing.CustomRaytracer;
import me.trouper.alias.server.systems.display.visual.Outliner;
import me.trouper.alias.server.systems.display.visual.Patterns;
public class DisplayManager {
private final Patterns patterns;
private final Outliner outliner;
private final BlockDisplayRaytracer blockDisplayRaytracer;
private final CustomRaytracer customRaytracer;
public DisplayManager(AliasContext context) {
this.patterns = new Patterns(context);
this.blockDisplayRaytracer = new BlockDisplayRaytracer(context);
this.outliner = new Outliner(blockDisplayRaytracer);
this.customRaytracer = new CustomRaytracer(context);
}
public Patterns getPatterns() { return patterns; }
public Outliner getOutliner() { return outliner; }
public BlockDisplayRaytracer getBlockDisplayRaytracer() { return blockDisplayRaytracer; }
public CustomRaytracer getCustomRaytracer() { return customRaytracer; }
}

View File

@@ -0,0 +1,213 @@
package me.trouper.alias.server.systems.display.tracing;
import me.trouper.alias.AliasContext;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.entity.BlockDisplay;
import org.bukkit.entity.Display;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Transformation;
import org.bukkit.util.Vector;
import org.bukkit.util.VoxelShape;
import org.joml.AxisAngle4f;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class BlockDisplayRaytracer {
private final AliasContext context;
public BlockDisplayRaytracer(AliasContext context) {
this.context = context;
}
public void cleanup() {
JavaPlugin plugin = context.getPlugin();
List<World> worlds = plugin.getServer().getWorlds();
List<Entity> entities = new ArrayList<>();
for (World world : worlds) {
entities.addAll(world.getEntities().stream().filter(entity -> entity.getScoreboardTags().contains(context.getCommon().getTempTag())).toList());
entities.forEach(entity -> {
if (entity != null) entity.remove();
});
}
}
public void trace(Material display, Location start, Location end, long stayTime, List<Player> viewers) {
trace(display, start, end.toVector().subtract(start.toVector()), 0.05, end.distance(start), stayTime, viewers);
}
public void trace(Material display, Location start, Location end, double thickness, long stayTime, List<Player> viewers) {
trace(display, start, end.toVector().subtract(start.toVector()), thickness, end.distance(start), stayTime, viewers);
}
public void trace(Material display, Location start, Vector direction, double thickness, double distance, long stayTime, List<Player> viewers) {
World world = start.getWorld();
BlockDisplay beam = world.spawn(start, BlockDisplay.class, entity -> {
AxisAngle4f angle = new AxisAngle4f(0, 0, 0, 1);
Vector3f transition = new Vector3f(-(float)(thickness / 2F));
Vector3f scale = new Vector3f((float)thickness, (float)thickness, (float)distance);
Transformation trans = new Transformation(transition, angle, scale, angle);
Location vector = entity.getLocation();
vector.setDirection(direction);
entity.teleport(vector);
entity.setBlock(display.createBlockData());
entity.setBrightness(new Display.Brightness(15, 15));
entity.setInterpolationDelay(0);
entity.setTransformation(trans);
entity.addScoreboardTag(context.getCommon().getTempTag());
for (Player player : Bukkit.getOnlinePlayers()) {
if (!viewers.contains(player)) {
player.hideEntity(context.getPlugin(), entity);
}
}
Bukkit.getScheduler().runTaskLater(context.getPlugin(), entity::remove, stayTime);
});
}
public void trace(Material display, Location start, Vector direction, double thickness, double distance, long stayTime, Consumer<BlockDisplay> onEntitySpawn, List<Player> viewers) {
World world = start.getWorld();
BlockDisplay beam = world.spawn(start, BlockDisplay.class, entity -> {
AxisAngle4f angle = new AxisAngle4f(0, 0, 0, 1);
Vector3f transition = new Vector3f(-(float)(thickness / 2F));
Vector3f scale = new Vector3f((float)thickness, (float)thickness, (float)distance);
Transformation trans = new Transformation(transition, angle, scale, angle);
Location vector = entity.getLocation();
vector.setDirection(direction);
entity.teleport(vector);
entity.setBlock(display.createBlockData());
entity.setBrightness(new Display.Brightness(15, 15));
entity.setInterpolationDelay(0);
entity.setTransformation(trans);
entity.addScoreboardTag(context.getCommon().getTempTag());
for (Player player : Bukkit.getOnlinePlayers()) {
if (!viewers.contains(player)) {
player.hideEntity(context.getPlugin(), entity);
}
}
Bukkit.getScheduler().runTaskLater(context.getPlugin(), entity::remove, stayTime);
Bukkit.getScheduler().runTaskLater(context.getPlugin(), () -> onEntitySpawn.accept(entity), 5);
});
}
public void traceGlowing(World world, double x1, double y1, double z1, double x2, double y2, double z2, Color color, long stayTime) {
Location loc1 = new Location(world, x1, y1, z1);
Location loc2 = new Location(world, x2, y2, z2);
BlockDisplay ent = trace(Material.WHITE_CONCRETE, loc1, loc2, 0.01, stayTime);
ent.setGlowColorOverride(color);
ent.setGlowing(true);
}
public BlockDisplay trace(Material display, Location start, Location end, long stayTime) {
return trace(display, start, end.toVector().subtract(start.toVector()), 0.05, end.distance(start), stayTime);
}
public BlockDisplay trace(Material display, Location start, Location end, double thickness, long stayTime) {
return trace(display, start, end.toVector().subtract(start.toVector()), thickness, end.distance(start), stayTime);
}
public BlockDisplay trace(Material display, Location start, Vector direction, double thickness, double distance, long stayTime) {
World world = start.getWorld();
BlockDisplay entity = world.spawn(start, BlockDisplay.class);
AxisAngle4f angle = new AxisAngle4f(0, 0, 0, 1);
Vector3f transition = new Vector3f(-(float)(thickness / 2F));
Vector3f scale = new Vector3f((float)thickness, (float)thickness, (float)distance);
Transformation trans = new Transformation(transition, angle, scale, angle);
Location vector = entity.getLocation();
vector.setDirection(direction);
entity.teleport(vector);
entity.setBlock(display.createBlockData());
entity.setBrightness(new Display.Brightness(15, 15));
entity.setInterpolationDelay(0);
entity.setTransformation(trans);
entity.addScoreboardTag(context.getCommon().getTempTag());
Bukkit.getScheduler().runTaskLater(context.getPlugin(), entity::remove, stayTime);
return entity;
}
public void transform(BlockDisplay display, Location start, Location end, double thickness) {
Vector direction = end.toVector().subtract(start.toVector());
double distance = direction.length();
Location loc = start.clone();
loc.setDirection(direction);
display.teleport(loc);
Vector3f translation = new Vector3f(-(float)(thickness / 2F), 0, 0); // Centered
Vector3f scale = new Vector3f((float)thickness, (float)thickness, (float)distance);
AxisAngle4f rotation = new AxisAngle4f(0, 0, 0, 1);
Transformation transformation = new Transformation(translation, rotation, scale, rotation);
display.setTransformation(transformation);
}
public void transform(BlockDisplay display, Location start, Vector direction, double distance, double thickness) {
Location loc = start.clone();
loc.setDirection(direction);
display.teleport(loc);
Vector3f translation = new Vector3f(-(float)(thickness / 2F), 0, 0);
Vector3f scale = new Vector3f((float)thickness, (float)thickness, (float)distance);
AxisAngle4f rotation = new AxisAngle4f(0, 0, 0, 1);
Transformation transformation = new Transformation(translation, rotation, scale, rotation);
display.setTransformation(transformation);
}
public void translate(BlockDisplay display, Vector3f offset) {
Transformation current = display.getTransformation();
Vector3f translation = new Vector3f(current.getTranslation()).add(offset);
display.setTransformation(new Transformation(
translation,
current.getLeftRotation(),
current.getScale(),
current.getRightRotation()
));
}
public void scale(BlockDisplay display, Vector3f scale) {
Transformation current = display.getTransformation();
display.setTransformation(new Transformation(
current.getTranslation(),
current.getLeftRotation(),
scale,
current.getRightRotation()
));
}
public void rotate(BlockDisplay display, AxisAngle4f rotation) {
Transformation current = display.getTransformation();
display.setTransformation(new Transformation(
current.getTranslation(),
rotation,
current.getScale(),
rotation
));
}
public void alignToDirection(BlockDisplay display, Vector direction) {
Location loc = display.getLocation().clone();
loc.setDirection(direction);
display.teleport(loc);
}
}

View File

@@ -1,5 +1,6 @@
package me.trouper.alias.server.systems.tracing;
package me.trouper.alias.server.systems.display.tracing;
import me.trouper.alias.AliasContext;
import org.bukkit.FluidCollisionMode;
import org.bukkit.Location;
import org.bukkit.block.Block;
@@ -19,7 +20,13 @@ import java.util.Random;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
public class CustomDisplayRaytracer {
public class CustomRaytracer {
private final AliasContext context;
public CustomRaytracer(AliasContext context) {
this.context = context;
}
public static final Predicate<Point> HIT_BLOCK = point -> {
Block b = point.getBlock();
@@ -77,22 +84,22 @@ public class CustomDisplayRaytracer {
return point -> HIT_BLOCK.test(point) && !point.getNearbyEntities(null, 5, true, 0.1, e -> e instanceof LivingEntity le && !le.isDead() && condition.test(e)).isEmpty();
}
public static Point trace(Location start, Location end, Predicate<Point> hitCondition) {
public Point trace(Location start, Location end, Predicate<Point> hitCondition) {
return trace(start, end, 0.5, hitCondition);
}
public static Point trace(Location start, Location end, double interval, Predicate<Point> hitCondition) {
public Point trace(Location start, Location end, double interval, Predicate<Point> hitCondition) {
Vector direction = end.toVector().subtract(start.toVector()).normalize();
double distance = end.distance(start);
return trace(start, direction, distance, interval, hitCondition);
}
public static Point trace(Location start, Vector direction, double distance, Predicate<Point> hitCondition) {
public Point trace(Location start, Vector direction, double distance, Predicate<Point> hitCondition) {
Vector normal = direction.clone().normalize();
return trace(start, normal, distance, 0.5, hitCondition);
}
public static Point trace(Location start, Vector direction, double distance, double interval, Predicate<Point> hitCondition) {
public Point trace(Location start, Vector direction, double distance, double interval, Predicate<Point> hitCondition) {
if (interval < 0) throw new IllegalArgumentException("interval cannot be zero!");
if (distance < 0) throw new IllegalArgumentException("distance cannot be zero!");
@@ -106,15 +113,14 @@ public class CustomDisplayRaytracer {
}
public static BukkitTask traceDelayed(Plugin plugin, Location start, Vector direction, double distance, double interval, long tickDelay, int pointsPerTick, Predicate<Point> hitCondition) {
public BukkitTask traceDelayed(Location start, Vector direction, double distance, double interval, long tickDelay, int pointsPerTick, Predicate<Point> hitCondition) {
if (interval <= 0) throw new IllegalArgumentException("interval cannot be zero or negative!");
if (distance <= 0) throw new IllegalArgumentException("distance cannot be zero or negative!");
if (tickDelay < 0) throw new IllegalArgumentException("tickDelay cannot be negative!");
Vector normalizedDir = direction.clone().normalize();
return new BukkitRunnable() {
private double currentDistance = 0.0;
private boolean hit = false;
@@ -139,33 +145,33 @@ public class CustomDisplayRaytracer {
currentDistance += interval;
}
}
}.runTaskTimer(plugin, 0, tickDelay);
}.runTaskTimer(context.getPlugin(), 0, tickDelay);
}
public static BukkitTask traceDelayed(Plugin plugin, Location start, Location end, double interval, long tickDelay, int pointsPerTick, Predicate<Point> hitCondition) {
public BukkitTask traceDelayed(Location start, Location end, double interval, long tickDelay, int pointsPerTick, Predicate<Point> hitCondition) {
Vector direction = end.toVector().subtract(start.toVector()).normalize();
double distance = start.distance(end);
return traceDelayed(plugin, start, direction, distance, interval, tickDelay,pointsPerTick, hitCondition);
return traceDelayed(start, direction, distance, interval, tickDelay,pointsPerTick, hitCondition);
}
public static BukkitTask traceDelayed(Plugin plugin,
public BukkitTask traceDelayed(Plugin plugin,
Location start,
Location end,
long tickDelay,
Predicate<Point> hitCondition) {
return traceDelayed(plugin, start, end,0.5, tickDelay, 1, hitCondition);
return traceDelayed(start, end,0.5, tickDelay, 1, hitCondition);
}
public static BukkitTask traceDelayed(Plugin plugin,
public BukkitTask traceDelayed(Plugin plugin,
Location start,
Vector direction,
double distance,
long tickDelay,
Predicate<Point> hitCondition) {
return traceDelayed(plugin, start, direction, distance, 0.5, tickDelay,1, hitCondition);
return traceDelayed(start, direction, distance, 0.5, tickDelay,1, hitCondition);
}
public static Point traceWithReflection(Location start, Vector direction, double distance, double interval,
public Point traceWithReflection(Location start, Vector direction, double distance, double interval,
int maxReflections, Predicate<Point> hitCondition,
BiPredicate<Point, Block> blockReflectCondition,
BiPredicate<Point, Entity> entityReflectCondition) {
@@ -236,25 +242,23 @@ public class CustomDisplayRaytracer {
}
if (i + interval >= remainingDistance) {
Point finalPoint = blocksInFrontOf(currentLocation, currentDirection, remainingDistance, true);
return finalPoint;
return blocksInFrontOf(currentLocation, currentDirection, remainingDistance, true);
}
}
if (reflections > maxReflections) {
Point finalPoint = blocksInFrontOf(currentLocation, currentDirection, remainingDistance, true);
return finalPoint;
return blocksInFrontOf(currentLocation, currentDirection, remainingDistance, true);
}
}
return blocksInFrontOf(start, normalizedDir, distance, true);
}
private static Vector glanceReflect(Vector incident) {
private Vector glanceReflect(Vector incident) {
return offsetVector(incident,4).multiply(-1);
}
private static BlockFace traceBlockFace(Location startLocation, Vector direction, double maxDistance) {
private BlockFace traceBlockFace(Location startLocation, Vector direction, double maxDistance) {
Predicate<Block> blockPredicate = block -> true;
Predicate<Entity> entityPredicate = entity -> false;
@@ -267,7 +271,7 @@ public class CustomDisplayRaytracer {
return null;
}
private static Vector calculateReflection(Vector incident, Vector normal) {
private Vector calculateReflection(Vector incident, Vector normal) {
// r = i - 2(i dot n)n
double dot = incident.dot(normal);
Vector reflection = incident.clone().subtract(normal.clone().multiply(2 * dot));
@@ -275,7 +279,7 @@ public class CustomDisplayRaytracer {
return reflection.normalize();
}
private static Vector getFaceNormal(BlockFace face) {
private Vector getFaceNormal(BlockFace face) {
return switch (face) {
case DOWN -> new Vector(0, -1, 0);
case NORTH -> new Vector(0, 0, -1);
@@ -286,12 +290,12 @@ public class CustomDisplayRaytracer {
};
}
public static Point blocksInFrontOf(Location loc, Vector dir, double blocks, boolean missed) {
public Point blocksInFrontOf(Location loc, Vector dir, double blocks, boolean missed) {
Vector normal = dir.clone().normalize();
return new Point(loc.clone().add(normal.getX() * blocks, normal.getY() * blocks, normal.getZ() * blocks), blocks, missed);
}
public static Vector offsetVector(Vector original, double angleDegrees) {
private Vector offsetVector(Vector original, double angleDegrees) {
Random random = new Random();
original = original.clone().normalize();

View File

@@ -1,4 +1,4 @@
package me.trouper.alias.server.systems.tracing;
package me.trouper.alias.server.systems.display.tracing;
import org.bukkit.Location;
import org.bukkit.World;

View File

@@ -0,0 +1,169 @@
package me.trouper.alias.server.systems.display.visual;
import me.trouper.alias.server.systems.display.tracing.BlockDisplayRaytracer;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.BlockDisplay;
import org.bukkit.entity.Player;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import org.bukkit.util.VoxelShape;
import java.util.ArrayList;
import java.util.List;
public class Outliner {
private final BlockDisplayRaytracer rt;
public Outliner(BlockDisplayRaytracer raytracer) {
this.rt = raytracer;
}
public void highlightCollisions(Block block, Color color, long stayTime) {
if (block == null || block.isEmpty() || !block.isCollidable())
return;
VoxelShape shape = block.getCollisionShape();
World world = block.getWorld();
Vector offset = block.getLocation().toVector();
for (BoundingBox box : shape.getBoundingBoxes()) {
highlight(box, offset, world, color, stayTime);
}
}
public List<BlockDisplay> outline(Material display, Location location, long stayTime) {
return outline(display, location, 0.05, stayTime);
}
public List<BlockDisplay> outline(Material display, Location location, double thickness, long stayTime) {
Location og = location.getBlock().getLocation();
Location a1 = og.clone().add(0, 0, 0);
Location a2 = og.clone().add(1, 0, 0);
Location a3 = og.clone().add(1, 0, 1);
Location a4 = og.clone().add(0, 0, 1);
Location b1 = og.clone().add(0, 1, 0);
Location b2 = og.clone().add(1, 1, 0);
Location b3 = og.clone().add(1, 1, 1);
Location b4 = og.clone().add(0, 1, 1);
List<BlockDisplay> a = new ArrayList<>();
a.add(rt.trace(display, a1, a2, thickness, stayTime));
a.add(rt.trace(display, a2, a3, thickness, stayTime));
a.add(rt.trace(display, a3, a4, thickness, stayTime));
a.add(rt.trace(display, a4, a1, thickness, stayTime));
a.add(rt.trace(display, b1, b2, thickness, stayTime));
a.add(rt.trace(display, b2, b3, thickness, stayTime));
a.add(rt.trace(display, b3, b4, thickness, stayTime));
a.add(rt.trace(display, b4, b1, thickness, stayTime));
a.add(rt.trace(display, a1, b1, thickness, stayTime));
a.add(rt.trace(display, a2, b2, thickness, stayTime));
a.add(rt.trace(display, a3, b3, thickness, stayTime));
a.add(rt.trace(display, a4, b4, thickness, stayTime));
return a;
}
public void highlight(BoundingBox box, Vector offset, World world, Color color, long stayTime) {
double x1 = box.getMinX() + offset.getX();
double y1 = box.getMinY() + offset.getY();
double z1 = box.getMinZ() + offset.getZ();
double x2 = box.getMaxX() + offset.getX();
double y2 = box.getMaxY() + offset.getY();
double z2 = box.getMaxZ() + offset.getZ();
rt.traceGlowing(world, x1, y1, z1, x2, y1, z1, color, stayTime);
rt.traceGlowing(world, x2, y1, z1, x2, y1, z2, color, stayTime);
rt.traceGlowing(world, x2, y1, z2, x1, y1, z2, color, stayTime);
rt.traceGlowing(world, x1, y1, z2, x1, y1, z1, color, stayTime);
rt.traceGlowing(world, x1, y2, z1, x2, y2, z1, color, stayTime);
rt.traceGlowing(world, x2, y2, z1, x2, y2, z2, color, stayTime);
rt.traceGlowing(world, x2, y2, z2, x1, y2, z2, color, stayTime);
rt.traceGlowing(world, x1, y2, z2, x1, y2, z1, color, stayTime);
rt.traceGlowing(world, x1, y1, z1, x1, y2, z1, color, stayTime);
rt.traceGlowing(world, x2, y1, z1, x2, y2, z1, color, stayTime);
rt.traceGlowing(world, x2, y1, z2, x2, y2, z2, color, stayTime);
rt.traceGlowing(world, x1, y1, z2, x1, y2, z2, color, stayTime);
}
public void outline(Material display, Location location, long stayTime, List<Player> viewers) {
outline(display, location, 0.05, stayTime, viewers);
}
public void outline(Material display, Location corner1, Location corner2, double thickness, long stayTime, List<Player> viewers) {
World world = corner1.getWorld();
int minX = Math.min(corner1.getBlockX(), corner2.getBlockX());
int minY = Math.min(corner1.getBlockY(), corner2.getBlockY());
int minZ = Math.min(corner1.getBlockZ(), corner2.getBlockZ());
int maxX = Math.max(corner1.getBlockX(), corner2.getBlockX());
int maxY = Math.max(corner1.getBlockY(), corner2.getBlockY());
int maxZ = Math.max(corner1.getBlockZ(), corner2.getBlockZ());
Location a1 = new Location(world, minX, minY, minZ);
Location a2 = new Location(world, maxX + 1, minY, minZ);
Location a3 = new Location(world, maxX + 1, minY, maxZ + 1);
Location a4 = new Location(world, minX, minY, maxZ + 1);
Location b1 = new Location(world, minX, maxY + 1, minZ);
Location b2 = new Location(world, maxX + 1, maxY + 1, minZ);
Location b3 = new Location(world, maxX + 1, maxY + 1, maxZ + 1);
Location b4 = new Location(world, minX, maxY + 1, maxZ + 1);
rt.trace(display, a1, a2, thickness, stayTime, viewers);
rt.trace(display, a2, a3, thickness, stayTime, viewers);
rt.trace(display, a3, a4, thickness, stayTime, viewers);
rt.trace(display, a4, a1, thickness, stayTime, viewers);
rt.trace(display, b1, b2, thickness, stayTime, viewers);
rt.trace(display, b2, b3, thickness, stayTime, viewers);
rt.trace(display, b3, b4, thickness, stayTime, viewers);
rt.trace(display, b4, b1, thickness, stayTime, viewers);
rt.trace(display, a1, b1, thickness, stayTime, viewers);
rt.trace(display, a2, b2, thickness, stayTime, viewers);
rt.trace(display, a3, b3, thickness, stayTime, viewers);
rt.trace(display, a4, b4, thickness, stayTime, viewers);
}
public void outline(Material display, Location location, double thickness, long stayTime, List<Player> viewers) {
Location og = location.getBlock().getLocation();
Location a1 = og.clone().add(0, 0, 0);
Location a2 = og.clone().add(1, 0, 0);
Location a3 = og.clone().add(1, 0, 1);
Location a4 = og.clone().add(0, 0, 1);
Location b1 = og.clone().add(0, 1, 0);
Location b2 = og.clone().add(1, 1, 0);
Location b3 = og.clone().add(1, 1, 1);
Location b4 = og.clone().add(0, 1, 1);
rt.trace(display, a1, a2, thickness, stayTime, viewers);
rt.trace(display, a2, a3, thickness, stayTime, viewers);
rt.trace(display, a3, a4, thickness, stayTime, viewers);
rt.trace(display, a4, a1, thickness, stayTime, viewers);
rt.trace(display, b1, b2, thickness, stayTime, viewers);
rt.trace(display, b2, b3, thickness, stayTime, viewers);
rt.trace(display, b3, b4, thickness, stayTime, viewers);
rt.trace(display, b4, b1, thickness, stayTime, viewers);
rt.trace(display, a1, b1, thickness, stayTime, viewers);
rt.trace(display, a2, b2, thickness, stayTime, viewers);
rt.trace(display, a3, b3, thickness, stayTime, viewers);
rt.trace(display, a4, b4, thickness, stayTime, viewers);
}
}

View File

@@ -1,6 +1,6 @@
package me.trouper.alias.server.systems.visual;
package me.trouper.alias.server.systems.display.visual;
import me.trouper.alias.server.Main;
import me.trouper.alias.AliasContext;
import me.trouper.alias.utils.misc.Randomizer;
import org.bukkit.Bukkit;
import org.bukkit.Color;
@@ -16,22 +16,28 @@ import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
public class DisplayUtils implements Main {
public class Patterns {
// This will 100% get Javadoc in the future when I try to use it. Everything in here is so convoluted.
public static final Function<Particle, Consumer<Location>> PARTICLE_FACTORY = particle -> l -> l.getWorld().spawnParticle(particle, l, 1, 0, 0, 0, 0);
private final AliasContext context;
public static final BiFunction<Color, Float, Consumer<Location>> DUST_PARTICLE_FACTORY = (color, thickness) -> {
public final Function<Particle, Consumer<Location>> PARTICLE_FACTORY = particle -> l -> l.getWorld().spawnParticle(particle, l, 1, 0, 0, 0, 0);
public final BiFunction<Color, Float, Consumer<Location>> DUST_PARTICLE_FACTORY = (color, thickness) -> {
Particle.DustOptions dust = new Particle.DustOptions(color, thickness);
return l -> l.getWorld().spawnParticle(Particle.DUST, l, 1, 0, 0, 0, 0, dust);
};
public static void ring(Location loc, double radius, Color color, float thickness) {
public Patterns(AliasContext context) {
this.context = context;
}
public void ring(Location loc, double radius, Color color, float thickness) {
ring(loc, radius, DUST_PARTICLE_FACTORY.apply(color, thickness));
}
public static void sphere(Location center, double radius, double pointDistance, Consumer<Location> action) {
public void sphere(Location center, double radius, double pointDistance, Consumer<Location> action) {
double dPhi = pointDistance / radius;
for (double phi = 0.0; phi <= Math.PI; phi += dPhi) {
@@ -55,10 +61,10 @@ public class DisplayUtils implements Main {
}
}
public static void sphereWave(Location center, double maxRadius, double radialStep, double maxDistanceBetweenPoints, Consumer<Location> action) {
public void sphereWave(Location center, double maxRadius, double radialStep, double maxDistanceBetweenPoints, Consumer<Location> action) {
AtomicReference<Double> currentRadius = new AtomicReference<>(radialStep);
Bukkit.getScheduler().runTaskTimer(main.getPlugin(), (task) -> {
Bukkit.getScheduler().runTaskTimer(context.getPlugin(), (task) -> {
double r = currentRadius.get();
if (r > maxRadius) {
task.cancel();
@@ -70,7 +76,7 @@ public class DisplayUtils implements Main {
}, 0L, 1L);
}
public static void ring(Location loc, double radius, Consumer<Location> action) {
public void ring(Location loc, double radius, Consumer<Location> action) {
for (int theta = 0; theta < 360; theta += 10) {
double x = Math.cos(Math.toRadians(theta)) * radius;
double z = Math.sin(Math.toRadians(theta)) * radius;
@@ -79,17 +85,17 @@ public class DisplayUtils implements Main {
}
}
public static void ring(Location loc, double radius, double maxDistanceBetweenPoints, Consumer<Location> action) {
public void ring(Location loc, double radius, double maxDistanceBetweenPoints, Consumer<Location> action) {
arc(loc, radius, 0, 360, maxDistanceBetweenPoints, action);
}
public static void wave(Location loc, double radius, Color color, float thickness, double gap) {
public void wave(Location loc, double radius, Color color, float thickness, double gap) {
wave(loc, radius, DUST_PARTICLE_FACTORY.apply(color, thickness), gap);
}
public static void wave(Location loc, double radius, Consumer<Location> action, double gap) {
public void wave(Location loc, double radius, Consumer<Location> action, double gap) {
AtomicReference<Double> i = new AtomicReference<>(gap);
Bukkit.getScheduler().runTaskTimer(main.getPlugin(), (task) -> {
Bukkit.getScheduler().runTaskTimer(context.getPlugin(), (task) -> {
if (i.get() >= radius) {
task.cancel();
return;
@@ -99,9 +105,9 @@ public class DisplayUtils implements Main {
}, 0, 1);
}
public static void wave(Location loc, double radius, double radialGap, double maxDistanceBetweenPoints, Consumer<Location> action) {
public void wave(Location loc, double radius, double radialGap, double maxDistanceBetweenPoints, Consumer<Location> action) {
AtomicReference<Double> r = new AtomicReference<>(radialGap);
Bukkit.getScheduler().runTaskTimer(main.getPlugin(), (task) -> {
Bukkit.getScheduler().runTaskTimer(context.getPlugin(), (task) -> {
if (r.get() > radius) {
task.cancel();
return;
@@ -111,19 +117,19 @@ public class DisplayUtils implements Main {
}, 0, 1);
}
public static void disc(Location loc, double radius, Consumer<Location> action, double gap) {
public void disc(Location loc, double radius, Consumer<Location> action, double gap) {
for (double i = gap; i < radius; i += gap) {
ring(loc, i, action);
}
}
public static void disc(Location loc, double radius, double radialGap, double maxDistanceBetweenPoints, Consumer<Location> action) {
public void disc(Location loc, double radius, double radialGap, double maxDistanceBetweenPoints, Consumer<Location> action) {
for (double r = radialGap; r <= radius; r += radialGap) {
ring(loc, r, maxDistanceBetweenPoints, action);
}
}
public static void helix(Location loc, double radius, Consumer<Location> action, double gap, int height) {
public void helix(Location loc, double radius, Consumer<Location> action, double gap, int height) {
int theta = 0;
for (double y = 0; y <= height; y += gap) {
double x = Math.cos(Math.toRadians(theta)) * radius;
@@ -135,7 +141,7 @@ public class DisplayUtils implements Main {
}
}
public static void vortex(Location loc, double radius, Consumer<Location> action, double gapH, double gapV, int height) {
public void vortex(Location loc, double radius, Consumer<Location> action, double gapH, double gapV, int height) {
double r = radius;
int theta = 0;
for (double y = 0; y <= height; y += gapV) {
@@ -149,14 +155,14 @@ public class DisplayUtils implements Main {
}
}
public static void beam(Location loc, Consumer<Location> action, double gap, int height) {
public void beam(Location loc, Consumer<Location> action, double gap, int height) {
for (double y = 0; y <= height; y += gap) {
Location newLoc = loc.clone().add(0, y, 0);
action.accept(newLoc);
}
}
public static void arc(Location loc, double radius, int angleFrom, int angleTo, Consumer<Location> action) {
public void arc(Location loc, double radius, int angleFrom, int angleTo, Consumer<Location> action) {
for (int theta = angleFrom; theta < angleTo; theta += 10) {
double x = Math.cos(Math.toRadians(theta)) * radius;
double z = Math.sin(Math.toRadians(theta)) * radius;
@@ -165,7 +171,7 @@ public class DisplayUtils implements Main {
}
}
public static void arc(Location loc, double radius, int angleFrom, int angleTo, double maxDistanceBetweenPoints, Consumer<Location> action) {
public void arc(Location loc, double radius, int angleFrom, int angleTo, double maxDistanceBetweenPoints, Consumer<Location> action) {
int angleSpan = angleTo - angleFrom;
if (angleSpan <= 0) return;
@@ -182,23 +188,23 @@ public class DisplayUtils implements Main {
}
public static void fan(Location loc, double radius, int angleFrom, int angleTo, Consumer<Location> action, double gap) {
public void fan(Location loc, double radius, int angleFrom, int angleTo, Consumer<Location> action, double gap) {
for (double i = gap; i < radius; i += gap) {
arc(loc, i, angleFrom, angleTo, action);
}
}
public static void fan(Location loc, double radius, int angleFrom, int angleTo, double maxDistanceBetweenPoints, Consumer<Location> action, double radialGap) {
public void fan(Location loc, double radius, int angleFrom, int angleTo, double maxDistanceBetweenPoints, Consumer<Location> action, double radialGap) {
for (double r = radialGap; r < radius; r += radialGap) {
arc(loc, r, angleFrom, angleTo, maxDistanceBetweenPoints, action);
}
}
public static void fanWave(Location loc, double radius, int sections, Consumer<Location> action, double gap) {
public void fanWave(Location loc, double radius, int sections, Consumer<Location> action, double gap) {
double arcLength = 360.0 / sections;
AtomicReference<Double> i = new AtomicReference<>(0.0);
Bukkit.getScheduler().runTaskTimer(main.getPlugin(), (task) -> {
Bukkit.getScheduler().runTaskTimer(context.getPlugin(), (task) -> {
if (i.get() >= 360) {
task.cancel();
return;
@@ -209,7 +215,7 @@ public class DisplayUtils implements Main {
}, 0, 5);
}
public static void fanWaveRandom(Location loc, double radius, int sections, Consumer<Location> action, double gap) {
public void fanWaveRandom(Location loc, double radius, int sections, Consumer<Location> action, double gap) {
double arcLength = 360.0 / sections;
List<Double> ints = new ArrayList<>();
for (double start = 0; start < 360; start += arcLength) {
@@ -218,7 +224,7 @@ public class DisplayUtils implements Main {
AtomicInteger i = new AtomicInteger(0);
Randomizer random = new Randomizer();
Bukkit.getScheduler().runTaskTimer(main.getPlugin(), (task) -> {
Bukkit.getScheduler().runTaskTimer(context.getPlugin(), (task) -> {
if (i.get() >= sections) {
task.cancel();
return;
@@ -230,9 +236,9 @@ public class DisplayUtils implements Main {
}, 0, 5);
}
public static void waveFan(Location loc, double radius, int angleFrom, int angleTo, double maxDistanceBetweenPoints, Consumer<Location> action, double radialGap) {
public void waveFan(Location loc, double radius, int angleFrom, int angleTo, double maxDistanceBetweenPoints, Consumer<Location> action, double radialGap) {
AtomicReference<Double> r = new AtomicReference<>(radialGap);
Bukkit.getScheduler().runTaskTimer(main.getPlugin(), (task) -> {
Bukkit.getScheduler().runTaskTimer(context.getPlugin(), (task) -> {
if (r.get() >= radius) {
task.cancel();
return;
@@ -242,7 +248,7 @@ public class DisplayUtils implements Main {
}, 0, 1);
}
public static void waveFan(Location loc, double radius, Vector direction, int angle, double maxDistanceBetweenPoints, Consumer<Location> action, double radialGap) {
public void waveFan(Location loc, double radius, Vector direction, int angle, double maxDistanceBetweenPoints, Consumer<Location> action, double radialGap) {
double baseAngle = Math.toDegrees(Math.atan2(direction.getZ(), direction.getX()));
int angleFrom = (int) (baseAngle - angle / 2.0);
int angleTo = (int) (baseAngle + angle / 2.0);

View File

@@ -1,6 +1,5 @@
package me.trouper.alias.server.systems.gui;
import me.trouper.alias.server.Main;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
@@ -17,21 +16,18 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
public class QuickGui implements InventoryHolder, Main {
public class QuickGui implements InventoryHolder {
private static final Map<String, QuickGui> registry = new ConcurrentHashMap<>();
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
private final Map<Integer, GuiAction> slotActions;
private final Map<Integer, ItemStack> slotItems;
private final Map<Integer, BukkitTask> animations;
private final GuiAction globalAction;
private final GuiCreateAction createAction;
private final GuiCloseAction closeAction;
@@ -62,7 +58,6 @@ public class QuickGui implements InventoryHolder, Main {
this.clickSound = clickSound;
this.soundVolume = soundVolume;
this.soundPitch = soundPitch;
this.animations = new HashMap<>();
this.viewers = ConcurrentHashMap.newKeySet();
}
@@ -141,46 +136,6 @@ public class QuickGui implements InventoryHolder, Main {
}
}
public void startAnimation(int slot, List<ItemStack> frames, long interval) {
stopAnimation(slot);
if (frames.isEmpty()) return;
BukkitTask task = new BukkitRunnable() {
private int frameIndex = 0;
@Override
public void run() {
if (getInventory().getViewers().isEmpty()) {
cancel();
return;
}
ItemStack frame = frames.get(frameIndex);
getInventory().setItem(slot, frame);
frameIndex = (frameIndex + 1) % frames.size();
}
}.runTaskTimer(main.getPlugin(), 0L, interval);
animations.put(slot, task);
}
public void stopAnimation(int slot) {
BukkitTask task = animations.remove(slot);
if (task != null && !task.isCancelled()) {
task.cancel();
}
}
public void stopAllAnimations() {
animations.values().forEach(task -> {
if (!task.isCancelled()) {
task.cancel();
}
});
animations.clear();
}
private int calculateSize() {
if (size > 0 && size % 9 == 0) {
return Math.min(size, 54);
@@ -233,10 +188,6 @@ public class QuickGui implements InventoryHolder, Main {
viewers.remove(player);
}
if (viewers.isEmpty()) {
stopAllAnimations();
}
closeAction.onClose(this, event);
}

View File

@@ -1,351 +0,0 @@
package me.trouper.alias.server.systems.tracing;
import me.trouper.alias.server.Main;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.entity.BlockDisplay;
import org.bukkit.entity.Display;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Transformation;
import org.bukkit.util.Vector;
import org.bukkit.util.VoxelShape;
import org.joml.AxisAngle4f;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class BlockDisplayRaytracer implements Main {
public static void cleanup() {
JavaPlugin plugin = main.getPlugin();
List<World> worlds = plugin.getServer().getWorlds();
List<Entity> entities = new ArrayList<>();
for (World world : worlds) {
entities.addAll(world.getEntities().stream().filter(entity -> entity.getScoreboardTags().contains(main.getCommon().getTempTag())).toList());
entities.forEach(entity -> {
if (entity != null) entity.remove();
});
}
}
public static void outline(Material display, Location location, long stayTime, List<Player> viewers) {
outline(display, location, 0.05, stayTime, viewers);
}
public static void outline(Material display, Location corner1, Location corner2, double thickness, long stayTime, List<Player> viewers) {
World world = corner1.getWorld();
int minX = Math.min(corner1.getBlockX(), corner2.getBlockX());
int minY = Math.min(corner1.getBlockY(), corner2.getBlockY());
int minZ = Math.min(corner1.getBlockZ(), corner2.getBlockZ());
int maxX = Math.max(corner1.getBlockX(), corner2.getBlockX());
int maxY = Math.max(corner1.getBlockY(), corner2.getBlockY());
int maxZ = Math.max(corner1.getBlockZ(), corner2.getBlockZ());
Location a1 = new Location(world, minX, minY, minZ);
Location a2 = new Location(world, maxX + 1, minY, minZ);
Location a3 = new Location(world, maxX + 1, minY, maxZ + 1);
Location a4 = new Location(world, minX, minY, maxZ + 1);
Location b1 = new Location(world, minX, maxY + 1, minZ);
Location b2 = new Location(world, maxX + 1, maxY + 1, minZ);
Location b3 = new Location(world, maxX + 1, maxY + 1, maxZ + 1);
Location b4 = new Location(world, minX, maxY + 1, maxZ + 1);
trace(display, a1, a2, thickness, stayTime, viewers);
trace(display, a2, a3, thickness, stayTime, viewers);
trace(display, a3, a4, thickness, stayTime, viewers);
trace(display, a4, a1, thickness, stayTime, viewers);
trace(display, b1, b2, thickness, stayTime, viewers);
trace(display, b2, b3, thickness, stayTime, viewers);
trace(display, b3, b4, thickness, stayTime, viewers);
trace(display, b4, b1, thickness, stayTime, viewers);
trace(display, a1, b1, thickness, stayTime, viewers);
trace(display, a2, b2, thickness, stayTime, viewers);
trace(display, a3, b3, thickness, stayTime, viewers);
trace(display, a4, b4, thickness, stayTime, viewers);
}
public static void outline(Material display, Location location, double thickness, long stayTime, List<Player> viewers) {
Location og = location.getBlock().getLocation();
Location a1 = og.clone().add(0, 0, 0);
Location a2 = og.clone().add(1, 0, 0);
Location a3 = og.clone().add(1, 0, 1);
Location a4 = og.clone().add(0, 0, 1);
Location b1 = og.clone().add(0, 1, 0);
Location b2 = og.clone().add(1, 1, 0);
Location b3 = og.clone().add(1, 1, 1);
Location b4 = og.clone().add(0, 1, 1);
trace(display, a1, a2, thickness, stayTime, viewers);
trace(display, a2, a3, thickness, stayTime, viewers);
trace(display, a3, a4, thickness, stayTime, viewers);
trace(display, a4, a1, thickness, stayTime, viewers);
trace(display, b1, b2, thickness, stayTime, viewers);
trace(display, b2, b3, thickness, stayTime, viewers);
trace(display, b3, b4, thickness, stayTime, viewers);
trace(display, b4, b1, thickness, stayTime, viewers);
trace(display, a1, b1, thickness, stayTime, viewers);
trace(display, a2, b2, thickness, stayTime, viewers);
trace(display, a3, b3, thickness, stayTime, viewers);
trace(display, a4, b4, thickness, stayTime, viewers);
}
public static void trace(Material display, Location start, Location end, long stayTime, List<Player> viewers) {
trace(display, start, end.toVector().subtract(start.toVector()), 0.05, end.distance(start), stayTime, viewers);
}
public static void trace(Material display, Location start, Location end, double thickness, long stayTime, List<Player> viewers) {
trace(display, start, end.toVector().subtract(start.toVector()), thickness, end.distance(start), stayTime, viewers);
}
public static void trace(Material display, Location start, Vector direction, double thickness, double distance, long stayTime, List<Player> viewers) {
World world = start.getWorld();
BlockDisplay beam = world.spawn(start, BlockDisplay.class, entity -> {
AxisAngle4f angle = new AxisAngle4f(0, 0, 0, 1);
Vector3f transition = new Vector3f(-(float)(thickness / 2F));
Vector3f scale = new Vector3f((float)thickness, (float)thickness, (float)distance);
Transformation trans = new Transformation(transition, angle, scale, angle);
Location vector = entity.getLocation();
vector.setDirection(direction);
entity.teleport(vector);
entity.setBlock(display.createBlockData());
entity.setBrightness(new Display.Brightness(15, 15));
entity.setInterpolationDelay(0);
entity.setTransformation(trans);
entity.addScoreboardTag(main.getCommon().getTempTag());
for (Player player : Bukkit.getOnlinePlayers()) {
if (!viewers.contains(player)) {
player.hideEntity(main.getPlugin(), entity);
}
}
Bukkit.getScheduler().runTaskLater(main.getPlugin(), entity::remove, stayTime);
});
}
public static void trace(Material display, Location start, Vector direction, double thickness, double distance, long stayTime, Consumer<BlockDisplay> onEntitySpawn, List<Player> viewers) {
World world = start.getWorld();
BlockDisplay beam = world.spawn(start, BlockDisplay.class, entity -> {
AxisAngle4f angle = new AxisAngle4f(0, 0, 0, 1);
Vector3f transition = new Vector3f(-(float)(thickness / 2F));
Vector3f scale = new Vector3f((float)thickness, (float)thickness, (float)distance);
Transformation trans = new Transformation(transition, angle, scale, angle);
Location vector = entity.getLocation();
vector.setDirection(direction);
entity.teleport(vector);
entity.setBlock(display.createBlockData());
entity.setBrightness(new Display.Brightness(15, 15));
entity.setInterpolationDelay(0);
entity.setTransformation(trans);
entity.addScoreboardTag(main.getCommon().getTempTag());
for (Player player : Bukkit.getOnlinePlayers()) {
if (!viewers.contains(player)) {
player.hideEntity(main.getPlugin(), entity);
}
}
Bukkit.getScheduler().runTaskLater(main.getPlugin(), entity::remove, stayTime);
Bukkit.getScheduler().runTaskLater(main.getPlugin(), () -> onEntitySpawn.accept(entity), 5);
});
}
public static List<BlockDisplay> outline(Material display, Location location, long stayTime) {
return outline(display, location, 0.05, stayTime);
}
public static List<BlockDisplay> outline(Material display, Location location, double thickness, long stayTime) {
Location og = location.getBlock().getLocation();
Location a1 = og.clone().add(0, 0, 0);
Location a2 = og.clone().add(1, 0, 0);
Location a3 = og.clone().add(1, 0, 1);
Location a4 = og.clone().add(0, 0, 1);
Location b1 = og.clone().add(0, 1, 0);
Location b2 = og.clone().add(1, 1, 0);
Location b3 = og.clone().add(1, 1, 1);
Location b4 = og.clone().add(0, 1, 1);
List<BlockDisplay> a = new ArrayList<>();
a.add(trace(display, a1, a2, thickness, stayTime));
a.add(trace(display, a2, a3, thickness, stayTime));
a.add(trace(display, a3, a4, thickness, stayTime));
a.add(trace(display, a4, a1, thickness, stayTime));
a.add(trace(display, b1, b2, thickness, stayTime));
a.add(trace(display, b2, b3, thickness, stayTime));
a.add(trace(display, b3, b4, thickness, stayTime));
a.add(trace(display, b4, b1, thickness, stayTime));
a.add(trace(display, a1, b1, thickness, stayTime));
a.add(trace(display, a2, b2, thickness, stayTime));
a.add(trace(display, a3, b3, thickness, stayTime));
a.add(trace(display, a4, b4, thickness, stayTime));
return a;
}
public static void highlightCollisions(Block block, Color color, long stayTime) {
if (block == null || block.isEmpty() || !block.isCollidable())
return;
VoxelShape shape = block.getCollisionShape();
World world = block.getWorld();
Vector offset = block.getLocation().toVector();
for (BoundingBox box : shape.getBoundingBoxes()) {
highlight(box, offset, world, color, stayTime);
}
}
public static void highlight(BoundingBox box, Vector offset, World world, Color color, long stayTime) {
double x1 = box.getMinX() + offset.getX();
double y1 = box.getMinY() + offset.getY();
double z1 = box.getMinZ() + offset.getZ();
double x2 = box.getMaxX() + offset.getX();
double y2 = box.getMaxY() + offset.getY();
double z2 = box.getMaxZ() + offset.getZ();
traceGlowing(world, x1, y1, z1, x2, y1, z1, color, stayTime);
traceGlowing(world, x2, y1, z1, x2, y1, z2, color, stayTime);
traceGlowing(world, x2, y1, z2, x1, y1, z2, color, stayTime);
traceGlowing(world, x1, y1, z2, x1, y1, z1, color, stayTime);
traceGlowing(world, x1, y2, z1, x2, y2, z1, color, stayTime);
traceGlowing(world, x2, y2, z1, x2, y2, z2, color, stayTime);
traceGlowing(world, x2, y2, z2, x1, y2, z2, color, stayTime);
traceGlowing(world, x1, y2, z2, x1, y2, z1, color, stayTime);
traceGlowing(world, x1, y1, z1, x1, y2, z1, color, stayTime);
traceGlowing(world, x2, y1, z1, x2, y2, z1, color, stayTime);
traceGlowing(world, x2, y1, z2, x2, y2, z2, color, stayTime);
traceGlowing(world, x1, y1, z2, x1, y2, z2, color, stayTime);
}
public static void traceGlowing(World world, double x1, double y1, double z1, double x2, double y2, double z2, Color color, long stayTime) {
Location loc1 = new Location(world, x1, y1, z1);
Location loc2 = new Location(world, x2, y2, z2);
BlockDisplay ent = trace(Material.WHITE_CONCRETE, loc1, loc2, 0.01, stayTime);
ent.setGlowColorOverride(color);
ent.setGlowing(true);
}
public static BlockDisplay trace(Material display, Location start, Location end, long stayTime) {
return trace(display, start, end.toVector().subtract(start.toVector()), 0.05, end.distance(start), stayTime);
}
public static BlockDisplay trace(Material display, Location start, Location end, double thickness, long stayTime) {
return trace(display, start, end.toVector().subtract(start.toVector()), thickness, end.distance(start), stayTime);
}
public static BlockDisplay trace(Material display, Location start, Vector direction, double thickness, double distance, long stayTime) {
World world = start.getWorld();
BlockDisplay entity = world.spawn(start, BlockDisplay.class);
AxisAngle4f angle = new AxisAngle4f(0, 0, 0, 1);
Vector3f transition = new Vector3f(-(float)(thickness / 2F));
Vector3f scale = new Vector3f((float)thickness, (float)thickness, (float)distance);
Transformation trans = new Transformation(transition, angle, scale, angle);
Location vector = entity.getLocation();
vector.setDirection(direction);
entity.teleport(vector);
entity.setBlock(display.createBlockData());
entity.setBrightness(new Display.Brightness(15, 15));
entity.setInterpolationDelay(0);
entity.setTransformation(trans);
entity.addScoreboardTag(main.getCommon().getTempTag());
Bukkit.getScheduler().runTaskLater(main.getPlugin(), entity::remove, stayTime);
return entity;
}
public static void transform(BlockDisplay display, Location start, Location end, double thickness) {
Vector direction = end.toVector().subtract(start.toVector());
double distance = direction.length();
Location loc = start.clone();
loc.setDirection(direction);
display.teleport(loc);
Vector3f translation = new Vector3f(-(float)(thickness / 2F), 0, 0); // Centered
Vector3f scale = new Vector3f((float)thickness, (float)thickness, (float)distance);
AxisAngle4f rotation = new AxisAngle4f(0, 0, 0, 1);
Transformation transformation = new Transformation(translation, rotation, scale, rotation);
display.setTransformation(transformation);
}
public static void transform(BlockDisplay display, Location start, Vector direction, double distance, double thickness) {
Location loc = start.clone();
loc.setDirection(direction);
display.teleport(loc);
Vector3f translation = new Vector3f(-(float)(thickness / 2F), 0, 0);
Vector3f scale = new Vector3f((float)thickness, (float)thickness, (float)distance);
AxisAngle4f rotation = new AxisAngle4f(0, 0, 0, 1);
Transformation transformation = new Transformation(translation, rotation, scale, rotation);
display.setTransformation(transformation);
}
public static void translate(BlockDisplay display, Vector3f offset) {
Transformation current = display.getTransformation();
Vector3f translation = new Vector3f(current.getTranslation()).add(offset);
display.setTransformation(new Transformation(
translation,
current.getLeftRotation(),
current.getScale(),
current.getRightRotation()
));
}
public static void scale(BlockDisplay display, Vector3f scale) {
Transformation current = display.getTransformation();
display.setTransformation(new Transformation(
current.getTranslation(),
current.getLeftRotation(),
scale,
current.getRightRotation()
));
}
public static void rotate(BlockDisplay display, AxisAngle4f rotation) {
Transformation current = display.getTransformation();
display.setTransformation(new Transformation(
current.getTranslation(),
rotation,
current.getScale(),
rotation
));
}
public static void alignToDirection(BlockDisplay display, Vector direction) {
Location loc = display.getLocation().clone();
loc.setDirection(direction);
display.teleport(loc);
}
}

View File

@@ -1,27 +0,0 @@
package me.trouper.alias.server.systems.tracing;
import org.bukkit.util.Vector;
public class ReflectionResult {
private final Point hitPoint;
private final boolean shouldReflect;
private final Vector reflectedDirection;
public ReflectionResult(Point hitPoint, boolean shouldReflect, Vector reflectedDirection) {
this.hitPoint = hitPoint;
this.shouldReflect = shouldReflect;
this.reflectedDirection = reflectedDirection;
}
public Point getHitPoint() {
return hitPoint;
}
public boolean shouldReflect() {
return shouldReflect;
}
public Vector getReflectedDirection() {
return reflectedDirection;
}
}

View File

@@ -1,20 +1,26 @@
package me.trouper.alias.server.systems.world;
import me.trouper.alias.server.Main;
import me.trouper.alias.AliasContext;
import me.trouper.alias.server.systems.TaskManager;
import me.trouper.alias.server.systems.burning.BlockBurner;
import me.trouper.alias.server.systems.world.burning.BlockBurner;
import me.trouper.alias.utils.ParticleUtils;
import me.trouper.alias.utils.SoundPlayer;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.entity.LivingEntity;
import org.bukkit.util.Vector;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
public class ExplosionUtils implements Main {
public class Explosion {
public static ExplosionResult createExplosion(Location center, ExplosionOptions options) {
private final AliasContext context;
public Explosion(AliasContext context) {
this.context = context;
}
public ExplosionResult createExplosion(Location center, ExplosionOptions options) {
World world = center.getWorld();
if (world == null) throw new IllegalArgumentException("Center location must have a valid world");
@@ -24,8 +30,8 @@ public class ExplosionUtils implements Main {
Map<Block, Double> affectedBlocks = getBlocksInRadius(center, maxBurnRadius);
Map<UUID, Double> affectedEntities = getEntitiesInRadius(center, maxBurnRadius);
BlockBurner burner = new BlockBurner(options.getBurnOptions());
TaskManager sharedTaskManager = burner.getTaskManager();
TaskManager sharedTaskManager = context.createTaskManager();
BlockBurner burner = new BlockBurner(sharedTaskManager,options.getBurnOptions());
ExplosionResult result = new ExplosionResult(affectedBlocks.keySet(), sharedTaskManager);
List<Block> blocksToDestroy = new ArrayList<>();
@@ -39,7 +45,7 @@ public class ExplosionUtils implements Main {
scheduleDamage(affectedEntities, options, sharedTaskManager);
if (options.isCreateParticles() || options.isPlaySound()) {
createExplosionEffects(center, options);
createExplosionEffects(center, options, sharedTaskManager);
}
return result;
@@ -50,7 +56,7 @@ public class ExplosionUtils implements Main {
}
}
private static Map<Block, Double> getBlocksInRadius(Location center, double radius) {
private Map<Block, Double> getBlocksInRadius(Location center, double radius) {
World world = center.getWorld();
if (world == null) return Collections.emptyMap();
@@ -82,7 +88,7 @@ public class ExplosionUtils implements Main {
return blocks;
}
private static Map<UUID, Double> getEntitiesInRadius(Location center, double radius) {
private Map<UUID, Double> getEntitiesInRadius(Location center, double radius) {
List<LivingEntity> rawList = center.getNearbyEntities(radius, radius, radius).stream()
.filter(entity -> entity instanceof LivingEntity)
.map(entity -> (LivingEntity) entity)
@@ -101,7 +107,7 @@ public class ExplosionUtils implements Main {
return entities;
}
private static void categorizeBlocks(Map<Block, Double> affectedBlocks, ExplosionOptions options,
private void categorizeBlocks(Map<Block, Double> affectedBlocks, ExplosionOptions options,
List<Block> blocksToDestroy, List<Block> blocksToBurn,
Map<Block, Float> blocksHeatMap) {
ThreadLocalRandom random = ThreadLocalRandom.current();
@@ -154,14 +160,14 @@ public class ExplosionUtils implements Main {
}
}
private static float calculateHeat(double distance, ExplosionOptions options) {
private float calculateHeat(double distance, ExplosionOptions options) {
double normalizedDistance = distance / options.getMaxBurnRadius();
double heatRange = options.getMaxHeat() - options.getMinHeat();
double heatFactor = Math.pow(1.0 - normalizedDistance, 2.0);
return (float) (options.getMinHeat() + heatRange * heatFactor);
}
private static void scheduleDestruction(List<Block> blocksToDestroy, ExplosionOptions options, TaskManager taskManager) {
private void scheduleDestruction(List<Block> blocksToDestroy, ExplosionOptions options, TaskManager taskManager) {
if (blocksToDestroy.isEmpty()) return;
long destructionDelayTicks = (long) (options.getDestructionDelay() * 20);
@@ -193,7 +199,7 @@ public class ExplosionUtils implements Main {
}, destructionDelayTicks);
}
private static void scheduleBurning(List<Block> blocksToMaybeBurn, Map<Block, Float> blocksHeatMap,
private void scheduleBurning(List<Block> blocksToMaybeBurn, Map<Block, Float> blocksHeatMap,
BlockBurner burner, Location center, ExplosionOptions options,
TaskManager taskManager) {
if (blocksToMaybeBurn.isEmpty()) return;
@@ -237,7 +243,7 @@ public class ExplosionUtils implements Main {
}, burnDelayTicks);
}
private static void scheduleDamage(Map<UUID, Double> affected, ExplosionOptions options, TaskManager taskManager) {
private void scheduleDamage(Map<UUID, Double> affected, ExplosionOptions options, TaskManager taskManager) {
if (affected.isEmpty()) return;
double baseDamage = options.getBaseDamage();
@@ -279,7 +285,7 @@ public class ExplosionUtils implements Main {
}
}
private static void createExplosionEffects(Location center, ExplosionOptions options) {
private void createExplosionEffects(Location center, ExplosionOptions options, TaskManager taskManager) {
World world = center.getWorld();
if (world == null) return;
@@ -296,16 +302,22 @@ public class ExplosionUtils implements Main {
world.spawnParticle(Particle.EXPLOSION, center, 20, 2, 2, 2, 0.1);
world.spawnParticle(Particle.LARGE_SMOKE, center, 15, 1, 1, 1, 0.05);
world.spawnParticle(Particle.FLAME, center, 30, 3, 3, 3, 0.1);
Bukkit.getScheduler().runTaskLater(main.getPlugin(), () -> {
taskManager.scheduleTask(()->{
if (center.getWorld() != null) {
center.getWorld().spawnParticle(Particle.SMOKE, center, 50, 4, 4, 4, 0.02);
ParticleUtils.builder()
.type(Particle.SMOKE)
.count((int) options.getCoreRadius()*10)
.offset(options.getCoreRadius()/2,options.getCoreRadius()/2,options.getCoreRadius()/2)
.speed(0.05F)
.spawn(center);
}
}, 20L);
},20L);
}
}
private static boolean isOccluded(Block block, Set<Block> doesNotOcclude) {
private boolean isOccluded(Block block, Set<Block> doesNotOcclude) {
if (block == null) return true;
return isOccluding(block.getRelative(0, 1, 0), doesNotOcclude) &&
@@ -316,7 +328,7 @@ public class ExplosionUtils implements Main {
isOccluding(block.getRelative(0, 0, -1), doesNotOcclude);
}
private static boolean isOccluding(Block block, Set<Block> doesNotOcclude) {
private boolean isOccluding(Block block, Set<Block> doesNotOcclude) {
return block != null && block.getType().isOccluding() && !doesNotOcclude.contains(block);
}
}

View File

@@ -1,6 +1,6 @@
package me.trouper.alias.server.systems.world;
import me.trouper.alias.server.systems.burning.BurnOptions;
import me.trouper.alias.server.systems.world.burning.BurnOptions;
public class ExplosionOptions {
private double coreRadius = 3.0;

View File

@@ -1,13 +1,12 @@
package me.trouper.alias.server.systems.world;
import me.trouper.alias.server.Main;
import me.trouper.alias.server.systems.TaskManager;
import org.bukkit.block.Block;
import java.io.Closeable;
import java.util.Set;
public class ExplosionResult implements Closeable, Main {
public class ExplosionResult implements Closeable {
private State previousState;
private TaskManager taskManager;
private volatile boolean closed = false;

View File

@@ -1,7 +1,5 @@
package me.trouper.alias.server.systems.world;
import me.trouper.alias.server.Main;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.inventory.Inventory;
@@ -50,29 +48,27 @@ public class Snapshot {
public void restore(Block block) {
if (block == null || state == null) return;
Bukkit.getScheduler().runTask(Main.main.getPlugin(), () -> {
try {
block.setBlockData(state.getBlockData());
try {
block.setBlockData(state.getBlockData());
if (inventory != null && block.getState() instanceof InventoryHolder) {
InventoryHolder holder = (InventoryHolder) block.getState();
Inventory inv = holder.getInventory();
if (inventory != null && block.getState() instanceof InventoryHolder) {
InventoryHolder holder = (InventoryHolder) block.getState();
Inventory inv = holder.getInventory();
inv.clear();
inv.clear();
for (Map.Entry<Integer, ItemStack> entry : inventory.entrySet()) {
int slot = entry.getKey();
ItemStack item = entry.getValue();
for (Map.Entry<Integer, ItemStack> entry : inventory.entrySet()) {
int slot = entry.getKey();
ItemStack item = entry.getValue();
if (slot >= 0 && slot < inv.getSize() && item != null) {
inv.setItem(slot, item.clone());
}
if (slot >= 0 && slot < inv.getSize() && item != null) {
inv.setItem(slot, item.clone());
}
}
} catch (Exception e) {
System.err.println("Failed to restore block at " + block.getLocation() + ": " + e.getMessage());
}
});
} catch (Exception e) {
System.err.println("Failed to restore block at " + block.getLocation() + ": " + e.getMessage());
}
}
public BlockState getState() {

View File

@@ -4,11 +4,7 @@ import org.bukkit.Location;
import org.bukkit.block.Block;
import java.io.Closeable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
public class State implements Closeable {
private Map<Location, Snapshot> snapshots;

View File

@@ -1,6 +1,5 @@
package me.trouper.alias.server.systems.burning;
package me.trouper.alias.server.systems.world.burning;
import me.trouper.alias.server.Main;
import me.trouper.alias.server.systems.TaskManager;
import org.bukkit.Material;
import org.bukkit.block.Block;
@@ -13,17 +12,17 @@ import java.io.Closeable;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
public class BlockBurner implements Closeable, Main {
public class BlockBurner implements Closeable {
private final BurnOptions options;
private final BurnPalette palette;
private final TaskManager taskManager;
private final Set<Block> visited = new HashSet<>();
private final Map<Block, Material> burning = new HashMap<>();
public BlockBurner(BurnOptions options) {
public BlockBurner(TaskManager taskManager, BurnOptions options) {
this.taskManager = taskManager;
this.options = options;
this.palette = new BurnPalette();
this.taskManager = new TaskManager();
}
@Override

View File

@@ -1,4 +1,4 @@
package me.trouper.alias.server.systems.burning;
package me.trouper.alias.server.systems.world.burning;
public class BurnOptions {
private boolean disabled = false;

View File

@@ -1,4 +1,4 @@
package me.trouper.alias.server.systems.burning;
package me.trouper.alias.server.systems.world.burning;
import org.bukkit.Material;
import org.bukkit.Tag;
@@ -30,7 +30,6 @@ public class BurnPalette {
private final List<BlockData> burnWaveTrail;
public BurnPalette() {
// Initialize burn wave trail
this.burnWaveTrail = Arrays.asList(
Material.ORANGE_STAINED_GLASS.createBlockData(),
Material.BLACK_STAINED_GLASS.createBlockData(),
@@ -38,7 +37,6 @@ public class BurnPalette {
Material.LIGHT_GRAY_STAINED_GLASS.createBlockData()
);
// Initialize main burn wave
List<BlockData> baseBurnWave = new ArrayList<>();
addRepeated(baseBurnWave, Material.ORANGE_STAINED_GLASS, 3);
addRepeated(baseBurnWave, Material.SHROOMLIGHT, 2);

View File

@@ -1,4 +1,4 @@
package me.trouper.alias.server.systems.burning;
package me.trouper.alias.server.systems.world.burning;
import org.bukkit.block.data.BlockData;

View File

@@ -1,41 +1,46 @@
package me.trouper.alias.update;
package me.trouper.alias.server.update;
import me.trouper.alias.Alias;
import me.trouper.alias.AliasContext;
import me.trouper.alias.data.Common;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import me.trouper.alias.utils.UpdateUtils;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
public class AutoUpdater {
public static boolean checkUpdate(JavaPlugin plugin, Common common) {
private final AliasContext context;
public AutoUpdater(AliasContext context) {
this.context = context;
}
public boolean checkUpdate() {
try {
if (UpdateUtils.isDevelopmentEnvironment(plugin)) {
plugin.getLogger().info("Development environment detected, bypassing update check.");
if (UpdateUtils.isDevelopmentEnvironment(context.getPlugin())) {
context.getPlugin().getLogger().info("Development environment detected, bypassing update check.");
return false;
}
String updateURL = common.getUpdateURL();
String updateURL = context.getCommon().getUpdateURL();
if (updateURL == null || updateURL.isEmpty()) {
plugin.getLogger().warning("Update URL is not set.");
context.getPlugin().getLogger().warning("Update URL is not set.");
return false;
}
File updateDir = new File("plugins/update");
if (!updateDir.exists()) updateDir.mkdirs();
File currentFile = UpdateUtils.findPluginJar(plugin);
File currentFile = UpdateUtils.findPluginJar(context.getPlugin());
if (currentFile == null) {
plugin.getLogger().severe("Could not locate plugin file in plugins folder.");
context.getPlugin().getLogger().severe("Could not locate plugin file in plugins folder.");
return false;
}
@@ -44,13 +49,13 @@ public class AutoUpdater {
String remoteHashHex = UpdateUtils.fetchRemoteHash(remoteHashURL);
if (remoteHashHex == null) {
plugin.getLogger().warning("Failed to fetch remote hash from: " + remoteHashURL);
context.getPlugin().getLogger().warning("Failed to fetch remote hash from: " + remoteHashURL);
return false;
}
String currentHashHex = UpdateUtils.bytesToHex(currentHash);
if (remoteHashHex.equalsIgnoreCase(currentHashHex)) {
plugin.getLogger().info("Plugin is up to date.");
context.getPlugin().getLogger().info("Plugin is up to date.");
return false;
}
@@ -60,35 +65,35 @@ public class AutoUpdater {
String updateHashHex = UpdateUtils.bytesToHex(updateHash);
if (remoteHashHex.equalsIgnoreCase(updateHashHex)) {
plugin.getLogger().info("An update is already downloaded and ready.");
context.getPlugin().getLogger().info("An update is already downloaded and ready.");
return false;
} else {
plugin.getLogger().info("Found outdated update file in plugins/update/. It will be replaced.");
context.getPlugin().getLogger().info("Found outdated update file in plugins/update/. It will be replaced.");
updateFile.delete();
}
}
plugin.getLogger().info("Update available. Downloading new version...");
context.getPlugin().getLogger().info("Update available. Downloading new version...");
File downloaded = downloadFile(updateURL);
if (downloaded == null) {
plugin.getLogger().warning("Failed to download update file.");
context.getPlugin().getLogger().warning("Failed to download update file.");
return false;
}
File destination = new File(updateDir, currentFile.getName());
Files.copy(downloaded.toPath(), destination.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
plugin.getLogger().info("Saved updated plugin to: " + destination.getAbsolutePath());
context.getPlugin().getLogger().info("Saved updated plugin to: " + destination.getAbsolutePath());
return true;
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Error during update check", e);
context.getPlugin().getLogger().log(Level.SEVERE, "Error during update check", e);
return false;
}
}
private static File downloadFile(String urlStr) throws IOException {
private File downloadFile(String urlStr) throws IOException {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("User-Agent", "AliasUpdater");

View File

@@ -4,13 +4,14 @@ import org.bukkit.block.BlockState;
import org.bukkit.block.Container;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BlockStateMeta;
public final class InventoryUtils {
public class InventoryUtils {
public static Inventory getInventory(Entity entity) {
if (entity instanceof org.bukkit.inventory.InventoryHolder inventoryHolder) {
if (entity instanceof InventoryHolder inventoryHolder) {
return inventoryHolder.getInventory();
}
return null;

View File

@@ -1,19 +1,27 @@
package me.trouper.alias.utils;
import com.destroystokyo.paper.profile.PlayerProfile;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.profile.PlayerTextures;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.function.Function;
public class ItemBuilder {
@@ -202,6 +210,78 @@ public class ItemBuilder {
return this;
}
public ItemBuilder playerHead(String playerName) {
ensurePlayerHead();
if (this.meta instanceof SkullMeta skullMeta) {
OfflinePlayer player = Bukkit.getOfflinePlayer(playerName);
skullMeta.setOwningPlayer(player);
}
return this;
}
public ItemBuilder playerHead(OfflinePlayer player) {
ensurePlayerHead();
if (this.meta instanceof SkullMeta skullMeta) {
skullMeta.setOwningPlayer(player);
}
return this;
}
public ItemBuilder playerHead(UUID uuid) {
ensurePlayerHead();
if (this.meta instanceof SkullMeta skullMeta) {
OfflinePlayer player = Bukkit.getOfflinePlayer(uuid);
skullMeta.setOwningPlayer(player);
}
return this;
}
public ItemBuilder skullTexture(String textureUrl) {
ensurePlayerHead();
if (this.meta instanceof SkullMeta skullMeta) {
try {
PlayerProfile profile = Bukkit.createProfile(UUID.randomUUID());
PlayerTextures textures = profile.getTextures();
textures.setSkin(new URL(textureUrl));
profile.setTextures(textures);
skullMeta.setPlayerProfile(profile);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Invalid texture URL: " + textureUrl, e);
}
}
return this;
}
public ItemBuilder skullProfile(PlayerProfile profile) {
ensurePlayerHead();
if (this.meta instanceof SkullMeta skullMeta) {
skullMeta.setPlayerProfile(profile);
}
return this;
}
public ItemBuilder createPlayerHead(String playerName, String displayName) {
return material(Material.PLAYER_HEAD)
.playerHead(playerName)
.displayName(displayName);
}
public ItemBuilder createCustomHead(String textureUrl, String displayName) {
return material(Material.PLAYER_HEAD)
.skullTexture(textureUrl)
.displayName(displayName);
}
private void ensurePlayerHead() {
if (this.stack.getType() != Material.PLAYER_HEAD) {
this.stack = this.stack.withType(Material.PLAYER_HEAD);
this.meta = this.stack.getItemMeta();
if (this.meta == null) {
throw new IllegalStateException("Failed to get SkullMeta after converting to player head");
}
}
}
public ItemStack build() {
this.stack.setItemMeta(this.meta);
return this.stack.clone();
@@ -246,4 +326,14 @@ public class ItemBuilder {
public static ItemBuilder of(ItemStack stack) {
return create(stack);
}
public static ItemBuilder headOf(String playerName) {
return create(Material.PLAYER_HEAD)
.playerHead(playerName);
}
public static ItemBuilder headOfTexture(String url) {
return create(Material.PLAYER_HEAD)
.skullTexture(url);
}
}

View File

@@ -1,6 +1,8 @@
package me.trouper.alias.server.systems.visual;
package me.trouper.alias.utils;
import org.bukkit.*;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;

View File

@@ -1,4 +1,4 @@
package me.trouper.alias.update;
package me.trouper.alias.utils;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
@@ -86,7 +86,6 @@ public class UpdateUtils {
try {
return "TRUE".equalsIgnoreCase(System.getenv("ALIAS_DEVELOPMENT"));
} catch (Exception e) {
plugin.getLogger().warning("Could not determine runtime environment, assuming production.");
return false;
}
}

View File

@@ -3,7 +3,6 @@ package me.trouper.alias.utils.misc;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;