Initial commit
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
package com.alttd.halloween;
|
||||
|
||||
import com.alttd.halloween.leaderboard.Leaderboard;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Slf4j
|
||||
public class Main extends JavaPlugin {
|
||||
|
||||
AtomicInteger ai = new AtomicInteger(0);
|
||||
|
||||
@Getter
|
||||
private ProtocolManager protocolManager;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
log.info("Halloween2024 enabled!");
|
||||
World world = Bukkit.getWorld("world");
|
||||
Location location = new Location(world, 34, 122, 8);
|
||||
Leaderboard halloween2024 = new Leaderboard(location, 5, protocolManager, "Halloween2024");
|
||||
Bukkit.getScheduler().runTaskTimer(this, () -> Bukkit.getOnlinePlayers().forEach(player -> {
|
||||
log.info("Adding viewer {}", player.getName());
|
||||
halloween2024.addViewer(player);
|
||||
}), 20, 20);
|
||||
Bukkit.getScheduler().runTaskTimer(this, () -> halloween2024.updateScoreboard((line -> {
|
||||
log.info("Updating line {} iteration {}", line, ai.get());
|
||||
return String.format("This is line %d called %d times", line, ai.getAndIncrement());
|
||||
})), 0, 20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
protocolManager = ProtocolLibrary.getProtocolManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
log.info("Halloween2024 disabled!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.alttd.halloween.leaderboard;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Slf4j
|
||||
public class HoverText {
|
||||
|
||||
private final ProtocolManager protocolManager;
|
||||
|
||||
public HoverText(ProtocolManager protocolManager) {
|
||||
this.protocolManager = protocolManager;
|
||||
}
|
||||
|
||||
public Optional<PacketContainer> setLine(LeaderboardLineEntity entity, String text) {
|
||||
return setLine(entity.entityId(), text);
|
||||
}
|
||||
|
||||
public Optional<LeaderboardLineEntity> createLeaderboardLineEntity(Location location) {
|
||||
try {
|
||||
PacketContainer spawnPacket = protocolManager.createPacket(PacketType.Play.Server.SPAWN_ENTITY);
|
||||
int entityId = (int) (Math.random() * Integer.MAX_VALUE);
|
||||
|
||||
spawnPacket.getModifier().writeDefaults();
|
||||
spawnPacket.getIntegers().write(0, entityId);
|
||||
spawnPacket.getUUIDs().write(0, UUID.randomUUID());
|
||||
spawnPacket.getDoubles()
|
||||
.write(0, location.getX())
|
||||
.write(1, location.getY())
|
||||
.write(2, location.getZ());
|
||||
spawnPacket.getIntegers().write(1, 78); // Armor Stand type
|
||||
PacketContainer destroyPacket = protocolManager.createPacket(PacketType.Play.Server.ENTITY_DESTROY);
|
||||
destroyPacket.getIntegerArrays().write(0, new int[]{entityId});
|
||||
return Optional.of(new LeaderboardLineEntity(entityId, spawnPacket, destroyPacket));
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to create hover text entity", e);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public Optional<PacketContainer> setLine(int entityId, String text) {
|
||||
try {
|
||||
PacketContainer metaPacket = protocolManager.createPacket(PacketType.Play.Server.ENTITY_METADATA);
|
||||
metaPacket.getIntegers().write(0, entityId);
|
||||
WrappedDataWatcher watcher = new WrappedDataWatcher();
|
||||
|
||||
WrappedDataWatcher.Serializer serializer = WrappedDataWatcher.Registry.get(MinecraftReflection.getIChatBaseComponentClass());
|
||||
WrappedDataWatcher.WrappedDataWatcherObject displayName = new WrappedDataWatcher.WrappedDataWatcherObject(2, serializer);
|
||||
WrappedChatComponent component = WrappedChatComponent.fromText(text);
|
||||
|
||||
watcher.setObject(displayName, Optional.of(component.getHandle()));
|
||||
watcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(3, WrappedDataWatcher.Registry.get(Boolean.class)), true); // Custom Name Visible
|
||||
watcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, WrappedDataWatcher.Registry.get(Byte.class)), (byte) 0x20); // Invisible
|
||||
|
||||
metaPacket.getWatchableCollectionModifier().write(0, watcher.getWatchableObjects());
|
||||
return Optional.of(metaPacket);
|
||||
} catch (FieldAccessException e) {
|
||||
log.error("Failed to edit line on hover text", e);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.alttd.halloween.leaderboard;
|
||||
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Slf4j
|
||||
public class Leaderboard {
|
||||
|
||||
private final LeaderboardLineEntity title;
|
||||
private final List<LeaderboardLineEntity> lines;
|
||||
private final HashMap<Integer, PacketContainer> metaPacket = new HashMap<>();
|
||||
private final HashMap<UUID, Player> viewers = new HashMap<>();
|
||||
private final ProtocolManager protocolManager;
|
||||
private final int leaderboardSize;
|
||||
|
||||
public Leaderboard(Location location, int leaderboardSize, ProtocolManager protocolManager, String title) {
|
||||
this.leaderboardSize = leaderboardSize;
|
||||
this.protocolManager = protocolManager;
|
||||
if (leaderboardSize < 1) {
|
||||
throw new IllegalArgumentException("Leaderboard must have at least one line");
|
||||
}
|
||||
HoverText hoverText = new HoverText(protocolManager);
|
||||
this.title = createTitle(hoverText, location, title, leaderboardSize + 1);
|
||||
this.lines = createLines(new HoverText(protocolManager), location);
|
||||
}
|
||||
|
||||
private LeaderboardLineEntity createTitle(HoverText hoverText, Location location, String title, int titleLocation) {
|
||||
Location clone = location.clone();
|
||||
clone.setY(clone.getY() + titleLocation);
|
||||
Optional<LeaderboardLineEntity> leaderboardLineEntity = hoverText.createLeaderboardLineEntity(clone);
|
||||
if (leaderboardLineEntity.isEmpty()) {
|
||||
log.error("Failed to create title");
|
||||
throw new ExceptionInInitializerError("Failed to create title");
|
||||
}
|
||||
Optional<PacketContainer> packetContainer = hoverText.setLine(leaderboardLineEntity.get(), title);
|
||||
if (packetContainer.isEmpty()) {
|
||||
log.error("Failed to create title text");
|
||||
throw new ExceptionInInitializerError("Failed to create title text");
|
||||
}
|
||||
metaPacket.put(leaderboardLineEntity.get().entityId(), packetContainer.get());
|
||||
return leaderboardLineEntity.get();
|
||||
}
|
||||
|
||||
private List<LeaderboardLineEntity> createLines(HoverText hoverText, Location location) throws ExceptionInInitializerError {
|
||||
List<LeaderboardLineEntity> lines = new ArrayList<>();
|
||||
for (int i = 0; i < leaderboardSize; i++) {
|
||||
Location clone = location.clone();
|
||||
clone.setY(clone.getY() + leaderboardSize - i);
|
||||
Optional<LeaderboardLineEntity> optionalLeaderboardLineEntity = hoverText.createLeaderboardLineEntity(clone);
|
||||
if (optionalLeaderboardLineEntity.isEmpty()) {
|
||||
log.error("Failed to create leaderboard");
|
||||
throw new ExceptionInInitializerError("Failed to create leaderboard");
|
||||
}
|
||||
LeaderboardLineEntity leaderboardLineEntity = optionalLeaderboardLineEntity.get();
|
||||
Optional<PacketContainer> packetContainer = hoverText.setLine(leaderboardLineEntity, "");
|
||||
if (packetContainer.isEmpty()) {
|
||||
log.error("Failed to create line text");
|
||||
throw new ExceptionInInitializerError("Failed to create line text");
|
||||
}
|
||||
metaPacket.put(leaderboardLineEntity.entityId(), packetContainer.get());
|
||||
lines.add(leaderboardLineEntity);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
public void updateScoreboard(Function<Integer, String> func) {//TODO remove offline players and check if the player is still nearby?
|
||||
HoverText hoverText = new HoverText(protocolManager); //TODO make it so this doesnt have to be recreated? Could be static maybe
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
LeaderboardLineEntity leaderboardLineEntity = lines.get(i);
|
||||
Optional<PacketContainer> packetContainer = hoverText.setLine(leaderboardLineEntity, func.apply(i));
|
||||
if (packetContainer.isEmpty()) {
|
||||
log.error("Failed to update line text");
|
||||
throw new ExceptionInInitializerError("Failed to update line text");
|
||||
}
|
||||
metaPacket.put(leaderboardLineEntity.entityId(), packetContainer.get());
|
||||
}
|
||||
viewers.values().forEach(this::updateScoreboard);
|
||||
}
|
||||
|
||||
private void updateScoreboard(Player player) {
|
||||
metaPacket.values().forEach(metaPacket -> protocolManager.sendServerPacket(player, metaPacket));
|
||||
}
|
||||
|
||||
public void addViewer(Player player) {
|
||||
if (viewers.put(player.getUniqueId(), player) == null) {
|
||||
return; //Player was already in viewers list
|
||||
}
|
||||
protocolManager.sendServerPacket(player, title.entitySpawnPacket());
|
||||
lines.forEach(line -> protocolManager.sendServerPacket(player, line.entitySpawnPacket()));
|
||||
}
|
||||
|
||||
public void removeViewer(Player player) {
|
||||
Player removed = viewers.remove(player.getUniqueId());
|
||||
if (removed == null || !removed.isOnline()) {
|
||||
return;
|
||||
}
|
||||
protocolManager.sendServerPacket(player, title.entityDestroyPacket());
|
||||
lines.forEach(line -> protocolManager.sendServerPacket(player, line.entityDestroyPacket()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.alttd.halloween.leaderboard;
|
||||
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
|
||||
public record LeaderboardLineEntity(int entityId, PacketContainer entitySpawnPacket, PacketContainer entityDestroyPacket) {
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
name: Halloween
|
||||
version: '1.0.0'
|
||||
main: com.alttd.halloween.Main
|
||||
description: A plugin for the 2024 halloween event
|
||||
author: Stijn
|
||||
website: https://alttd.com
|
||||
api-version: '1.21'
|
||||
commands:
|
||||
custommobs:
|
||||
description: Base command for halloween event
|
||||
permission: halloween.use
|
||||
usage: /halloween
|
||||
aliases:
|
||||
- event
|
||||
- h
|
||||
Reference in New Issue
Block a user