too many things, kinda forgor to push/commit
Some checks failed
Build / build (push) Successful in 3m43s
Format / formatting (push) Failing after 19s

This commit is contained in:
unurled 2024-10-11 12:29:44 +02:00
parent 897edf1d37
commit bb514f8a63
Signed by: unurled
GPG key ID: EFC5F5E709B47DDD
69 changed files with 1691 additions and 1256 deletions

View file

@ -0,0 +1,17 @@
name: Format
run-name: ${{ github.actor }} is formatting
on: [ push, pull_request ]
jobs:
formatting:
runs-on: docker
steps:
- uses: actions/checkout@v4
- uses: axel-op/googlejavaformat-action@v3
with:
args: "--replace"
skip-commit: true
- name: Print diffs
run: git --no-pager diff --exit-code

View file

@ -20,3 +20,5 @@ see [docs](https://git.unurled.me/SacredRealms/docs) for more information
- [Java 17](https://adoptium.net/temurin/releases/?version=17)
- [PaperMC 1.20.6](https://papermc.io/downloads/paper) or any fork of it (purpur, etc)
- a build of the plugin
spigot plugin development 90 replay plugin - 1:43:02

View file

@ -2,7 +2,7 @@ import net.minecrell.pluginyml.bukkit.BukkitPluginDescription
plugins {
`java-library`
id("io.papermc.paperweight.userdev") version "1.7.2"
id("io.papermc.paperweight.userdev") version "1.7.3"
id("org.sonarqube") version "5.1.0.4882"
id("net.minecrell.plugin-yml.paper") version "0.6.0"
}
@ -36,6 +36,10 @@ repositories {
name = "unurled"
url = uri("https://repo.unurled.me/releases")
}
maven {
name = "cubbossa"
url = uri("https://nexus.leonardbausenwein.de/repository/maven-releases/")
}
}
dependencies {
@ -47,9 +51,9 @@ dependencies {
paperLibrary("redis.clients", "jedis", redisVersion)
paperLibrary("com.github.retrooper", "packetevents-spigot", "2.4.0")
paperLibrary("com.github.retrooper", "packetevents-spigot", "2.5.0")
paperLibrary("me.unurled", "SR-Core", "0.1.0")
compileOnly("me.unurled:SR-Core:0.1.1")
}
java {
@ -106,7 +110,7 @@ paper {
"sr.resetadventure",
"sr.treasure.manage",
"sr.difficulty.*",
"sr.cutscene"
"sr.cutscene.*"
)
description = "Gives access to all Sacred Realms permissions."
}
@ -151,6 +155,10 @@ paper {
}
register("sr.cutscene") {
description = "Gives access to the cutscene command."
children = listOf(
"sr.cutscene.create",
"sr.cutscene.replay"
)
}
}
}

View file

@ -6,6 +6,9 @@ import java.util.List;
import me.unurled.sacredrealms.sr.components.block.BlockManager;
import me.unurled.sacredrealms.sr.components.clientbuild.ClientBuildManager;
import me.unurled.sacredrealms.sr.components.combat.CombatManager;
import me.unurled.sacredrealms.sr.components.cutscene.CutsceneManager;
import me.unurled.sacredrealms.sr.components.cutscene.RecordingManager;
import me.unurled.sacredrealms.sr.components.cutscene.ReplayManager;
import me.unurled.sacredrealms.sr.components.entity.EntityManager;
import me.unurled.sacredrealms.sr.components.item.ItemManager;
import me.unurled.sacredrealms.sr.components.npc.NPCManager;
@ -31,6 +34,7 @@ public final class SR extends JavaPlugin {
@Override
public void onLoad() {
PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this));
PacketEvents.getAPI().getSettings().reEncodeByDefault(false).checkForUpdates(true);
// On Bukkit, calling this here is essential, hence the name "load"
PacketEvents.getAPI().load();
}
@ -39,10 +43,10 @@ public final class SR extends JavaPlugin {
public void onEnable() {
plugin = this;
SRCore.getInstance().setPlugin(this);
PacketEvents.getAPI().init();
SRCore.getInstance().setPlugin(this);
InvUI.getInstance().setPlugin(this);
SRCore.getInstance()
@ -61,7 +65,10 @@ public final class SR extends JavaPlugin {
ClientBuildManager.class,
TreasureManager.class,
BackgroundManager.class,
ResourcePackManager.class));
ResourcePackManager.class,
CutsceneManager.class,
RecordingManager.class,
ReplayManager.class));
}
@Override

View file

