Skip to content

Commit

Permalink
Redo a lot of NuVotifier for Folia Support
Browse files Browse the repository at this point in the history
  • Loading branch information
GoodrichDev committed Jun 25, 2024
1 parent 66eddbd commit 923b7c6
Show file tree
Hide file tree
Showing 10 changed files with 433 additions and 94 deletions.
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/CommonConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fun Project.applyCommonConfiguration() {

plugins.withId("java") {
the<JavaPluginExtension>().toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
languageVersion.set(JavaLanguageVersion.of(21))
}
}
}
3 changes: 2 additions & 1 deletion bukkit/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ configurations {

dependencies {
"compileOnly"("io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT")
"compileOnly"("dev.folia:folia-api:1.20.6-R0.1-SNAPSHOT")
"api"(project(":nuvotifier-api"))
"api"(project(":nuvotifier-common"))
}
Expand Down Expand Up @@ -53,4 +54,4 @@ tasks.named<ShadowJar>("shadowJar") {

tasks.named("assemble").configure {
dependsOn("shadowJar")
}
}
26 changes: 16 additions & 10 deletions bukkit/src/main/java/com/vexsoftware/votifier/BukkitScheduler.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,47 @@

import com.vexsoftware.votifier.platform.scheduler.ScheduledVotifierTask;
import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler;
import org.bukkit.scheduler.BukkitTask;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

class BukkitScheduler implements VotifierScheduler {
private final NuVotifierBukkit plugin;
private final ScheduledExecutorService executorService;

public BukkitScheduler(NuVotifierBukkit plugin) {
this.plugin = plugin;
this.executorService = Executors.newSingleThreadScheduledExecutor();
}

private int toTicks(int time, TimeUnit unit) {
return (int) (unit.toMillis(time) / 50);
private long toMillis(int time, TimeUnit unit) {
return unit.toMillis(time);
}

@Override
public ScheduledVotifierTask delayedOnPool(Runnable runnable, int delay, TimeUnit unit) {
return new BukkitTaskWrapper(plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, runnable, toTicks(delay, unit)));
ScheduledFuture<?> future = executorService.schedule(runnable, toMillis(delay, unit), TimeUnit.MILLISECONDS);
return new ScheduledVotifierTaskWrapper(future);
}

@Override
public ScheduledVotifierTask repeatOnPool(Runnable runnable, int delay, int repeat, TimeUnit unit) {
return new BukkitTaskWrapper(plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, runnable, toTicks(delay, unit), toTicks(repeat, unit)));
ScheduledFuture<?> future = executorService.scheduleAtFixedRate(runnable, toMillis(delay, unit), toMillis(repeat, unit), TimeUnit.MILLISECONDS);
return new ScheduledVotifierTaskWrapper(future);
}

private static class BukkitTaskWrapper implements ScheduledVotifierTask {
private final BukkitTask task;
private static class ScheduledVotifierTaskWrapper implements ScheduledVotifierTask {
private final ScheduledFuture<?> future;

private BukkitTaskWrapper(BukkitTask task) {
this.task = task;
private ScheduledVotifierTaskWrapper(ScheduledFuture<?> future) {
this.future = future;
}

@Override
public void cancel() {
task.cancel();
future.cancel(false);
}
}
}
98 changes: 17 additions & 81 deletions bukkit/src/main/java/com/vexsoftware/votifier/NuVotifierBukkit.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
/*
* Copyright (C) 2012 Vex Software LLC
* This file is part of Votifier.
*
* Votifier is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Votifier is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Votifier. If not, see <http://www.gnu.org/licenses/>.
*/

package com.vexsoftware.votifier;

import com.vexsoftware.votifier.cmd.NVReloadCmd;
Expand All @@ -33,6 +15,10 @@
import com.vexsoftware.votifier.platform.LoggingAdapter;
import com.vexsoftware.votifier.platform.VotifierPlugin;
import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler;
import com.vexsoftware.votifier.scheduling.FoliaTaskScheduler;
import com.vexsoftware.votifier.scheduling.ScheduledTask;
import com.vexsoftware.votifier.scheduling.TaskScheduler;
import com.vexsoftware.votifier.scheduling.TaskSchedulerAdapter;
import com.vexsoftware.votifier.util.IOUtil;
import com.vexsoftware.votifier.util.KeyCreator;
import com.vexsoftware.votifier.util.TokenUtil;
Expand All @@ -51,40 +37,23 @@
import java.security.KeyPair;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;

/**
* The main Votifier plugin class.
*
* @author Blake Beaupain
* @author Kramer Campbell
*/
public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, VotifierPlugin, ForwardedVoteListener {

/**
* The server bootstrap.
*/
private VotifierServerBootstrap bootstrap;

/**
* The RSA key pair.
*/
private KeyPair keyPair;

/**
* Debug mode flag
*/
private boolean debug;

/**
* Keys used for websites.
*/
private Map<String, Key> tokens = new HashMap<>();

private ForwardingVoteSink forwardingMethod;
private VotifierScheduler scheduler;
private LoggingAdapter pluginLogger;
private boolean isFolia;
private TaskScheduler scheduler;
private VotifierScheduler votifierScheduler;

private boolean loadAndBind() {
try {
Expand All @@ -96,50 +65,33 @@ private boolean loadAndBind() {
isFolia = false;
}

scheduler = new BukkitScheduler(this);
scheduler = new FoliaTaskScheduler(this);
votifierScheduler = new TaskSchedulerAdapter(scheduler);
pluginLogger = new JavaUtilLogger(getLogger());
if (!getDataFolder().exists()) {
if (!getDataFolder().mkdir()) {
throw new RuntimeException("Unable to create the plugin data folder " + getDataFolder());
}
}

// Handle configuration.
File config = new File(getDataFolder(), "config.yml");

/*
* Use IP address from server.properties as a default for
* configurations. Do not use InetAddress.getLocalHost() as it most
* likely will return the main server address instead of the address
* assigned to the server.
*/
String hostAddr = Bukkit.getServer().getIp();
if (hostAddr == null || hostAddr.length() == 0)
hostAddr = "0.0.0.0";

/*
* Create configuration file if it does not exists; otherwise, load it
*/
if (!config.exists()) {
try {
// First time run - do some initialization.
getLogger().info("Configuring Votifier for the first time...");

// Initialize the configuration file.
if (!config.createNewFile()) {
throw new IOException("Unable to create the config file at " + config);
}

// Load and manually replace variables in the configuration.
String cfgStr = new String(IOUtil.readAllBytes(getResource("bukkitConfig.yml")), StandardCharsets.UTF_8);
String token = TokenUtil.newToken();
cfgStr = cfgStr.replace("%default_token%", token).replace("%ip%", hostAddr);
Files.copy(new ByteArrayInputStream(cfgStr.getBytes(StandardCharsets.UTF_8)), config.toPath(), StandardCopyOption.REPLACE_EXISTING);

/*
* Remind hosted server admins to be sure they have the right
* port number.
*/
getLogger().info("------------------------------------------------------------------------------");
getLogger().info("Assigning NuVotifier to listen on port 8192. If you are hosting Craftbukkit on a");
getLogger().info("shared server please check with your hosting provider to verify that this port");
Expand All @@ -159,13 +111,8 @@ private boolean loadAndBind() {
YamlConfiguration cfg;
File rsaDirectory = new File(getDataFolder(), "rsa");

// Load configuration.
cfg = YamlConfiguration.loadConfiguration(config);

/*
* Create RSA directory and keys if it does not exist; otherwise, read
* keys.
*/
try {
if (!rsaDirectory.exists()) {
if (!rsaDirectory.mkdir()) {
Expand All @@ -177,20 +124,16 @@ private boolean loadAndBind() {
keyPair = RSAIO.load(rsaDirectory);
}
} catch (Exception ex) {
getLogger().log(Level.SEVERE,
"Error reading configuration file or RSA tokens", ex);
getLogger().log(Level.SEVERE, "Error reading configuration file or RSA tokens", ex);
return false;
}

// the quiet flag always runs priority to the debug flag
if (cfg.isBoolean("quiet")) {
debug = !cfg.getBoolean("quiet");
} else {
// otherwise, default to being noisy
debug = cfg.getBoolean("debug", true);
}

// Load Votifier tokens.
ConfigurationSection tokenSection = cfg.getConfigurationSection("tokens");

if (tokenSection != null) {
Expand All @@ -207,8 +150,7 @@ private boolean loadAndBind() {
try {
cfg.save(config);
} catch (IOException e) {
getLogger().log(Level.SEVERE,
"Error generating Votifier token", e);
getLogger().log(Level.SEVERE, "Error generating Votifier token", e);
return false;
}
getLogger().info("------------------------------------------------------------------------------");
Expand All @@ -219,7 +161,6 @@ private boolean loadAndBind() {
getLogger().info("------------------------------------------------------------------------------");
}

// Initialize the receiver.
final String host = cfg.getString("host", hostAddr);
final int port = cfg.getInt("port", 8192);
if (!debug)
Expand All @@ -246,7 +187,7 @@ private boolean loadAndBind() {

ConfigurationSection forwardingConfig = cfg.getConfigurationSection("forwarding");
if (forwardingConfig != null) {
String method = forwardingConfig.getString("method", "none").toLowerCase(); //Default to lower case for case-insensitive searches
String method = forwardingConfig.getString("method", "none").toLowerCase();
if ("none".equals(method)) {
getLogger().info("Method none selected for vote forwarding: Votes will not be received from a forwarder.");
} else if ("pluginmessaging".equals(method)) {
Expand All @@ -265,7 +206,6 @@ private boolean loadAndBind() {
}

private void halt() {
// Shut down the network handlers.
if (bootstrap != null) {
bootstrap.shutdown();
bootstrap = null;
Expand All @@ -284,7 +224,7 @@ public void onEnable() {

if (!loadAndBind()) {
gracefulExit();
setEnabled(false); // safer to just bomb out
setEnabled(false);
}
}

Expand Down Expand Up @@ -326,7 +266,7 @@ public LoggingAdapter getPluginLogger() {

@Override
public VotifierScheduler getScheduler() {
return scheduler;
return votifierScheduler;
}

public boolean isDebug() {
Expand Down Expand Up @@ -381,13 +321,9 @@ private void fireVotifierEvent(Vote vote) {
}

if (!isFolia) {
getServer().getScheduler().runTask(
this, () -> getServer().getPluginManager().callEvent(new VotifierEvent(vote))
);
votifierScheduler.delayedOnPool(() -> getServer().getPluginManager().callEvent(new VotifierEvent(vote)), 0, TimeUnit.MILLISECONDS);
} else {
getServer().getScheduler().runTaskAsynchronously(
this, () -> getServer().getPluginManager().callEvent(new VotifierEvent(vote, true))
);
votifierScheduler.delayedOnPool(() -> getServer().getPluginManager().callEvent(new VotifierEvent(vote, true)), 0, TimeUnit.MILLISECONDS);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.vexsoftware.votifier.scheduling;

import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;

public class FoliaScheduledTask implements com.vexsoftware.votifier.scheduling.ScheduledTask {
private final ScheduledTask task;

public FoliaScheduledTask(final ScheduledTask task) {
this.task = task;
}

@Override
public void cancel() {
this.task.cancel();
}

@Override
public boolean isCancelled() {
return this.task.isCancelled();
}

@Override
public @NotNull Plugin getOwningPlugin() {
return this.task.getOwningPlugin();
}

@Override
public boolean isCurrentlyRunning() {
final ScheduledTask.ExecutionState state = this.task.getExecutionState();
return state == ScheduledTask.ExecutionState.RUNNING || state == ScheduledTask.ExecutionState.CANCELLED_RUNNING;
}

@Override
public boolean isRepeatingTask() {
return this.task.isRepeatingTask();
}
}
Loading

0 comments on commit 923b7c6

Please sign in to comment.