Initial commit

This commit is contained in:
2024-10-20 19:05:26 +02:00
commit 023e9386ce
14 changed files with 739 additions and 0 deletions
@@ -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) {
}
+15
View File
@@ -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