first
This commit is contained in:
commit
80a175e5eb
|
|
@ -0,0 +1,119 @@
|
|||
# User-specific stuff
|
||||
.idea/
|
||||
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
Thumbs.db:encryptable
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
.gradle
|
||||
build/
|
||||
|
||||
# Ignore Gradle GUI config
|
||||
gradle-app.setting
|
||||
|
||||
# Cache of project
|
||||
.gradletasknamecache
|
||||
|
||||
**/build/
|
||||
|
||||
# Common working directory
|
||||
run/
|
||||
runs/
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
plugins {
|
||||
id 'java-library'
|
||||
id 'maven-publish'
|
||||
id 'idea'
|
||||
id 'net.neoforged.moddev' version '2.0.115'
|
||||
}
|
||||
|
||||
version = mod_version
|
||||
group = mod_group_id
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
base {
|
||||
archivesName = mod_id
|
||||
}
|
||||
|
||||
java.toolchain.languageVersion = JavaLanguageVersion.of(21)
|
||||
|
||||
neoForge {
|
||||
// Specify the version of NeoForge to use.
|
||||
version = project.neo_version
|
||||
|
||||
parchment {
|
||||
mappingsVersion = project.parchment_mappings_version
|
||||
minecraftVersion = project.parchment_minecraft_version
|
||||
}
|
||||
|
||||
// This line is optional. Access Transformers are automatically detected
|
||||
// accessTransformers.add('src/main/resources/META-INF/accesstransformer.cfg')
|
||||
|
||||
// Default run configurations.
|
||||
// These can be tweaked, removed, or duplicated as needed.
|
||||
runs {
|
||||
client {
|
||||
client()
|
||||
|
||||
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
|
||||
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
|
||||
}
|
||||
|
||||
server {
|
||||
server()
|
||||
programArgument '--nogui'
|
||||
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
|
||||
}
|
||||
|
||||
// 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 {
|
||||
type = "gameTestServer"
|
||||
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
|
||||
}
|
||||
|
||||
data {
|
||||
data()
|
||||
|
||||
// example of overriding the workingDirectory set in configureEach above, uncomment if you want to use it
|
||||
// gameDirectory = project.file('run-data')
|
||||
|
||||
// Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
|
||||
programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath()
|
||||
}
|
||||
|
||||
// applies to all the run configs above
|
||||
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
|
||||
logLevel = org.slf4j.event.Level.DEBUG
|
||||
}
|
||||
}
|
||||
|
||||
mods {
|
||||
// define mod <-> source bindings
|
||||
// these are used to tell the game which sources are for which mod
|
||||
// mostly optional in a single mod project
|
||||
// but multi mod projects should define one per mod
|
||||
"${mod_id}" {
|
||||
sourceSet(sourceSets.main)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Include resources generated by data generators.
|
||||
sourceSets.main.resources { srcDir 'src/generated/resources' }
|
||||
|
||||
|
||||
dependencies {
|
||||
// Gson для работы с JSON
|
||||
implementation 'com.google.code.gson:gson:2.10.1'
|
||||
|
||||
// Example mod dependency with JEI
|
||||
// The JEI API is declared for compile time use, while the full JEI artifact is used at runtime
|
||||
// compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}"
|
||||
// compileOnly "mezz.jei:jei-${mc_version}-forge-api:${jei_version}"
|
||||
// runtimeOnly "mezz.jei:jei-${mc_version}-forge:${jei_version}"
|
||||
|
||||
// Example mod dependency using a mod jar from ./libs with a flat dir repository
|
||||
// This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar
|
||||
// The group id is ignored when searching -- in this case, it is "blank"
|
||||
// implementation "blank:coolmod-${mc_version}:${coolmod_version}"
|
||||
|
||||
// Example mod dependency using a file as dependency
|
||||
// implementation files("libs/coolmod-${mc_version}-${coolmod_version}.jar")
|
||||
|
||||
// Example project dependency using a sister or child project:
|
||||
// implementation project(":myproject")
|
||||
|
||||
// For more info:
|
||||
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
|
||||
// http://www.gradle.org/docs/current/userguide/dependency_management.html
|
||||
}
|
||||
|
||||
// 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.
|
||||
var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) {
|
||||
var replaceProperties = [
|
||||
minecraft_version : minecraft_version,
|
||||
minecraft_version_range: minecraft_version_range,
|
||||
neo_version : neo_version,
|
||||
neo_version_range : neo_version_range,
|
||||
loader_version_range : loader_version_range,
|
||||
mod_id : mod_id,
|
||||
mod_name : mod_name,
|
||||
mod_license : mod_license,
|
||||
mod_version : mod_version,
|
||||
mod_authors : mod_authors,
|
||||
mod_description : mod_description
|
||||
]
|
||||
inputs.properties replaceProperties
|
||||
expand replaceProperties
|
||||
from "src/main/templates"
|
||||
into "build/generated/sources/modMetadata"
|
||||
}
|
||||
|
||||
// Include the output of "generateModMetadata" as an input directory for the build
|
||||
// this works with both building through Gradle and the IDE.
|
||||
sourceSets.main.resources.srcDir generateModMetadata
|
||||
// To avoid having to run "generateModMetadata" manually, make it run on every project reload
|
||||
neoForge.ideSyncTask generateModMetadata
|
||||
|
||||
// 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IDEA no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior.
|
||||
idea {
|
||||
module {
|
||||
downloadSources = true
|
||||
downloadJavadoc = true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
|
||||
org.gradle.jvmargs=-Xmx2G
|
||||
org.gradle.daemon=true
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
org.gradle.configuration-cache=true
|
||||
## 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,1.22)
|
||||
# The Neo version must agree with the Minecraft version to get a valid artifact
|
||||
neo_version=21.1.209
|
||||
# The Neo version range can use any version of Neo as bounds
|
||||
neo_version_range=[21,)
|
||||
# The loader version range can only use the major version of FML as bounds
|
||||
loader_version_range=[4,)
|
||||
parchment_minecraft_version=1.21.1
|
||||
parchment_mappings_version=2024.11.13
|
||||
## 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=whitelist
|
||||
# The human-readable display name for the mod.
|
||||
mod_name=whitelist
|
||||
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
|
||||
mod_license=All Rights Reserved
|
||||
# The mod version. See https://semver.org/
|
||||
mod_version=0.1-BETA
|
||||
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
|
||||
# This should match the base package used for the mod sources.
|
||||
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||
mod_group_id=org.itqop
|
||||
# The authors of the mod. This is a simple text string that is used for display purposes in the mod list.
|
||||
mod_authors=itqop
|
||||
# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list.
|
||||
mod_description=whitelist
|
||||
|
|
@ -0,0 +1 @@
|
|||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
pluginManagement {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
gradlePluginPortal()
|
||||
maven { url = 'https://maven.neoforged.net/releases' }
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package org.itqop.whitelist;
|
||||
|
||||
import net.neoforged.fml.event.config.ModConfigEvent;
|
||||
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||
|
||||
public final class Config {
|
||||
private static final ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder();
|
||||
|
||||
// API настройки
|
||||
private static final ModConfigSpec.ConfigValue<String> API_BASE_URL = BUILDER
|
||||
.comment("Base URL for whitelist API")
|
||||
.define("apiBaseUrl", "http://localhost:8080/api/v1/whitelist");
|
||||
|
||||
private static final ModConfigSpec.ConfigValue<String> API_KEY = BUILDER
|
||||
.comment("API key for whitelist service")
|
||||
.define("apiKey", "your-secret-api-key");
|
||||
|
||||
private static final ModConfigSpec.IntValue REQUEST_TIMEOUT = BUILDER
|
||||
.comment("Request timeout in seconds")
|
||||
.defineInRange("requestTimeout", 30, 5, 300);
|
||||
|
||||
private static final ModConfigSpec.BooleanValue ENABLE_LOGGING = BUILDER
|
||||
.comment("Enable detailed API logging")
|
||||
.define("enableLogging", true);
|
||||
|
||||
static final ModConfigSpec SPEC = BUILDER.build();
|
||||
|
||||
// кэш значений
|
||||
public static String apiBaseUrl;
|
||||
public static String apiKey;
|
||||
public static int requestTimeout;
|
||||
public static boolean enableLogging;
|
||||
|
||||
private Config() {}
|
||||
|
||||
// подписка идёт через modEventBus.addListener(Config::onLoad) — без @EventBusSubscriber и без устаревшего 'bus'
|
||||
static void onLoad(final ModConfigEvent event) {
|
||||
if (event.getConfig().getSpec() != SPEC) return;
|
||||
|
||||
apiBaseUrl = API_BASE_URL.get();
|
||||
apiKey = API_KEY.get();
|
||||
requestTimeout = REQUEST_TIMEOUT.get();
|
||||
enableLogging = ENABLE_LOGGING.get();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package org.itqop.whitelist;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.fml.ModContainer;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.fml.config.ModConfig;
|
||||
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@Mod(Whitelist.MODID)
|
||||
public class Whitelist {
|
||||
public static final String MODID = "whitelist";
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(MODID);
|
||||
public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(MODID);
|
||||
public static final DeferredRegister<CreativeModeTab> CREATIVE_MODE_TABS =
|
||||
DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MODID);
|
||||
|
||||
public Whitelist(IEventBus modEventBus, ModContainer modContainer) {
|
||||
modEventBus.addListener(this::commonSetup);
|
||||
modEventBus.addListener(this::addCreative);
|
||||
modEventBus.addListener(Config::onLoad);
|
||||
|
||||
BLOCKS.register(modEventBus);
|
||||
ITEMS.register(modEventBus);
|
||||
CREATIVE_MODE_TABS.register(modEventBus);
|
||||
|
||||
modContainer.registerConfig(ModConfig.Type.COMMON, Config.SPEC);
|
||||
}
|
||||
|
||||
private void commonSetup(final FMLCommonSetupEvent event) {
|
||||
LOGGER.info("whitelist initialized");
|
||||
}
|
||||
|
||||
private void addCreative(BuildCreativeModeTabContentsEvent event) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
package org.itqop.whitelist;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class WhitelistApiClient {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
private final HttpClient httpClient;
|
||||
private final String baseUrl;
|
||||
private final String apiKey;
|
||||
private final int timeoutSeconds;
|
||||
private final boolean enableLogging;
|
||||
|
||||
public WhitelistApiClient() {
|
||||
this.baseUrl = Config.apiBaseUrl;
|
||||
this.apiKey = Config.apiKey;
|
||||
this.timeoutSeconds = Config.requestTimeout;
|
||||
this.enableLogging = Config.enableLogging;
|
||||
|
||||
this.httpClient = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(timeoutSeconds))
|
||||
.build();
|
||||
}
|
||||
|
||||
public CompletableFuture<Boolean> addPlayer(String playerName, UUID playerUuid, String addedBy, String reason) {
|
||||
JsonObject requestBody = new JsonObject();
|
||||
requestBody.addProperty("player_name", playerName);
|
||||
requestBody.addProperty("player_uuid", playerUuid.toString());
|
||||
requestBody.addProperty("added_by", addedBy);
|
||||
requestBody.addProperty("added_at", Instant.now().toString());
|
||||
requestBody.addProperty("is_active", true);
|
||||
if (reason != null && !reason.isEmpty()) {
|
||||
requestBody.addProperty("reason", reason);
|
||||
}
|
||||
|
||||
return makeRequest("POST", "/add", requestBody.toString())
|
||||
.thenApply(response -> {
|
||||
if (response.statusCode() == 201) {
|
||||
if (enableLogging) {
|
||||
LOGGER.info("Player {} successfully added to whitelist", playerName);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
LOGGER.error("Error adding player {}: HTTP {}", playerName, response.statusCode());
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
LOGGER.error("Error adding player {}: {}", playerName, throwable.getMessage());
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Boolean> removePlayer(String playerName) {
|
||||
JsonObject requestBody = new JsonObject();
|
||||
requestBody.addProperty("player_name", playerName);
|
||||
|
||||
return makeRequest("POST", "/remove", requestBody.toString())
|
||||
.thenApply(response -> {
|
||||
if (response.statusCode() == 204) {
|
||||
if (enableLogging) {
|
||||
LOGGER.info("Player {} successfully removed from whitelist", playerName);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
LOGGER.error("Error removing player {}: HTTP {}", playerName, response.statusCode());
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
LOGGER.error("Error removing player {}: {}", playerName, throwable.getMessage());
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<WhitelistCheckResult> checkPlayer(String playerName) {
|
||||
JsonObject requestBody = new JsonObject();
|
||||
requestBody.addProperty("player_name", playerName);
|
||||
|
||||
return makeRequest("POST", "/check", requestBody.toString())
|
||||
.thenApply(response -> {
|
||||
if (response.statusCode() == 200) {
|
||||
try {
|
||||
JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject();
|
||||
boolean isWhitelisted = jsonResponse.get("is_whitelisted").getAsBoolean();
|
||||
String playerUuid = jsonResponse.has("player_uuid") && !jsonResponse.get("player_uuid").isJsonNull()
|
||||
? jsonResponse.get("player_uuid").getAsString()
|
||||
: null;
|
||||
|
||||
if (enableLogging) {
|
||||
LOGGER.info("Player {} check: {}", playerName, isWhitelisted ? "whitelisted" : "not whitelisted");
|
||||
}
|
||||
|
||||
return new WhitelistCheckResult(true, isWhitelisted, playerUuid);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Error parsing response for player {}: {}", playerName, e.getMessage());
|
||||
return new WhitelistCheckResult(false, false, null);
|
||||
}
|
||||
} else {
|
||||
LOGGER.error("Error checking player {}: HTTP {}", playerName, response.statusCode());
|
||||
return new WhitelistCheckResult(false, false, null);
|
||||
}
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
LOGGER.error("Error checking player {}: {}", playerName, throwable.getMessage());
|
||||
return new WhitelistCheckResult(false, false, null);
|
||||
});
|
||||
}
|
||||
|
||||
private CompletableFuture<HttpResponse<String>> makeRequest(String method, String endpoint, String body) {
|
||||
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
|
||||
.uri(URI.create(baseUrl + endpoint))
|
||||
.header("X-API-Key", apiKey)
|
||||
.header("Content-Type", "application/json")
|
||||
.timeout(Duration.ofSeconds(timeoutSeconds));
|
||||
|
||||
if ("POST".equals(method)) {
|
||||
requestBuilder.POST(HttpRequest.BodyPublishers.ofString(body));
|
||||
} else {
|
||||
requestBuilder.GET();
|
||||
}
|
||||
|
||||
HttpRequest request = requestBuilder.build();
|
||||
|
||||
return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
|
||||
}
|
||||
|
||||
public static class WhitelistCheckResult {
|
||||
private final boolean success;
|
||||
private final boolean isWhitelisted;
|
||||
private final String playerUuid;
|
||||
|
||||
public WhitelistCheckResult(boolean success, boolean isWhitelisted, String playerUuid) {
|
||||
this.success = success;
|
||||
this.isWhitelisted = isWhitelisted;
|
||||
this.playerUuid = playerUuid;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public boolean isWhitelisted() {
|
||||
return isWhitelisted;
|
||||
}
|
||||
|
||||
public String getPlayerUuid() {
|
||||
return playerUuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
package org.itqop.whitelist;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class WhitelistCommands {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static WhitelistApiClient apiClient;
|
||||
|
||||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
||||
apiClient = new WhitelistApiClient();
|
||||
|
||||
dispatcher.register(Commands.literal("whitelist")
|
||||
.then(Commands.literal("add")
|
||||
.then(Commands.argument("player", StringArgumentType.string())
|
||||
.executes(WhitelistCommands::addPlayer)
|
||||
.then(Commands.argument("reason", StringArgumentType.greedyString())
|
||||
.executes(WhitelistCommands::addPlayerWithReason))))
|
||||
.then(Commands.literal("remove")
|
||||
.then(Commands.argument("player", StringArgumentType.string())
|
||||
.executes(WhitelistCommands::removePlayer)))
|
||||
.then(Commands.literal("check")
|
||||
.then(Commands.argument("player", StringArgumentType.string())
|
||||
.executes(WhitelistCommands::checkPlayer)))
|
||||
.then(Commands.literal("list")
|
||||
.executes(WhitelistCommands::listPlayers))
|
||||
.then(Commands.literal("count")
|
||||
.executes(WhitelistCommands::countPlayers)));
|
||||
}
|
||||
|
||||
private static int addPlayer(CommandContext<CommandSourceStack> context) {
|
||||
return addPlayerWithReason(context);
|
||||
}
|
||||
|
||||
private static int addPlayerWithReason(CommandContext<CommandSourceStack> context) {
|
||||
String playerName = StringArgumentType.getString(context, "player");
|
||||
String reason = "";
|
||||
|
||||
try {
|
||||
reason = StringArgumentType.getString(context, "reason");
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
String addedBy = context.getSource().getTextName();
|
||||
|
||||
MinecraftServer server = context.getSource().getServer();
|
||||
ServerPlayer player = server.getPlayerList().getPlayerByName(playerName);
|
||||
UUID playerUuid = player != null ? player.getUUID() : null;
|
||||
|
||||
context.getSource().sendSuccess(() ->
|
||||
Component.literal("Adding player " + playerName + " to whitelist..."), false);
|
||||
|
||||
assert playerUuid != null;
|
||||
apiClient.addPlayer(playerName, playerUuid, addedBy, reason)
|
||||
.thenAccept(success -> {
|
||||
if (success) {
|
||||
context.getSource().sendSuccess(() ->
|
||||
Component.literal("Player " + playerName + " successfully added to whitelist"), true);
|
||||
} else {
|
||||
context.getSource().sendFailure(
|
||||
Component.literal("Error adding player " + playerName + " to whitelist"));
|
||||
}
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
LOGGER.error("Error adding player: ", throwable);
|
||||
context.getSource().sendFailure(
|
||||
Component.literal("Error adding player " + playerName + ": " + throwable.getMessage()));
|
||||
return null;
|
||||
});
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int removePlayer(CommandContext<CommandSourceStack> context) {
|
||||
String playerName = StringArgumentType.getString(context, "player");
|
||||
|
||||
context.getSource().sendSuccess(() ->
|
||||
Component.literal("Removing player " + playerName + " from whitelist..."), false);
|
||||
|
||||
apiClient.removePlayer(playerName)
|
||||
.thenAccept(success -> {
|
||||
if (success) {
|
||||
context.getSource().sendSuccess(() ->
|
||||
Component.literal("Player " + playerName + " successfully removed from whitelist"), true);
|
||||
} else {
|
||||
context.getSource().sendFailure(
|
||||
Component.literal("Error removing player " + playerName + " from whitelist"));
|
||||
}
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
LOGGER.error("Error removing player: ", throwable);
|
||||
context.getSource().sendFailure(
|
||||
Component.literal("Error removing player " + playerName + ": " + throwable.getMessage()));
|
||||
return null;
|
||||
});
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int checkPlayer(CommandContext<CommandSourceStack> context) {
|
||||
String playerName = StringArgumentType.getString(context, "player");
|
||||
|
||||
context.getSource().sendSuccess(() ->
|
||||
Component.literal("Checking player " + playerName + " status..."), false);
|
||||
|
||||
apiClient.checkPlayer(playerName)
|
||||
.thenAccept(result -> {
|
||||
if (result.isSuccess()) {
|
||||
String status = result.isWhitelisted() ? "whitelisted" : "not whitelisted";
|
||||
String uuidInfo = result.getPlayerUuid() != null ?
|
||||
" (UUID: " + result.getPlayerUuid() + ")" : "";
|
||||
|
||||
context.getSource().sendSuccess(() ->
|
||||
Component.literal("Player " + playerName + " is " + status + uuidInfo), true);
|
||||
} else {
|
||||
context.getSource().sendFailure(
|
||||
Component.literal("Error checking player " + playerName + " status"));
|
||||
}
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
LOGGER.error("Error checking player: ", throwable);
|
||||
context.getSource().sendFailure(
|
||||
Component.literal("Error checking player " + playerName + ": " + throwable.getMessage()));
|
||||
return null;
|
||||
});
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int listPlayers(CommandContext<CommandSourceStack> context) {
|
||||
context.getSource().sendSuccess(() ->
|
||||
Component.literal("Getting whitelist..."), false);
|
||||
|
||||
// TODO: Implement full list retrieval
|
||||
context.getSource().sendSuccess(() ->
|
||||
Component.literal("List functionality will be implemented in the next version"), true);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int countPlayers(CommandContext<CommandSourceStack> context) {
|
||||
context.getSource().sendSuccess(() ->
|
||||
Component.literal("Counting players in whitelist..."), false);
|
||||
|
||||
// TODO: Implement player counting
|
||||
context.getSource().sendSuccess(() ->
|
||||
Component.literal("Count functionality will be implemented in the next version"), true);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package org.itqop.whitelist;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.neoforge.event.RegisterCommandsEvent;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@EventBusSubscriber(modid = Whitelist.MODID)
|
||||
public class WhitelistEventHandler {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerCommands(RegisterCommandsEvent event) {
|
||||
WhitelistCommands.register(event.getDispatcher());
|
||||
LOGGER.info("Whitelist commands registered");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"itemGroup.whitelist": "Example Mod Tab",
|
||||
"block.whitelist.example_block": "Example Block",
|
||||
"item.whitelist.example_item": "Example Item"
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
# This is an example mods.toml file. It contains the data relating to the loading mods.
|
||||
# There are several mandatory fields (#mandatory), and many more that are optional (#optional).
|
||||
# The overall format is standard TOML format, v0.5.0.
|
||||
# Note that there are a couple of TOML lists in this file.
|
||||
# Find more information on toml format here: https://github.com/toml-lang/toml
|
||||
# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml
|
||||
modLoader = "javafml" #mandatory
|
||||
# A version range to match for said mod loader - for regular FML @Mod it will be the the FML version. This is currently 47.
|
||||
loaderVersion = "${loader_version_range}" #mandatory
|
||||
# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties.
|
||||
# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here.
|
||||
license = "${mod_license}"
|
||||
# A URL to refer people to when problems occur with this mod
|
||||
#issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional
|
||||
# A list of mods - how many allowed here is determined by the individual mod loader
|
||||
[[mods]] #mandatory
|
||||
# The modid of the mod
|
||||
modId = "${mod_id}" #mandatory
|
||||
# The version number of the mod
|
||||
version = "${mod_version}" #mandatory
|
||||
# A display name for the mod
|
||||
displayName = "${mod_name}" #mandatory
|
||||
# A URL to query for updates for this mod. See the JSON update specification https://docs.neoforge.net/docs/misc/updatechecker/
|
||||
#updateJSONURL="https://change.me.example.invalid/updates.json" #optional
|
||||
# A URL for the "homepage" for this mod, displayed in the mod UI
|
||||
#displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional
|
||||
# A file name (in the root of the mod JAR) containing a logo for display
|
||||
#logoFile="whitelist.png" #optional
|
||||
# A text field displayed in the mod UI
|
||||
#credits="" #optional
|
||||
# A text field displayed in the mod UI
|
||||
authors = "${mod_authors}" #optional
|
||||
|
||||
# The description text for the mod (multi line!) (#mandatory)
|
||||
description = '''${mod_description}'''
|
||||
|
||||
# The [[mixins]] block allows you to declare your mixin config to FML so that it gets loaded.
|
||||
#[[mixins]]
|
||||
#config="${mod_id}.mixins.json"
|
||||
|
||||
# The [[accessTransformers]] block allows you to declare where your AT file is.
|
||||
# If this block is omitted, a fallback attempt will be made to load an AT from META-INF/accesstransformer.cfg
|
||||
#[[accessTransformers]]
|
||||
#file="META-INF/accesstransformer.cfg"
|
||||
|
||||
# The coremods config file path is not configurable and is always loaded from META-INF/coremods.json
|
||||
|
||||
# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional.
|
||||
[[dependencies."${mod_id}"]] #optional
|
||||
# the modid of the dependency
|
||||
modId = "neoforge" #mandatory
|
||||
# The type of the dependency. Can be one of "required", "optional", "incompatible" or "discouraged" (case insensitive).
|
||||
# 'required' requires the mod to exist, 'optional' does not
|
||||
# 'incompatible' will prevent the game from loading when the mod exists, and 'discouraged' will show a warning
|
||||
type = "required" #mandatory
|
||||
# Optional field describing why the dependency is required or why it is incompatible
|
||||
# reason="..."
|
||||
# The version range of the dependency
|
||||
versionRange = "${neo_version_range}" #mandatory
|
||||
# An ordering relationship for the dependency.
|
||||
# BEFORE - This mod is loaded BEFORE the dependency
|
||||
# AFTER - This mod is loaded AFTER the dependency
|
||||
ordering = "NONE"
|
||||
# Side this dependency is applied on - BOTH, CLIENT, or SERVER
|
||||
side = "BOTH"
|
||||
# Here's another dependency
|
||||
[[dependencies."${mod_id}"]]
|
||||
modId = "minecraft"
|
||||
type = "required"
|
||||
# This version range declares a minimum of the current minecraft version up to but not including the next major version
|
||||
versionRange = "${minecraft_version_range}"
|
||||
ordering = "NONE"
|
||||
side = "BOTH"
|
||||
|
||||
# Features are specific properties of the game environment, that you may want to declare you require. This example declares
|
||||
# that your mod requires GL version 3.2 or higher. Other features will be added. They are side aware so declaring this won't
|
||||
# stop your mod loading on the server for example.
|
||||
#[features."${mod_id}"]
|
||||
#openGLVersion="[3.2,)"
|
||||
Loading…
Reference in New Issue