Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-680 Afk addon #698

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
51 changes: 51 additions & 0 deletions eternalcore-afk-addon/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
plugins {
`java-library`
`eternalcode-java`
`eternalcore-repositories`
id("com.github.johnrengelman.shadow")
id("net.minecrell.plugin-yml.bukkit")
}

group = "com.eternalcode.core"
version = "1.0.0"

repositories {
maven("https://jitpack.io")
}

dependencies {
compileOnly(project(":eternalcore-api"))

compileOnly("org.spigotmc:spigot-api:${Versions.SPIGOT_API}")

implementation("net.dzikoysk:cdn:${Versions.CDN_CONFIGS}")
implementation("com.github.unldenis:holoeasy:3.1.1")
implementation("com.eternalcode:eternalcode-commons-adventure:1.1.1")
implementation("com.eternalcode:eternalcode-commons-shared:1.1.1")
}

bukkit {
main = "com.eternalcode.core.addon.afk.AfkAddonPlugin"
apiVersion = "1.13"
prefix = "EternalCore-AfkAddon"
author = "P1otrulla"
name = "EternalCore-DiscordSpyAddon"
description = "AfkAddon for EternalCore!"
website = "https://eternalcode.pl"
version = "${project.version}"
depend = listOf("EternalCore", "ProtocolLib")
}

tasks.shadowJar {
archiveFileName.set("EternalCore-AfkAddon v${project.version}.jar")

listOf(
"com.github.unldenis",
"net.dzikoysk"
).forEach {
relocate(it, "com.eternalcode.core.addon.afk.shared.$it")
}
}



Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.eternalcode.core.addon.afk;

import com.eternalcode.commons.adventure.AdventureLegacyColorPostProcessor;
import com.eternalcode.commons.adventure.AdventureLegacyColorPreProcessor;
import com.eternalcode.core.EternalCoreApi;
import com.eternalcode.core.EternalCoreApiProvider;
import com.eternalcode.core.addon.afk.config.ConfigService;
import com.eternalcode.core.addon.afk.config.PluginConfiguration;
import com.eternalcode.core.feature.afk.AfkService;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Server;
import org.bukkit.plugin.java.JavaPlugin;

