first commit

This commit is contained in:
2026-06-09 16:22:22 -04:00
commit c411e35ea2
12 changed files with 383 additions and 0 deletions
View File
+47
View File
@@ -0,0 +1,47 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bitnix</groupId>
<artifactId>DirtSleep</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>DirtSleep</name>
<description>Simple sleep vote / night speedup plugin for Paper</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>21</maven.compiler.release>
</properties>
<repositories>
<repository>
<id>papermc-repo</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.21.1-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>DirtSleep</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>21</release>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,225 @@
package com.bitnix.dirtsleep;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.*;
import java.util.stream.Collectors;
public final class DirtSleepPlugin extends JavaPlugin implements TabExecutor {
private final Map<String, Set<UUID>> worldVotes = new HashMap<>();
@Override
public void onEnable() {
saveDefaultConfig();
Objects.requireNonNull(getCommand("voteday")).setExecutor(this);
Objects.requireNonNull(getCommand("voteday")).setTabCompleter(this);
Objects.requireNonNull(getCommand("dirtsleep")).setExecutor(this);
Objects.requireNonNull(getCommand("dirtsleep")).setTabCompleter(this);
}
@Override
public void onDisable() {
worldVotes.clear();
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (command.getName().equalsIgnoreCase("voteday")) {
if (!(sender instanceof Player player)) {
sender.sendMessage(color("&cOnly players can use /voteday."));
return true;
}
handleVoteDay(player);
return true;
}
if (command.getName().equalsIgnoreCase("dirtsleep")) {
if (args.length == 1 && args[0].equalsIgnoreCase("reload")) {
if (!sender.hasPermission("dirtsleep.admin")) {
sender.sendMessage(message("messages.no-permission"));
return true;
}
reloadConfig();
worldVotes.clear();
sender.sendMessage(message("messages.reloaded"));
return true;
}
sender.sendMessage(message("messages.usage"));
return true;
}
return false;
}
private void handleVoteDay(Player player) {
if (!getConfig().getBoolean("vote-day.enabled", true)) {
player.sendMessage(message("messages.disabled"));
return;
}
World world = player.getWorld();
if (!isWorldEnabled(world)) {
player.sendMessage(message("messages.world-disabled"));
return;
}
if (!canVoteInWorld(world)) {
player.sendMessage(message("messages.not-night"));
clearVotes(world);
return;
}
String worldKey = world.getName().toLowerCase(Locale.ROOT);
Set<UUID> votes = worldVotes.computeIfAbsent(worldKey, k -> new HashSet<>());
if (votes.contains(player.getUniqueId())) {
player.sendMessage(message("messages.already-voted"));
return;
}
votes.add(player.getUniqueId());
int currentVotes = countValidVotes(world, votes);
int requiredVotes = getRequiredVotes(world);
String voteMessage = message("messages.vote-added")
.replace("%player%", player.getName())
.replace("%votes%", String.valueOf(currentVotes))
.replace("%required%", String.valueOf(requiredVotes))
.replace("%remaining%", String.valueOf(Math.max(0, requiredVotes - currentVotes)));
broadcast(world, voteMessage);
if (currentVotes >= requiredVotes) {
makeDay(world);
clearVotes(world);
broadcast(world, message("messages.vote-passed"));
}
}
private void makeDay(World world) {
world.setTime(1000);
world.setStorm(false);
world.setThundering(false);
}
private void clearVotes(World world) {
worldVotes.remove(world.getName().toLowerCase(Locale.ROOT));
}
private int countValidVotes(World world, Set<UUID> votes) {
votes.removeIf(uuid -> {
Player p = Bukkit.getPlayer(uuid);
return p == null || !p.isOnline() || !p.getWorld().equals(world);
});
return votes.size();
}
private boolean isWorldEnabled(World world) {
List<String> worlds = getConfig().getStringList("vote-day.worlds");
return worlds.isEmpty() || worlds.contains(world.getName());
}
private boolean canVoteInWorld(World world) {
if (world.getEnvironment() != World.Environment.NORMAL) {
return false;
}
if (!getConfig().getBoolean("vote-day.only-during-night", true)) {
return true;
}
long time = world.getTime();
int nightStartsAt = getConfig().getInt("vote-day.night-starts-at", 12542);
return time >= nightStartsAt && time < 24000;
}
private int getRequiredVotes(World world) {
int eligible = 0;
boolean excludeBypass = getConfig().getBoolean("vote-day.exclude-bypass", true);
for (Player player : world.getPlayers()) {
if (player.getGameMode() == GameMode.SPECTATOR) {
continue;
}
if (excludeBypass && player.hasPermission("dirtsleep.bypass")) {
continue;
}
eligible++;
}
if (eligible <= 0) {
return 1;
}
String raw = getConfig().getString("vote-day.required-votes", "50%");
if (raw == null) {
return 1;
}
raw = raw.trim();
if (raw.endsWith("%")) {
String percentText = raw.substring(0, raw.length() - 1).trim();
try {
double percent = Double.parseDouble(percentText);
int required = (int) Math.ceil(eligible * (percent / 100.0));
return Math.max(1, required);
} catch (NumberFormatException ignored) {
return 1;
}
}
try {
return Math.max(1, Integer.parseInt(raw));
} catch (NumberFormatException ignored) {
return 1;
}
}
private void broadcast(World world, String message) {
for (Player player : world.getPlayers()) {
player.sendMessage(message);
}
}
private String message(String path) {
String prefix = color(getConfig().getString("messages.prefix", "&8[&bDirtSleep&8] &7"));
String text = getConfig().getString(path, "");
return color(text.replace("%prefix%", prefix));
}
private String color(String text) {
return ChatColor.translateAlternateColorCodes('&', text == null ? "" : text);
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
if (command.getName().equalsIgnoreCase("dirtsleep")) {
if (args.length == 1) {
return Arrays.asList("reload").stream()
.filter(s -> s.toLowerCase(Locale.ROOT).startsWith(args[0].toLowerCase(Locale.ROOT)))
.collect(Collectors.toList());
}
}
return Collections.emptyList();
}
}
+31
View File
@@ -0,0 +1,31 @@
vote-day:
enabled: true
# Empty list = all worlds
worlds: []
# Only allow /voteday during night
only-during-night: true
# Tick time where night starts
night-starts-at: 12542
# Required votes before changing to day
# Examples: "1", "2", "50%", "75%"
required-votes: "50%"
# Ignore players with this permission from vote requirement:
# dirtsleep.bypass
exclude-bypass: true
messages:
prefix: "&8[&bDirtSleep&8] &7"
vote-added: "%prefix%&e%player% &7voted for day. &f(%votes%/%required% votes, %remaining% remaining)"
vote-passed: "%prefix%&aVote passed! Skipping to day."
already-voted: "%prefix%&cYou already voted."
not-night: "%prefix%&cYou can only use this at night."
disabled: "%prefix%&cVote day is disabled."
world-disabled: "%prefix%&cVote day is disabled in this world."
reloaded: "%prefix%&aConfig reloaded."
no-permission: "%prefix%&cYou do not have permission."
usage: "%prefix%&7Use: &f/dirtsleep reload"
+21
View File
@@ -0,0 +1,21 @@
name: DirtSleep
version: 1.0
main: com.bitnix.dirtsleep.DirtSleepPlugin
api-version: '1.21'
author: bitnix
description: Simple vote day plugin
commands:
voteday:
description: Vote to make it day
usage: /voteday
dirtsleep:
description: DirtSleep admin command
usage: /dirtsleep reload
permission: dirtsleep.admin
permissions:
dirtsleep.admin:
description: Allows reloading DirtSleep
default: op
dirtsleep.bypass:
description: Excludes player from required vote calculations
default: false
Binary file not shown.
+31
View File
@@ -0,0 +1,31 @@
vote-day:
enabled: true
# Empty list = all worlds
worlds: []
# Only allow /voteday during night
only-during-night: true
# Tick time where night starts
night-starts-at: 12542
# Required votes before changing to day
# Examples: "1", "2", "50%", "75%"
required-votes: "50%"
# Ignore players with this permission from vote requirement:
# dirtsleep.bypass
exclude-bypass: true
messages:
prefix: "&8[&bDirtSleep&8] &7"
vote-added: "%prefix%&e%player% &7voted for day. &f(%votes%/%required% votes, %remaining% remaining)"
vote-passed: "%prefix%&aVote passed! Skipping to day."
already-voted: "%prefix%&cYou already voted."
not-night: "%prefix%&cYou can only use this at night."
disabled: "%prefix%&cVote day is disabled."
world-disabled: "%prefix%&cVote day is disabled in this world."
reloaded: "%prefix%&aConfig reloaded."
no-permission: "%prefix%&cYou do not have permission."
usage: "%prefix%&7Use: &f/dirtsleep reload"
+21
View File
@@ -0,0 +1,21 @@
name: DirtSleep
version: 1.0
main: com.bitnix.dirtsleep.DirtSleepPlugin
api-version: '1.21'
author: bitnix
description: Simple vote day plugin
commands:
voteday:
description: Vote to make it day
usage: /voteday
dirtsleep:
description: DirtSleep admin command
usage: /dirtsleep reload
permission: dirtsleep.admin
permissions:
dirtsleep.admin:
description: Allows reloading DirtSleep
default: op
dirtsleep.bypass:
description: Excludes player from required vote calculations
default: false
+5
View File
@@ -0,0 +1,5 @@
#Generated by Maven
#Tue Jun 09 16:14:06 EDT 2026
artifactId=DirtSleep
groupId=com.bitnix
version=1.0-SNAPSHOT
@@ -0,0 +1 @@
com/bitnix/dirtsleep/DirtSleepPlugin.class
@@ -0,0 +1 @@
/home/bitnix/Desktop/DirtSleep/src/main/java/com/bitnix/dirtsleep/DirtSleepPlugin.java