Skip to content
Open
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ You can find all our modules if you wish to modify them yourself below.
- [paynow-sponge](./paynow-sponge)
- [paynow-velocity](./paynow-velocity)
- [paynow-fabric](./paynow-fabric)
- [paynow-neoforge](./paynow-neoforge)
152 changes: 152 additions & 0 deletions paynow-neoforge/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
plugins {
id 'java-library'
id 'maven-publish'
id 'com.gradleup.shadow' version '9.3.1'
id 'net.neoforged.gradle.userdev' version '7.1.38'
}

sourceSets.main.resources {
// Include resources generated by data generators.
srcDir('src/generated/resources')

// Exclude common development only resources from finalized outputs
exclude("**/*.bbmodel") // BlockBench project files
exclude("src/generated/**/.cache") // datagen cache files
}

repositories {
// Add here additional repositories if required by some of the dependencies below.
}

configurations {
runtimeClasspath.extendsFrom localRuntime
shadowed
implementation.extendsFrom shadowed
}

base {
archivesName = mod_id
}

// Mojang ships Java 21 to end users in 1.21.1, so mods should target Java 21.
java.toolchain.languageVersion = JavaLanguageVersion.of(21)

//minecraft.accessTransformers.file rootProject.file('src/main/resources/META-INF/accesstransformer.cfg')
//minecraft.accessTransformers.entry public net.minecraft.client.Minecraft textureManager # textureManager

// Default run configurations.
// These can be tweaked, removed, or duplicated as needed.
runs {
// applies to all the run configs below
configureEach {
// Recommended logging data for a userdev environment
// The markers can be added/remove as needed separated by commas.
// "SCAN": For mods scan.
// "REGISTRIES": For firing of registry events.
// "REGISTRYDUMP": For getting the contents of all registries.
systemProperty 'forge.logging.markers', 'REGISTRIES'

// Recommended logging level for the console
// You can set various levels here.
// Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
systemProperty 'forge.logging.console.level', 'debug'

workingDirectory project.layout.projectDirectory.dir('run').dir(name)

modSource project.sourceSets.main
}

client {
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
}

server {
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
argument '--nogui'
}

// This run config launches GameTestServer and runs all registered gametests, then exits.
// By default, the server will crash when no gametests are provided.
// The gametest system is also enabled by default for other run configs under the /test command.
gameTestServer {
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
}

data {
// example of overriding the workingDirectory set in configureEach above, uncomment if you want to use it
// workingDirectory project.file('run-data')

// Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
arguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath()
}
}

dependencies {
implementation "net.neoforged:neoforge:${neo_version}"

shadowed(implementation project(":paynow-lib"))
}

// This block of code expands all declared replace properties in the specified resource targets.
// A missing property will result in an error. Properties are expanded using ${} Groovy notation.
// When "copyIdeResources" is enabled, this will also run before the game launches in IDE environments.
// See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html
tasks.withType(ProcessResources).configureEach {
var replaceProperties = [
minecraft_version : minecraft_version,
minecraft_version_range: minecraft_version_range,
neo_version : neo_version,
loader_version_range : loader_version_range,
mod_id : mod_id,
mod_name : mod_name,
mod_license : mod_license,
mod_version : version,
]
inputs.properties replaceProperties

filesMatching(['META-INF/neoforge.mods.toml']) {
expand replaceProperties
}
}

shadowJar {
configurations = [project.configurations.shadowed]
archiveClassifier.set('') // This is required to ensure that the shadow jar is the default jar output of the project.
exclude 'net/minecraft/**'
}

// 3. Inform Gradle's assembling engine to favor the Shadow output over the normal jar
tasks.named('jar', Jar) {
// This tells Gradle to skip the vanilla jar task since shadowJar will generate it
finalizedBy tasks.shadowJar
}

// Ensure assembling lifecycle triggers your shadow processing
assemble.dependsOn shadowJar

// Example configuration to allow publishing using the maven-publish plugin
publishing {
publications {
register('mavenJava', MavenPublication) {
from components.java
}
}
repositories {
maven {
url "file://${project.projectDir}/repo"
}
}
}

tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
}

// IDEA no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior.
idea {
module {
downloadSources = true
downloadJavadoc = true
}
}
33 changes: 33 additions & 0 deletions paynow-neoforge/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
org.gradle.jvmargs=-Xmx1G
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=true

#read more on this at https://github.com/neoforged/NeoGradle/blob/NG_7.0/README.md#apply-parchment-mappings
# you can also find the latest versions at: https://parchmentmc.org/docs/getting-started
neogradle.subsystems.parchment.minecraftVersion=1.21.1
neogradle.subsystems.parchment.mappingsVersion=2024.11.17
# Environment Properties
# You can find the latest versions here: https://projects.neoforged.net/neoforged/neoforge
# The Minecraft version must agree with the Neo version to get a valid artifact
minecraft_version=1.21.1
# The Minecraft version range can use any release version of Minecraft as bounds.
# Snapshots, pre-releases, and release candidates are not guaranteed to sort properly
# as they do not follow standard versioning conventions.
minecraft_version_range=[1.21.1]
# The Neo version must agree with the Minecraft version to get a valid artifact
neo_version=21.1.234
# The loader version range can only use the major version of FML as bounds
loader_version_range=[1,)

## Mod Properties

