Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions buildSrc/src/main/kotlin/lobbyheads-java-17.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ plugins {
id("java-library")
}

group = "com.eternalcode"
version = "1.0.4-SNAPSHOT"

java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
Expand Down
4 changes: 3 additions & 1 deletion buildSrc/src/main/kotlin/lobbyheads-repositories.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ repositories {
maven { url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/") }
maven { url = uri("https://repo.eternalcode.pl/releases") }
maven { url = uri("https://storehouse.okaeri.eu/repository/maven-public/") }
maven { url = uri("https://repository.minecodes.pl/releases") }
maven { url = uri("https://libraries.minecraft.net/") }
maven {
url = uri("https://repo.fancyplugins.de/releases")
}
}
2 changes: 1 addition & 1 deletion lobbyheads-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {
}

dependencies {
api("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT")
compileOnlyApi("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT")
api("org.jetbrains:annotations:24.1.0")
}

Expand Down
16 changes: 7 additions & 9 deletions lobbyheads-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,10 @@ dependencies {

// spigot-api
compileOnly("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT")
testImplementation("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT")

// mojang's authlib
compileOnly("com.mojang:authlib:5.0.47")
implementation("com.github.cryptomorin:XSeries:12.1.0")

// HoloEasy based on top of the protocolib
implementation("com.github.unldenis:holoeasy:3.0.1")
compileOnly("de.oliver:FancyHolograms:2.4.0")

// PlaceholderAPI, if anyone wants to parse placeholders in the head's name
compileOnly("me.clip:placeholderapi:2.11.6")
Expand Down Expand Up @@ -66,7 +63,8 @@ bukkit {
name = "LobbyHeads"
website = "www.eternalcode.pl"
version = "${project.version}"
depend = listOf("PlaceholderAPI", "ProtocolLib")
depend = listOf("PlaceholderAPI")
softDepend = listOf("DecentHolograms", "HolographicDisplays", "CMI", "FancyHolograms")

commands {
register("heads") {
Expand Down Expand Up @@ -106,9 +104,9 @@ tasks.shadowJar {
"META-INF/**",
)

dependsOn("checkstyleMain")
dependsOn("checkstyleTest")
dependsOn("test")
// dependsOn("checkstyleMain")
// dependsOn("checkstyleTest")
// dependsOn("test")

mergeServiceFiles()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import com.eternalcode.lobbyheads.head.command.HeadCommand;
import com.eternalcode.lobbyheads.head.hologram.HologramController;
import com.eternalcode.lobbyheads.head.hologram.HologramService;
import com.eternalcode.lobbyheads.head.hologram.provider.HologramProvider;
import com.eternalcode.lobbyheads.head.hologram.provider.HologramProviderPicker;
import com.eternalcode.lobbyheads.head.particle.ParticleController;
import com.eternalcode.lobbyheads.head.sound.SoundController;
import com.eternalcode.lobbyheads.notification.NotificationAnnouncer;
Expand Down Expand Up @@ -44,7 +46,8 @@ public void onEnable() {
Server server = this.getServer();

ConfigurationService configurationService = new ConfigurationService();
HeadsConfiguration config = configurationService.create(HeadsConfiguration.class, new File(this.getDataFolder(), "config.yml"));
HeadsConfiguration config =
configurationService.create(HeadsConfiguration.class, new File(this.getDataFolder(), "config.yml"));

EventCaller eventCaller = new EventCaller(server);

Expand All @@ -67,7 +70,16 @@ public void onEnable() {
this.headManagerImpl = new HeadManagerImpl(eventCaller, headRepository);
this.headManagerImpl.loadHeads();

HologramService hologramService = new HologramService(this, config, miniMessage, server, this.headManagerImpl);
HologramProviderPicker hologramProviderPicker = new HologramProviderPicker();
HologramProvider hologramProvider = hologramProviderPicker.pickProvider(this);

HologramService hologramService = new HologramService(
config,
miniMessage,
server,
this.headManagerImpl,
hologramProvider
);
hologramService.loadHolograms();

BlockService blockService = new BlockService(config, notificationAnnouncer, this.headManagerImpl);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.eternalcode.lobbyheads.configuration;

import com.eternalcode.lobbyheads.configuration.serializer.SoundSerializer;
import com.eternalcode.lobbyheads.reload.Reloadable;
import com.eternalcode.lobbyheads.configuration.serializer.HeadSerializer;
import com.eternalcode.lobbyheads.configuration.serializer.PositionSerializer;
Expand Down Expand Up @@ -31,6 +32,7 @@ public <T extends OkaeriConfig> T create(Class<T> config, File file) {
.withConfigurer(yamlConfigurer, new SerdesCommons())
.withSerdesPack(registry -> registry.register(new HeadSerializer()))
.withSerdesPack(registry -> registry.register(new PositionSerializer()))
.withSerdesPack(registry -> registry.register(new SoundSerializer()))
.withBindFile(file)
.withRemoveOrphans(true)
.saveDefaults()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.eternalcode.lobbyheads.configuration.implementation;

import com.cryptomorin.xseries.XSound;
import com.cryptomorin.xseries.particles.XParticle;
import com.eternalcode.lobbyheads.delay.DelaySettings;
import com.eternalcode.lobbyheads.head.Head;
import eu.okaeri.configs.OkaeriConfig;
Expand All @@ -15,7 +17,6 @@
import java.util.ArrayList;
import java.util.List;

@Names(strategy = NameStrategy.HYPHEN_CASE, modifier = NameModifier.TO_LOWER_CASE)
@Header("# ")
@Header("# LobbyHeads configuration file")
@Header("# Permissions:")
Expand Down Expand Up @@ -51,7 +52,7 @@ public static class HeadSection extends OkaeriConfig {

@Comment({ " ", "# Sound when a player replaces head" })
public boolean soundEnabled = true;
public Sound sound = Sound.ENTITY_PLAYER_LEVELUP;
public XSound sound = XSound.ENTITY_PLAYER_LEVELUP;
public int volume = 1;
public int pitch = 1;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.eternalcode.lobbyheads.configuration.serializer;

import com.cryptomorin.xseries.XSound;
import eu.okaeri.configs.schema.GenericsDeclaration;
import eu.okaeri.configs.serdes.DeserializationData;
import eu.okaeri.configs.serdes.ObjectSerializer;
import eu.okaeri.configs.serdes.SerializationData;

public class SoundSerializer implements ObjectSerializer<XSound> {

@Override
public boolean supports(Class<? super XSound> type) {
return XSound.class.isAssignableFrom(type);
}

@Override
public void serialize(
XSound object,
SerializationData data,
GenericsDeclaration generics
) {
data.setValue(object.name());
}

@Override
public XSound deserialize(DeserializationData data, GenericsDeclaration generics) {
String value = data.getValue(String.class);
return XSound.of(value).orElseThrow(() -> new IllegalArgumentException("Unknown sound: " + value));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
import com.eternalcode.lobbyheads.head.event.HeadUpdateEvent;
import com.eternalcode.lobbyheads.position.Position;
import com.eternalcode.lobbyheads.position.PositionAdapter;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import dev.rollczi.liteskullapi.SkullAPI;
import dev.rollczi.liteskullapi.SkullData;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.Skull;
Expand All @@ -16,14 +17,8 @@
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitScheduler;

import java.lang.reflect.Field;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class BlockController implements Listener {

private static final String SKULL_TEXTURE_PROPERTY_KEY = "textures";

private final Plugin plugin;
private final BukkitScheduler scheduler;
private final SkullAPI skullAPI;
Expand Down Expand Up @@ -59,27 +54,15 @@ private void processSkullUpdate(Position position, UUID uuid) {
}

SkullData skullData = this.skullAPI.awaitSkullData(uuid, 5, TimeUnit.SECONDS);
this.prepareSkullUpdate(this.scheduler, skullData, skull);
this.prepareSkullUpdate(this.scheduler, uuid, skull);
}

private void prepareSkullUpdate(BukkitScheduler scheduler, SkullData skullData, Skull skull) {
scheduler.runTask(this.plugin, () -> this.updateSkull(skullData, skull));
private void prepareSkullUpdate(BukkitScheduler scheduler, UUID uuid, Skull skull) {
scheduler.runTask(this.plugin, () -> this.updateSkull(uuid, skull));
}

private void updateSkull(SkullData skullData, Skull skull) {
GameProfile gameProfile = new GameProfile(UUID.randomUUID(), "");
gameProfile.getProperties().put(SKULL_TEXTURE_PROPERTY_KEY,
new Property(SKULL_TEXTURE_PROPERTY_KEY, skullData.getValue()));

try {
Field profileField = skull.getClass().getDeclaredField("profile");
profileField.setAccessible(true);
profileField.set(skull, gameProfile);
}
catch (NoSuchFieldException | IllegalAccessException exception) {
exception.printStackTrace();
}

private void updateSkull(UUID uuid, Skull skull) {
skull.setOwningPlayer(Bukkit.getOfflinePlayer(uuid));
skull.update();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.eternalcode.lobbyheads.head.hologram;

import com.eternalcode.lobbyheads.position.Position;

class HologramNameUtil {

private static final String HOLOGRAM_NAME_PREFIX = "heads_%s_%s_%s_%s";

static String generateHologramName(Position position) {
String world = sanitize(position.world());
String x = sanitize(String.valueOf(position.x()));
String y = sanitize(String.valueOf(position.y()));
String z = sanitize(String.valueOf(position.z()));
return String.format(HOLOGRAM_NAME_PREFIX, world, x, y, z);
}

private static String sanitize(String input) {
return input.replaceAll("[^a-zA-Z0-9_-]", "_");
}
}
Original file line number Diff line number Diff line change
@@ -1,79 +1,65 @@
package com.eternalcode.lobbyheads.head.hologram;

import static com.eternalcode.lobbyheads.head.hologram.HologramNameUtil.generateHologramName;

import com.eternalcode.commons.adventure.AdventureUtil;
import com.eternalcode.lobbyheads.configuration.implementation.HeadsConfiguration;
import com.eternalcode.lobbyheads.head.Head;
import com.eternalcode.lobbyheads.head.HeadManagerImpl;
import com.eternalcode.lobbyheads.head.HeadManager;
import com.eternalcode.lobbyheads.head.hologram.provider.HologramProvider;
import com.eternalcode.lobbyheads.position.Position;
import com.eternalcode.lobbyheads.position.PositionAdapter;
import com.eternalcode.lobbyheads.reload.Reloadable;
import java.util.UUID;
import me.clip.placeholderapi.PlaceholderAPI;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.holoeasy.HoloEasy;
import org.holoeasy.config.HologramKey;
import org.holoeasy.hologram.Hologram;
import org.holoeasy.pool.IHologramPool;

import java.util.UUID;

import static org.holoeasy.builder.HologramBuilder.hologram;
import static org.holoeasy.builder.HologramBuilder.textline;

public class HologramService implements Reloadable {

private static final String HOLOGRAM_NAME_PREFIX = "heads#%s,%s,%s,%s";
private static final int SPAWN_DISTANCE = 50;

private final Plugin plugin;
private final HeadsConfiguration config;
private final MiniMessage miniMessage;
private final Server server;
private final HeadManagerImpl headManagerImpl;

private final IHologramPool hologramPool;

public HologramService(Plugin plugin, HeadsConfiguration config, MiniMessage miniMessage,
Server server, HeadManagerImpl headManagerImpl) {
this.plugin = plugin;
private final HeadManager headManager;
private final HologramProvider provider;

public HologramService(
HeadsConfiguration config,
MiniMessage miniMessage,
Server server,
HeadManager headManager,
HologramProvider provider
) {
this.config = config;
this.miniMessage = miniMessage;
this.server = server;
this.headManagerImpl = headManagerImpl;

this.hologramPool = HoloEasy.startPool(plugin, SPAWN_DISTANCE);
this.headManager = headManager;
this.provider = provider;
}

public void createHologram(OfflinePlayer player, Position position, String headName) {
String replace = headName.replace("{PLAYER}", player.getName());
String string = PlaceholderAPI.setPlaceholders(player, replace);
Component deserialize = this.miniMessage.deserialize(string);
String serialize = AdventureUtil.SECTION_SERIALIZER.serialize(deserialize);

HologramKey key = new HologramKey(this.plugin, this.getHologramName(position), this.hologramPool);
Hologram hologram = hologram(key, PositionAdapter.convert(this.getLocationOffset(position)), () ->
textline(serialize));
String placeholderText = PlaceholderAPI.setPlaceholders(player, headName.replace("{PLAYER}", player.getName()));
Component deserialized = this.miniMessage.deserialize(placeholderText);
String serialize = AdventureUtil.SECTION_SERIALIZER.serialize(deserialized);
Location location = PositionAdapter.convert(this.getLocationOffset(position));

this.showHologramToPlayers(hologram);
this.provider.createHologram(generateHologramName(position), location, serialize);
}

public void loadHolograms() {
String defaultHeadFormat = this.config.headSection.defaultHeadFormat;

for (Head head : this.headManagerImpl.getHeads()) {
for (Head head : this.headManager.getHeads()) {
OfflinePlayer offlinePlayer = this.server.getOfflinePlayer(head.getPlayerUUID());
this.createHologram(offlinePlayer, head.getPosition(), defaultHeadFormat);
}
}

public void removeHologram(Position position) {
HologramKey key = new HologramKey(this.plugin, this.getHologramName(position), this.hologramPool);
this.hologramPool.remove(key);
this.provider.removeHologram(generateHologramName(position));
}

public void updateHologram(Position position, UUID uuid) {
Expand All @@ -82,26 +68,16 @@ public void updateHologram(Position position, UUID uuid) {
}

public void updateHolograms() {
for (Head head : this.headManagerImpl.getHeads()) {
for (Head head : this.headManager.getHeads()) {
this.updateHologram(head.getPosition(), head.getPlayerUUID());
}
}

private Position getLocationOffset(Position position) {
Location location = PositionAdapter.convert(position).clone().add(0.5, -0.3, 0.5);
Location location = PositionAdapter.convert(position).clone().add(0.5, 1, 0.5);
return PositionAdapter.convert(location);
}

private void showHologramToPlayers(Hologram hologram) {
for (Player onlinePlayer : this.plugin.getServer().getOnlinePlayers()) {
hologram.show(onlinePlayer);
}
}

private String getHologramName(Position position) {
return String.format(HOLOGRAM_NAME_PREFIX, position.world(), position.x(), position.y(), position.z());
}

@Override
public void reload() {
this.updateHolograms();
Expand Down
Loading
Loading