@ -25,6 +25,11 @@ public class SRLoader implements PluginLoader {
resolver.addRepository(
new RemoteRepository.Builder("invui", "default", "https://repo.xenondevs.xyz/releases/")
.build());
resolver.addDependency(new Dependency(new DefaultArtifact("me.unurled:SR-Core:0.1.1"), null));
resolver.addRepository(
new RemoteRepository.Builder("srcore", "default", "https://repo.unurled.me/releases")
.build());
classpathBuilder.addLibrary(resolver);
PluginLibraries pluginLibraries = load();

View file

@ -11,12 +11,14 @@ import java.util.Collection;
import java.util.List;
import me.unurled.sacredrealms.sr.commands.admin.AttributeCommand;
import me.unurled.sacredrealms.sr.commands.admin.ClientBuildCommand;
import me.unurled.sacredrealms.sr.commands.admin.CutsceneCommand;
import me.unurled.sacredrealms.sr.commands.admin.EntityTypeCommand;
import me.unurled.sacredrealms.sr.commands.admin.ItemCommand;
import me.unurled.sacredrealms.sr.commands.admin.LevelCommand;
import me.unurled.sacredrealms.sr.commands.admin.SpawnEntityCommand;
import me.unurled.sacredrealms.sr.commands.admin.TreasureCommand;
import me.unurled.sacredrealms.sr.commands.admin.cutscene.CreateCutsceneCommand;
import me.unurled.sacredrealms.sr.commands.admin.cutscene.RecordCutsceneCommand;
import me.unurled.sacredrealms.sr.commands.admin.cutscene.StopRecordingCommand;
import me.unurled.sacredrealms.sr.commands.player.DifficultyCommand;
import me.unurled.sacredrealms.sr.commands.player.ResetAdventureCommand;
import me.unurled.srcore.api.Manager;
@ -51,7 +53,6 @@ public class CommandManager extends Manager {
}
public static void loadCommands(BootstrapContext ctx) {
registerCommand("attributes", "Set the attributes of the player.", ctx, AttributeCommand.class);
registerCommand(
"clientbuild", "Set the client build of the player.", ctx, ClientBuildCommand.class);
@ -66,6 +67,17 @@ public class CommandManager extends Manager {
registerCommand(
"difficulty", "Set the difficulty of the player.", ctx, DifficultyCommand.class);
registerCommand("cutscene", "Cutscene commands.", List.of("cs"), ctx, CutsceneCommand.class);
registerCommand("createcustcene", "Create a new Cutscene", ctx, CreateCutsceneCommand.class);
registerCommand(
"recordcutscene",
"Record a cutscene entity movement and everything",
ctx,
RecordCutsceneCommand.class);
registerCommand(
"stopcutscene",
"stop a record of a cutscene entity movement and everything",
ctx,
StopRecordingCommand.class);
}
}

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.commands.admin;
import static me.unurled.sacredrealms.sr.utils.Component.comp;
import static me.unurled.srcore.utils.Component.comp;
import static me.unurled.sacredrealms.sr.utils.SRPlayerUtils.syncSRToPlayer;
import io.papermc.paper.command.brigadier.BasicCommand;

View file

@ -1,7 +1,7 @@
package me.unurled.sacredrealms.sr.commands.admin;
import static me.unurled.sacredrealms.sr.utils.Component.ERROR;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.ERROR;
import static me.unurled.srcore.utils.Component.textComp;
import static me.unurled.sacredrealms.sr.utils.Logger.log;
import io.papermc.paper.command.brigadier.BasicCommand;

View file

@ -1,166 +0,0 @@
package me.unurled.sacredrealms.sr.commands.admin;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import me.unurled.sacredrealms.sr.components.cutscene.Cutscene;
import me.unurled.sacredrealms.sr.components.cutscene.CutsceneManager;
import me.unurled.srcore.api.Manager;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class CutsceneCommand implements BasicCommand {
private CutsceneManager cutsceneManager;
/**
* Returns the permission for the root command used in {@link #canUse(CommandSender)} by default.
*
* @return the permission for the root command used in {@link #canUse(CommandSender)}
*/
@Override
public @Nullable String permission() {
return "cutscenes.admin";
}
/**
* Executes the command with the given {@link CommandSourceStack} and arguments.
*
* @param sender the commandSourceStack of the command
* @param args the arguments of the command ignoring repeated spaces
*/
@Override
public void execute(@NotNull CommandSourceStack sender, @NotNull String @NotNull [] args) {
if (cutsceneManager == null) {
cutsceneManager = Manager.getInstance(CutsceneManager.class);
}
// /cs stop, list, reload, play, create, remove
if (args.length == 1) {
if (args[0].equals("stop")) {
if (sender.getSender() instanceof Player p) {
cutsceneManager.stopCutscene(p);
} else {
sender
.getSender()
.sendMessage(
textComp("<red>You must be a player to stop a cutscene. Use /cs stop <player>"));
}
} else if (args[0].equals("list")) {
sender
.getSender()
.sendMessage(
textComp("<yellow>Cutscenes: " + cutsceneManager.getCutscenesId().toString()));
} else if (args[0].equals("reload")) {
}
} else if (args.length == 2) {
if (args[0].equals("play")) {
if (sender.getSender() instanceof Player p) {
Cutscene cutscene = cutsceneManager.getCutscene(args[1]);
cutsceneManager.playCutscene(cutscene, p);
} else {
sender
.getSender()
.sendMessage(
textComp(
"<red>You must be a player to play a cutscene. Use /cs play <cutscene_id> <player>"));
}
} else if (args[0].equals("stop")) {
Player p = Bukkit.getPlayer(args[1]);
if (p != null) {
cutsceneManager.stopCutscene(p);
}
} else if (args[0].equals("create")) {
String name = args[1];
cutsceneManager.createCutscene(name);
sender.getSender().sendMessage(textComp("<green>Created cutscene " + name));
} else if (args[0].equals("remove")) {
String name = args[1];
cutsceneManager.removeCutscene(name);
sender.getSender().sendMessage(textComp("<red>Removed cutscene " + name));
}
} else if (args.length == 3) {
if (args[0].equals("play")) {
Player p = Bukkit.getPlayer(args[2]);
if (p != null) {
Cutscene cutscene = cutsceneManager.getCutscene(args[1]);
cutsceneManager.playCutscene(cutscene, p);
}
}
} else {
sender
.getSender()
.sendMessage(
textComp(
"<yellow>Usage: /cs <play|stop|reload|list> <cutscene_id|player (only play and stop)> <player (only possible if play with an id before)>"));
}
}
/**
* Suggests possible completions for the given command {@link CommandSourceStack} and arguments.
*
* @param sender the commandSourceStack of the command
* @param args the arguments of the command including repeated spaces
* @return a collection of suggestions
*/
@Override
public @NotNull Collection<String> suggest(
@NotNull CommandSourceStack sender, @NotNull String[] args) {
if (cutsceneManager == null) {
cutsceneManager = Manager.getInstance(CutsceneManager.class);
}
List<String> complete = new ArrayList<>();
complete.add("stop");
if (sender.getSender().hasPermission("cutscenes.admin")) {
complete.add("play");
complete.add("list");
complete.add("reload");
complete.add("create");
complete.add("remove");
}
List<String> result = new ArrayList<>();
if (args.length == 1) {
for (String s : complete) {
if (s.toLowerCase().startsWith(args[0].toLowerCase())) {
result.add(s);
}
}
return result;
} else if (args.length == 2) {
if (sender.getSender().hasPermission("cutscenes.admin")) {
if (args[0].equalsIgnoreCase("stop")) {
for (Player p : Bukkit.getOnlinePlayers()) {
if (p.getName().toLowerCase().startsWith(args[1].toLowerCase())) {
result.add(p.getName());
}
}
} else if (args[0].equalsIgnoreCase("play") || args[0].equalsIgnoreCase("remove")) {
for (String s : cutsceneManager.getCutscenesId()) {
if (s.toLowerCase().startsWith(args[1].toLowerCase())) {
result.add(s);
}
}
}
}
return result;
} else if (args.length == 3) {
if (sender.getSender().hasPermission("cutscenes.admin")) {
if (args[0].equalsIgnoreCase("play")) {
for (Player p : Bukkit.getOnlinePlayers()) {
if (p.getName().toLowerCase().startsWith(args[2].toLowerCase())) {
result.add(p.getName());
}
}
}
}
}
return List.of();
}
}

View file

@ -1,8 +1,8 @@
package me.unurled.sacredrealms.sr.commands.admin;
import static me.unurled.sacredrealms.sr.utils.Component.NOT_PLAYER;
import static me.unurled.sacredrealms.sr.utils.Component.comp;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.NOT_PLAYER;
import static me.unurled.srcore.utils.Component.comp;
import static me.unurled.srcore.utils.Component.textComp;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.commands.admin;
import static me.unurled.sacredrealms.sr.utils.Component.comp;
import static me.unurled.srcore.utils.Component.comp;
import static me.unurled.sacredrealms.sr.utils.Logger.error;
import io.papermc.paper.command.brigadier.BasicCommand;

View file

@ -1,7 +1,7 @@
package me.unurled.sacredrealms.sr.commands.admin;
import static me.unurled.sacredrealms.sr.utils.Component.NO_PERMISSION;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.NO_PERMISSION;
import static me.unurled.srcore.utils.Component.textComp;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;

View file

@ -1,7 +1,7 @@
package me.unurled.sacredrealms.sr.commands.admin;
import static me.unurled.sacredrealms.sr.utils.Component.NOT_PLAYER;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.NOT_PLAYER;
import static me.unurled.srcore.utils.Component.textComp;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;

View file

@ -0,0 +1,53 @@
package me.unurled.sacredrealms.sr.commands.admin.cutscene;
import static me.unurled.srcore.utils.Component.NOT_PLAYER;
import static me.unurled.srcore.utils.Component.NO_PERMISSION;
import static me.unurled.srcore.utils.Component.textComp;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import java.util.Collection;
import java.util.List;
import me.unurled.sacredrealms.sr.components.cutscene.CutsceneManager;
import me.unurled.srcore.api.Manager;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class CreateCutsceneCommand implements BasicCommand {
private CutsceneManager cm;
@Override
public void execute(@NotNull CommandSourceStack sender, String[] args) {
if (!(sender.getSender() instanceof Player p)) {
sender.getSender().sendMessage(textComp(NOT_PLAYER));
return;
}
if (!p.hasPermission("sr.cutscene.create")) {
p.sendMessage(textComp(NO_PERMISSION));
return;
}
// get the name
if (args.length < 1) {
p.sendMessage("Usage: /cs <name>");
return;
}
String name = args[0];
// create the cutscene
if (cm == null) {
cm = Manager.getInstance(CutsceneManager.class);
}
cm.startCreatingCutscene(p, name);
}
@Override
public Collection<String> suggest(
CommandSourceStack commandSourceStack, String @NotNull [] args) {
if (args.length == 1) {
return List.of("name");
}
return BasicCommand.super.suggest(commandSourceStack, args);
}
}

View file

@ -0,0 +1,51 @@
package me.unurled.sacredrealms.sr.commands.admin.cutscene;
import static me.unurled.srcore.utils.Component.NO_PERMISSION;
import static me.unurled.srcore.utils.Component.textComp;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import me.unurled.sacredrealms.sr.components.cutscene.Cutscene;
import me.unurled.sacredrealms.sr.components.cutscene.CutsceneManager;
import me.unurled.sacredrealms.sr.components.cutscene.RecordingManager;
import me.unurled.sacredrealms.sr.components.cutscene.recording.Recording;
import me.unurled.srcore.api.Manager;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class RecordCutsceneCommand implements BasicCommand {
private RecordingManager rm;
@Override
public void execute(@NotNull CommandSourceStack stack, String[] args) {
if (!(stack.getSender() instanceof Player p)) {
return;
}
if (!p.hasPermission("sr.cutscene.create")) {
p.sendMessage(textComp(NO_PERMISSION));
return;
}
if (rm == null) {
rm = Manager.getInstance(RecordingManager.class);
}
Recording activeRecording = rm.getPlayerActiveRecording(p);
if (activeRecording != null) {
p.sendMessage("You are already recording a cutscene.");
return;
}
Cutscene cutscene =
Manager.getInstance(CutsceneManager.class).getCutsceneBeingCreated(p.getUniqueId());
if (cutscene == null) {
p.sendMessage("You are not creating a cutscene.");
return;
}
activeRecording = new Recording(cutscene, p);
// open menu for selection cutscene
}
}

View file

@ -0,0 +1,33 @@
package me.unurled.sacredrealms.sr.commands.admin.cutscene;
import static me.unurled.srcore.utils.Component.NOT_PLAYER;
import static me.unurled.srcore.utils.Component.NO_PERMISSION;
import static me.unurled.srcore.utils.Component.textComp;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import java.util.Collection;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class ReplayCommand implements BasicCommand {
@Override
public void execute(@NotNull CommandSourceStack stack, String[] args) {
if (!(stack.getSender() instanceof Player p)) {
stack.getSender().sendMessage(textComp(NOT_PLAYER));
return;
}
if (!p.hasPermission("sr.cutscene.replay")) {
p.sendMessage(textComp(NO_PERMISSION));
}
// aaa
}
@Override
public Collection<String> suggest(CommandSourceStack stack, String[] args) {
return BasicCommand.super.suggest(stack, args);
}
}

View file

@ -0,0 +1,35 @@
package me.unurled.sacredrealms.sr.commands.admin.cutscene;
import static me.unurled.srcore.utils.Component.NOT_PLAYER;
import static me.unurled.srcore.utils.Component.NO_PERMISSION;
import static me.unurled.srcore.utils.Component.textComp;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import java.util.Collection;
import me.unurled.sacredrealms.sr.components.cutscene.RecordingManager;
import me.unurled.srcore.api.Manager;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class StopRecordingCommand implements BasicCommand {
@Override
public void execute(@NotNull CommandSourceStack stack, String[] args) {
if (!(stack.getSender() instanceof Player p)) {
stack.getSender().sendMessage(textComp(NOT_PLAYER));
return;
}
if (!p.hasPermission("sr.cutscene.create")) {
p.sendMessage(textComp(NO_PERMISSION));
return;
}
Manager.getInstance(RecordingManager.class).stopRecording(p);
}
@Override
public Collection<String> suggest(CommandSourceStack commandSourceStack, String[] args) {
return BasicCommand.super.suggest(commandSourceStack, args);
}
}

View file

@ -1,9 +1,9 @@
package me.unurled.sacredrealms.sr.commands.player;
import static me.unurled.sacredrealms.sr.utils.Component.NOT_PLAYER;
import static me.unurled.sacredrealms.sr.utils.Component.NO_PERMISSION;
import static me.unurled.sacredrealms.sr.utils.Component.PLAYER_NOT_FOUND;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.NOT_PLAYER;
import static me.unurled.srcore.utils.Component.NO_PERMISSION;
import static me.unurled.srcore.utils.Component.PLAYER_NOT_FOUND;
import static me.unurled.srcore.utils.Component.textComp;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.commands.player;
import static me.unurled.sacredrealms.sr.utils.Component.comp;
import static me.unurled.srcore.utils.Component.comp;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.components.block;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.textComp;
import static me.unurled.sacredrealms.sr.utils.Logger.error;
import java.util.ArrayList;

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.components.combat;
import static me.unurled.sacredrealms.sr.utils.Component.comp;
import static me.unurled.srcore.utils.Component.comp;
import static me.unurled.sacredrealms.sr.utils.SRPlayerUtils.spawnIndicator;
import static me.unurled.sacredrealms.sr.utils.SRPlayerUtils.updateActionBar;

View file

@ -1,26 +0,0 @@
package me.unurled.sacredrealms.sr.components.cutscene;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity;
public enum Action {
IDLE(),
MOVE(Location.class),
TELEPORT(Location.class),
SPAWN(Location.class),
DESPAWN(),
HIT(Entity.class),
SNEAK(),
JUMP(),
PLACE(Location.class, BlockData.class),
INTERACT(Location.class, org.bukkit.event.block.Action.class),
BREAK(Location.class);
private final List<Class> types;
Action(Class... types) {
this.types = List.of(types);
}
}

View file

@ -0,0 +1,121 @@
package me.unurled.sacredrealms.sr.components.cutscene;
import static me.unurled.srcore.utils.Component.textComp;
import static org.bukkit.Material.RED_WOOL;
import me.unurled.sacredrealms.sr.utils.Region;
import me.unurled.sacredrealms.sr.utils.RegionUtil;
import me.unurled.srcore.api.Manager;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.jetbrains.annotations.NotNull;
public class CreationListener implements Listener {
private CutsceneManager cm;
@EventHandler
public void onInventoryClick(@NotNull InventoryClickEvent e) {
if (e.getWhoClicked() instanceof Player p) {
if (cm == null) {
cm = Manager.getInstance(CutsceneManager.class);
}
Cutscene cutscene = cm.getCutsceneBeingCreated(p.getUniqueId());
if (cutscene == null) {
return;
}
e.setCancelled(true);
}
}
@EventHandler
public void onRightClick(@NotNull PlayerInteractEvent e) {
if (!e.getAction().isRightClick()) {
return;
}
Player p = e.getPlayer();
if (cm == null) {
cm = Manager.getInstance(CutsceneManager.class);
}
Cutscene cutscene = cm.getCutsceneBeingCreated(p.getUniqueId());
if (cutscene == null) {
return;
}
e.setCancelled(true);
if (e.getItem() == null) {
return;
}
switch (e.getItem().getType()) {
case BARRIER -> {
RegionUtil.killSelectorsWithTag(cutscene.name());
cm.cancelCreatingCutscene(p);
}
case EMERALD_BLOCK -> {
if (cutscene.pos1() == null) {
p.sendMessage(textComp("<red>Pos1 not set. Click on Red Wool."));
return;
}
if (cutscene.pos2() == null) {
p.sendMessage(textComp("<red>Pos2 not set. Click on Blue Wool."));
return;
}
cm.finishCreatingCutscene(p);
RegionUtil.killSelectorsWithTag(cutscene.name());
}
case RED_WOOL, BLUE_WOOL -> {
Location loc = null;
if (e.getAction() == Action.RIGHT_CLICK_BLOCK && e.getClickedBlock() != null) {
loc = e.getClickedBlock().getLocation();
} else if (e.getAction() == Action.RIGHT_CLICK_AIR) {
loc = e.getPlayer().getLocation();
}
if (e.getItem().getType() == RED_WOOL) {
p.sendMessage(textComp("<green>Pos1 set."));
cutscene.setPos1(loc);
} else {
p.sendMessage(textComp("<green>Pos2 set."));
cutscene.setPos2(loc);
}
if (cutscene.pos1() != null && cutscene.pos2() != null) {
Region region = new Region();
region.setCorner1(cutscene.pos1());
region.setCorner2(cutscene.pos2());
if (loc == null) return;
RegionUtil.killSelectorsWithTag(cutscene.name());
RegionUtil.drawSelector(region, loc.getWorld(), cutscene.name(), NamedTextColor.GREEN);
p.sendMessage(
textComp(
"<green>You have set both corners! Right click the Emerald block to finish."));
} else if (cutscene.pos1() != null && cutscene.pos2() == null) {
Region region = new Region();
region.setCorner1(cutscene.pos1());
region.setCorner2(cutscene.pos1());
if (loc == null) return;
RegionUtil.killSelectorsWithTag(cutscene.name());
RegionUtil.drawSelector(region, loc.getWorld(), cutscene.name(), NamedTextColor.YELLOW);
} else if (cutscene.pos1() == null && cutscene.pos2() != null) {
Region region = new Region();
region.setCorner1(cutscene.pos2());
region.setCorner2(cutscene.pos2());
if (loc == null) return;
RegionUtil.killSelectorsWithTag(cutscene.name());
RegionUtil.drawSelector(region, loc.getWorld(), cutscene.name(), NamedTextColor.YELLOW);
}
}
}
}
}

View file

@ -1,239 +1,80 @@
package me.unurled.sacredrealms.sr.components.cutscene;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.sacredrealms.sr.utils.CutsceneUtil.showBlackScreen;
import static me.unurled.sacredrealms.sr.utils.Logger.error;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import me.unurled.sacredrealms.sr.SR;
import me.unurled.srcore.api.Manager;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull;
/**
* Cutscene class
*
* <p>Represents a cutscene
*
* <pre>{@code
* {
* "id": "cutscene1",
* "name": "Cutscene 1",
* "markers": [1, 2, 3], // Marker IDs
* "start": {
* "world": "world",
* "x": 0,
* "y": 0,
* "z": 0,
* "yaw": 0,
* "pitch": 0
* },
* "end": {
* "world": "world",
* "x": 0,
* "y": 0,
* "z": 0,
* "yaw": 0,
* "pitch": 0
* }
* "blackBorders": true,
* "startFadeToBlack": true,
* "endFadeToBlack": true
* }
* }</pre>
*/
public class Cutscene {
private final String id;
private final String name;
private final List<Marker> markers;
private final List<Integer> markerIds;
private CutsceneManager cutsceneManager;
private Location start;
private Location end;
private Map<UUID, BukkitTask> tasks;
private boolean blackBorders;
private boolean startFadeToBlack;
private boolean endFadeToBlack;
private UUID id = UUID.randomUUID();
private String name;
private Location pos1;
private Location pos2;
public Cutscene(String id, String name) {
public Cutscene() {}
public Cutscene(String name) {
this.name = name;
}
public Cutscene(UUID id, String name, Location pos1, Location pos2) {
this.id = id;
this.name = name;
this.markers = new ArrayList<>();
this.markerIds = new ArrayList<>();
this.tasks = new HashMap<>();
cutsceneManager = Manager.getInstance(CutsceneManager.class);
if (cutsceneManager == null) {
error("CutsceneManager is null, could not create a Cutscene");
}
this.pos1 = pos1;
this.pos2 = pos2;
}
public Cutscene(@NotNull String id, String name, @NotNull ArrayList<Marker> markers) {
this.id = id.toUpperCase();
public boolean isInRegion(@NotNull Location location) {
double x1 = pos1.getX();
double x2 = pos2.getX();
double y1 = pos1.getY();
double y2 = pos2.getY();
double z1 = pos1.getZ();
double z2 = pos2.getZ();
double x = location.getX();
double y = location.getY();
double z = location.getZ();
return x >= Math.min(x1, x2)
&& x <= Math.max(x1, x2)
&& y >= Math.min(y1, y2)
&& y <= Math.max(y1, y2)
&& z >= Math.min(z1, z2)
&& z <= Math.max(z1, z2);
}
public UUID id() {
return id;
}
public Cutscene setId(UUID id) {
this.id = id;
return this;
}
public String name() {
return name;
}
public Cutscene setName(String name) {
this.name = name;
this.markers = markers;
markerIds = new ArrayList<>();
for (Marker marker : markers) {
markerIds.add(marker.getId());
}
if (markers.isEmpty()) return;
if (markers.getFirst().getFrames().isEmpty()) return;
start = markers.getFirst().getFrames().getFirst().getLocation();
end = markers.getLast().getFrames().getLast().getLocation();
this.tasks = new HashMap<>();
cutsceneManager = Manager.getInstance(CutsceneManager.class);
if (cutsceneManager == null) {
error("CutsceneManager is null, could not create a Cutscene");
}
return this;
}
public void setMarkers() {
for (Integer i : markerIds) {
markers.add(Marker.getMarker(i));
}
public Location pos1() {
return pos1;
}
public void addMarker(Marker marker) {
this.markers.add(marker);
public Cutscene setPos1(Location pos1) {
this.pos1 = pos1;
return this;
}
public String getId() {
return this.id.toUpperCase();
public Location pos2() {
return pos2;
}
public String getName() {
return this.name;
}
public List<Marker> getMarkers() {
return this.markers;
}
public Location getStart() {
return this.start;
}
public void setStart(Location start) {
this.start = start;
}
public Location getEnd() {
return this.end;
}
public void setEnd(Location end) {
this.end = end;
}
public void addMarkerId(Integer id) {
this.markerIds.add(id);
}
public long time() {
long time = 0;
for (Marker marker : this.markers) {
if (marker.getOverAllTime() != null) time += marker.getOverAllTime();
}
return time;
}
public void play(@NotNull Player p) {
if (cutsceneManager.isPlayingCutscene(p)) {
p.sendMessage(textComp("You are already playing a cutscene!"));
}
cutsceneManager.addCurrentPlayingCutscene(this, p);
// hide toolbar and make it spectate entity
p.setGameMode(GameMode.SPECTATOR);
// set black borders
if (blackBorders) {
p.getInventory().setHelmet(new ItemStack(Material.PUMPKIN));
p.updateInventory();
}
if (startFadeToBlack) {
showBlackScreen(p, 2, 1, 1);
}
BukkitTask task =
Bukkit.getScheduler()
.runTaskAsynchronously(
SR.getPlugin(),
() -> {
int finalI = 0;
for (Marker marker : markers) {
for (int i = 0; i < marker.getFrames().size(); i++) {
int finalI1 = i;
Bukkit.getScheduler()
.runTaskLater(
SR.getPlugin(),
() -> {
p.teleport(marker.getFrames().get(finalI1).getLocation());
marker.getFrames().get(finalI1).play();
},
(marker.getTimeBetweenFrames() * finalI) / 50);
finalI++;
}
}
if (endFadeToBlack) {
Bukkit.getScheduler()
.runTask(SR.getPlugin(), () -> showBlackScreen(p, 2, 1, 1));
}
});
Bukkit.getScheduler()
.runTaskAsynchronously(
SR.getPlugin(),
() -> {
try {
Thread.sleep(time());
} catch (InterruptedException e) {
error("Error while playing cutscene: " + e.getMessage());
}
Bukkit.getScheduler().runTask(SR.getPlugin(), () -> stop(p));
});
tasks.put(p.getUniqueId(), task);
}
public void stop(UUID player) {
Player p = Bukkit.getPlayer(player);
if (p == null) return;
stop(p);
}
public void stop(@NotNull Player p) {
if (cutsceneManager.isPlayingCutscene(p)) {
if (cutsceneManager.getPlayingCutscene(p).equals(this.id)) {
cutsceneManager.removeCurrentPlayingCutscene(this, p);
tasks.get(p.getUniqueId()).cancel();
p.sendMessage(Component.text("You stopped playing the cutscene!"));
}
} else {
p.sendMessage(Component.text("You are not playing a cutscene!"));
}
}
public void calculateMarkers() {
if (markers.isEmpty()) return;
for (int i = 0; i < markers.size(); i++) {
if (i < markers.size() - 1) {
markers.get(i).calculateFrames(markers.get(i + 1));
} else {
ArrayList<Frame> frames = new ArrayList<>();
frames.add(new Frame(markers.get(i).getStart()));
markers.get(i).setFrames(frames);
}
}
public Cutscene setPos2(Location pos2) {
this.pos2 = pos2;
return this;
}
}

View file

@ -1,168 +1,138 @@
package me.unurled.sacredrealms.sr.components.cutscene;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.sacredrealms.sr.utils.Items.cancelItem;
import static me.unurled.srcore.utils.Component.textComp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import me.unurled.sacredrealms.sr.SR;
import me.unurled.sacredrealms.sr.components.cutscene.tasks.TickTracker;
import me.unurled.srcore.api.Manager;
import org.bukkit.Bukkit;
import net.kyori.adventure.text.TextComponent;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class CutsceneManager extends Manager {
// TODO: spectator to hide toolbar (make it ride an invisible entity to prevent movement)
// TODO: save modifications if any
// TODO: do you set player back to original position ?
// TODO: make a system to easily create cutscenesw
private static final TextComponent ALREADY_STARTED =
textComp("<red>You are already creating a cutscene.");
private List<Cutscene> cutscenes;
private Map<UUID, Cutscene> cutsceneBeingCreated;
private Map<UUID, PlayerInventory> savedInventories;
// cutscene id, player uuid
private Map<String, UUID> currentPlayingCutscenes;
private Map<UUID, PlayerOrigin> playerOrigins;
private List<String> cutsceneIds;
/** Load the manager */
@Override
public void load() {
super.load();
SR.getPlugin()
.getServer()
.getPluginManager()
.registerEvents(new CreationListener(), SR.getPlugin());
TickTracker.startTracking();
cutscenes = new ArrayList<>();
currentPlayingCutscenes = new HashMap<>();
playerOrigins = new HashMap<>();
cutsceneIds = new ArrayList<>();
cutsceneBeingCreated = new HashMap<>();
savedInventories = new HashMap<>();
}
/** Unload the manager */
@Override
public void unload() {
super.unload();
cutscenes.clear();
currentPlayingCutscenes.clear();
playerOrigins.clear();
cutsceneIds.clear();
cutsceneBeingCreated.clear();
savedInventories.clear();
}
public void createCutscene(String id) {
Cutscene cutscene = new Cutscene(id, id);
addCutscene(cutscene);
@Nullable
public Cutscene getCutsceneBeingCreated(@NotNull UUID uuid) {
return cutsceneBeingCreated.get(uuid);
}
public void removeCutscene(String id) {
Cutscene cutscene = getCutscene(id);
removeCutscene(cutscene);
public void startCreatingCutscene(@NotNull Player p, String name) {
if (cutsceneBeingCreated.containsKey(p.getUniqueId())) {
p.sendMessage(ALREADY_STARTED);
return;
}
cutsceneBeingCreated.put(p.getUniqueId(), new Cutscene(name));
// process to create cutscene
savedInventories.put(p.getUniqueId(), p.getInventory());
p.getInventory().clear();
p.sendMessage(
textComp("<green>You are now creating a cutscene. Place the <gold>corner blocks</gold>."));
ItemStack cancel = cancelItem();
ItemStack finish = new ItemStack(Material.EMERALD_BLOCK);
ItemMeta meta = finish.getItemMeta();
meta.displayName(textComp("<b><green>Finish</green></b>"));
finish.setItemMeta(meta);
ItemStack pos1 = new ItemStack(Material.RED_WOOL);
meta = pos1.getItemMeta();
meta.displayName(textComp("<b><red>Pos1</red></b>"));
pos1.setItemMeta(meta);
ItemStack pos2 = new ItemStack(Material.BLUE_WOOL);
meta = pos2.getItemMeta();
meta.displayName(textComp("<b><blue>Pos2</blue></b>"));
pos2.setItemMeta(meta);
p.getInventory().setItem(8, cancel);
p.getInventory().setItem(0, finish);
p.getInventory().setItem(3, pos1);
p.getInventory().setItem(5, pos2);
p.updateInventory();
}
public void addCutscene(Cutscene cutscene) {
public void finishCreatingCutscene(@NotNull Player p) {
if (!cutsceneBeingCreated.containsKey(p.getUniqueId())) {
p.sendMessage(textComp("<red>You are not creating a cutscene."));
return;
}
Cutscene cutscene = cutsceneBeingCreated.get(p.getUniqueId());
cutscenes.add(cutscene);
cutsceneIds.add(cutscene.getId());
p.getInventory().clear();
p.sendMessage(textComp("<green>Cutscene created."));
cutsceneBeingCreated.remove(p.getUniqueId());
PlayerInventory inv = savedInventories.get(p.getUniqueId());
for (int i = 0; i < inv.getSize(); i++) {
p.getInventory().setItem(i, inv.getItem(i));
}
p.updateInventory();
savedInventories.remove(p.getUniqueId());
}
public void removeCutscene(Cutscene cutscene) {
cutscenes.remove(cutscene);
cutsceneIds.remove(cutscene.getId().toUpperCase());
}
public void addCurrentPlayingCutscene(@NotNull Cutscene cutscene, @NotNull Player p) {
currentPlayingCutscenes.put(cutscene.getId(), p.getUniqueId());
}
public void removeCurrentPlayingCutscene(@NotNull Cutscene cutscene, @NotNull Player p) {
currentPlayingCutscenes.remove(cutscene.getId(), p.getUniqueId());
}
public List<String> getCutscenesId() {
return cutsceneIds;
}
public void stopCutscene(Player p) {
for (String string : currentPlayingCutscenes.keySet()) {
if (currentPlayingCutscenes.get(string).equals(p.getUniqueId())) {
currentPlayingCutscenes.remove(string, p.getUniqueId());
Cutscene cutscene = getCutscene(string);
if (cutscene != null) {
cutscene.stop(p);
PlayerOrigin.restore(playerOrigins.get(p.getUniqueId()), p);
playerOrigins.remove(p.getUniqueId());
}
public void cancelCreatingCutscene(@NotNull Player p) {
if (!cutsceneBeingCreated.containsKey(p.getUniqueId())) {
p.sendMessage(textComp("<red>You are not creating a cutscene."));
return;
}
p.getInventory().clear();
p.sendMessage(textComp("<green>Canceled creating cutscene."));
cutsceneBeingCreated.remove(p.getUniqueId());
PlayerInventory inv = savedInventories.get(p.getUniqueId());
for (int i = 0; i < inv.getSize(); i++) {
p.getInventory().setItem(i, inv.getItem(i));
}
p.updateInventory();
savedInventories.remove(p.getUniqueId());
}
public void stopCutscenesForAllPlayers() {
for (String string : currentPlayingCutscenes.keySet()) {
Cutscene cutscene = getCutscene(string);
if (cutscene != null) {
UUID uuid = currentPlayingCutscenes.get(string);
cutscene.stop(uuid);
currentPlayingCutscenes.remove(cutscene.getId(), uuid);
Player player = Bukkit.getPlayer(uuid);
if (player == null) return;
PlayerOrigin.restore(playerOrigins.get(uuid), player);
playerOrigins.remove(uuid);
}
}
}
public void playCutscene(Cutscene cutscene, Player p) {
if (cutscene == null) {
p.sendMessage(textComp("<red>There was an error with the cutscene!"));
return;
}
if (cutscenes.contains(cutscene) && !currentPlayingCutscenes.containsValue(p.getUniqueId())) {
currentPlayingCutscenes.put(cutscene.getId(), p.getUniqueId());
setPlayerOrigins(p);
cutscene.play(p);
}
public List<Cutscene> cutscenes() {
return cutscenes;
}
@Nullable
public Cutscene getCutscene(Player p) {
for (Entry<String, UUID> entry : currentPlayingCutscenes.entrySet()) {
if (entry.getValue().equals(p.getUniqueId())) return getCutscene(entry.getKey());
}
return null;
}
@Nullable
public Cutscene getCutscene(@NotNull String id) {
if (!cutsceneIds.contains(id.toUpperCase())) {
return null;
}
for (Cutscene cutscene : cutscenes) {
if (cutscene.getId().equalsIgnoreCase(id.toUpperCase())) return cutscene;
}
return null;
}
public boolean isPlayingCutscene(@NotNull Player p) {
return currentPlayingCutscenes.containsValue(p.getUniqueId());
}
@Nullable
public String getPlayingCutscene(@NotNull Player p) {
for (Entry<String, UUID> entry : currentPlayingCutscenes.entrySet()) {
if (entry.getValue().equals(p.getUniqueId())) return entry.getKey();
}
return null;
}
public void setPlayerOrigins(@NotNull Player p) {
playerOrigins.put(
p.getUniqueId(),
new PlayerOrigin(
p.getLocation(),
p.getAllowFlight(),
p.isFlying(),
p.getWalkSpeed(),
p.getFlySpeed(),
p.getGameMode()));
public Cutscene findByUUID(UUID uuid) {
return cutscenes.stream().filter(c -> c.id().equals(uuid)).findFirst().orElse(null);
}
}

View file

@ -1,7 +0,0 @@
package me.unurled.sacredrealms.sr.components.cutscene;
import org.bukkit.entity.Player;
public class EntityCinematicAction {
private Player p;
}

View file

@ -1,113 +0,0 @@
package me.unurled.sacredrealms.sr.components.cutscene;
import static me.unurled.sacredrealms.sr.utils.Logger.error;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import java.util.Map;
import me.unurled.sacredrealms.sr.utils.gson.LocationSerializer;
import org.bukkit.Location;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Frame class
*
* <p>example of serializable frame:
*
* <pre>{@code
* {
* "id": 1,
* "entities": "entities serializable",
* "blocks": "blocks serializable",
* "action": "action", // if type is entity
* "location": {
* "world": "world",
* "x": 0,
* "y": 0,
* "z": 0,
* "yaw": 0,
* "pitch": 0
* }
* }
* }</pre>
*/
public class Frame {
private static int idCounter = 0;
private final Location location;
private final int id;
@Nullable private Map<Location, BlockData> blocks;
public Frame(Location location) {
this.location = location;
id = idCounter;
idCounter++;
blocks = null;
}
public Frame(Location location, int ID) {
this.location = location;
this.id = ID;
blocks = null;
}
@Contract("_ -> new")
public static @NotNull Frame deserialize(@NotNull JsonElement jsonElement) {
int id = jsonElement.getAsJsonObject().get("id").getAsInt();
Location loc = null;
try {
LocationSerializer locationDeserializer = new LocationSerializer();
loc =
locationDeserializer.deserialize(
jsonElement.getAsJsonObject().get("location"), Location.class, null);
} catch (Exception e) {
error("Error deserializing location in Frame with ID: " + id);
}
Frame frame = new Frame(loc, id);
try {
frame.setBlocks((Map<Location, BlockData>) jsonElement.getAsJsonObject().get("blocks"));
} catch (Exception e) {
error("Error deserializing blocks in Frame with ID: " + id);
}
return frame;
}
public Location getLocation() {
return location;
}
/** Play the frame aka move stuff around :shrug: */
public void play() {}
public int getId() {
return id;
}
public @Nullable Map<Location, BlockData> getBlocks() {
return blocks;
}
public void setBlocks(@Nullable Map<Location, BlockData> blocks) {
this.blocks = blocks;
}
public JsonElement serialize() {
String s =
"{"
+ "\"id\":"
+ id
+ ","
+ ","
+ "\"blocks\":"
+ blocks
+ ","
+ "\"location\":"
+ location.serialize()
+ "}";
return new JsonPrimitive(s);
}
}

View file

@ -1,146 +0,0 @@
package me.unurled.sacredrealms.sr.components.cutscene;
import static me.unurled.sacredrealms.sr.utils.CutsceneUtil.interpolateFrames;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Marker class
*
* <pre>{@code
* {
* "id": 1,
* "frames": [ 1, 2, 3 ], // Frame IDs
* "timeBetweenFrames": 20,
* "overAllTime": 60,
* "start": {
* "world": "world",
* "x": 0,
* "y": 0,
* "z": 0,
* "yaw": 0,
* "pitch": 0
* }
* }
* }</pre>
*/
public class Marker {
private static int idCounter = 0;
private static List<Marker> markers = new ArrayList<>();
private final int id;
private List<Frame> frames;
private Long timeBetweenFrames;
private Long overAllTime;
private Location start;
public Marker(Integer id) {
frames = new ArrayList<>();
timeBetweenFrames = 0L;
overAllTime = 0L;
if (id == null) {
this.id = idCounter;
idCounter++;
} else {
this.id = id;
}
}
public Marker(@NotNull List<Frame> frames, long timeBetweenFrames, Location start) {
this.frames = frames;
this.timeBetweenFrames = timeBetweenFrames;
this.overAllTime = timeBetweenFrames * frames.size();
this.start = start;
id = idCounter;
idCounter++;
}
public static List<Marker> getMarkers() {
return markers;
}
public static void setMarkers(List<Marker> markers) {
Marker.markers = markers;
}
public static @Nullable Marker getMarker(int ID) {
for (Marker marker : markers) {
if (marker.getId() == ID) {
return marker;
}
}
return null;
}
public List<Frame> getFrames() {
return frames;
}
public void setFrames(List<Frame> frames) {
this.frames = frames;
}
public Long getTimeBetweenFrames() {
return timeBetweenFrames;
}
public void setTimeBetweenFrames(Long timeBetweenFrames) {
this.timeBetweenFrames = timeBetweenFrames;
}
public Long getOverAllTime() {
return overAllTime;
}
public void setOverAllTime(Long overAllTime) {
this.overAllTime = overAllTime;
}
public Location getStart() {
return start;
}
public void setStart(Location start) {
this.start = start;
}
public void calculateFrames(Marker endMarker) {
frames = interpolateFrames(this, endMarker, timeBetweenFrames);
}
public int getId() {
return id;
}
public void addFrame(Frame frame) {
frames.add(frame);
}
public void removeFrame(Frame frame) {
frames.remove(frame);
}
public void removeFrame(int index) {
frames.remove(index);
}
@Override
public String toString() {
return "Marker{"
+ "ID="
+ id
+ ", frames="
+ frames
+ ", timeBetweenFrames="
+ timeBetweenFrames
+ ", overAllTime="
+ overAllTime
+ ", start="
+ start
+ '}';
}
}

View file

@ -1,23 +0,0 @@
package me.unurled.sacredrealms.sr.components.cutscene;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public record PlayerOrigin(
Location location,
boolean allowFlight,
boolean flying,
float walkSpeed,
float flySpeed,
GameMode gameMode) {
public static void restore(@NotNull PlayerOrigin origin, @NotNull Player p) {
p.teleport(origin.location());
p.setAllowFlight(origin.allowFlight());
p.setFlying(origin.flying());
p.setWalkSpeed(origin.walkSpeed());
p.setFlySpeed(origin.flySpeed());
p.setGameMode(origin.gameMode());
}
}

View file

@ -1,82 +0,0 @@
package me.unurled.sacredrealms.sr.components.cutscene;
import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose;
import io.papermc.paper.event.player.PlayerArmSwingEvent;
import me.unurled.sacredrealms.sr.components.cutscene.npc.ArmSwing;
import me.unurled.sacredrealms.sr.components.cutscene.npc.EntityFrame;
import org.bukkit.entity.Player;
import org.bukkit.entity.Pose;
import org.bukkit.event.EventHandler;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.PlayerInventory;
import org.jetbrains.annotations.NotNull;
public class PlayerRecording {
private final Player player;
private final EntityFrame entityFrame;
private ArmSwing swing;
public PlayerRecording(Player player, EntityFrame entityFrame) {
this.player = player;
this.entityFrame = entityFrame;
}
private static EntityPose toEntityPose(Pose pose) {
return pose == Pose.SNEAKING ? EntityPose.SITTING : EntityPose.valueOf(pose.name());
}
private static Pose toBukkitPose(EntityPose pose) {
return pose == EntityPose.SITTING ? Pose.SNEAKING : Pose.valueOf(pose.name());
}
@EventHandler
public void onArmSwing(@NotNull PlayerArmSwingEvent e) {
if (e.getPlayer().getUniqueId() != player.getUniqueId()) {
return;
}
addSwing(
e.getHand() == EquipmentSlot.HAND
? ArmSwing.RIGHT
: (e.getHand() == EquipmentSlot.OFF_HAND ? ArmSwing.LEFT : ArmSwing.BOTH));
}
private void addSwing(ArmSwing swing) {
if (this.swing != null && this.swing != swing) {
this.swing = ArmSwing.BOTH;
return;
}
this.swing = swing;
}
public EntityFrame captureFrame() {
PlayerInventory inv = player.getInventory();
Pose pose = player.isInsideVehicle() ? Pose.SITTING : player.getPose();
EntityFrame data =
new EntityFrame(
player.getLocation(),
toEntityPose(pose),
swing,
inv.getItemInMainHand().isEmpty() ? null : inv.getItemInMainHand(),
inv.getItemInOffHand().isEmpty() ? null : inv.getItemInOffHand(),
inv.getHelmet(),
inv.getChestplate(),
inv.getLeggings(),
inv.getBoots());
swing = null;
return data;
}
public void applyState(@NotNull EntityFrame value) {
player.teleport(value.location());
player.setPose(toBukkitPose(value.pose()));
PlayerInventory inv = player.getInventory();
inv.setItemInMainHand(value.mainHand());
inv.setItemInOffHand(value.offHand());
inv.setHelmet(value.helmet());
inv.setChestplate(value.chestplate());
inv.setLeggings(value.leggings());
inv.setBoots(value.boots());
player.updateInventory();
}
}

View file

@ -0,0 +1,75 @@
package me.unurled.sacredrealms.sr.components.cutscene;
import static me.unurled.srcore.utils.Component.textComp;
import java.util.ArrayList;
import java.util.List;
import me.unurled.sacredrealms.sr.components.cutscene.recording.Recordable;
import me.unurled.sacredrealms.sr.components.cutscene.recording.Recording;
import me.unurled.sacredrealms.sr.components.cutscene.tasks.TickTracker;
import me.unurled.srcore.api.Manager;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class RecordingManager extends Manager {
private List<Recording> recordings; // existing recordings
private List<Recording> activeRecordings; // currently recording
@Override
public void load() {
super.load();
recordings = new ArrayList<>();
activeRecordings = new ArrayList<>();
}
@Override
public void unload() {
super.unload();
recordings.clear();
activeRecordings.clear();
}
@Nullable
public Recording getPlayerActiveRecording(Player player) {
return activeRecordings.stream()
.filter(r -> r.recordingPlayer().equals(player))
.findFirst()
.orElse(null);
}
public void startRecording(Cutscene cutscene, Player player) {
Recording recording = new Recording(cutscene, player);
player.sendMessage(textComp("<green>Recording started."));
activeRecordings.add(recording);
}
public void stopRecording(Player player) {
Recording recording = getPlayerActiveRecording(player);
if (recording == null) {
player.sendMessage(textComp("<red>You are not recording a cutscene."));
return;
}
activeRecordings.remove(recording);
recording.stopRecording();
recordings.add(recording);
player.sendMessage(textComp("<green>Recording stopped."));
}
public void addRecordable(@NotNull Recording recording, @NotNull Recordable recordable) {
long tick = TickTracker.currentTick();
// normalize tick
tick = tick - recording.startTick();
recordable.setTick(tick);
if (recording.recordables().containsKey(tick)) {
recording.recordables().get(tick).add(recordable);
} else {
List<Recordable> recordables = new ArrayList<>();
recordables.add(recordable);
recording.recordables().put(tick, recordables);
}
}
}

View file

@ -0,0 +1,45 @@
package me.unurled.sacredrealms.sr.components.cutscene;
import me.unurled.sacredrealms.sr.SR;
import me.unurled.sacredrealms.sr.components.cutscene.recording.Recording;
import me.unurled.sacredrealms.sr.components.cutscene.tasks.ReplayTask;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull;
public class Replay {
private final Player viewer;
private final Recording recording;
private final BukkitTask replayTask;
public Replay(Recording recording, @NotNull Player viewer) {
this.recording = recording;
this.viewer = viewer;
viewer.getInventory().clear();
// TODO: control cutscene replay
replayTask =
Bukkit.getScheduler()
.runTaskTimerAsynchronously(SR.getPlugin(), new ReplayTask(this), 0L, 1L);
}
public Player viewer() {
return viewer;
}
public Recording recording() {
return recording;
}
public BukkitTask replayTask() {
return replayTask;
}
public void endReplay() {
if (replayTask != null) {
replayTask.cancel();
}
}
}

View file

@ -0,0 +1,53 @@
package me.unurled.sacredrealms.sr.components.cutscene;
import java.util.HashSet;
import java.util.Set;
import me.unurled.sacredrealms.sr.components.cutscene.recording.Recording;
import me.unurled.srcore.api.Manager;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ReplayManager extends Manager {
private Set<Replay> replays;
@Override
public void load() {
super.load();
replays = new HashSet<>();
}
@Override
public void unload() {
super.unload();
}
@Nullable
public Replay getReplayForPlayer(Player player) {
return replays.stream()
.filter(replay -> replay.viewer().equals(player))
.findFirst()
.orElse(null);
}
public void replayRecording(Recording recording, Player player) {
if (getReplayForPlayer(player) != null) {
return;
}
Replay replay = new Replay(recording, player);
replays.add(replay);
}
public void stopReplay(@NotNull Replay replay) {
// stop replay taskk
replay.endReplay();
replays.remove(replay);
}
public Set<Replay> replays() {
return replays;
}
}

View file

@ -1,63 +0,0 @@
package me.unurled.sacredrealms.sr.components.cutscene.gson;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import me.unurled.sacredrealms.sr.components.cutscene.Action;
import org.jetbrains.annotations.NotNull;
public class ActionGson {
public class Deserializer implements JsonDeserializer<Action> {
/**
* Gson invokes this call-back method during deserialization when it encounters a field of the
* specified type.
*
* <p>In the implementation of this call-back method, you should consider invoking {@link
* JsonDeserializationContext#deserialize(JsonElement, Type)} method to create objects for any
* non-trivial field of the returned object. However, you should never invoke it on the same
* type passing {@code json} since that will cause an infinite loop (Gson will call your
* call-back method again).
*
* @param json The Json data being deserialized
* @param typeOfT The type of the Object to deserialize to
* @param context
* @return a deserialized object of the specified type typeOfT which is a subclass of {@code T}
* @throws JsonParseException if json is not in the expected format of {@code typeofT}
*/
@Override
public Action deserialize(
@NotNull JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return Action.valueOf(json.getAsString());
}
}
public class Serializer implements JsonSerializer<Action> {
/**
* Gson invokes this call-back method during serialization when it encounters a field of the
* specified type.
*
* <p>In the implementation of this call-back method, you should consider invoking {@link
* JsonSerializationContext#serialize(Object, Type)} method to create JsonElements for any
* non-trivial field of the {@code src} object. However, you should never invoke it on the
* {@code src} object itself since that will cause an infinite loop (Gson will call your
* call-back method again).
*
* @param src the object that needs to be converted to Json.
* @param typeOfSrc the actual type (fully genericized version) of the source object.
* @param context
* @return a JsonElement corresponding to the specified object.
*/
@Override
public JsonElement serialize(Action src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.name());
}
}
}

View file

@ -1,64 +0,0 @@
package me.unurled.sacredrealms.sr.components.cutscene.gson;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import java.util.Map;
import me.unurled.sacredrealms.sr.components.cutscene.Action;
import org.bukkit.entity.Entity;
public class EntityActionGson {
public class Deserializer implements JsonDeserializer<Map<Entity, Action>> {
/**
* Gson invokes this call-back method during deserialization when it encounters a field of the
* specified type.
*
* <p>In the implementation of this call-back method, you should consider invoking {@link
* JsonDeserializationContext#deserialize(JsonElement, Type)} method to create objects for any
* non-trivial field of the returned object. However, you should never invoke it on the same
* type passing {@code json} since that will cause an infinite loop (Gson will call your
* call-back method again).
*
* @param json The Json data being deserialized
* @param typeOfT The type of the Object to deserialize to
* @param context
* @return a deserialized object of the specified type typeOfT which is a subclass of {@code T}
* @throws JsonParseException if json is not in the expected format of {@code typeofT}
*/
@Override
public Map<Entity, Action> deserialize(
JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return null;
}
}
public class Serializer implements JsonSerializer<Map<Entity, Action>> {
/**
* Gson invokes this call-back method during serialization when it encounters a field of the
* specified type.
*
* <p>In the implementation of this call-back method, you should consider invoking {@link
* JsonSerializationContext#serialize(Object, Type)} method to create JsonElements for any
* non-trivial field of the {@code src} object. However, you should never invoke it on the
* {@code src} object itself since that will cause an infinite loop (Gson will call your
* call-back method again).
*
* @param src the object that needs to be converted to Json.
* @param typeOfSrc the actual type (fully genericized version) of the source object.
* @param context
* @return a JsonElement corresponding to the specified object.
*/
@Override
public JsonElement serialize(
Map<Entity, Action> src, Type typeOfSrc, JsonSerializationContext context) {
return null;
}
}
}

View file

@ -1,37 +0,0 @@
package me.unurled.sacredrealms.sr.components.cutscene.npc;
import static me.unurled.sacredrealms.sr.components.packet.PacketManager.sendPacketTo;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityAnimation;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityAnimation.EntityAnimationType;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
public enum ArmSwing {
LEFT,
RIGHT,
BOTH;
public static void swingArm(@NotNull ArmSwing arm, Player p, int entityId) {
// Swing the arm
if (arm.isLeft()) {
sendPacketTo(
new WrapperPlayServerEntityAnimation(entityId, EntityAnimationType.SWING_OFF_HAND), p);
}
if (arm.isRight()) {
sendPacketTo(
new WrapperPlayServerEntityAnimation(entityId, EntityAnimationType.SWING_MAIN_ARM), p);
}
}
@Contract(pure = true)
public @NotNull Boolean isLeft() {
return this == LEFT || this == BOTH;
}
@Contract(pure = true)
public @NotNull Boolean isRight() {
return this == RIGHT || this == BOTH;
}
}

View file

@ -1,66 +0,0 @@
package me.unurled.sacredrealms.sr.components.cutscene.npc;
import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import me.unurled.sacredrealms.sr.utils.Items;
import me.unurled.sacredrealms.sr.utils.gson.LocationSerializer;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public record EntityFrame(
Location location,
EntityPose pose,
ArmSwing swing,
ItemStack mainHand,
ItemStack offHand,
ItemStack helmet,
ItemStack chestplate,
ItemStack leggings,
ItemStack boots) {
public static @NotNull EntityFrame deserialize(@NotNull JsonElement jsonElement) {
Location location =
new LocationSerializer()
.deserialize(jsonElement.getAsJsonObject().get("location"), Location.class, null);
EntityPose pose = EntityPose.valueOf(jsonElement.getAsJsonObject().get("pose").getAsString());
ArmSwing swing = ArmSwing.valueOf(jsonElement.getAsJsonObject().get("swing").getAsString());
ItemStack mainHand = Items.deserialize(jsonElement.getAsJsonObject().get("mainHand"));
ItemStack offHand = Items.deserialize(jsonElement.getAsJsonObject().get("offHand"));
ItemStack helmet = Items.deserialize(jsonElement.getAsJsonObject().get("helmet"));
ItemStack chestplate = Items.deserialize(jsonElement.getAsJsonObject().get("chestplate"));
ItemStack leggings = Items.deserialize(jsonElement.getAsJsonObject().get("leggings"));
ItemStack boots = Items.deserialize(jsonElement.getAsJsonObject().get("boots"));
return new EntityFrame(
location, pose, swing, mainHand, offHand, helmet, chestplate, leggings, boots);
}
public @NotNull JsonElement serialize() {
String s =
"""
{
"location": %s,
"pose": %s,
"swing": %s,
"mainHand": %s,
"offHand": %s,
"helmet": %s,
"chestplate": %s,
"leggings": %s,
"boots": %s
}
"""
.formatted(
location.serialize(),
pose.name(),
swing.name(),
mainHand.serialize(),
offHand.serialize(),
helmet.serialize(),
chestplate.serialize(),
leggings.serialize(),
boots.serialize());
return new JsonPrimitive(s);
}
}

View file

@ -0,0 +1,16 @@
package me.unurled.sacredrealms.sr.components.cutscene.recording;
public abstract class Recordable {
private long tick;
public abstract void replay();
public long tick() {
return tick;
}
public Recordable setTick(long tick) {
this.tick = tick;
return this;
}
}

View file

@ -0,0 +1,124 @@
package me.unurled.sacredrealms.sr.components.cutscene.recording;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
import me.unurled.sacredrealms.sr.SR;
import me.unurled.sacredrealms.sr.components.cutscene.Cutscene;
import me.unurled.sacredrealms.sr.components.cutscene.tasks.ScanEntityTracker;
import me.unurled.sacredrealms.sr.components.cutscene.tasks.TickTracker;
import me.unurled.sacredrealms.sr.components.cutscene.tasks.TrackLocationTask;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
public class Recording {
// recordables
private final Map<Long, List<Recordable>> recordables = new HashMap<>();
private final Queue<UUID> recordableEntities = new ConcurrentLinkedQueue<>();
private final BukkitTask trackLocationTask;
private final BukkitTask scanEntitiesTask;
private Cutscene cutscene;
private Player recordingPlayer;
private long startTime;
private long endTime;
private long startTick;
private long endTick;
public Recording(Cutscene cutscene, Player recordingPlayer) {
this.cutscene = cutscene;
this.recordingPlayer = recordingPlayer;
this.startTime = System.currentTimeMillis();
this.startTick = 1; // TODO: get tick
this.endTick = 1; // TODO: get tick
this.scanEntitiesTask =
Bukkit.getScheduler().runTaskTimer(SR.getPlugin(), new ScanEntityTracker(this), 0L, 20L);
this.trackLocationTask =
Bukkit.getScheduler().runTaskTimer(SR.getPlugin(), new TrackLocationTask(this), 0L, 1L);
}
public Map<Long, List<Recordable>> recordables() {
return recordables;
}
public Cutscene cutscene() {
return cutscene;
}
public Queue<UUID> recordableEntities() {
return recordableEntities;
}
public Recording setCutscene(Cutscene cutscene) {
this.cutscene = cutscene;
return this;
}
public Player recordingPlayer() {
return recordingPlayer;
}
public Recording setRecordingPlayer(Player recordingPlayer) {
this.recordingPlayer = recordingPlayer;
return this;
}
public long startTime() {
return startTime;
}
public Recording setStartTime(long startTime) {
this.startTime = startTime;
return this;
}
public long endTime() {
return endTime;
}
public Recording setEndTime(long endTime) {
this.endTime = endTime;
return this;
}
public long startTick() {
return startTick;
}
public Recording setStartTick(long startTick) {
this.startTick = startTick;
return this;
}
public void stopRecording() {
this.endTime = System.currentTimeMillis();
this.endTick = TickTracker.currentTick();
scanEntitiesTask.cancel();
trackLocationTask.cancel();
}
public long tickDuration() {
return endTick - startTick;
}
public boolean isEntityBeingTracked(UUID uuid) {
synchronized (recordableEntities) {
return recordableEntities.contains(uuid);
}
}
public boolean addEntityIfNotBeingTracked(UUID uuid) {
synchronized (recordableEntities) {
if (recordableEntities.contains(uuid)) {
return false;
}
recordableEntities.add(uuid);
return true;
}
}
}

View file

@ -0,0 +1,29 @@
package me.unurled.sacredrealms.sr.components.cutscene.recording.recordables;
import java.util.UUID;
import me.unurled.sacredrealms.sr.components.cutscene.recording.Recordable;
public class DespawnEntityRecordable extends Recordable {
private UUID entityId;
public DespawnEntityRecordable() {}
public DespawnEntityRecordable(UUID entityId) {
this.entityId = entityId;
}
@Override
public void replay() {
// TODO: fake spawn entity
}
public UUID entityId() {
return entityId;
}
public DespawnEntityRecordable setEntityId(UUID entityId) {
this.entityId = entityId;
return this;
}
}

View file

@ -0,0 +1,39 @@
package me.unurled.sacredrealms.sr.components.cutscene.recording.recordables;
import java.util.UUID;
import me.unurled.sacredrealms.sr.components.cutscene.recording.Recordable;
import org.bukkit.Location;
public class LocationChangeRecordable extends Recordable {
private UUID entityId;
private Location location;
public LocationChangeRecordable() {}
public LocationChangeRecordable(UUID entityId, Location location) {
this.entityId = entityId;
this.location = location;
}
@Override
public void replay() {}
public UUID entityId() {
return entityId;
}
public LocationChangeRecordable setEntityId(UUID entityId) {
this.entityId = entityId;
return this;
}
public Location location() {
return location;
}
public LocationChangeRecordable setLocation(Location location) {
this.location = location;
return this;
}
}

View file

@ -0,0 +1,75 @@
package me.unurled.sacredrealms.sr.components.cutscene.recording.recordables;
import java.util.UUID;
import me.unurled.sacredrealms.sr.components.cutscene.recording.Recordable;
import net.kyori.adventure.text.Component;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.NotNull;
public class SpawnEntityRecordable extends Recordable {
private EntityType entityType;
private Location location;
private UUID entityId;
private Component name;
public SpawnEntityRecordable() {}
public SpawnEntityRecordable(@NotNull Entity e) {
this.entityType = e.getType();
this.location = e.getLocation();
this.entityId = e.getUniqueId();
this.name = e.name();
}
public SpawnEntityRecordable(
EntityType entityType, Location location, UUID entityId, Component name) {
this.entityType = entityType;
this.location = location;
this.entityId = entityId;
this.name = name;
}
@Override
public void replay() {
// TODO: fake spawn entity
}
public EntityType entityType() {
return entityType;
}
public SpawnEntityRecordable setEntityType(EntityType entityType) {
this.entityType = entityType;
return this;
}
public Location location() {
return location;
}
public SpawnEntityRecordable setLocation(Location location) {
this.location = location;
return this;
}
public UUID entityId() {
return entityId;
}
public SpawnEntityRecordable setEntityId(UUID entityId) {
this.entityId = entityId;
return this;
}
public Component name() {
return name;
}
public SpawnEntityRecordable setName(Component name) {
this.name = name;
return this;
}
}

View file

@ -0,0 +1,51 @@
package me.unurled.sacredrealms.sr.components.cutscene.tasks;
import static me.unurled.sacredrealms.sr.utils.Logger.error;
import static me.unurled.srcore.utils.Component.textComp;
import me.unurled.sacredrealms.sr.components.cutscene.Replay;
import me.unurled.sacredrealms.sr.components.cutscene.ReplayManager;
import me.unurled.sacredrealms.sr.components.cutscene.recording.Recordable;
import me.unurled.srcore.api.Manager;
public class ReplayTask implements Runnable {
private final Replay replay;
private final ReplayManager rm;
private long currentTick = 0;
public ReplayTask(Replay replay) {
this.replay = replay;
rm = Manager.getInstance(ReplayManager.class);
}
@Override
public void run() {
if (currentTick >= replay.recording().tickDuration()) {
replay.viewer().sendMessage(textComp("<yellow>Replay has ended."));
rm.stopReplay(replay);
return;
}
// get all recordables for current tick
var recordables = replay.recording().recordables().get(currentTick);
try {
if (recordables == null) {
currentTick++;
return;
}
for (Recordable r : recordables) {
// figure out how to replay a recordable
r.replay();
}
} catch (Exception e) {
error("Tick: " + currentTick);
error(e.getMessage());
} finally {
currentTick++;
}
}
}

View file

@ -0,0 +1,57 @@
package me.unurled.sacredrealms.sr.components.cutscene.tasks;
import java.util.ArrayList;
import java.util.List;
import me.unurled.sacredrealms.sr.components.cutscene.Cutscene;
import me.unurled.sacredrealms.sr.components.cutscene.RecordingManager;
import me.unurled.sacredrealms.sr.components.cutscene.recording.Recording;
import me.unurled.sacredrealms.sr.components.cutscene.recording.recordables.SpawnEntityRecordable;
import me.unurled.srcore.api.Manager;
import org.bukkit.Chunk;
import org.bukkit.Location;
public class ScanEntityTracker implements Runnable {
private final Recording recording;
public ScanEntityTracker(Recording recording) {
this.recording = recording;
}
@Override
public void run() {
Cutscene cutscene = recording.cutscene();
Location pos1 = cutscene.pos1();
Location pos2 = cutscene.pos2();
int chunkZ = pos1.getBlockZ() >> 4;
int chunkX = pos1.getBlockX() >> 4;
int chunkX2 = pos2.getBlockX() >> 4;
int chunkZ2 = pos2.getBlockZ() >> 4;
var loadedChunks = pos1.getWorld().getLoadedChunks();
List<Chunk> chunksInRegion = new ArrayList<>();
for (Chunk chunk : loadedChunks) {
if (chunk.getX() >= chunkX
&& chunk.getX() <= chunkX2
&& chunk.getZ() >= chunkZ
&& chunk.getZ() <= chunkZ2) {
chunksInRegion.add(chunk);
}
}
for (Chunk chunk : chunksInRegion) {
var entities = chunk.getEntities();
for (var entity : entities) {
if (!cutscene.isInRegion(entity.getLocation())) {
continue;
}
if (recording.addEntityIfNotBeingTracked(entity.getUniqueId())) {
// TODO: spawn entity
SpawnEntityRecordable recordable = new SpawnEntityRecordable(entity);
Manager.getInstance(RecordingManager.class).addRecordable(recording, recordable);
}
}
}
}
}

View file

@ -0,0 +1,16 @@
package me.unurled.sacredrealms.sr.components.cutscene.tasks;
import me.unurled.sacredrealms.sr.SR;
import org.bukkit.Bukkit;
public class TickTracker {
private static long currentTick = 0;
public static void startTracking() {
Bukkit.getScheduler().scheduleSyncRepeatingTask(SR.getPlugin(), () -> currentTick++, 0L, 1L);
}
public static long currentTick() {
return currentTick;
}
}

View file

@ -0,0 +1,47 @@
package me.unurled.sacredrealms.sr.components.cutscene.tasks;
import me.unurled.sacredrealms.sr.components.cutscene.RecordingManager;
import me.unurled.sacredrealms.sr.components.cutscene.recording.Recording;
import me.unurled.sacredrealms.sr.components.cutscene.recording.recordables.DespawnEntityRecordable;
import me.unurled.sacredrealms.sr.components.cutscene.recording.recordables.LocationChangeRecordable;
import me.unurled.srcore.api.Manager;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
public class TrackLocationTask implements Runnable {
private final Recording recording;
public TrackLocationTask(Recording recording) {
this.recording = recording;
}
@Override
public void run() {
var recordebaleEntities = recording.recordableEntities();
synchronized (recordebaleEntities) {
recordebaleEntities.forEach(
uuid -> {
Entity entity = Bukkit.getEntity(uuid);
if (entity == null) {
recording.recordableEntities().remove(uuid);
DespawnEntityRecordable recordable = new DespawnEntityRecordable(uuid);
Manager.getInstance(RecordingManager.class).addRecordable(recording, recordable);
return;
}
if (!recording.cutscene().isInRegion(entity.getLocation())) {
recording.recordableEntities().remove(uuid);
DespawnEntityRecordable recordable = new DespawnEntityRecordable(uuid);
Manager.getInstance(RecordingManager.class).addRecordable(recording, recordable);
return;
}
var recordable =
new LocationChangeRecordable(entity.getUniqueId(), entity.getLocation());
Manager.getInstance(RecordingManager.class).addRecordable(recording, recordable);
});
}
}
}

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.components.difficulty;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.textComp;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.components.entity;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.textComp;
import java.util.UUID;
import me.unurled.sacredrealms.sr.components.attributes.Attribute;

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.components.item;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.textComp;
import static me.unurled.sacredrealms.sr.utils.Items.lore;
import static me.unurled.sacredrealms.sr.utils.Logger.error;

View file

@ -69,6 +69,9 @@ public class ResourcePackManager extends Manager {
super.saveData();
DataManager dm = Manager.getInstance(DataManager.class);
DataHandler dh = dm.getDataHandler();
if (hostingProvider.getMinecraftPackURL() == null) {
return;
}
dh.set("pack.url", hostingProvider.getMinecraftPackURL());
dh.set("pack.uuid", hostingProvider.getPackUUID().toString());
dh.set("pack.sha1", hostingProvider.getPackUUID().toString());

View file

@ -1,9 +1,9 @@
package me.unurled.sacredrealms.sr.components.player;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.sacredrealms.sr.utils.Logger.error;
import static me.unurled.sacredrealms.sr.utils.Logger.log;
import static me.unurled.sacredrealms.sr.utils.SRPlayerUtils.updateActionBar;
import static me.unurled.srcore.utils.Component.textComp;
import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent;
import com.google.gson.Gson;
@ -167,7 +167,9 @@ public class PlayerManager extends Manager {
} catch (Exception ex) {
error("Failed to send resource pack to player. " + ex.getMessage());
log(rpm.getHostingProvider().getOriginalSHA1());
if (rpm.getHostingProvider().getPackUUID() != null) {
log(rpm.getHostingProvider().getPackUUID().toString());
}
log(rpm.getHostingProvider().getMinecraftPackURL());
}
}

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.components.treasure;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.textComp;
import java.util.HashMap;
import java.util.Map;

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.components.treasure;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.textComp;
import static me.unurled.sacredrealms.sr.utils.Logger.error;
import static me.unurled.sacredrealms.sr.utils.Logger.log;

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.events.player;
import static me.unurled.sacredrealms.sr.utils.Component.comp;
import static me.unurled.srcore.utils.Component.comp;
import me.unurled.sacredrealms.sr.components.player.SRPlayer;
import net.kyori.adventure.text.Component;

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.gui.attributes;
import static me.unurled.sacredrealms.sr.utils.Component.comp;
import static me.unurled.srcore.utils.Component.comp;
import static me.unurled.sacredrealms.sr.utils.SRPlayerUtils.syncSRToPlayer;
import me.unurled.sacredrealms.sr.components.attributes.Attribute;

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.gui.attributes;
import static me.unurled.sacredrealms.sr.utils.Component.comp;
import static me.unurled.srcore.utils.Component.comp;
import me.unurled.sacredrealms.sr.components.attributes.Attribute;
import org.bukkit.Material;

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.gui.entitytype;
import static me.unurled.sacredrealms.sr.utils.Component.comp;
import static me.unurled.srcore.utils.Component.comp;
import me.unurled.sacredrealms.sr.components.entity.SREntityType;
import org.bukkit.Material;

View file

@ -0,0 +1,71 @@
package me.unurled.sacredrealms.sr.gui.recordings;
import static me.unurled.srcore.utils.Component.textComp;
import java.util.UUID;
import me.unurled.sacredrealms.sr.SR;
import me.unurled.sacredrealms.sr.components.cutscene.Cutscene;
import me.unurled.sacredrealms.sr.components.cutscene.CutsceneManager;
import me.unurled.sacredrealms.sr.components.cutscene.RecordingManager;
import me.unurled.srcore.api.Manager;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.item.ItemProvider;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.AbstractItem;
public class CutsceneItem extends AbstractItem {
private static NamespacedKey ID = null;
private final String name;
private final UUID uuid;
public CutsceneItem(String name, UUID uuid) {
this.name = name;
this.uuid = uuid;
ID = new NamespacedKey(SR.getPlugin(), "cutscene_id");
}
@Override
public ItemProvider getItemProvider() {
ItemStack itemStack = new ItemStack(Material.PAPER);
ItemMeta itemMeta = itemStack.getItemMeta();
itemMeta.displayName(textComp(name));
itemMeta.getPersistentDataContainer().set(ID, PersistentDataType.STRING, uuid.toString());
itemStack.setItemMeta(itemMeta);
return new ItemBuilder(itemStack);
}
@Override
public void handleClick(
@NotNull ClickType clickType, @NotNull Player player, @NotNull InventoryClickEvent event) {
// get uuid
if (event.getCurrentItem() != null) {
String uuid =
event
.getCurrentItem()
.getItemMeta()
.getPersistentDataContainer()
.get(ID, PersistentDataType.STRING);
Cutscene cutscene =
Manager.getInstance(CutsceneManager.class).findByUUID(UUID.fromString(uuid));
if (cutscene == null) {
player.sendMessage(textComp("<red>Unexpected error."));
return;
}
if (clickType.isLeftClick()) {
Manager.getInstance(RecordingManager.class).startRecording(cutscene, player);
}
}
}
}

View file

@ -0,0 +1,45 @@
package me.unurled.sacredrealms.sr.gui.recordings;
import static me.unurled.sacredrealms.sr.utils.Items.glassPane;
import java.util.ArrayList;
import java.util.List;
import me.unurled.sacredrealms.sr.components.cutscene.Cutscene;
import me.unurled.sacredrealms.sr.components.cutscene.CutsceneManager;
import me.unurled.sacredrealms.sr.gui.BackItem;
import me.unurled.sacredrealms.sr.gui.ForwardItem;
import me.unurled.srcore.api.Manager;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.PagedGui;
import xyz.xenondevs.invui.gui.structure.Markers;
import xyz.xenondevs.invui.item.Item;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
public class StartRecordingGui {
private StartRecordingGui() {}
public static @NotNull Gui listGui() {
CutsceneManager cm = Manager.getInstance(CutsceneManager.class);
List<Item> items = new ArrayList<>();
for (Cutscene cs : cm.cutscenes()) {
CutsceneItem item = new CutsceneItem(cs.name(), cs.id());
items.add(item);
}
return PagedGui.items()
.setStructure(
"# # # # # # # # #",
"# X X X X X X X #",
"# X X X X X X X #",
"# X X X X X X X #",
"# # # < # > # # #")
.addIngredient('#', new ItemBuilder(glassPane()))
.addIngredient('X', Markers.CONTENT_LIST_SLOT_HORIZONTAL)
.addIngredient('<', new BackItem())
.addIngredient('>', new ForwardItem())
.setContent(items)
.build();
}
}

View file

@ -0,0 +1,42 @@
package me.unurled.sacredrealms.sr.gui.replay;
import static me.unurled.sacredrealms.sr.utils.Items.glassPane;
import java.util.ArrayList;
import java.util.List;
import me.unurled.sacredrealms.sr.components.cutscene.Replay;
import me.unurled.sacredrealms.sr.components.cutscene.ReplayManager;
import me.unurled.sacredrealms.sr.gui.BackItem;
import me.unurled.sacredrealms.sr.gui.ForwardItem;
import me.unurled.srcore.api.Manager;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.PagedGui;
import xyz.xenondevs.invui.gui.structure.Markers;
import xyz.xenondevs.invui.item.Item;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
public class ReplayGui {
private ReplayGui() {}
public static @NotNull Gui listGui() {
ReplayManager rm = Manager.getInstance(ReplayManager.class);
List<Item> items = new ArrayList<>();
for (Replay r : rm.replays()) {}
return PagedGui.items()
.setStructure(
"# # # # # # # # #",
"# X X X X X X X #",
"# X X X X X X X #",
"# X X X X X X X #",
"# # # < # > # # #")
.addIngredient('#', new ItemBuilder(glassPane()))
.addIngredient('X', Markers.CONTENT_LIST_SLOT_HORIZONTAL)
.addIngredient('<', new BackItem())
.addIngredient('>', new ForwardItem())
.setContent(items)
.build();
}
}

View file

@ -0,0 +1,72 @@
package me.unurled.sacredrealms.sr.gui.replay;
import static me.unurled.srcore.utils.Component.textComp;
import java.util.UUID;
import me.unurled.sacredrealms.sr.SR;
import me.unurled.sacredrealms.sr.components.cutscene.Cutscene;
import me.unurled.sacredrealms.sr.components.cutscene.CutsceneManager;
import me.unurled.sacredrealms.sr.components.cutscene.RecordingManager;
import me.unurled.srcore.api.Manager;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.item.ItemProvider;
import xyz.xenondevs.invui.item.builder.ItemBuilder;
import xyz.xenondevs.invui.item.impl.AbstractItem;
public class ReplayItem extends AbstractItem {
private static NamespacedKey ID = null;
private final String name;
private final UUID uuid;
public ReplayItem(String name, UUID uuid) {
ID = new NamespacedKey(SR.getPlugin(), "cutscene_id");
this.name = name;
this.uuid = uuid;
}
@Override
public ItemProvider getItemProvider() {
ItemStack itemStack = new ItemStack(Material.PAPER);
ItemMeta itemMeta = itemStack.getItemMeta();
itemMeta.displayName(textComp(name));
itemMeta.getPersistentDataContainer().set(ID, PersistentDataType.STRING, uuid.toString());
itemStack.setItemMeta(itemMeta);
return new ItemBuilder(itemStack);
}
@Override
public void handleClick(
@NotNull ClickType clickType, @NotNull Player player, @NotNull InventoryClickEvent event) {
if (event.getCurrentItem() != null) {
String uuid =
event
.getCurrentItem()
.getItemMeta()
.getPersistentDataContainer()
.get(ID, PersistentDataType.STRING);
if (uuid == null) {
return;
}
Cutscene cutscene =
Manager.getInstance(CutsceneManager.class).findByUUID(UUID.fromString(uuid));
if (cutscene == null) {
player.sendMessage(textComp("<red>Unexpected error."));
return;
}
if (clickType.isLeftClick()) {
Manager.getInstance(RecordingManager.class).startRecording(cutscene, player);
}
}
}
}

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.gui.treasure;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.textComp;
import static me.unurled.sacredrealms.sr.utils.Logger.log;
import java.util.HashMap;

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.gui.treasure;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.textComp;
import me.unurled.sacredrealms.sr.components.treasure.Treasure;
import me.unurled.sacredrealms.sr.components.treasure.TreasureManager;

View file

@ -1,39 +0,0 @@
package me.unurled.sacredrealms.sr.utils;
import java.util.List;
import java.util.stream.Collectors;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.jetbrains.annotations.NotNull;
public class Component {
public static final String NOT_PLAYER = "<red>You must be a player to use this command.";
public static final String NO_PERMISSION = "<red>You do not have permission to use this command.";
public static final String ERROR =
"<red>An error occurred while executing this command. Please" + " contact an admin.";
public static final String PLAYER_NOT_FOUND = "<red>Player not found.";
private static MiniMessage miniMessage;
private Component() {}
public static net.kyori.adventure.text.@NotNull Component comp(String msg) {
if (miniMessage == null) {
miniMessage = MiniMessage.miniMessage();
}
return miniMessage.deserialize(msg);
}
public static net.kyori.adventure.text.@NotNull TextComponent textComp(String msg) {
if (miniMessage == null) {
miniMessage = MiniMessage.miniMessage();
}
return (TextComponent) miniMessage.deserialize(msg);
}
public static List<net.kyori.adventure.text.Component> fromStringList(
@NotNull List<String> list) {
return list.stream().map(Component::comp).collect(Collectors.toList());
}
}

View file

@ -1,12 +1,10 @@
package me.unurled.sacredrealms.sr.utils;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.srcore.utils.Component.textComp;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import me.unurled.sacredrealms.sr.components.cutscene.Frame;
import me.unurled.sacredrealms.sr.components.cutscene.Marker;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.title.Title;
import net.kyori.adventure.title.Title.Times;
@ -32,36 +30,4 @@ public class CutsceneUtil {
Duration.ofSeconds(fadeOut)));
p.showTitle(title);
}
public static @NotNull List<Frame> interpolateFrames(
@NotNull Marker startMarker, @NotNull Marker endMarker, long stepMillis) {
long duration = startMarker.getOverAllTime();
int numFrames = (int) (duration / stepMillis);
double xDiff = (endMarker.getStart().getX() - startMarker.getStart().getX()) / numFrames;
double yDiff = (endMarker.getStart().getY() - startMarker.getStart().getY()) / numFrames;
double zDiff = (endMarker.getStart().getZ() - startMarker.getStart().getZ()) / numFrames;
double yawDiff = (endMarker.getStart().getYaw() - startMarker.getStart().getYaw()) / numFrames;
double pitchDiff =
(endMarker.getStart().getPitch() - startMarker.getStart().getPitch()) / numFrames;
ArrayList<Frame> frames = new ArrayList<>();
for (int i = 0; i < numFrames; i++) {
double x = startMarker.getStart().getX() + xDiff * i;
double y = startMarker.getStart().getY() + yDiff * i;
double z = startMarker.getStart().getZ() + zDiff * i;
double yaw = startMarker.getStart().getYaw() + yawDiff * i;
double pitch = startMarker.getStart().getPitch() + pitchDiff * i;
Frame frame =
new Frame(
new Location(startMarker.getStart().getWorld(), x, y, z, (float) yaw, (float) pitch));
frames.add(frame);
}
return frames;
}
}

View file

@ -1,8 +1,8 @@
package me.unurled.sacredrealms.sr.utils;
import static me.unurled.sacredrealms.sr.utils.Component.comp;
import static me.unurled.sacredrealms.sr.utils.Component.textComp;
import static me.unurled.sacredrealms.sr.utils.SRPlayerUtils.syncSRToPlayer;
import static me.unurled.srcore.utils.Component.comp;
import static me.unurled.srcore.utils.Component.textComp;
import com.google.gson.JsonElement;
import java.util.ArrayList;

View file

@ -0,0 +1,145 @@
package me.unurled.sacredrealms.sr.utils;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class Region {
private Location corner1;
private Location corner2;
public Region() {
this.corner1 = null;
this.corner2 = null;
}
public boolean isSet() {
return corner1 != null && corner2 != null;
}
@Nullable
public World getWorld() {
if (corner1 == null) return null;
return corner1.getWorld();
}
public boolean isIn(final @NotNull Location loc) {
if (corner1 == null || corner2 == null) {
return false;
}
double xMin = Math.min(corner1.getX(), corner2.getX());
double xMax = Math.max(corner1.getX(), corner2.getX());
double yMin = Math.min(corner1.getY(), corner2.getY());
double yMax = Math.max(corner1.getY(), corner2.getY());
double zMin = Math.min(corner1.getZ(), corner2.getZ());
double zMax = Math.max(corner1.getZ(), corner2.getZ());
// if the location is within the region in the x, y, and z axis
return loc.getBlockX() >= xMin
&& loc.getBlockX() <= xMax
&& loc.getBlockY() >= yMin
&& loc.getBlockY() <= yMax
&& loc.getBlockZ() >= zMin
&& loc.getBlockZ() <= zMax;
}
public int getTotalBlockSize() {
return (int) (this.getHeight() * this.getXWidth() * this.getZWidth());
}
public double getHeight() {
if (corner1 == null || corner2 == null) {
return -1;
}
double yMin = Math.min(corner1.getY(), corner2.getY());
double yMax = Math.max(corner1.getY(), corner2.getY());
return yMax - yMin + 1;
}
public double getXWidth() {
if (corner1 == null || corner2 == null) {
return -1;
}
double xMin = Math.min(corner1.getX(), corner2.getX());
double xMax = Math.max(corner1.getX(), corner2.getX());
return xMax - xMin + 1;
}
public double getZWidth() {
if (corner1 == null || corner2 == null) {
return -1;
}
double zMin = Math.min(corner1.getZ(), corner2.getZ());
double zMax = Math.max(corner1.getZ(), corner2.getZ());
return zMax - zMin + 1;
}
@NotNull
public List<Block> blockList(World world) {
if (corner1 == null || corner2 == null) {
return List.of();
}
double xMin = Math.min(corner1.getX(), corner2.getX());
double xMax = Math.max(corner1.getX(), corner2.getX());
double yMin = Math.min(corner1.getY(), corner2.getY());
double yMax = Math.max(corner1.getY(), corner2.getY());
double zMin = Math.min(corner1.getZ(), corner2.getZ());
double zMax = Math.max(corner1.getZ(), corner2.getZ());
final ArrayList<Block> bL = new ArrayList<>(this.getTotalBlockSize());
for (double x = xMin; x <= xMax; ++x) {
for (double y = yMin; y <= yMax; ++y) {
for (double z = zMin; z <= zMax; ++z) {
final Block b = world.getBlockAt((int) x, (int) y, (int) z);
bL.add(b);
}
}
}
return bL;
}
public boolean isPlayerIn(@NotNull Player player) {
return this.isIn(player.getLocation());
}
@NotNull
public List<Entity> getEntities() {
List<Entity> entities = new ArrayList<>();
if (corner1 == null || corner1.getWorld() == null) {
return entities;
}
List<Block> blocks = blockList(corner1.getWorld());
if (blocks == null) {
return entities;
}
for (Block block : blocks) {
entities.addAll(block.getWorld().getNearbyEntities(block.getLocation(), 1, 1, 1));
}
return entities;
}
public Location corner1() {
return corner1;
}
public Location corner2() {
return corner2;
}
public Region setCorner1(Location corner1) {
this.corner1 = corner1;
return this;
}
public Region setCorner2(Location corner2) {
this.corner2 = corner2;
return this;
}
}

View file

@ -0,0 +1,139 @@
package me.unurled.sacredrealms.sr.utils;
import static me.unurled.sacredrealms.sr.utils.Logger.error;
import static me.unurled.sacredrealms.sr.utils.Logger.log;
import static org.bukkit.Bukkit.getServer;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Slime;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.scoreboard.Team;
import org.jetbrains.annotations.NotNull;
public class RegionUtil {
private static final String REGIONSELECTOR = "srselector";
public static void killSelectorsWithTag(String inputTag) {
for (World world : getServer().getWorlds()) {
for (Entity entity : world.getEntities()) {
for (String tag : entity.getScoreboardTags()) {
if (tag.equals(REGIONSELECTOR + "-" + inputTag)) {
entity.remove();
break;
}
}
}
}
}
public static void killAllSelectors() {
for (World world : getServer().getWorlds()) {
for (Entity entity : world.getEntities()) {
for (String tag : entity.getScoreboardTags()) {
if (tag.startsWith(REGIONSELECTOR + "-")) {
entity.remove();
break;
}
}
}
}
}
public static void drawSelector(
@NotNull Region region, World world, String id, NamedTextColor glowColor) {
Location loc1 = region.corner1();
Location loc2 = region.corner2();
if (loc1.getWorld() == null || !loc1.getWorld().equals(loc2.getWorld())) {
return;
}
int minx = Math.min(loc1.getBlockX(), loc2.getBlockX());
int miny = Math.min(loc1.getBlockY(), loc2.getBlockY());
int minz = Math.min(loc1.getBlockZ(), loc2.getBlockZ());
int maxx = Math.max(loc1.getBlockX(), loc2.getBlockX());
int maxy = Math.max(loc1.getBlockY(), loc2.getBlockY());
int maxz = Math.max(loc1.getBlockZ(), loc2.getBlockZ());
Scoreboard board = Bukkit.getScoreboardManager().getMainScoreboard();
int highestNumber = 0;
for (Team team : board.getTeams()) {
if (team.getName().startsWith(REGIONSELECTOR + "+")) {
String number = team.getName().substring(11);
try {
int tempNumber = Integer.parseInt(number);
if (tempNumber >= highestNumber) {
highestNumber = tempNumber;
}
} catch (NumberFormatException e) {
error(e.getMessage());
}
}
}
log(REGIONSELECTOR + "+" + (highestNumber + 1));
Team selectorTeam = board.registerNewTeam(REGIONSELECTOR + "+" + (highestNumber + 1));
if (glowColor != null) {
selectorTeam.color(glowColor);
}
selectorTeam.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
for (double x = minx; x <= maxx; x++) {
makeSlime(id, world, selectorTeam, x, miny, minz);
makeSlime(id, world, selectorTeam, x, maxy, minz);
makeSlime(id, world, selectorTeam, x, miny, maxz);
makeSlime(id, world, selectorTeam, x, maxy, maxz);
}
for (double y = miny; y <= maxy; y++) {
makeSlime(id, world, selectorTeam, minx, y, minz);
makeSlime(id, world, selectorTeam, maxx, y, minz);
makeSlime(id, world, selectorTeam, minx, y, maxz);
makeSlime(id, world, selectorTeam, maxx, y, maxz);
}
for (double z = minz; z <= maxz; z++) {
makeSlime(id, world, selectorTeam, minx, miny, z);
makeSlime(id, world, selectorTeam, maxx, miny, z);
makeSlime(id, world, selectorTeam, minx, maxy, z);
makeSlime(id, world, selectorTeam, maxx, maxy, z);
}
}
private static void makeSlime(
String id, @NotNull World world, @NotNull Team selectorTeam, double x, double y, double z) {
Slime slime =
(Slime)
world.spawnEntity(
new Location(world, x + 0.5, y, z + 0.5), EntityType.SLIME, SpawnReason.CUSTOM);
slime.setSize(2);
slime.setAI(false);
slime.setGravity(false);
slime.setCollidable(false);
slime.setSilent(true);
slime.setCanPickupItems(false);
slime.setGlowing(true);
slime.setInvulnerable(true);
slime.setInvisible(true);
slime.addScoreboardTag(REGIONSELECTOR + "-" + id);
slime.setPersistent(true);
selectorTeam.addEntry(String.valueOf(slime.getUniqueId()));
}
public void removeTempTeams() {
Scoreboard board = Bukkit.getScoreboardManager().getMainScoreboard();
for (Team team : board.getTeams()) {
if (team.getName().startsWith(REGIONSELECTOR + "+")) {
team.unregister();
}
}
}
}

View file

@ -1,6 +1,6 @@
package me.unurled.sacredrealms.sr.utils;
import static me.unurled.sacredrealms.sr.utils.Component.comp;
import static me.unurled.srcore.utils.Component.comp;
import java.util.List;
import java.util.Random;