public class AfkAddonPlugin extends JavaPlugin {

private ConfigService configService;
private PluginConfiguration configuration;

private AfkHologramService afkHologramService;

private MiniMessage miniMessage;

@Override
public void onEnable() {
this.miniMessage = MiniMessage.builder()
.postProcessor(new AdventureLegacyColorPostProcessor())
.preProcessor(new AdventureLegacyColorPreProcessor())
.build();

this.configService = new ConfigService(this.getDataFolder());
this.configuration = this.configService.load(new PluginConfiguration());

AfkService afkService = EternalCoreApiProvider.provide().getAfkService();
Server server = this.getServer();

this.afkHologramService = new AfkHologramService(this.configuration, this.miniMessage, afkService, this);
server.getPluginManager().registerEvents(new AfkController(this.afkHologramService, afkService), this);
server.getScheduler().runTaskTimer(this, new AfkHologramTask(this.afkHologramService, server), 20L, 20L);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.eternalcode.core.addon.afk;

import com.eternalcode.core.feature.afk.AfkService;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;

import java.util.UUID;

public class AfkController implements Listener {

private final AfkHologramService afkHologramService;
private final AfkService afkService;

public AfkController(AfkHologramService afkHologramService, AfkService afkService) {
this.afkHologramService = afkHologramService;
this.afkService = afkService;
}

@EventHandler
void onMove(PlayerMoveEvent event) {
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();

if (this.afkService.isAfk(uuid)) {
this.afkHologramService.deleteHologram(uuid);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package com.eternalcode.core.addon.afk;

import com.eternalcode.commons.time.DurationParser;
import com.eternalcode.core.addon.afk.config.PluginConfiguration;
import com.eternalcode.core.feature.afk.Afk;
import com.eternalcode.core.feature.afk.AfkService;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
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.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import static net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection;
import static org.holoeasy.builder.HologramBuilder.hologram;
import static org.holoeasy.builder.HologramBuilder.item;
import static org.holoeasy.builder.HologramBuilder.textline;

public class AfkHologramService {

private static final String HOLOGRAM_NAME_PREFIX = "afk#%s,%s,%s,%s";
private static final int HOLOGRAM_VIEW_DISTANCE = 0x32;

private final Map<UUID, HologramKey> holograms = new HashMap<>();
private final PluginConfiguration configuration;
private final MiniMessage miniMessage;
private final AfkService afkService;
private final IHologramPool pool;
private final Plugin plugin;
private final Server server;

public AfkHologramService(PluginConfiguration configuration, MiniMessage miniMessage, AfkService afkService, Plugin plugin) {
this.configuration = configuration;
this.miniMessage = miniMessage;
this.afkService = afkService;
this.plugin = plugin;
this.server = plugin.getServer();

this.pool = HoloEasy.startPool(plugin, HOLOGRAM_VIEW_DISTANCE);
}

public void createHologram(Player player) {
if (!this.afkService.isAfk(player.getUniqueId())) {
return;
}
Afk afk = this.afkService.getAfk(player.getUniqueId());

Duration afkSince = Duration.between(afk.getStart(), Instant.now());
Location location = player.getLocation().clone();

HologramKey key = new HologramKey(this.plugin, fetchName(location), this.pool);
Hologram hologram = hologram(key, this.fetchLocation(player), () -> {
if (this.configuration.hologramItemEnabled) {
item(new ItemStack(this.configuration.hologramItem));
}
this.configuration.hologramEntries.stream()
.map(entry -> entry.replace("{TIME}", DurationParser.TIME_UNITS.format(afkSince)))
.forEach(entry -> textline(legacySection().serialize(this.miniMessage.deserialize(entry))));
});

this.holograms.put(player.getUniqueId(), key);

this.showForAll(hologram);
}

public void deleteHologram(UUID uuid) {
HologramKey hologramKey = this.holograms.remove(uuid);

this.pool.remove(hologramKey);
}

public void updateHologram(Player player) {
this.deleteHologram(player.getUniqueId());
this.createHologram(player);
}

void showForAll(Hologram hologram) {
this.server.getOnlinePlayers().forEach(hologram::show);
}

String fetchName(Location location) {
return String.format(HOLOGRAM_NAME_PREFIX, location.getWorld(), location.getX(), location.getY(), location.getZ());
}

Location fetchLocation(Player player) {
return player.getLocation().add(0, 2, 0).clone();
}

public Set<UUID> getAfkPlayers() {
return Collections.unmodifiableSet(this.holograms.keySet());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.eternalcode.core.addon.afk;

import org.bukkit.Server;
import org.bukkit.entity.Player;

import java.util.UUID;

public class AfkHologramTask implements Runnable {

private final AfkHologramService afkHologramService;
private final Server server;

public AfkHologramTask(AfkHologramService afkHologramService, Server server) {
this.afkHologramService = afkHologramService;
this.server = server;
}

@Override
public void run() {
for (UUID uuid : this.afkHologramService.getAfkPlayers()) {
Player player = this.server.getPlayer(uuid);

if (player == null) {
this.afkHologramService.deleteHologram(uuid);
continue;
}

this.afkHologramService.updateHologram(player);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.eternalcode.core.addon.afk.config;

import java.io.File;
import java.util.HashSet;
import java.util.Set;
import net.dzikoysk.cdn.Cdn;
import net.dzikoysk.cdn.CdnFactory;
import net.dzikoysk.cdn.reflect.Visibility;

public class ConfigService {

private final Cdn cdn = CdnFactory
.createYamlLike()
.getSettings()
.withMemberResolver(Visibility.PRIVATE)
.build();

private final Set<ReloadableConfig> configs = new HashSet<>();
private final File dataFolder;

public ConfigService(File dataFolder) {
this.dataFolder = dataFolder;
}

public <T extends ReloadableConfig> T load(T config) {
cdn.load(config.resource(this.dataFolder), config).orThrow(RuntimeException::new);

cdn.render(config, config.resource(this.dataFolder)).orThrow(RuntimeException::new);

this.configs.add(config);

return config;
}

public <T extends ReloadableConfig> T save(T config) {
cdn.render(config, config.resource(this.dataFolder)).orThrow(RuntimeException::new);

this.configs.add(config);

return config;
}

public void reload() {
for (ReloadableConfig config : this.configs) {
load(config);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.eternalcode.core.addon.afk.config;

import net.dzikoysk.cdn.source.Resource;
import net.dzikoysk.cdn.source.Source;
import org.bukkit.Material;

import java.io.File;
import java.util.Arrays;
import java.util.List;

public class PluginConfiguration implements ReloadableConfig {

public boolean hologramItemEnabled = true;
public Material hologramItem = Material.BARRIER;

public List<String> hologramEntries = Arrays.asList(
"&6This player is &cAFK",
"&6Since: &c{TIME}"
);

@Override
public Resource resource(File folder) {
return Source.of(folder, "config.yml");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.eternalcode.core.addon.afk.config;

import java.io.File;
import net.dzikoysk.cdn.source.Resource;

public interface ReloadableConfig {

Resource resource(File folder);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ public interface AfkService {
*/
boolean isAfk(UUID playerUniqueId);

/**
* Returns the AFK status of a uniqueId.
*
* @param playerUniqueId Unique identifier of the player.
* @return Afk object representing player's AFK status.
*/
Afk getAfk(UUID playerUniqueId);

/**
* Switches player's AFK status.
*
Expand Down Expand Up @@ -46,4 +54,4 @@ public interface AfkService {
* @return Created an Afk object representing player's AFK status.
*/
Afk markAfk(UUID playerUniqueId, AfkReason reason);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ public boolean isAfk(UUID playerUniqueId) {
return this.afkByPlayer.containsKey(playerUniqueId);
}

@Override
public Afk getAfk(UUID playerUniqueId) {
return this.afkByPlayer.get(playerUniqueId);
}

@ApiStatus.Internal
boolean isInactive(UUID playerUniqueId) {
Instant now = Instant.now();
Expand Down
3 changes: 2 additions & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ include(":eternalcore-paper")
include(":eternalcore-plugin")
include(":eternalcore-docs-api")
include(":eternalcore-docs-generate")
include(":eternalcore-api-example")
include(":eternalcore-api-example")
include("eternalcore-afk-addon")