# The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63}
# Must match the String constant located in the main mod class annotated with @Mod.
mod_id=paynow_neoforge
# The human-readable display name for the mod.
mod_name=PayNow NeoForge
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=MIT
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package gg.paynow.paynowneoforge;

import com.mojang.brigadier.exceptions.CommandSyntaxException;
import gg.paynow.paynowlib.PayNowLib;
import gg.paynow.paynowlib.PayNowUtils;
import gg.paynow.paynowlib.events.PayNowEvent;
import gg.paynow.paynowlib.events.PlayerJoinEventData;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.neoforged.fml.loading.FMLPaths;
import net.neoforged.neoforge.event.RegisterCommandsEvent;
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
import net.neoforged.neoforge.event.tick.ServerTickEvent;
import org.slf4j.Logger;

import com.mojang.logging.LogUtils;

import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.Mod;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.server.ServerStartingEvent;

import java.io.File;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;

@Mod(PayNowNeoForge.MODID)
public class PayNowNeoForge {
public static final String MODID = "paynow_neoforge";
public static final Logger LOGGER = LogUtils.getLogger();

private static PayNowNeoForge instance;
private MinecraftServer server;
private PayNowLib payNowLib;

private int lastCheck = 0;
private int lastEventsCheck = 0;

public PayNowNeoForge() {
instance = this;
// Register ourselves for server and other game events we are interested in.
// Note that this is necessary if and only if we want *this* class (ExampleMod) to respond directly to events.
// Do not add this line if there are no @SubscribeEvent-annotated functions in this class, like onServerStarting() below.
NeoForge.EVENT_BUS.register(this);
}

@SubscribeEvent
public void onCommandsRegistration(RegisterCommandsEvent event) {
event.getDispatcher().register(PayNowNeoForgeCommand.generateCommand(this));
}

@SubscribeEvent
public void onServerStarting(ServerStartingEvent event) {
server = event.getServer();
String motd = server.getMotd();
String serverIp = server.getLocalIp();

this.payNowLib = new PayNowLib(command -> CompletableFuture.supplyAsync(() -> {
try {
server.getCommands().getDispatcher().execute(command, server.createCommandSourceStack());
} catch (CommandSyntaxException ignored) {}
return true; // Assume the command always succeeds, else it gets stuck.
}, server).join(), Objects.equals(serverIp, "") ? "0.0.0.0" : serverIp + ":" + server.getPort(), Objects.equals(motd, "") ? "NeoForge Server" : motd);

this.payNowLib.setLogCallback((s, level) -> {
if (level == Level.SEVERE) {
LOGGER.error(s);
} else if(level == Level.WARNING) {
LOGGER.warn(s);
} else {
LOGGER.info(s);
}
});

this.payNowLib.loadPayNowConfig(this.getConfigFile());
}

@SubscribeEvent
public void onServerTick(ServerTickEvent.Post event) {
if(lastCheck > 0) {
lastCheck--;
} else {
lastCheck = this.payNowLib.getConfig().getApiCheckInterval() * 20;
this.check();
}

if(lastEventsCheck > 0) {
lastEventsCheck--;
} else {
lastEventsCheck = this.payNowLib.getConfig().getEventsQueueReportInterval() * 20;
this.payNowLib.reportEvents();
}
}

@SubscribeEvent
public void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) {
if (event.getEntity().level().isClientSide) return;
ServerPlayer player = event.getEntity() instanceof ServerPlayer ? (ServerPlayer) event.getEntity() : null;
if (player == null) return;
String ip = player.getIpAddress();
PayNowEvent payNowEvent = new PayNowEvent("player_join", new Date(), new PlayerJoinEventData(ip, player.getUUID()));
instance.getPayNowLib().registerEvent(payNowEvent);
}

@SubscribeEvent
public void onServerStopping(ServerStoppingEvent event) {
server = null;
PayNowUtils.ASYNC_EXEC.shutdown();
}

private void check() {
List<String> onlinePlayersName = new ArrayList<>();
List<UUID> onlinePlayersUUID = new ArrayList<>();
for(ServerPlayer player : this.server.getPlayerList().getPlayers()) {
onlinePlayersName.add(player.getName().getString());
onlinePlayersUUID.add(player.getUUID());
}
payNowLib.fetchPendingCommands(onlinePlayersName, onlinePlayersUUID);
}

public void triggerConfigUpdate(){
this.payNowLib.savePayNowConfig(this.getConfigFile());
this.payNowLib.updateConfig();
}

private File getConfigFile() {
return new File(FMLPaths.CONFIGDIR.get().toFile(), "paynow.json");
}

public PayNowLib getPayNowLib() {
return payNowLib;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package gg.paynow.paynowneoforge;

import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.minecraft.ChatFormatting;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.Component;

import static com.mojang.brigadier.arguments.StringArgumentType.string;

public class PayNowNeoForgeCommand {
public static LiteralArgumentBuilder<CommandSourceStack> generateCommand(PayNowNeoForge mod) {
return Commands.literal("paynow")
.requires(source -> source.hasPermission(4))
.then(Commands.literal("link")
.then(Commands.argument("token", string())
.executes(context -> {
String token = context.getArgument("token", String.class);
mod.getPayNowLib().getConfig().setApiToken(token);
mod.triggerConfigUpdate();
context.getSource().sendSystemMessage(Component.literal("API token updated").withStyle(ChatFormatting.RED));
return 1;
})));
}
}
Loading