This commit is contained in:
JeremyStar™ 2024-10-08 03:15:46 +02:00
parent 11a25dd8e9
commit 15b04de3c4
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
86 changed files with 2684 additions and 161720 deletions

View file

@ -1,12 +1,12 @@
# PickShadow Server Plugin # PickShadow Server Extension
PSSP is intended as a all-in-one plugin for Bukkit-implementing server software for JeremyStarTM's PickShadow survival server. PSSE is intended as an all-in-one PaperMC Bukkit plugin for JeremyStarTM's PickShadow network.
## Index ## Index
- [Used where?](#used-where) - [Used where?](#used-where)
- [Contributing](#contributing) - [Contributing](#contributing)
## Used where? ## Used where?
This plugin is used on JeremyStarTM's **PickShadow** server, a survival server (or SMP, if you like) and replaces many commands such as /msg but also adds a few new ones. And before you ask: No you can't join. This plugin is used on JeremyStarTM's **PickShadow** network. Before you ask: No you can't join.
## Contributing ## Contributing
Please don't. Please don't lol

View file

@ -1,13 +1,36 @@
plugins { /*
id 'com.github.johnrengelman.shadow' version '7.1.2' * PICKSHADOW SERVER KIT SOURCE FILE
id 'java' * Copyright (c) 2024 The PickShadow Server Kit Contributors
} * Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
group = 'de.pickshadow' // Plugins
version = '1-alpha2' plugins {}
// Set group, version and repositories for all projects
allprojects {
group = project.group
version = project.versioningVersion + "-" + project.versioningType + project.versioningTyperelease + project.versioningFork + "+" + project.minecraftVersion
repositories { repositories {
mavenCentral() mavenCentral()
maven {
name = "staropensource-sosengine"
url = "https://mvn.staropensource.de/sosengine"
}
maven { maven {
name = "papermc-repo" name = "papermc-repo"
url = "https://repo.papermc.io/repository/maven-public/" url = "https://repo.papermc.io/repository/maven-public/"
@ -17,35 +40,4 @@ repositories {
url = "https://oss.sonatype.org/content/groups/public/" url = "https://oss.sonatype.org/content/groups/public/"
} }
} }
dependencies {
compileOnly "io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT"
implementation 'com.nikialeksey:jhunspell:1.0.5'
}
def targetJavaVersion = 17
java {
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
sourceCompatibility = javaVersion
targetCompatibility = javaVersion
if (JavaVersion.current() < javaVersion) {
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
}
}
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
options.release.set(targetJavaVersion)
}
}
processResources {
def props = [version: version]
inputs.properties props
filteringCharset 'UTF-8'
filesMatching('plugin.yml') {
expand props
}
} }

View file

@ -1,4 +1,23 @@
#!/bin/bash #!/bin/bash
#
# PICKSHADOW SERVER KIT SOURCE FILE
# Copyright (c) 2024 The PickShadow Server Kit Contributors
# Licensed under the GNU Affero General Public License v3
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
set -euo pipefail set -euo pipefail
echo ":: Renaming GitHead.java to GitHead.javabak" echo ":: Renaming GitHead.java to GitHead.javabak"
mv src/main/java/de/pickshadow/plugin/GitHead.java src/main/java/de/pickshadow/plugin/GitHead.javabak mv src/main/java/de/pickshadow/plugin/GitHead.java src/main/java/de/pickshadow/plugin/GitHead.javabak

133
extension/build.gradle Normal file
View file

@ -0,0 +1,133 @@
import io.papermc.paperweight.userdev.ReobfArtifactConfiguration
import java.nio.file.Files
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// Plugins
plugins {
id("java")
id("io.freefair.lombok") version("${pluginLombok}")
id("io.papermc.paperweight.userdev") version("${pluginPaperweight}")
id("io.github.goooler.shadow") version("${pluginShadow}")
id("com.gorylenko.gradle-git-properties") version("${pluginGitProperties}")
id("xyz.jpenilla.run-paper") version("${pluginRunTask}")
}
// Dependencies
dependencies {
// Lombok
compileOnly("org.projectlombok:lombok:${dependencyLombok}")
annotationProcessor("org.projectlombok:lombok:${dependencyLombok}")
// JetBrains Annotations
compileOnly("org.jetbrains:annotations:${dependencyJetbrainsAnnotations}")
// Libraries
compileOnly("de.staropensource.sosengine:base:${dependencyStarOpenSourceEngine}")
implementation("com.google.code.gson:gson:${dependencyGson}")
// Server
compileOnly("io.papermc.paper:paper-api:${minecraftVersion}-${dependencyPaper}-SNAPSHOT")
compileOnly("net.kyori:adventure-api:${dependencyAdventure}")
paperweight.paperDevBundle("${minecraftVersion}-${dependencyPaper}-SNAPSHOT")
// Plugins
compileOnly("net.luckperms:api:${dependencyLuckPerms}")
}
// Set Java version
java {
toolchain.languageVersion.set(JavaLanguageVersion.of("${javaTarget}"))
}
// Update plugin.yml
processResources {
filesMatching("plugin.yml") {
expand project.properties
}
}
// Git properties configuration
// Allows us to embed git commit information in the plugin build
gitProperties {
dotGitDirectory = file("${rootProject.rootDir}/.git")
failOnNoGitDirectory = false // Allow continuing if .git directory is missing for the few who use tarballs
extProperty = "gitProps"
dateFormat = "yyyy-MM-dd'T'HH:mmZ"
dateFormatTimeZone = "UTC"
}
tasks.register("writeGitProperties") { // This task's only purpose is to copy the git.properties from our git properties plugin to the resources directory so it's included in the final build
doLast {
File target = file("${project.projectDir}/src/main/resources/psse-git.properties")
File source = file("${project.projectDir}/build/resources/main/git.properties")
target.delete()
source.renameTo(target)
}
outputs.upToDateWhen({ false }) // Force task execution
}
generateGitProperties.outputs.upToDateWhen({ false }) // Force task execution
processResources.dependsOn(writeGitProperties) // Ensure git.properties file is present
// Copy gradle.properties file for inclusion in final build
tasks.register("copyGradleProperties") {
doFirst {
File target = file("${project.projectDir}/src/main/resources/psse-gradle.properties")
File source = file(project(":").projectDir.getPath() + "/gradle.properties")
target.delete()
Files.copy(source.toPath(), target.toPath())
}
outputs.upToDateWhen({ false }) // Force task execution
}
processResources.dependsOn(copyGradleProperties)
// Configure paperweight
paperweight {
reobfArtifactConfiguration = ReobfArtifactConfiguration.getMOJANG_PRODUCTION()
}
// Configure server
runServer {
minecraftVersion("${minecraftVersion}")
systemProperty("file.encoding", "UTF-8")
systemProperty("com.mojang.eula.agree", "true")
systemProperty("sosengine.base.loggerLevel", "diagnostic")
downloadPlugins {
modrinth("freedomchat", "${downloadFreedomChat}")
url("${downloadEngineMC}")
url("${downloadLuckPerms}")
}
doFirst {
// Disable bStats
File config = new File(runDirectory.get().getAsFile().getPath() + "/plugins/bStats/config.yml")
if (!config.exists()) {
config.getParentFile().mkdirs()
config.createNewFile()
config.write("enabled: false\n")
}
}
}

1
extension/gradle Symbolic link
View file

@ -0,0 +1 @@
../gradle

1
extension/gradlew vendored Symbolic link
View file

@ -0,0 +1 @@
../gradlew

1
extension/gradlew.bat vendored Symbolic link
View file

@ -0,0 +1 @@
../gradlew.batr

View file

@ -0,0 +1,132 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow;
import de.jeremystartm.pickshadow.api.translation.TranslationManager;
import de.jeremystartm.pickshadow.command.general.*;
import de.jeremystartm.pickshadow.command.survival.HomeCommand;
import de.jeremystartm.pickshadow.listener.ChatListener;
import de.staropensource.sosengine.base.logging.LoggerInstance;
import de.staropensource.sosengine.base.utility.Miscellaneous;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
/**
* PSSE's main class.
*
* @since v1-release0
*/
@SuppressWarnings({ "JavadocDeclaration", "unused" })
public final class Extension extends JavaPlugin {
/**
* Contains the global instance of this class.
*
* @since v1-release0
* -- GETTER --
* Returns the global instance of this class.
*
* @return global instance
* @since v1-release0
*/
@Getter
private static Extension instance = null;
/**
* Contains the logger instance for this instance.
*
* @since v1-release0
*/
private final LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("PSSE").build();
/**
* Creates and initializes an instance of this class.
*
* @since v1-release0
*/
public Extension() {
instance = this;
}
/**
* Called after the plugin has been loaded.
*
* @since v1-release0
*/
@Override
public void onLoad() {
logger.info("Bootstrapping");
// Check for NMS
try {
Class.forName("net.minecraft.server.MinecraftServer");
} catch (Exception exception) {
logger.crash("This Bukkit implementation does not run on NMS.\nPSSE is designed to only run on NMS-based server software.\nYou may need to rewrite certain parts of PSSE so it can run on non-NMS server softwares.", exception);
return;
}
// Load classes
new ExtensionConfiguration().loadConfiguration();
ExtensionInformation.update();
TranslationManager.loadTranslations();
TranslationManager.processTranslations();
logger.info("Bootstrapped in " + Miscellaneous.measureExecutionTime(() -> {}) + "ms");
}
/**
* Called after the plugin has been enabled.
*
* @since v1-release0
*/
@Override
public void onEnable() {
logger.info("Initializing");
try {
logger.info("Initialized in " + Miscellaneous.measureExecutionTime(() -> {
logger.verb("Registering commands");
new AnnounceCommand();
new ClearChatCommand();
new ExtensionCommand();
new HomeCommand();
new LinkCommand();
new MessageCommand();
new ToggleDownfallCommand();
new TrollCommand();
logger.verb("Registering listeners");
Bukkit.getPluginManager().registerEvents(new ChatListener(), this);
}) + "ms");
} catch (Exception exception) {
logger.crash("Initialization failed", exception);
}
}
/**
* Called before the plugin is shut down.
*
* @since v1-release0
*/
@Override
public void onDisable() {
logger.info("Shutting down");
logger.info("Shut down in " + Miscellaneous.measureExecutionTime(() -> {}) + "ms");
}
}

View file

@ -0,0 +1,137 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow;
import de.jeremystartm.pickshadow.api.command.completion.StaticTabCompletion;
import de.staropensource.sosengine.base.implementable.Configuration;
import de.staropensource.sosengine.base.utility.PropertiesReader;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class ExtensionConfiguration extends Configuration {
/**
* Contains the class instance.
*
* @since v1-release0
* -- GETTER --
* Returns the class instance.
*
* @return class instance unless {@link Extension} is uninitialized
* @since v1-release0
*/
@Getter
private static ExtensionConfiguration instance;
/**
* Contains prefix properties must begin with.
*
* @since v1-release0
* -- GETTER --
* Returns prefix properties must begin with.
*
* @return property group
* @since v1-release0
*/
private final @NotNull String group = "pickshadow.extension.";
/**
* If enabled, allows for unintentional behaviour
* and excess logging. Unless you want to debug or work
* on a sensitive part of the engine, don't enable this!
*
* @since v1-release0
* -- GETTER --
* Gets the value for {@link #debug}.
*
* @return variable value
* @see #debug
* @since v1-release0
*/
private boolean debug;
/**
* Causes {@link StaticTabCompletion} to print lots debugging information.
*
* @since v1-release0
* -- GETTER --
* Gets the value for {@link #debugStaticCompletion}.
*
* @return variable value
* @see #debugStaticCompletion
* @since v1-release0
*/
private boolean debugStaticCompletion;
/**
* Creates and initializes an instance of this class.
*
* @see Extension
* @since v1-release0
*/
ExtensionConfiguration() {
super("PSSE");
instance = this;
// Load default configuration
loadDefaultConfiguration();
}
/** {@inheritDoc} */
@Override
protected void matchProperty(@NotNull PropertiesReader parser, @NotNull String property) {
try {
switch (property) {
case "debug" -> debug = parser.getBoolean(group + property);
case "debugStaticCompletion" -> debugStaticCompletion = parser.getBoolean(group + property);
}
} catch (NullPointerException ignored) {}
}
/** {@inheritDoc} */
@Override
protected void processSettings(@NotNull PropertiesReader parser) {
// Disable all debugging switches if 'debug' is disabled
if (!debug) {
debugStaticCompletion = false;
}
}
/** {@inheritDoc} */
@Override
public void loadDefaultConfiguration() {
debug = false;
debugStaticCompletion = false;
}
/** {@inheritDoc} */
@Override
public @Nullable Object getSetting(@NotNull String setting) {
return switch (setting) {
case "debug" -> debug;
case "debugStaticCompletion" -> debugStaticCompletion;
default -> null;
};
}
}

View file

@ -0,0 +1,379 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow;
import de.staropensource.sosengine.base.Engine;
import de.staropensource.sosengine.base.logging.LoggerInstance;
import de.staropensource.sosengine.base.type.VersionType;
import de.staropensource.sosengine.base.utility.Miscellaneous;
import de.staropensource.sosengine.base.utility.PropertiesReader;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Properties;
/**
* Provides build information about the engine.
*
* @since v1-alpha0
*/
@SuppressWarnings({ "JavadocDeclaration" })
public final class ExtensionInformation {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha2
*/
private static final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(ExtensionInformation.class).setOrigin("PSSE").build();
/**
* Contains the extensions's version codename.
*
* @since v1-alpha2
* -- GETTER --
* Returns the extensions's version codename.
*
* @return extensions version codename
* @since v1-alpha2
*/
@Getter
private static String versioningCodename;
/**
* Contains the extensions's version.
*
* @since v1-alpha0
* -- GETTER --
* Returns the extensions's version.
*
* @return extensions version
* @since v1-alpha0
*/
@Getter
private static int versioningVersion;
/**
* Contains the extensions's version type.
*
* @since v1-alpha0
* -- GETTER --
* Returns the extensions's version type.
*
* @return extensions version type
* @since v1-alpha0
*/
@Getter
private static VersionType versioningType;
/**
* Contains the extensions's typerelease.
*
* @since v1-alpha0
* -- GETTER --
* Returns the extensions's typerelease.
*
* @return extensions typerelease
* @since v1-alpha0
*/
@Getter
private static int versioningTyperelease;
/**
* Contains the extensions's fork identifier.
* <p>
* Likely empty. If not, prefixed with a dash.
*
* @since v1-alpha0
* -- GETTER --
* Returns the extensions's fork identifier.
* <p>
* Likely empty. If not, prefixed with a dash.
*
* @return extensions fork identifier
* @since v1-alpha0
*/
@Getter
private static String versioningFork;
/**
* Contains the extensions's full version string.
*
* @since v1-alpha1
* -- GETTER --
* Returns the extensions's full version string.
*
* @return extensions version string
* @since v1-alpha1
*/
@Getter
private static String versioningString;
/**
* Contains the Java version of the extensions source.
*
* @since v1-alpha4
* -- GETTER --
* Returns the Java version of the extensions source.
*
* @return java version of extensions source
* @since v1-alpha4
*/
@Getter
private static short javaSource;
/**
* Contains the Java version the extensions was compiled against.
*
* @since v1-alpha4
* -- GETTER --
* Returns the Java version the extensions was compiled against.
*
* @return Java version compiled against
* @since v1-alpha4
*/
@Getter
private static short javaTarget;
/**
* Contains the {@code dirty} value (i.e. if the source tree has been modified).
*
* @since v1-alpha1
* -- GETTER --
* Returns the {@code dirty} value (i.e. if the source tree has been modified).
*
* @return git dirty value
* @since v1-alpha1
*/
@Getter
private static boolean gitDirty;
/**
* Contains the branch the extensions was built on.
*
* @since v1-alpha1
* -- GETTER --
* Returns the branch the extensions was built on.
*
* @return git branch
* @since v1-alpha1
*/
@Getter
private static String gitBranch;
/**
* Contains the commit count.
*
* @since v1-alpha1
* -- GETTER --
* Returns the commit count.
*
* @return git commit count
* @since v1-alpha1
*/
@Getter
private static int gitCommitCount;
/**
* Contains the commit identifier (short form).
*
* @since v1-alpha1
* -- GETTER --
* Returns the commit identifier (short form).
*
* @return git long commit id
* @since v1-alpha1
*/
@Getter
private static String gitCommitIdentifierShort;
/**
* Contains the commit identifier (long form).
*
* @since v1-alpha1
* -- GETTER --
* Returns the commit identifier (long form).
*
* @return git long commit id
* @since v1-alpha1
*/
@Getter
private static String gitCommitIdentifierLong;
/**
* Contains the commit header.
*
* @since v1-alpha1
* -- GETTER --
* Returns the commit header.
*
* @return git commit header
* @since v1-alpha1
*/
@Getter
private static String gitCommitHeader;
/**
* Contains the commit time.
*
* @since v1-alpha1
* -- GETTER --
* Returns the commit time.
*
* @return git commit time
* @since v1-alpha1
*/
@Getter
private static ZonedDateTime gitCommitTime;
/**
* Contains the commiter's name.
*
* @since v1-alpha1
* -- GETTER --
* Returns the commiter's name.
*
* @return git committer name
* @since v1-alpha1
*/
@Getter
private static String gitCommitterName;
/**
* Contains the commiter's email.
*
* @since v1-alpha1
* -- GETTER --
* Returns the commiter's email.
*
* @return git committer email
* @since v1-alpha1
*/
@Getter
private static String gitCommitterEmail;
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha6
*/
private ExtensionInformation() {}
/**
* Updates all variables.
* <p>
* This method does not need to be invoked manually, as the information provided by
* this class is static (does not change) and is already populated at engine startup.
*
* @since v1-alpha1
*/
public static synchronized void update() {
logger.diag("Updating extension information");
// Load properties from bundled gradle.properties
Properties gradleProperties = new Properties();
InputStream gradleStream = ExtensionInformation.class.getClassLoader().getResourceAsStream("psse-gradle.properties");
if (gradleStream == null) {
logger.crash("Unable to load build information: The bundled gradle.properties file could not be found.");
return;
}
try {
gradleProperties.load(gradleStream);
gradleStream.close();
} catch (IOException exception) {
logger.crash("Unable to load build information: InputStream 'gradleStream' failed", exception);
return;
}
// Load properties from bundled git.properties
// or fill in blank information if file missing
Properties gitProperties = new Properties();
InputStream gitStream = ExtensionInformation.class.getClassLoader().getResourceAsStream("psse-git.properties");
if (gitStream == null) {
logger.error("Unable to load build information: The bundled git.properties file could not be found. Did you download a tarball?");
// Fake information
gitProperties.setProperty("git.total.commit.count", "0");
gitProperties.setProperty("git.dirty", "true");
gitProperties.setProperty("git.branch", "/git.properties is missing/");
gitProperties.setProperty("git.commit.id", "########################################");
gitProperties.setProperty("git.commit.id.abbrev", "#######");
gitProperties.setProperty("git.commit.message.short", "git.properties file is missing :/");
gitProperties.setProperty("git.commit.time", "1970-01-01T00:00+0000");
gitProperties.setProperty("git.commit.user.name", "git.properties file is missing :/");
gitProperties.setProperty("git.commit.user.email", "git.properties-is-missing@example.com");
} else {
// Load real information from git.properties file
try {
gitProperties.load(gitStream);
gitStream.close();
} catch (IOException exception) {
logger.crash("Unable to load build information: InputStream 'gitStream' failed", exception);
return;
}
}
// Create new PropertyParsers
PropertiesReader gradleParser = new PropertiesReader(gradleProperties);
PropertiesReader gitParser = new PropertiesReader(gitProperties);
// Apply properties to fields
versioningCodename = gradleParser.getString("versioningCodename");
versioningVersion = gradleParser.getInteger("versioningVersion", true);
versioningType = VersionType.valueOf(gradleParser.getString("versioningType").toUpperCase());
versioningTyperelease = gradleParser.getInteger("versioningTyperelease", true);
versioningFork = gradleParser.getString("versioningFork");
versioningString = "v" + versioningVersion + "-" + (versioningType == VersionType.RELEASE_CANDIDATE ? "releasecandidate" : versioningType.name().toLowerCase(Locale.ROOT)) + versioningTyperelease + versioningFork;
javaSource = gradleParser.getShort("javaSource");
javaTarget = gradleParser.getShort("javaTarget");
gitDirty = gitParser.getBoolean("git.dirty");
gitBranch = gitParser.getString("git.branch");
gitCommitCount = gitParser.getInteger("git.total.commit.count", true);
gitCommitIdentifierShort = gitParser.getString("git.commit.id.abbrev");
gitCommitIdentifierLong = gitParser.getString("git.commit.id");
gitCommitHeader = gitParser.getString("git.commit.message.short");
try {
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ").parse(gitParser.getString("git.commit.time"));
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(date);
gitCommitTime = calendar.toZonedDateTime();
} catch (ParseException exception) {
logger.crash("Unable to load build information: Can't parse \"" + gitParser.getString("git.commit.time") + "\" using format \"yyyy-MM-dd'T'HH:mmZ\"", exception);
}
gitCommitterName = gitParser.getString("git.commit.user.name");
gitCommitterEmail = gitParser.getString("git.commit.user.email");
}
}

View file

@ -0,0 +1,102 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.api.command;
import de.jeremystartm.pickshadow.api.translation.LanguageString;
import de.jeremystartm.pickshadow.api.translation.TranslationManager;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* Abstract class for implementing commands.
*/
public abstract class CommandBase implements CommandExecutor {
/**
* Initializes this abstract class
* and registers the command.
*
* @param commands all commands this class should handle
* @throws IllegalArgumentException if a command does not exist
* @since v1-release0
*/
public CommandBase(@NotNull String... commands) throws IllegalArgumentException {
for (String command : commands) {
PluginCommand pluginCommand = Bukkit.getPluginCommand(command);
if (pluginCommand == null)
throw new IllegalArgumentException("Command registration failed: The command \"" + command + "\" does not exist");
pluginCommand.setExecutor(this);
pluginCommand.setTabCompleter(new TabCompleter() {
@Override
public @NotNull List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
return StringUtil.copyPartialMatches(args[args.length - 1], getCompletion().complete(sender, label, args), new ArrayList<>());
}
});
}
}
/** {@inheritDoc} */
@Override
public final boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
invoke(sender, command, alias, args);
return true;
}
/**
* Executes this command.
*
* @since v1-release0
*/
public abstract void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments);
/**
* Provides tab completions for this command.
*
* @since v1-release0
*/
public abstract @NotNull TabCompletion getCompletion();
/**
* Performs a permission check, sends the sender
* an error message and then returns.
* Useful for easy permission checks.
*
* @param sender sender to check
* @param permission permission to check for
* @return return?
* @since v1-release0
*/
protected static boolean checkPermission(@NotNull CommandSender sender, @NotNull String permission) {
if (!sender.hasPermission(permission)) {
sender.sendRichMessage(
TranslationManager.get(LanguageString.ERROR_MISSING_PERM, sender, true)
.replace("%permission%", permission)
);
return true;
}
return false;
}
}

View file

@ -0,0 +1,39 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.api.command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Interface for building tab completioners.
*
* @since v1-release0
*/
public interface TabCompletion {
/**
* Resolves and returns a matching completion.
*
* @since v1-release0
*/
@NotNull List<@NotNull String> complete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments);
}

View file

@ -0,0 +1,241 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.api.command.completion;
import de.jeremystartm.pickshadow.ExtensionConfiguration;
import de.jeremystartm.pickshadow.api.command.TabCompletion;
import de.staropensource.sosengine.base.logging.LoggerInstance;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Range;
import java.util.*;
/**
* Provides static, yet configurable tab completions.
*
* @since v1-release0
*/
public final class StaticTabCompletion implements TabCompletion {
/**
* Contains the logger instance for this instance.
*
* @since v1-release0
*/
private final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("PSSE").setMetadata(String.valueOf(hashCode())).build();
/**
* Creates and initializes an instance of this class.
*
* @since v1-release0
*/
public StaticTabCompletion() {}
/**
* Contains all aliases and their completions.
* <p>
* Reference: {@code Map<alias, List<Map<completion entry, required permission>>>}
*
* @since v1-release0
*/
private final @NotNull Map<@NotNull String, @NotNull Map<@NotNull Integer, @Nullable Map<@NotNull String, @NotNull String>>> completions = new HashMap<>();
/**
* Resolves and returns a matching completion.
*
* @since v1-release0
*/
@Override
public @NotNull List<@NotNull String> complete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) {
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("complete(sender=" + sender.getName() + " alias=" + alias + " arguments=" + Arrays.toString(arguments) + ")");
try {
// Get correct alias or return empty list
if (!completions.containsKey(alias))
if (completions.containsKey(""))
alias = "";
else
return List.of();
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion() && alias.isEmpty())
logger.diag("Alias has been corrected");
// Get and add completions
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Compiling completions");
List<@NotNull String> output = new ArrayList<>(getCompletions(sender, alias, arguments.length - 1));
// Get and add alias-wide completions
if (completions.get(alias).containsKey(-1)) {
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Compiling alias-wide completions");
output.addAll(getCompletions(sender, alias, -1));
}
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("=== Completion finished");
return output;
} catch (Exception exception) {
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Caught " + exception.getClass().getName() + ", returning error list");
return Arrays.stream(new String[]{ "An error occurred" }).toList();
}
}
/**
* Returns all completions for the specified alias and index.
*
* @param sender sender to check permissions for
* @param alias alias to get
* @param index index to get
* @throws IndexOutOfBoundsException no completions were found
* @return completion list
*/
private @NotNull List<@NotNull String> getCompletions(@NotNull CommandSender sender, @NotNull String alias, @Range(from = -1, to = Integer.MAX_VALUE) int index) throws IndexOutOfBoundsException {
List<@NotNull String> output = new ArrayList<>();
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("getCompletions(sender=" + sender.getName() + " alias=" + alias + " index=" + index + ")");
if (!completions.get(alias).containsKey(index))
return List.of();
// Get and add completions
if (completions.get(alias).get(index) == null) {
// Empty index, display player list
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Index is null, getting player list");
for (Player player : Bukkit.getOnlinePlayers())
output.add(player.getName());
} else {
// Filled index, check permissions and add arguments accordingly
// Note: You can safely ignore these NPE warnings, we catch them down below. I just didn't
// put these lines into Objects#requireNonNull so that the code is still fairly readable
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Index is map, getting arguments");
for (String argument : completions.get(alias).get(index).keySet())
if (sender.hasPermission(completions.get(alias).get(index).get(argument))) {
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Adding completion argument \"" + argument + "\"");
output.add(argument);
} else if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Permission is missing, skipping completion argument \"" + argument + "\"");
}
return output;
}
/**
* Marks an index as empty.
*
* @param alias alias to operate in
* @param index index to mark as empty
* @return the same instance
* @since v1-release0
*/
public @NotNull StaticTabCompletion empty(@NotNull String alias, @Range(from = -1, to = Integer.MAX_VALUE) int index) {
createAlias(alias);
createIndex(alias, index);
return this;
}
/**
* Marks an index for use as a player list.
*
* @param alias alias to operate in
* @param index index to mark as a player list
* @return the same instance
* @since v1-release0
*/
public @NotNull StaticTabCompletion players(@NotNull String alias, @Range(from = -1, to = Integer.MAX_VALUE) int index) {
createAlias(alias);
completions.get(alias).put(index, null);
return this;
}
/**
* Adds a new completion entry.
*
* @param alias alias to operate in
* @param index index to mark as empty
* @param completionEntry entry to add
* @param permission required permission to be displayed
* @return the same instance
* @since v1-release0
*/
public @NotNull StaticTabCompletion add(@NotNull String alias, @Range(from = -1, to = Integer.MAX_VALUE) int index, @NotNull String completionEntry, @NotNull String permission) {
createAlias(alias);
createIndex(alias, index);
Objects.requireNonNull(completions.get(alias).get(index)).put(completionEntry, permission);
return this;
}
/**
* Copies a whole alias.
*
* @param from alias to copy from
* @param to alias to copy to
* @return the same instance
* @since v1-release0
*/
public @NotNull StaticTabCompletion copy(@NotNull String from, @NotNull String to) {
createAlias(from);
completions.put(to, completions.get(from));
return this;
}
/**
* Creates a new alias.
*
* @param alias alias to create
* @since v1-release0
*/
private void createAlias(@NotNull String alias) {
if (!completions.containsKey(alias)) {
completions.put(alias, new HashMap<>());
}
}
/**
* Creates a new index.
*
* @param alias alias to create in
* @param index index to create
* @since v1-release0
*/
private void createIndex(@NotNull String alias, @Range(from = -1, to = Integer.MAX_VALUE) int index) {
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("createIndex(alias=" + alias + " index=" + index + ")");
try {
if (completions.get(alias).get(index) == null)
throw new IndexOutOfBoundsException();
} catch (IndexOutOfBoundsException exception) {
completions.get(alias).put(index, new HashMap<>());
}
}
}

View file

@ -0,0 +1,63 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.api.command.completion;
import de.jeremystartm.pickshadow.api.command.TabCompletion;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Returns empty tab completions.
*
* @since v1-release0
*/
public final class StubTabCompletion implements TabCompletion {
/**
* Contains the global instance of this class.
*
* @since v1-release0
*/
private static final @NotNull StubTabCompletion INSTANCE = new StubTabCompletion();
/**
* Creates and initializes an instance of this class.
*
* @since v1-release0
*/
private StubTabCompletion() {}
/**
* Returns the global instance of this class.
*
* @return global instance
* @since v1-release0
*/
public static @NotNull StubTabCompletion completion() {
return INSTANCE;
}
/** {@inheritDoc} */
@Override
public @NotNull List<@NotNull String> complete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) {
return List.of();
}
}

View file

@ -0,0 +1,85 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.api.translation;
/**
* Contains all language strings which can be translated.
* <p>
* These are all undocumented. Look into {@code en.json} for their translations.
*
* @since v1-release0
*/
public enum LanguageString {
// Internal stuff
PREFIX,
PREFIX_NEWLINE,
TAG_GENERIC_OPEN,
TAG_GENERIC_CLOSE,
TAG_ERROR_OPEN,
TAG_ERROR_CLOSE,
TAG_MENTION_OPEN,
TAG_MENTION_CLOSE,
TAG_LINK_OPEN,
TAG_LINK_CLOSE,
// Errors
ERROR_UNKNOWN,
ERROR_UNIMPLEMENTED,
ERROR_NOT_A_PLAYER,
ERROR_MISSING_PERM,
ERROR_TOO_FEW_ARGUMENTS,
ERROR_TOO_MANY_ARGUMENTS,
ERROR_INVALID_ARGUMENT,
ERROR_PLAYER_NOT_FOUND,
// Command /psse
EXTENSIONCMD_GREETER,
EXTENSIONCMD_KILLJVM,
EXTENSIONCMD_LICENSE,
EXTENSIONCMD_SOURCE,
EXTENSIONCMD_ERROR_OLDCMD,
// Command group 'links'
LINKS_WEBSITE,
LINKS_DISCORD,
LINKS_TEAMSPEAK,
LINKS_MUMBLE,
// Command group 'messaging'
MESSAGING_FORMAT,
MESSAGING_ERROR_SELF,
// Command /clearchat
CLEARCHAT_GENERIC,
CLEARCHAT_VOID,
CLEARCHAT_SKILLISSUES,
CLEARCHAT_BRAINDAMAGE,
CLEARCHAT_CRINGE,
// Command /home
HOME_NORESPAWN,
HOME_TELEPORTED,
// Command /toggledownfall
TOGGLEDOWNFALL,
// Event for chat messages
CHATMESSAGE_SERVER,
}

View file

@ -0,0 +1,170 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.api.translation;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import de.staropensource.sosengine.base.logging.LoggerInstance;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
/**
* Manages and resolves translations.
*
* @since v1-release0
*/
public final class TranslationManager {
/**
* Contains the logger instance for this class.
*
* @since v1-release0
*/
private static final LoggerInstance LOGGER = new LoggerInstance.Builder().setClazz(TranslationManager.class).setOrigin("PSSE").build();
/**
* Contains all translations.
*
* @since v1-release0
*/
private static final @NotNull Map<@NotNull String, @NotNull Map<@NotNull LanguageString, @NotNull String>> translations = new HashMap<>();
/**
* Returns the translation for the specified language
* string for the specified {@link CommandSender}.
*
* @param languageString language string to get
* @param sender sender to translate for
* @param includePrefix if {@link LanguageString#PREFIX} should be prepended
* @since v1-release0
*/
public static @NotNull String get(@NotNull LanguageString languageString, @NotNull CommandSender sender, boolean includePrefix) {
String language = "en";
if (includePrefix)
return get(LanguageString.PREFIX, "en") + get(languageString, language).replace("\n", "\n" + get(LanguageString.PREFIX_NEWLINE, "en"));
else
return get(languageString, language);
}
/**
* Returns the translation for the specified language
* string for the specified {@link CommandSender}.
*
* @param languageString language string to get
* @param sender sender to translate for
* @since v1-release0
*/
public static @NotNull String get(@NotNull LanguageString languageString, @NotNull CommandSender sender) {
return get(languageString, sender, false);
}
/**
* Returns the translation for the specified
* language string in the specified language.
*
* @param languageString language string to get
* @param language language to translate into
* @since v1-release0
*/
public static @NotNull String get(@NotNull LanguageString languageString, @NotNull String language) {
if (language.equals("en"))
return translations.get(language).getOrDefault(languageString, "!" + languageString.name() + "!");
if (!(translations.containsKey(language) && translations.get(language).containsKey(languageString)))
return get(languageString, "en");
return translations.get(language).get(languageString);
}
/**
* Loads all translations into memory.
*
* @since v1-release0
*/
public static void loadTranslations() {
LOGGER.verb("Loading translations");
Map<@NotNull String, @NotNull String> translationsLanguage;
translations.clear();
for (String language : new String[]{ "en", "de" }) {
LOGGER.diag("Loading translations for language \"" + language + "\"");
translations.put(language, new HashMap<>());
// Load, parse and store translations
try (InputStream stream = TranslationManager.class.getClassLoader().getResourceAsStream("translations/" + language.toLowerCase(Locale.ROOT) + ".json")) {
translationsLanguage = new Gson().fromJson(new String(Objects.requireNonNull(stream).readAllBytes(), StandardCharsets.UTF_8), new TypeToken<Map<@NotNull String, @NotNull String>>(){}.getType());
} catch (IOException | NullPointerException exception) {
LOGGER.crash("Failed loading translations for language \"" + language + "\": IOException occurred", exception);
return;
} catch (JsonSyntaxException exception) {
LOGGER.crash("Failed loading translations for language \"" + language + "\": JSON Syntax does not match Map<LanguageString, String>", exception);
return;
}
// Convert and save translations
for (String languageString : translationsLanguage.keySet())
translations.get(language).put(LanguageString.valueOf(languageString), translationsLanguage.get(languageString));
}
}
/**
* Processes all translations.
*
* @since v1-release0
*/
public static void processTranslations() {
LOGGER.verb("Processing translations");
String tagGenericOpen = get(LanguageString.TAG_GENERIC_OPEN, "en");
String tagGenericClose = get(LanguageString.TAG_GENERIC_CLOSE, "en");
String tagErrorOpen = get(LanguageString.TAG_ERROR_OPEN, "en");
String tagErrorClose = get(LanguageString.TAG_ERROR_CLOSE, "en");
String tagMentionOpen = get(LanguageString.TAG_MENTION_OPEN, "en");
String tagMentionClose = get(LanguageString.TAG_MENTION_CLOSE, "en");
String tagLinkOpen = get(LanguageString.TAG_LINK_OPEN, "en");
String tagLinkClose = get(LanguageString.TAG_LINK_CLOSE, "en");
for (String language : translations.keySet()) {
LOGGER.diag("Processing translations for language \"" + language + "\"");
for (LanguageString languageString : translations.get(language).keySet())
translations.get(language).put(
languageString,
translations.get(language).get(languageString)
.replace("<generic>", tagGenericOpen)
.replace("</generic>", tagGenericClose)
.replace("<error>", tagErrorOpen)
.replace("</error>", tagErrorClose)
.replace("<mention>", tagMentionOpen)
.replace("</mention>", tagMentionClose)
.replace("<link>", tagLinkOpen)
.replace("</link>", tagLinkClose)
);
}
}
}

View file

@ -0,0 +1,98 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.command.general;
import de.jeremystartm.pickshadow.api.command.CommandBase;
import de.jeremystartm.pickshadow.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.api.command.TabCompletion;
import de.jeremystartm.pickshadow.api.translation.LanguageString;
import de.jeremystartm.pickshadow.api.translation.TranslationManager;
import de.staropensource.sosengine.base.utility.PlaceholderEngine;
import lombok.Getter;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
/**
* Handles the {@code /announce} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class AnnounceCommand extends CommandBase {
/**
* Contains the tab completion for this command.
*
* @since v1-release0
* -- GETTER --
* Returns the tab completion for this command.
*
* @return tab completion
* @since v1-release0
*/
private final @NotNull TabCompletion completion = new StaticTabCompletion()
.add("", -1, "--network", "pickshadow.command.announce.network");
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public AnnounceCommand() throws IllegalArgumentException {
super("announce");
}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.announce")) return;
if (arguments.length == 0) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_FEW_ARGUMENTS, sender, true));
return;
}
StringBuilder argumentsString = new StringBuilder();
boolean networkwide = false;
// Convert 'arguments' into a String
for (String argument : arguments) {
if (argument.equals("--network")) {
networkwide = true;
continue;
}
if (!argumentsString.isEmpty())
argumentsString.append(" ");
argumentsString.append(argument);
}
if (networkwide) {
if (!checkPermission(sender, "pickshadow.command.announce.network"))
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true));
} else
Bukkit.broadcast(MiniMessage.miniMessage().deserialize(PlaceholderEngine.getInstance().process(argumentsString.toString().replace("\\n", "\n"))));
}
}

View file

@ -0,0 +1,106 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.command.general;
import de.jeremystartm.pickshadow.api.command.CommandBase;
import de.jeremystartm.pickshadow.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.api.command.TabCompletion;
import de.jeremystartm.pickshadow.api.translation.LanguageString;
import de.jeremystartm.pickshadow.api.translation.TranslationManager;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* Handles the {@code /clearchat} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class ClearChatCommand extends CommandBase {
/**
* Contains the tab completion for this command.
*
* @since v1-release0
* -- GETTER --
* Returns the tab completion for this command.
*
* @return tab completion
* @since v1-release0
*/
private final @NotNull TabCompletion completion = new StaticTabCompletion()
.add("", -1, "--network", "pickshadow.command.clearchat");
/**
* Contains the amount of newlines to send.
*
* @since v1-release0
*/
private static final String NEWLINES = "Seems like clearing the chat does not prevent you from looking at the logs or using mods..." + "\n ".repeat(100);
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public ClearChatCommand() throws IllegalArgumentException {
super("clearchat");
}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.clearchat")) return;
if (arguments.length == 1 && arguments[0].equals("--network")) {
if (checkPermission(sender, "pickshadow.command.clearchat.network")) return;
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true));
return;
}
for (Player player : Bukkit.getOnlinePlayers())
player.sendRichMessage(NEWLINES + "\n" + getClearMessage(sender, player));
}
/**
* Returns a random clear message.
*
* @param sender {@link CommandSender} which invoked the command
* @return some clear message
* @since v1-release0
*/
private @NotNull String getClearMessage(@NotNull CommandSender sender, @NotNull CommandSender receiver) {
LanguageString[] strings = new LanguageString[]{
LanguageString.CLEARCHAT_GENERIC,
LanguageString.CLEARCHAT_VOID,
LanguageString.CLEARCHAT_SKILLISSUES,
LanguageString.CLEARCHAT_BRAINDAMAGE,
LanguageString.CLEARCHAT_CRINGE,
};
return TranslationManager.get(strings[(int) System.currentTimeMillis() % strings.length], receiver, true).replace("%sender%", sender.getName());
}
}

View file

@ -0,0 +1,102 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.command.general;
import de.jeremystartm.pickshadow.ExtensionInformation;
import de.jeremystartm.pickshadow.api.command.CommandBase;
import de.jeremystartm.pickshadow.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.api.command.TabCompletion;
import de.jeremystartm.pickshadow.api.translation.LanguageString;
import de.jeremystartm.pickshadow.api.translation.TranslationManager;
import lombok.Getter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
/**
* Handles the {@code /psse} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class ExtensionCommand extends CommandBase {
/**
* Contains the tab completion for this command.
*
* @since v1-release0
* -- GETTER --
* Returns the tab completion for this command.
*
* @return tab completion
* @since v1-release0
*/
private final @NotNull TabCompletion completion = new StaticTabCompletion()
.add("psse", 0, "killjvm", "pickshadow.command.extension.advanced")
.add("psse", 0, "license", "pickshadow.command.extension")
.add("psse", 0, "source", "pickshadow.command.extension")
.copy("psse", "pickshadow")
.copy("psse", "server");
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public ExtensionCommand() throws IllegalArgumentException {
super("psse");
}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.extension")) return;
switch (alias) {
case "psse", "pickshadow", "server" -> {
if (arguments.length == 0)
sender.sendRichMessage(
TranslationManager.get(LanguageString.EXTENSIONCMD_GREETER, sender, true)
.replace("%codename%", ExtensionInformation.getVersioningCodename())
.replace("%version%", ExtensionInformation.getVersioningString())
.replace("%commit%", ExtensionInformation.getGitCommitIdentifierShort())
.replace("%dirty%", String.valueOf(ExtensionInformation.isGitDirty()))
);
else {
switch (arguments[0]) {
case "killjvm" -> {
if (checkPermission(sender, "pickshadow.command.extension.advanced")) return;
sender.sendRichMessage(TranslationManager.get(LanguageString.EXTENSIONCMD_KILLJVM, sender, true));
Runtime.getRuntime().halt(0);
}
case "license" -> sender.sendRichMessage(TranslationManager.get(LanguageString.EXTENSIONCMD_LICENSE, sender, true));
case "source" -> sender.sendRichMessage(TranslationManager.get(LanguageString.EXTENSIONCMD_SOURCE, sender, true));
default -> sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_INVALID_ARGUMENT, sender, true).replace("%argument%", arguments[0]));
}
if (arguments[0].equals("killjvm"))
Runtime.getRuntime().halt(0);
}
}
case "pssp" -> sender.sendRichMessage(TranslationManager.get(LanguageString.EXTENSIONCMD_ERROR_OLDCMD, sender, true));
}
}
}

View file

@ -0,0 +1,75 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.command.general;
import de.jeremystartm.pickshadow.api.command.CommandBase;
import de.jeremystartm.pickshadow.api.command.completion.StubTabCompletion;
import de.jeremystartm.pickshadow.api.command.TabCompletion;
import de.jeremystartm.pickshadow.api.translation.LanguageString;
import de.jeremystartm.pickshadow.api.translation.TranslationManager;
import lombok.Getter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
/**
* Handles various social media- and hyperlink-related commands.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class LinkCommand extends CommandBase {
/**
* Contains the tab completion for this command.
*
* @since v1-release0
* -- GETTER --
* Returns the tab completion for this command.
*
* @return tab completion
* @since v1-release0
*/
private final @NotNull TabCompletion completion = StubTabCompletion.completion();
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public LinkCommand() throws IllegalArgumentException {
super("discord", "teamspeak", "mumble", "website");
}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.link")) return;
switch (alias) {
case "website" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_WEBSITE, sender, true));
case "discord", "dc" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_DISCORD, sender, true));
case "teamspeak", "ts" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_TEAMSPEAK, sender, true));
case "mumble" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_MUMBLE, sender, true));
default -> sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true));
}
}
}

View file

@ -0,0 +1,122 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.command.general;
import de.jeremystartm.pickshadow.api.command.CommandBase;
import de.jeremystartm.pickshadow.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.api.command.completion.StubTabCompletion;
import de.jeremystartm.pickshadow.api.command.TabCompletion;
import de.jeremystartm.pickshadow.api.translation.LanguageString;
import de.jeremystartm.pickshadow.api.translation.TranslationManager;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* Handles the {@code /message} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class MessageCommand extends CommandBase {
/**
* Contains the tab completion for this command.
*
* @since v1-release0
* -- GETTER --
* Returns the tab completion for this command.
*
* @return tab completion
* @since v1-release0
*/
private final @NotNull TabCompletion completion = new StaticTabCompletion()
.players("message", 0)
.copy("message", "msg")
.copy("message", "whisper")
.copy("message", "w");
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public MessageCommand() throws IllegalArgumentException {
super("message", "reply");
}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (sender instanceof Player player)
switch (alias) {
case "message", "msg", "whisper", "w" -> {
// Check message length
if (arguments.length < 2) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_FEW_ARGUMENTS, sender, true));
return;
}
Player receiver = Bukkit.getPlayer(arguments[0]);
StringBuilder message = new StringBuilder();
String output;
// Check if receiver is online
if (receiver == null || !receiver.isOnline()) {
player.sendRichMessage(
TranslationManager.get(LanguageString.ERROR_PLAYER_NOT_FOUND, sender, true)
.replace("%player%", arguments[0])
);
return;
}
// Check if the sender is the receiver
if (player.getUniqueId() == ((Player) sender).getUniqueId()) {
player.sendRichMessage(TranslationManager.get(LanguageString.MESSAGING_ERROR_SELF, sender, true));
return;
}
// Convert message
for (int i = 1; i < arguments.length; i++) {
if (!message.isEmpty())
message.append(" ");
message.append(arguments[i]);
}
output = TranslationManager.get(LanguageString.MESSAGING_FORMAT, sender, false)
.replace("%from%", player.getName())
.replace("%to%", receiver.getName())
.replace("%message%", message.toString());
// Send message
player.sendRichMessage(output);
receiver.sendRichMessage(output);
}
case "reply", "r" -> sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true));
}
else
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true));
}
}

View file

@ -0,0 +1,99 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.command.general;
import de.jeremystartm.pickshadow.api.command.CommandBase;
import de.jeremystartm.pickshadow.api.command.completion.StubTabCompletion;
import de.jeremystartm.pickshadow.api.command.TabCompletion;
import de.jeremystartm.pickshadow.api.translation.LanguageString;
import de.jeremystartm.pickshadow.api.translation.TranslationManager;
import lombok.Getter;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
/**
* Handles the {@code /toggledownfall} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class ToggleDownfallCommand extends CommandBase {
/**
* Contains the tab completion for this command.
*
* @since v1-release0
* -- GETTER --
* Returns the tab completion for this command.
*
* @return tab completion
* @since v1-release0
*/
private final @NotNull TabCompletion completion = StubTabCompletion.completion();
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public ToggleDownfallCommand() throws IllegalArgumentException {
super("toggledownfall");
}
/** {@inheritDoc} */
@Override
@SuppressWarnings("resource")
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (!checkPermission(sender, "pickshadow.command.toggledownfall"))
if (sender instanceof Player player) {
try {
ServerLevel level = Objects.requireNonNull(MinecraftServer.getServer().getPlayerList().getPlayer(player.getUniqueId())).serverLevel();
if (player.getWorld().isClearWeather())
level.setWeatherParameters(0, getDuration(), true, false);
else
level.setWeatherParameters(getDuration(), 0, false, false);
sender.sendRichMessage(TranslationManager.get(LanguageString.TOGGLEDOWNFALL, sender, false));
} catch (Exception exception) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNKNOWN, sender, true));
}
} else
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true));
}
/**
* Returns a "random" duration of time
* a clear sky or rain should last.
*
* @return duration
* @since v1-release0
*/
private int getDuration() {
return (int) (System.currentTimeMillis() * System.currentTimeMillis() * System.currentTimeMillis() % Short.MAX_VALUE);
}
}

View file

@ -0,0 +1,64 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.command.general;
import de.jeremystartm.pickshadow.api.command.CommandBase;
import de.jeremystartm.pickshadow.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.api.command.TabCompletion;
import de.jeremystartm.pickshadow.api.command.completion.StubTabCompletion;
import lombok.Getter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
/**
* Handles the {@code /troll} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class TrollCommand extends CommandBase {
/**
* Contains the tab completion for this command.
*
* @since v1-release0
* -- GETTER --
* Returns the tab completion for this command.
*
* @return tab completion
* @since v1-release0
*/
private final @NotNull TabCompletion completion = StubTabCompletion.completion();
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public TrollCommand() throws IllegalArgumentException {
super("troll");
}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {}
}

View file

@ -0,0 +1,78 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.command.survival;
import de.jeremystartm.pickshadow.api.command.CommandBase;
import de.jeremystartm.pickshadow.api.command.completion.StubTabCompletion;
import de.jeremystartm.pickshadow.api.command.TabCompletion;
import de.jeremystartm.pickshadow.api.translation.LanguageString;
import de.jeremystartm.pickshadow.api.translation.TranslationManager;
import lombok.Getter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* Handles the {@code /home} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class HomeCommand extends CommandBase {
/**
* Contains the tab completion for this command.
*
* @since v1-release0
* -- GETTER --
* Returns the tab completion for this command.
*
* @return tab completion
* @since v1-release0
*/
private final @NotNull TabCompletion completion = StubTabCompletion.completion();
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public HomeCommand() throws IllegalArgumentException {
super("home");
}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.home")) return;
if (sender instanceof Player player) {
if (player.getRespawnLocation() == null)
player.sendRichMessage(TranslationManager.get(LanguageString.HOME_NORESPAWN, player, true));
else {
player.teleport(player.getRespawnLocation());
player.setFallDistance(0f);
player.sendRichMessage(TranslationManager.get(LanguageString.HOME_TELEPORTED, player, true));
}
}
}
}

View file

@ -0,0 +1,54 @@
/*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.jeremystartm.pickshadow.listener;
import de.jeremystartm.pickshadow.api.translation.LanguageString;
import de.jeremystartm.pickshadow.api.translation.TranslationManager;
import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.jetbrains.annotations.NotNull;
/**
* Listens on chat events.
*
* @since v1-release0
*/
public final class ChatListener implements Listener {
/**
* Handles chat messages.
*
* @since v1-release0
*/
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void handleChatMessage(@NotNull AsyncChatEvent event) {
event.setCancelled(true);
Bukkit.broadcast(
MiniMessage.miniMessage().deserialize(
TranslationManager.get(LanguageString.CHATMESSAGE_SERVER, event.getPlayer(), false)
.replace("%sender%", event.getPlayer().getName())
).append(MiniMessage.miniMessage().deserialize(MiniMessage.miniMessage().serialize(event.originalMessage()).replace("\\<", "<")))
);
}
}

View file

@ -0,0 +1,84 @@
name: "PSSE"
version: "${version}"
main: "de.jeremystartm.pickshadow.Extension"
description: "Manages PickShadow's subservers"
author: "PickShadow Server Extension Authors"
website: "https://git.staropensource.de/JeremyStarTM/PSSE"
api-version: "${minecraftApi}"
load: POSTWORLD
prefix: "PSSE"
depend:
- "sosenginemc"
- "LuckPerms"
commands:
announce:
description: "Announces a message and broadcasts it to all players on the subserver or the network."
usage: "/announce [--network] <message>"
aliases:
- announcement
- broadcast
- bcast
- bc
clearchat:
description: "Clears the chat for all players on the subserver or the entire network."
usage: "/clearchat [--network]"
aliases:
- chatclear
- cc
psse:
description: "Interface for players and administrators to PSSE and the PickShadow network."
usage: "/psse <license|source|killjvm>"
aliases:
- pickshadow
- server
pssp:
description: "Notifies you that PSSP is no more."
usage: "/pssp"
home:
description: "Teleports you to your respawn point."
usage: "/home"
aliases:
- bed
- tphome
message:
description: "Messages another player."
usage: "/message <player> <message...>"
aliases:
- msg
- whisper
- w
reply:
description: "Messages the last messaged player."
usage: "/reply <message>"
aliases:
- reply
- r
website:
description: "Displays the link to PickShadow's website."
usage: "/website"
aliases:
- web
- www
discord:
description: "Displays the link to PickShadow's Discord server."
usage: "/discord"
aliases:
- dc
teamspeak:
description: "Displays the IP address to PickShadow's TeamSpeak server."
usage: "/teamspeak"
aliases:
- ts
mumble:
description: "Displays the IP address to PickShadow's Mumble server."
usage: "/mumble"
aliases: []
toggledownfall:
description: "A PSSE provided command."
usage: "/toggledownfall"
aliases: []
troll:
description: "Various torturing methods for misbehaving players ;)"
usage: "/troll <TODO>"
aliases: []

View file

@ -0,0 +1,19 @@
git.branch=develop
git.build.host=StarPC
git.build.user.email=jeremystartm@staropensource.de
git.build.user.name=JeremyStarTM
git.build.version=1-alpha0+1.21
git.closest.tag.commit.count=
git.closest.tag.name=
git.commit.id=11a25dd8e97b82ff63b06e0a617cda516a6f814b
git.commit.id.abbrev=11a25dd
git.commit.id.describe=
git.commit.message.full=Add profanity to /clearchat\n
git.commit.message.short=Add profanity to /clearchat
git.commit.time=2024-05-01T09\:56+0000
git.commit.user.email=jeremystartm@staropensource.de
git.commit.user.name=JeremyStarTM
git.dirty=true
git.remote.origin.url=https\://git.staropensource.de/JeremyStarTM/PSSP.git
git.tags=
git.total.commit.count=25

View file

@ -0,0 +1,58 @@
#
# PICKSHADOW SERVER KIT SOURCE FILE
# Copyright (c) 2024 The PickShadow Server Kit Contributors
# Licensed under the GNU Affero General Public License v3
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# Versioning
versioningCodename=Pulsar
versioningVersion=1
versioningType=alpha
versioningTyperelease=0
versioningFork=
# Java
javaSource=22
javaTarget=22
# Dependencies
dependencyLombok=1.18.32
dependencyJetbrainsAnnotations=24.1.0
dependencyStarOpenSourceEngine=1-alpha5
dependencyHikari=4.0.3
dependencyGson=2.11.0
dependencyPaper=R0.1
dependencyAdventure=4.17.0
dependencyLuckPerms=5.4
# Plugins
pluginLombok=8.6
pluginShadow=8.1.7
pluginPaperweight=1.7.3
pluginGitProperties=2.4.2
pluginRunTask=2.3.0
# Minecraft
minecraftVersion=1.21
minecraftApi=1.21
# Plugin download metadata
downloadFreedomChat=x6xcBZtb
downloadEngineMC=https://git.staropensource.de/StarOpenSource/EngineMC/releases/download/v1-alpha1/bukkit.jar
downloadLuckPerms=https://download.luckperms.net/1556/bukkit/loader/LuckPerms-Bukkit-5.4.141.jar
# etc
group = de.staropensource.pickshadow

View file

@ -0,0 +1,33 @@
{
"ERROR_UNKNOWN": "<error>Ein unbekannter Fehler ist aufgetreten. Bitte kontaktiere das Serverteam.</error>",
"ERROR_UNIMPLEMENTED": "<error>Diese Aktion wurde noch nicht implementiert.</error>",
"ERROR_NOT_A_PLAYER": "<error>Ein Spieler ist für diese Aktion benötigt.</error>",
"ERROR_MISSING_PERM": "<error>Dir ist es nicht erlaubt, diese Aktion durchzuführen (%permission% fehlt).</error>",
"ERROR_TOO_FEW_ARGUMENTS": "<error>Zu wenige Argumente.</error>",
"ERROR_TOO_MANY_ARGUMENTS": "<error>Zu viele Argumente.</error>",
"ERROR_INVALID_ARGUMENT": "<error>Ungültige(s) Argument(e) <mention>%argument%</mention>.</error>",
"ERROR_PLAYER_NOT_FOUND": "<error>Der Spieler <mention>%player%</mention> konnte nicht gefunden werden.</error>",
"EXTENSIONCMD_GREETER": "<generic>Dieser Subserver läuft <#d60532><bold>PSSE</bold> \"<italic>%codename%</italic>\" <italic>@ %version% (%commit%, dirty %dirty%)</italic></generic>\n<generic>Führe ein paar Subbefehle aus um mehr Informationen einzusehen.",
"EXTENSIONCMD_KILLJVM": "<generic>Bye bye!",
"EXTENSIONCMD_LICENSE": "<generic>PSSE ist lizensiert unter der <mention>GNU Affero General Public-Lizenz v3</mention>.",
"EXTENSIONCMD_SOURCE": "<generic>Du kannst PickShadow's serverseitigen Code auf <click:open_url:https://git.staropensource.de/JeremyStarTM/PSSE><link>sos!git</link></click> finden.",
"EXTENSIONCMD_ERROR_OLDCMD": "<error>Was ist <mention>PSSP</mention>...?</error>\n<error>Das PickShadow Server Plugin (PSSP) wurde in PickShadow Server <italic>Extension</italic> (PSSE) umbenannt.</error>\n<error>Bitte verwende diesen Namen stattdessen, vielen Dank.</error>",
"LINKS_WEBSITE": "<error>Das PickShadow Netzwerk hat aktuell keine Webseite.</error>",
"LINKS_DISCORD": "<error>Das PickShadow Netzwerk hat aktuell keine Discord Guilde.</error>",
"LINKS_TEAMSPEAK": "<error>Das PickShadow Netzwerk hat aktuell keinen TeamSpeak Server.</error>",
"LINKS_MUMBLE": "<error>Das PickShadow Netzwerk hat aktuell keinen Mumble Server.</error>",
"MESSAGING_ERROR_SELF": "<error>Du kannst dich nicht selber anschreiben.</error>",
"CLEARCHAT_GENERIC": "<generic>Der Chat wurde von %sender% geleert.",
"CLEARCHAT_VOID": "<generic>Der Chat wurde von %sender% ins Void geschubst.",
"CLEARCHAT_SKILLISSUES": "<generic>Der Chat wurde von %sender% aufgrund von Skill Issues der Chatteilnehmer gelöscht.",
"CLEARCHAT_BRAINDAMAGE": "<generic>Um weitverbreitenden Gehirnschaden zu verhinden, hat %sender% den Chat geleert.",
"CLEARCHAT_CRINGE": "<generic>Aufgrund von Massen an Cringe musste %sender% den Chat leeren.",
"HOME_NORESPAWN": "<error>Du hast keinen gültigen Respawnpunkt.</error>\n<error>Stelle sicher, dass dein Bett oder Respawn Anker nicht abgebaut oder behindert ist.</error>",
"TOGGLEDOWNFALL": "Niederschlag umgestellt",
}

View file

@ -0,0 +1,48 @@
{
"PREFIX": "<gradient:#FFFFFF:#A8A8A8>PickShadow</gradient> <#d60532>» </#d60532>",
"PREFIX_NEWLINE": " <#d60532>» </#d60532>",
"TAG_GENERIC_OPEN": "<gold>",
"TAG_GENERIC_CLOSE": "</gold>",
"TAG_ERROR_OPEN": "<red>",
"TAG_ERROR_CLOSE": "</red>",
"TAG_MENTION_OPEN": "<italic>",
"TAG_MENTION_CLOSE": "</italic>",
"TAG_LINK_OPEN": "<blue><underlined>",
"TAG_LINK_CLOSE": "</underlined></blue>",
"ERROR_UNKNOWN": "<error>An unknown error occurred. Please contact the server team.</error>",
"ERROR_UNIMPLEMENTED": "<error>This action is not yet implemented.</error>",
"ERROR_NOT_A_PLAYER": "<error>You must be a player to perform this action.</error>",
"ERROR_MISSING_PERM": "<error>You aren't allowed to perform this action (lacking <mention>%permission%</mention>).</error>",
"ERROR_TOO_FEW_ARGUMENTS": "<error>Too few arguments.</error>",
"ERROR_TOO_MANY_ARGUMENTS": "<error>Too many arguments.</error>",
"ERROR_INVALID_ARGUMENT": "<error>Invalid argument(s) <mention>%argument%</mention>.</error>",
"ERROR_PLAYER_NOT_FOUND": "<error>The player <mention>%player%</mention> could not be found.</error>",
"EXTENSIONCMD_GREETER": "<generic>This subserver is running <#d60532><bold>PSSE</bold> \"<italic>%codename%</italic>\" <italic>@ %version% (%commit%, dirty %dirty%)</italic></generic>\n<generic>To view additional information, invoke some subcommands.",
"EXTENSIONCMD_KILLJVM": "<generic>Bye bye!",
"EXTENSIONCMD_LICENSE": "<generic>PSSE is licensed under the <mention>GNU Affero General Public License v3</mention>.",
"EXTENSIONCMD_SOURCE": "<generic>You can find the source code of PickShadow's server-side code on <click:open_url:https://git.staropensource.de/JeremyStarTM/PSSE><link>sos!git</link></click>.",
"EXTENSIONCMD_ERROR_OLDCMD": "<error>What's <mention>PSSP</mention>...?</error>\n<error>The PickShadow Server Plugin (PSSP) has been renamed into PickShadow Server <italic>Extension</italic> (PSSE).</error>\n<error>Please use this name instead, thank you.</error>",
"LINKS_WEBSITE": "<error>The PickShadow Network doesn't currently have a website.</error>",
"LINKS_DISCORD": "<error>The PickShadow Network doesn't currently have a Discord guild.</error>",
"LINKS_TEAMSPEAK": "<error>The PickShadow Network doesn't currently have a TeamSpeak server.</error>",
"LINKS_MUMBLE": "<error>The PickShadow Network doesn't currently have a Mumble server.</error>",
"MESSAGING_FORMAT": "<generic><bold>%from%</bold> » <bold>%to%</bold> » </generic>%message%",
"MESSAGING_ERROR_SELF": "<error>You can't message yourself.</error>",
"CLEARCHAT_GENERIC": "<generic>The chat has been cleared by %sender%.</generic>",
"CLEARCHAT_VOID": "<generic>The chat has been pushed into the void by %sender%.</generic>",
"CLEARCHAT_SKILLISSUES": "<generic>The chat has been cleared by %sender% due to skill issues of the chat participants.</generic>",
"CLEARCHAT_BRAINDAMAGE": "<generic>To prevent widespread brain damage, the chat has been cleared by %sender%.</generic>",
"CLEARCHAT_CRINGE": "<generic>Due to masses of cringe, %sender% had to clear the chat.</generic>",
"HOME_NORESPAWN": "<error>You do not have a valid respawn point.</error>\n<error>Please make sure your bed or respawn anchor isn't missing or obstructed.</error>",
"HOME_TELEPORTED": "<generic><italic>... woosh ...</italic></generic>",
"TOGGLEDOWNFALL": "Toggled downfall",
"CHATMESSAGE_SERVER": "<mention>%sender%</mention> <#d60532>»</#d60532> ",
}

View file

@ -0,0 +1,58 @@
#
# PICKSHADOW SERVER KIT SOURCE FILE
# Copyright (c) 2024 The PickShadow Server Kit Contributors
# Licensed under the GNU Affero General Public License v3
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# Versioning
versioningCodename=Pulsar
versioningVersion=1
versioningType=alpha
versioningTyperelease=0
versioningFork=
# Java
javaSource=22
javaTarget=22
# Dependencies
dependencyLombok=1.18.32
dependencyJetbrainsAnnotations=24.1.0
dependencyStarOpenSourceEngine=1-alpha5
dependencyHikari=4.0.3
dependencyGson=2.11.0
dependencyPaper=R0.1
dependencyAdventure=4.17.0
dependencyLuckPerms=5.4
# Plugins
pluginLombok=8.6
pluginShadow=8.1.7
pluginPaperweight=1.7.3
pluginGitProperties=2.4.2
pluginRunTask=2.3.0
# Minecraft
minecraftVersion=1.21
minecraftApi=1.21
# Plugin download metadata
downloadFreedomChat=x6xcBZtb
downloadEngineMC=https://git.staropensource.de/StarOpenSource/EngineMC/releases/download/v1-alpha1/bukkit.jar
downloadLuckPerms=https://download.luckperms.net/1556/bukkit/loader/LuckPerms-Bukkit-5.4.141.jar
# etc
group = de.staropensource.pickshadow

Binary file not shown.

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

7
gradlew vendored
View file

@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum

22
gradlew.bat vendored
View file

@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail
@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail

View file

@ -1,32 +0,0 @@
settings:
allow-end: true
warn-on-overload: true
permissions-file: permissions.yml
update-folder: update
plugin-profiling: false
connection-throttle: 4000
query-plugins: true
deprecated-verbose: default
shutdown-message: Server closed
minimum-api: none
use-map-color-cache: true
spawn-limits:
monsters: 70
animals: 10
water-animals: 5
water-ambient: 20
water-underground-creature: 5
axolotls: 5
ambient: 15
chunk-gc:
period-in-ticks: 600
ticks-per:
animal-spawns: 400
monster-spawns: 1
water-spawns: 1
water-ambient-spawns: 1
water-underground-creature-spawns: 1
axolotl-spawns: 1
ambient-spawns: 1
autosave: 6000
aliases: now-in-commands.yml

View file

@ -1,31 +0,0 @@
#!/bin/bash
set -eo pipefail
if [ -z "${TIMEOUT}" ]; then
echo "-> Set \$TIMEOUT"
export "TIMEOUT=1s"
fi
while true; do
clear
echo "-> Removing plugin data"
rm -rfv /tmp/pssp-plugin-data
echo "-> Creating plugin directory"
mkdir -p /tmp/pssp-plugin-data
echo "-> Downloading server"
if [ ! -f "server.jar" ]; then
if ! wget "https://api.purpurmc.org/v2/purpur/1.20.4/latest/download" -O server.jar.tmp; then
echo "-> Failed to download server, exiting"
rm -rf server.jar.tmp
exit 1
fi
mv server.jar.tmp server.jar
fi
echo "-> Starting server"
if java --add-modules=jdk.incubator.vector -jar server.jar nogui --nogui; then
echo "-> Server shut down."
echo " Restarting in ${TIMEOUT}. Press CTRL+C to cancel."
else
echo "-> Server stopped with code ${?}."
echo " Restarting in ${TIMEOUT}. Press CTRL+C to cancel."
fi
sleep "${TIMEOUT}"
done

View file

@ -1 +0,0 @@
eula=true

View file

@ -1,15 +0,0 @@
# Whether FreedomChat should replace player (signed or unsigned) chat with
# system messages. This is what makes chat not reportable.
rewrite-chat: true
# Whether FreedomChat should claim to clients that secure chat is enforced.
# With this set to true, the "Chat messages can't be verified" toast will not
# be shown. This is, in default configurations, unrelated to allowing clients
# not signing their messages join.
claim-secure-chat-enforced: true
# Whether to report the server as secure (disabling chat reporting) to the
# NoChatReports client mod. This displays a green icon on the server list
# screen and if enforce-secure-profiles is disabled the open chat screen
# for users of the client-side mod.
send-prevents-chat-reports-to-client: false

View file

@ -1 +0,0 @@
/tmp/pssp-plugin-data

View file

@ -1,8 +0,0 @@
# bStats collects some data for plugin authors like how many servers are using their plugins.
# To honor their work, you should not disable it.
# This has nearly no effect on the server performance!
# Check out https://bStats.org/ to learn more :)
enabled: false
serverUuid: fuck-analytics
logFailedRequests: false

View file

@ -1,4 +0,0 @@
{
"_header": "spark configuration file - https://spark.lucko.me/docs/Configuration",
"backgroundProfiler": true
}

View file

@ -1,36 +0,0 @@
# Pufferfish Configuration
# Check out Pufferfish Host for maximum performance server hosting: https://pufferfish.host
# Join our Discord for support: https://discord.gg/reZw4vQV9H
# Download new builds at https://ci.pufferfish.host/job/Pufferfish
info:
version: '1.0'
# These values define a entity's maximum lifespan. If an
# entity is in this list and it has survived for longer than
# that number of ticks, then it will be removed. Setting a value to
# -1 disables this feature.
entity_timeouts:
SNOWBALL: -1
LLAMA_SPIT: -1
enable-books: true
enable-suffocation-optimization: true
enable-async-mob-spawning: true
# Optimizes projectile settings
projectile:
max-loads-per-tick: 10
max-loads-per-projectile: 10
# Optimizes entity brains when
# they're far away from the player
dab:
enabled: false
start-distance: 12
max-tick-freq: 20
activation-dist-mod: 8
blacklisted-entities: []
inactive-goal-selector-throttle: false
# Settings for things that don't belong elsewhere
misc:
disable-method-profiler: true
disable-out-of-order-chat: false
tps-catchup: true
allow-end-crystal-respawn: true
sentry-dsn: ''

File diff suppressed because it is too large Load diff

View file

@ -1,62 +0,0 @@
#Minecraft server properties
#Tue Apr 23 17:13:56 CEST 2024
enable-jmx-monitoring=false
rcon.port=25575
level-seed=
enable-command-block=true
gamemode=survival
enable-query=false
generator-settings={}
enforce-secure-profile=false
level-name=world
motd=A Minecraft Server
query.port=25565
pvp=true
generate-structures=true
max-chained-neighbor-updates=1000000
difficulty=easy
network-compression-threshold=256
max-tick-time=60000
require-resource-pack=false
max-players=20
use-native-transport=true
online-mode=true
enable-status=true
allow-flight=false
initial-disabled-packs=
broadcast-rcon-to-ops=true
view-distance=10
resource-pack-prompt=
server-ip=
allow-nether=true
server-port=25565
enable-rcon=false
sync-chunk-writes=true
resource-pack-id=
server-name=Unknown Server
op-permission-level=4
prevent-proxy-connections=false
hide-online-players=false
resource-pack=
entity-broadcast-range-percentage=100
simulation-distance=10
rcon.password=
player-idle-timeout=0
force-gamemode=false
debug=false
rate-limit=0
hardcore=false
white-list=true
broadcast-console-to-ops=true
spawn-npcs=true
spawn-animals=true
log-ips=true
function-permission-level=2
initial-enabled-packs=vanilla
level-type=minecraft\:normal
text-filtering-config=
spawn-monsters=true
enforce-whitelist=false
spawn-protection=16
resource-pack-sha1=
max-world-size=29999984

View file

@ -1,178 +0,0 @@
# This is the main configuration file for Spigot.
# As you can see, there's tons to configure. Some options may impact gameplay, so use
# with caution, and make sure you know what each option does before configuring.
# For a reference for any variable inside this file, check out the Spigot wiki at
# http://www.spigotmc.org/wiki/spigot-configuration/
#
# If you need help with the configuration or have any questions related to Spigot,
# join us at the Discord or drop by our forums and leave a post.
#
# Discord: https://www.spigotmc.org/go/discord
# Forums: http://www.spigotmc.org/
messages:
whitelist: You are not whitelisted on this server!
unknown-command: Unknown command. Type "/help" for help.
server-full: The server is full!
outdated-client: Outdated client! Please use {0}
outdated-server: Outdated server! I'm still on {0}
restart: Server is restarting
advancements:
disable-saving: false
disabled:
- minecraft:story/disabled
world-settings:
default:
below-zero-generation-in-existing-chunks: true
merge-radius:
item: 2.5
exp: 3.0
view-distance: default
simulation-distance: default
mob-spawn-range: 8
item-despawn-rate: 6000
arrow-despawn-rate: 1200
trident-despawn-rate: 1200
zombie-aggressive-towards-villager: true
nerf-spawner-mobs: false
enable-zombie-pigmen-portal-spawns: true
wither-spawn-sound-radius: 0
end-portal-sound-radius: 0
hanging-tick-frequency: 100
thunder-chance: 100000
growth:
cactus-modifier: 100
cane-modifier: 100
melon-modifier: 100
mushroom-modifier: 100
pumpkin-modifier: 100
sapling-modifier: 100
beetroot-modifier: 100
carrot-modifier: 100
potato-modifier: 100
torchflower-modifier: 100
wheat-modifier: 100
netherwart-modifier: 100
vine-modifier: 100
cocoa-modifier: 100
bamboo-modifier: 100
sweetberry-modifier: 100
kelp-modifier: 100
twistingvines-modifier: 100
weepingvines-modifier: 100
cavevines-modifier: 100
glowberry-modifier: 100
pitcherplant-modifier: 100
entity-activation-range:
animals: 32
monsters: 32
raiders: 48
misc: 16
water: 16
villagers: 32
flying-monsters: 32
wake-up-inactive:
animals-max-per-tick: 4
animals-every: 1200
animals-for: 100
monsters-max-per-tick: 8
monsters-every: 400
monsters-for: 100
villagers-max-per-tick: 4
villagers-every: 600
villagers-for: 100
flying-monsters-max-per-tick: 8
flying-monsters-every: 200
flying-monsters-for: 100
villagers-work-immunity-after: 100
villagers-work-immunity-for: 20
villagers-active-for-panic: true
tick-inactive-villagers: true
ignore-spectators: false
entity-tracking-range:
players: 48
animals: 48
monsters: 48
misc: 32
display: 128
other: 64
ticks-per:
hopper-transfer: 8
hopper-check: 1
hopper-amount: 1
hopper-can-load-chunks: false
dragon-death-sound-radius: 0
seed-village: 10387312
seed-desert: 14357617
seed-igloo: 14357618
seed-jungle: 14357619
seed-swamp: 14357620
seed-monument: 10387313
seed-shipwreck: 165745295
seed-ocean: 14357621
seed-outpost: 165745296
seed-endcity: 10387313
seed-slime: 987234911
seed-nether: 30084232
seed-mansion: 10387319
seed-fossil: 14357921
seed-portal: 34222645
seed-ancientcity: 20083232
seed-trailruins: 83469867
seed-trialchambers: 94251327
seed-buriedtreasure: 10387320
seed-mineshaft: default
seed-stronghold: default
hunger:
jump-walk-exhaustion: 0.05
jump-sprint-exhaustion: 0.2
combat-exhaustion: 0.1
regen-exhaustion: 6.0
swim-multiplier: 0.01
sprint-multiplier: 0.1
other-multiplier: 0.0
max-tnt-per-tick: 100
max-tick-time:
tile: 50
entity: 50
verbose: false
settings:
timeout-time: 60
restart-on-crash: true
restart-script: ./start.sh
bungeecord: false
save-user-cache-on-stop-only: false
sample-count: 12
player-shuffle: 0
user-cache-size: 1000
moved-wrongly-threshold: 0.0625
moved-too-quickly-multiplier: 10.0
netty-threads: 4
attribute:
maxHealth:
max: 2048.0
movementSpeed:
max: 2048.0
attackDamage:
max: 2048.0
log-villager-deaths: true
log-named-deaths: true
debug: false
commands:
spam-exclusions:
- /skill
silent-commandblock-console: false
replace-commands:
- setblock
- summon
- testforblock
- tellraw
log: true
tab-complete: 0
send-namespaced: true
players:
disable-saving: false
config-version: 12
stats:
disable-saving: false
forced-stats: {}

View file

@ -1 +1,22 @@
rootProject.name = 'PSSP' /*
* PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit Contributors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
rootProject.name = "PSSE"
include("extension")

View file

@ -1,73 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin;
import de.pickshadow.plugin.classes.Types;
public final class BuildConfiguration {
// Plugin information
// -> Update in plugin.yml and build.gradle when necessary
public static final String pluginName = "PickShadow Server Plugin";
public static final int pluginRelease = 1;
public static final Types.VersionType pluginVersionType = Types.VersionType.ALPHA;
public static final int pluginTyperelease = 2;
public static final String[] pluginAuthors = new String[]{ "JeremyStarTM" };
public static final String[] pluginContributors = new String[]{};
public static final String pluginLicense = "GNU AGPL v3 (or later)";
public static final String pluginSourceCode = "https://git.staropensource.de/JeremyStarTM/PSSP";
// General
public static final boolean shutdownServerOnInitializationFailure = true;
// Contact
public static final String contactName = "JeremyStar™";
public static final String contactEmail = "jeremystartm@staropensource.de";
// Verbose logging
public static final boolean provideVerboseLoggingForSpellingHelpers = false;
public static final boolean provideVerboseLoggingForSpellingCompletions = false;
public static final boolean announceSchedulingActionsInLogIfPlayers = true;
public static final boolean announceSchedulingActionsInLogIfAlone = false;
// Command configuration
// -> /msg & /reply
public static final boolean allowSelfMessaging = false;
// Returns the type as a String
public static String getTypeAsString(boolean technical) {
switch (pluginVersionType) {
case RELEASE -> {
return technical ? "r" : "Release";
}
case RELEASECANDIDATE -> {
return technical ? "rc" : "Release Candidate";
}
case BETA -> {
return technical ? "b" : "Beta";
}
case ALPHA -> {
return technical ? "a" : "Alpha";
}
default -> {
return "invalid";
}
}
}
}

View file

@ -1,7 +0,0 @@
package de.pickshadow.plugin;
public class GitHead {
public static String commitSha = "<unknown>";
public static String commitShaShort = "<unknown>";
public static String commitMessage = "<unknown>";
}

View file

@ -1,115 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.base;
import de.pickshadow.plugin.BuildConfiguration;
import de.pickshadow.plugin.classes.logger.LoggerInstanceImpl;
import de.pickshadow.plugin.classes.logger.implementations.ExtendedBukkitLogger;
import de.pickshadow.plugin.loaders.ConfigLoader;
import de.pickshadow.plugin.loaders.PlayerDataLoader;
import de.pickshadow.plugin.utils.SpellingHelper;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
public final class Main extends JavaPlugin {
// Ensure safety
private boolean failed = false;
private boolean preinitialized = false;
private boolean initialized = false;
private LoggerInstanceImpl logger;
// Initialize classes
@Override
public void onLoad() {
// Check operating system
if (!System.getProperty("os.name").contains("Linux")) {
failed = true;
if (BuildConfiguration.shutdownServerOnInitializationFailure) {
Bukkit.shutdown();
}
throw new IllegalStateException("Invalid operating system '" + System.getProperty("os.name") + "'. PSSP only supports Linux-based operating systems.");
}
// Update ObjHolder
ObjHolder.main = this;
ObjHolder.logger = new ExtendedBukkitLogger();
ObjHolder.spellingHelper = new SpellingHelper();
ObjHolder.configLoader = new ConfigLoader();
ObjHolder.playerDataLoader = new PlayerDataLoader();
ObjHolder.pluginInitializer = new PluginInitializer();
ObjHolder.scheduler = new Scheduler();
// Initialize objects
logger = ObjHolder.logger.getInstance(getClass());
logger.diag("Finished onLoad()");
preinitialized = true;
}
// Initialize plugin
@Override
public void onEnable() {
if (failed || !preinitialized) {
if (BuildConfiguration.shutdownServerOnInitializationFailure) {
Bukkit.shutdown();
}
throw new IllegalStateException("Preinitialization failed already, unable to execute onEnable method.");
} else if (logger == null) {
failed = true;
if (BuildConfiguration.shutdownServerOnInitializationFailure) {
Bukkit.shutdown();
}
throw new IllegalStateException("Logger is equal to null, unable to execute onEnable method.");
}
logger.diag("Called onEnable()");
// Invoke PluginInitializer
logger.verb("Invoking pluginInitializer.initialize()");
String error = ObjHolder.pluginInitializer.initialize();
if (!error.isEmpty()) {
// Could not initialize, throw error
failed = true;
throw new IllegalStateException("Could not initialize plugin: " + error);
}
logger.diag("Finished onEnable()");
initialized = true;
}
// Shutdown plugin
@Override
public void onDisable() {
if (failed || !initialized) {
throw new IllegalStateException("Initialization failed, unable to uninitialize for safety reasons.");
} else if (logger == null) {
if (BuildConfiguration.shutdownServerOnInitializationFailure) {
Bukkit.shutdown();
}
throw new IllegalStateException("Logger is equal to null, unable to execute onDisable method.");
}
logger.diag("Called onDisable()");
// Invoke PluginInitializer
logger.verb("Invoking pluginInitializer.uninitialize()");
ObjHolder.pluginInitializer.uninitialize();
logger.diag("Finished onDisable()");
}
}

View file

@ -1,46 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.base;
import de.pickshadow.plugin.classes.logger.LoggerImpl;
import de.pickshadow.plugin.loaders.ConfigLoader;
import de.pickshadow.plugin.classes.Configuration;
import de.pickshadow.plugin.loaders.PlayerDataLoader;
import de.pickshadow.plugin.utils.SpellingHelper;
public class ObjHolder {
/*
This class only holds references to various non-static objects.
This class is intended to ease development and prevent sharing
objects around classes.
*/
// Plugin management
public static Main main;
public static PluginInitializer pluginInitializer;
public static Scheduler scheduler;
// Utility classes
public static LoggerImpl logger;
public static SpellingHelper spellingHelper;
// Loaders
public static ConfigLoader configLoader;
public static PlayerDataLoader playerDataLoader;
// Configuration
public static Configuration config;
}

View file

@ -1,116 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.base;
import de.pickshadow.plugin.classes.CommandBase;
import de.pickshadow.plugin.classes.logger.LoggerInstanceImpl;
import de.pickshadow.plugin.commands.*;
import de.pickshadow.plugin.loaders.ConfigLoader;
import de.pickshadow.plugin.listeners.ChatMessageOverrideListener;
import de.pickshadow.plugin.listeners.JoinLeaveMessagesListener;
import de.pickshadow.plugin.utils.SpellingHelper;
import org.bukkit.Bukkit;
import java.util.UUID;
public class PluginInitializer {
// Objects
private final LoggerInstanceImpl logger;
// Lists
CommandBase[] commands = new CommandBase[0];
public PluginInitializer() {
logger = ObjHolder.logger.getInstance(getClass());
}
public String initialize() {
logger.info("Initializing PSSP");
// Load configuration file
logger.verb("Loading configuration");
ObjHolder.configLoader = new ConfigLoader();
ObjHolder.config = ObjHolder.configLoader.loadConfig();
if (ObjHolder.config == null) {
return "configLoader.loadConfig() returned null";
}
// Extract spelling files
logger.verb("Extracting spelling files");
ObjHolder.spellingHelper = new SpellingHelper();
String errorExtractFiles = ObjHolder.spellingHelper.extractFiles();
if (!errorExtractFiles.isEmpty()) {
return "Could not extract spelling files: " + errorExtractFiles;
}
// Update spelling language
logger.verb("Updating spelling language");
if (!ObjHolder.spellingHelper.setActiveLanguage(ObjHolder.config.defaultSpellingLanguage)) {
return "Could not update active spelling language";
}
// Initialize commands
logger.verb("Initializing commands");
commands = new CommandBase[]{new BroadcastCommand(), new DiscordCommand(), new HomeCommand(), new PluginCommand(), new SystemInformationCommand(), new TrollCommand(), new MsgCommand(), new ClearChatCommand(), new ToggleDownfallCommand()};
// Register commands
logger.verb("Registering commands");
try {
for (CommandBase command : commands) command.registerCommand();
} catch (NullPointerException e) {
logger.crash("Could not register plugin commands", e.getStackTrace());
}
// Register listeners
logger.verb("Registering listeners");
logger.diag("Registering ChatMessageOverrideListener");
Bukkit.getServer().getPluginManager().registerEvents(new ChatMessageOverrideListener(), ObjHolder.main);
logger.diag("Registering JoinLeaveMessagesListener");
Bukkit.getServer().getPluginManager().registerEvents(new JoinLeaveMessagesListener(), ObjHolder.main);
// Setup scheduler
logger.diag("Initializing scheduler");
ObjHolder.scheduler.initializeScheduler();
logger.info("Initialized PSSP");
return "";
}
public void uninitialize() {
logger.info("Uninitializing PSSP");
// Close active hunspell instance
logger.verb("Closing Hunspell instance");
ObjHolder.spellingHelper.setActiveLanguage(null);
// Save player data
logger.verb("Saving player data");
for (UUID uuid : ObjHolder.playerDataLoader.getLoadedUUIDs()) ObjHolder.playerDataLoader.savePlayerData(uuid);
// Unregister commands
logger.verb("Unregistering commands");
try {
for (CommandBase command : commands) command.unregisterCommand();
} catch (NullPointerException e) {
logger.crash("Could not unregister plugin commands", e.getStackTrace(), true);
}
logger.info("Uninitialized PSSP");
}
}

View file

@ -1,95 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.base;
import de.pickshadow.plugin.BuildConfiguration;
import de.pickshadow.plugin.classes.Configuration;
import de.pickshadow.plugin.classes.Types;
import de.pickshadow.plugin.classes.logger.LoggerInstanceImpl;
import de.pickshadow.plugin.utils.Miscellaneous;
import org.bukkit.Bukkit;
import java.util.UUID;
public class Scheduler {
LoggerInstanceImpl logger;
// Keeps track of running bukkit scheduler tasks
private int taskIdMinutely = 0;
private int taskIdHourly = 0;
public void initializeScheduler() {
logger = ObjHolder.logger.getInstance(getClass());
logger.verb("Initializing scheduler");
taskIdMinutely = Bukkit.getScheduler().runTaskLater(ObjHolder.main, this::runMinuteTasks, 1200L).getTaskId();
taskIdHourly = Bukkit.getScheduler().runTaskLater(ObjHolder.main, this::runHourTasks, 72000L).getTaskId();
}
public void executeScheduler(Types.SchedulerType type) {
switch (type) {
case MINUTELY:
Bukkit.getScheduler().cancelTask(taskIdMinutely);
runMinuteTasks();
break;
case HOURLY:
Bukkit.getScheduler().cancelTask(taskIdHourly);
runHourTasks();
}
}
public void runMinuteTasks() {
// Print announcement
printTaskAnnouncement("minutely");
// Save player data
for (UUID uuid : ObjHolder.playerDataLoader.getLoadedUUIDs()) ObjHolder.playerDataLoader.savePlayerData(uuid);
// Schedule
taskIdMinutely = Bukkit.getScheduler().runTaskLater(ObjHolder.main, this::runMinuteTasks, 1200L).getTaskId();
}
public void runHourTasks() {
// Print announcement
printTaskAnnouncement("hourly");
// Reload configuration file
Configuration newConfig = ObjHolder.configLoader.loadConfig();
if (newConfig == null) {
logger.error("Unable to reload configuration file automatically");
} else {
ObjHolder.config = newConfig;
}
// Run garbage collection (old gen gc)
Miscellaneous.threadedGc();
// Schedule
taskIdHourly = Bukkit.getScheduler().runTaskLater(ObjHolder.main, this::runHourTasks, 72000L).getTaskId();
}
private void printTaskAnnouncement(String timeframe) {
if (Bukkit.getOnlinePlayers().isEmpty() && !BuildConfiguration.announceSchedulingActionsInLogIfAlone) return;
if (!Bukkit.getOnlinePlayers().isEmpty() && !BuildConfiguration.announceSchedulingActionsInLogIfPlayers) return;
logger.diag("Running " + timeframe + " tasks");
}
}

View file

@ -1,132 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.base;
import de.pickshadow.plugin.BuildConfiguration;
import de.pickshadow.plugin.GitHead;
import java.util.Arrays;
public class Translation {
// Global
public static String GLOBAL_PREFIX = "<dark_gray>[<BRANDING>PickShadow<BRANDING_END><dark_gray>] <reset>";
public static String GLOBAL_EXCEPTION = "Ein Fehler ist während der Ausführung des Befehls aufgetreten. Bitte sende eine E-Mail an " + BuildConfiguration.contactName + " (" + BuildConfiguration.contactEmail + ") mit allen relevanten Details für die Fehlerbehebung.";
public static String GLOBAL_NOT_ENOUGH_ARGUMENTS = "Zu wenig Argumente. Syntax: <HIGHLIGHT>%usage%";
public static String GLOBAL_INVALID_ARGUMENT = "Ungültiges Argument. Syntax: <HIGHLIGHT>%usage%";
public static String GLOBAL_NOT_A_PLAYER = "Die Serverkonsole kann diesen Aktion nicht ausführen.";
public static String GLOBAL_PLAYER_NOT_ONLINE = "Der Spieler <HIGHLIGHT>%player% <reset>ist nicht online.";
// Player data-related
public static String PLAYERDATA_LOAD_FAILED = "Deine Spielerdaten konnten nicht geladen werden.\nBitte sende eine E-Mail an " + BuildConfiguration.contactName + " (" + BuildConfiguration.contactEmail + ").\n\n==== Es folgen Debugginginformationen ====\nUUID: %uuid%\nError:\n%error%\nPlayer data loader version: " + ObjHolder.playerDataLoader.playerDataVersion + "\nPSSP version:\n-> Release: " + BuildConfiguration.pluginRelease + "\n-> Type: " + BuildConfiguration.pluginVersionType.name() + "\n-> Typerelease: " + BuildConfiguration.pluginTyperelease;
public static String PLAYERDATA_RELOAD_FAILED = "Deine Spielerdaten konnten nicht neugeladen werden.\nBitte sende eine E-Mail an " + BuildConfiguration.contactName + " (" + BuildConfiguration.contactEmail + ").\n\n==== Es folgen Debugginginformationen ====\nUUID: %uuid%\nError:\n%error%\nPlayer data loader version: " + ObjHolder.playerDataLoader.playerDataVersion + "\nPSSP version:\n-> Release: " + BuildConfiguration.pluginRelease + "\n-> Type: " + BuildConfiguration.pluginVersionType.name() + "\n-> Typerelease: " + BuildConfiguration.pluginTyperelease;
// Events
public static String EVENT_JOIN = "<HIGHLIGHT>%player% <reset>ist dem Server beigetreten.";
public static String EVENT_LEAVE = "<HIGHLIGHT>%player% <reset>hat den Server verlassen.";
// Command: /pssp
public static String PLUGINCOMMAND_INFO = "<#d60532><bold>PickShadow Server Plugin v" + BuildConfiguration.pluginRelease + "-" + BuildConfiguration.getTypeAsString(true) + BuildConfiguration.pluginTyperelease + "</bold> (commit <bold><italic>" + GitHead.commitShaShort + "</italic></bold>)\n" +
"Entwickelt von <bold>" + Arrays.toString(BuildConfiguration.pluginAuthors).replace("[", "").replace("]", "") + " & Beitragenden</bold>.\n" +
"Der Quellcode ist unter der <bold>" + BuildConfiguration.pluginLicense + " Lizenz </bold>lizensiert und kann <underlined><click:open_url:" + BuildConfiguration.pluginSourceCode + ">hier</click></underlined> gefunden werden.";
public static String PLUGINCOMMAND_RELOAD_CONFIG = "Die Konfigurationsdatei wird neugeladen, einen Moment bitte...";
public static String PLUGINCOMMAND_RELOAD_CONFIG_SUCCESS = "Die Konfigurationsdatei wurde erfolgreich neugeladen.";
public static String PLUGINCOMMAND_RELOAD_CONFIG_FAIL = "Die Konfigurationsdatei konnte nicht neugeladen werden, siehe bitte die Serverkonsole ein für mehr Informationen.\nWarnung: Starte den Server NICHT neu oder dieser wird nicht wieder starten!";
public static String PLUGINCOMMAND_RELOAD_DATA = "Alle Spielerdaten werden neugeladen, einen Moment bitte...";
public static String PLUGINCOMMAND_RELOAD_DATA_SUCCESS = "Alle Spielerdaten wurden erfolgreich neugeladen.";
public static String PLUGINCOMMAND_RELOAD_DATA_FAIL = "Nicht alle Spielerdaten konnten erfolgreich neugeladen werden, folgende UUIDs sind betroffen:\n%uuids%";
public static String PLUGINCOMMAND_GARBAGECOLLECT = "Starte Garbage Collector, der Server könnte für ein paar Millisekunden einfrieren.";
public static String PLUGINCOMMAND_GARBAGECOLLECT_FINISHED = "Der Garbage Collector wurde gestartet und hat erfolgreich den Arbeitsspeicher entleert.";
public static String PLUGINCOMMAND_SCHEDULER = "Der Scheduler \"%timeframe%\" wurde gestartet und führt seine Hintergrundaufgaben aus, bitte warten.";
public static String PLUGINCOMMAND_SCHEDULER_DONE = "Der Scheduler \"%timeframe%\" wurde ausgeführt. Für eventuelle Fehler gucken sie sich bitte die Serverkonsole an.";
public static String PLUGINCOMMAND_PLAYERINFO = "Deine Spielerinformationen:\n%playerdata%";
// Command: /sysinfo
public static String SERVERINFO_SYSTEMINFO = """
<bold>Systeminformationen</bold>
Arbeitsspeicher (frei): <HIGHLIGHT>%mem_free%<reset>
Arbeitsspeicher (verwendet): <HIGHLIGHT>%mem_used%<reset>
Arbeitsspeicher (verfügbar): <HIGHLIGHT>%mem_usable%<reset>
Arbeitsspeicher (maximum): <HIGHLIGHT>%mem_max%<reset>
Ticks Pro Sekunde (TPS): <HIGHLIGHT>%tps%<reset>
Millisekunden pro Tick (MSPT): <HIGHLIGHT>%mspt%""";
public static String SERVERINFO_MEMORY = """
<bold>Arbeitsspeichernutzung</bold>
Arbeitsspeicher (frei): <HIGHLIGHT>%mem_free%<reset>
Arbeitsspeicher (verwendet): <HIGHLIGHT>%mem_used%<reset>
Arbeitsspeicher (verfügbar): <HIGHLIGHT>%mem_usable%<reset>
Arbeitsspeicher (maximum): <HIGHLIGHT>%mem_max%<reset>
""";
public static String SERVERINFO_PERF = """
<bold>Performancestatistiken</bold>
Ticks Pro Sekunde (TPS): <HIGHLIGHT>%tps%<reset>
Millisekunden pro Tick (MSPT): <HIGHLIGHT>%mspt%""";
// Command: /home
public static String HOME_TELEPORT = "Du wurdest zu deinem Bett teleportiert.";
public static String HOME_MISSING = "Es wurde kein Respawnpunkt gefunden. Entweder wurde dein Bett oder Respawnanker abgebaut, wurde noch nie platziert oder der Respawnpunkt ist blockiert.";
// Command: /discord
public static String DISCORD_INVITE = "Du kannst den Discord Server über diesen Link beitreten: <HIGHLIGHT>%invite%";
public static String DISCORD_UNAVAILABLE = "Es gibt aktuell noch keinen Discord Server.";
// Command: /troll
public static String TROLL_DEMO = "<HIGHLIGHT>%target%<reset> wird jetzt der Demobildschirm angezeigt.";
public static String TROLL_CREDITS = "<HIGHLIGHT>%target%<reset> werden jetzt die Credits angezeigt.";
public static String TROLL_GUARDIAN = "<HIGHLIGHT>%target%<reset> sieht jetzt einen Elder Guardian.";
public static String TROLL_HACK = "<HIGHLIGHT>%target%<reset> wird jetzt gehackt.";
public static String TROLL_MALWARE = "<HIGHLIGHT>%target%<reset> wird jetzt mit Malware infiziert.";
public static String TROLL_MALWARE_PERCENT = "<red>Extracting virus to disk (%percent%% complete)";
public static String TROLL_MALWARE_INFECTED = "<red>>>> DeStR Virus installed successfully <<<";
public static String TROLL_MALWARE_PASSWORDS = "<red>>>> Sending passwords to C&C Server <<<";
public static String TROLL_MALWARE_BANKING = "<red>>>> Transferring 1000€ to bank account <<<";
public static String TROLL_MALWARE_HACKED = "<red>>>> Hacked machine successfully <<<";
public static String TROLL_CREEPER = "<HIGHLIGHT>%target%<reset> hört jetzt einen Creeper.";
public static String TROLL_HEAVENS = "<HIGHLIGHT>%target%<reset> ist nun im Himmel.";
public static String TROLL_CRASH = "<HIGHLIGHT>%target%<reset>'s Minecraft ist soeben abgestürzt. Oops...";
// Command: /msg
public static String MSG_NO_SELF_MESSAGING = "Seit wann kann man sich denn selber anschreiben?";
public static String MSG_NO_LAST_MESSAGED_PLAYER = "Du scheinst keinen Spieler in der letzten Zeit angeschrieben zu haben.";
public static String MSG_TO = "<gold><bold>%reciever% <reset><gold>« <bold>%sender% <reset><gold>» <reset>%message%";
public static String MSG_FROM = "<gold><bold>%reciever% <reset><gold>» <bold>%sender% <reset><gold>» <reset>%message%";
// Command: /clearchat
public static String CLEARCHAT = "Der Chat wurde von %sender% geleert.";
public static String[] CLEARCHAT_CURSES = new String[]{
"Der Chat wurde von %sender% gemolken.",
"Der Chat wurde von %sender% gegessen.",
"Der Chat wurde von %sender% ins nichts gebumbst.",
"Der Chat wurde von %sender% ins Void geschubst.",
"Der Chat wurde von %sender% in die Mülltonne geworfen.",
"Der Chat wurde aufgrund von Skill Issues von Chatteilnehmern von %sender% gelöscht.",
"Der Chat wurde aufgrund von übermäßigem Cringe von %sender% gelöscht.",
"\"You shall not pass!\" wurde von %sender% ausgerufen!",
"%sender% hasst euch alle und hat daher den Chatverlauf gelöscht.",
"%sender% hat die Chattoilette ordentlich gespült!",
"%sender% hat den Gartenschlauch auf den Chat gerichtet.",
"Alle Nachrichten des Chats sind auf den Boden gefallen, weil %sender% ihn angerempelt hat."
};
// Command: /toggledownfall
public static String TOGGLEDOWNFALL = "Der Niederschlag wurde umgestellt.";
}

View file

@ -1,70 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.classes;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.logger.LoggerInstanceImpl;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public abstract class CommandBase implements CommandExecutor {
// Objects
protected final LoggerInstanceImpl logger;
// Command properties
protected String[] commandNames = new String[0];
// Constructor
public CommandBase() {
logger = ObjHolder.logger.getInstance(this.getClass());
}
// Registration
public void registerCommand() throws NullPointerException {
for (String commandName : commandNames) {
logger.diag("Registering command /" + commandName + " (" + this.getClass().getName().replace(this.getClass().getPackageName() + ".", "") + ")");
Objects.requireNonNull(Bukkit.getPluginCommand(commandName)).setExecutor(this);
Objects.requireNonNull(Bukkit.getPluginCommand(commandName)).setTabCompleter(this.getCompletion());
}
}
public void unregisterCommand() throws NullPointerException {
for (String commandName : commandNames) {
logger.diag("Unregistering command /" + commandName + " (" + this.getClass().getName().replace(this.getClass().getPackageName() + ".", "") + ")");
Objects.requireNonNull(Bukkit.getPluginCommand(commandName)).setExecutor(null);
Objects.requireNonNull(Bukkit.getPluginCommand(commandName)).setTabCompleter(null);
}
}
// Command code (from Bukkit, handled internally)
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
getCommand(new Interactable(sender), command, label, args);
return true;
}
// Command code (abstracted)
public abstract void getCommand(@NotNull Interactable intact, @NotNull Command command, @NotNull String label, @NotNull String[] args);
// Command completion
public abstract TabCompleter getCompletion();
}

View file

@ -1,28 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.classes;
public class Configuration {
public int version = -1;
public boolean enablePrefix = false;
public String inviteLink = "";
public String defaultSpellingLanguage = "de_DE";
public boolean useOldMcTranslationForToggleDownfall = true;
public boolean allowChatClearMessageWithProfanity = true;
}

View file

@ -1,140 +0,0 @@
package de.pickshadow.plugin.classes;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.exceptions.NotAPlayerException;
import de.pickshadow.plugin.utils.Miscellaneous;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.WeatherType;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Locale;
import java.util.UUID;
public class Interactable {
// Data
private UUID uuid;
private Player player;
private boolean isConsole;
// Constructors
public Interactable(@NotNull UUID uuid) {
this.uuid = uuid;
isConsole = false;
}
public Interactable(@NotNull Player player) {
uuid = player.getUniqueId();
this.player = player;
isConsole = false;
}
public Interactable(@NotNull CommandSender sender) {
if (sender instanceof ConsoleCommandSender) {
isConsole = true;
} else {
player = (Player) sender;
uuid = player.getUniqueId();
}
}
// Getters
public boolean isConsole() {
return isConsole;
}
public UUID getUniqueId() throws NotAPlayerException {
if (isConsole) throw new NotAPlayerException();
return uuid;
}
public boolean hasPermission(Permission permission) {
if (isConsole) return true;
else return player.hasPermission(permission);
}
public boolean hasPermission(String permission) {
if (isConsole) return true;
else return player.hasPermission(permission);
}
public String getClientBrand() {
if (isConsole) return "tty";
else return player.getClientBrandName();
}
public Component getDisplayName() {
if (isConsole) return Miscellaneous.format("<BRANDING>", Types.FormatType.NONE);
else return player.displayName();
}
public Locale getLocale() {
if (isConsole) return Locale.US;
else return player.locale();
}
public String getName() {
if (isConsole) return "CONSOLE";
else return player.getName();
}
public int getPing() {
if (isConsole) return 0;
else return player.getPing();
}
public WeatherType getWeather() throws NotAPlayerException {
if (isConsole) throw new NotAPlayerException();
else {
if (player.getWorld().isClearWeather()) return WeatherType.CLEAR;
else if (player.getWorld().isThundering()) return WeatherType.DOWNFALL;
else {
ObjHolder.logger.crash(getClass(), "Invalid weather type (not clear or downfall)");
return null;
}
}
}
public Location getRespawnLocation() {
if (isConsole) return new Location(Bukkit.getWorlds().get(0), 0, -64, 0);
else return player.getRespawnLocation();
}
public float getFallDistance() {
if (isConsole) return 0f;
else return player.getFallDistance();
}
public World getWorld() throws NotAPlayerException {
if (isConsole) throw new NotAPlayerException();
else return player.getWorld();
}
// Setters
public void setDisplayName(@Nullable Component name) {
if (!isConsole) player.displayName(name);
}
public void setRespawnLocation(@NotNull Location location) {
setRespawnLocation(location, false);
}
public void setRespawnLocation(@NotNull Location location, boolean force) {
if (!isConsole) player.setRespawnLocation(location, force);
}
public void setFallDistance(float fallDistance) {
if (!isConsole) player.setFallDistance(fallDistance);
}
// Other methods
public void message(Component message) {
if (isConsole) Bukkit.getConsoleSender().sendMessage(message);
else player.sendMessage(message);
}
public void message(String message) {
message(MiniMessage.miniMessage().deserialize(message));
}
public void sudo(String chatMessage) {
if (isConsole) Bukkit.dispatchCommand(Bukkit.getConsoleSender(), chatMessage);
else player.chat(chatMessage);
}
public void teleport(Entity entity) {
teleport(entity.getLocation());
}
public void teleport(Location location) {
if (!isConsole) player.teleport(location);
}
}

View file

@ -1,90 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.classes;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.exceptions.NotAPlayerException;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
public class PlayerData {
// Player data
public int version = 0;
public UUID playerId = null;
public long firstPlayed = 0;
public long lastPlayed = 0;
public UUID lastMessagedPlayer = null;
// Constructors
public PlayerData(@NotNull UUID uuid) {
playerId = uuid;
}
public PlayerData(@NotNull String name) {
playerId = Bukkit.getPlayerUniqueId(name);
}
public PlayerData(@NotNull Player player) {
playerId = player.getUniqueId();
}
public PlayerData(@NotNull Interactable intact) throws NotAPlayerException {
playerId = intact.getUniqueId();
}
// Used for loading player data off disk
@ApiStatus.Internal
public PlayerData() {}
// Convert data into config string
public String convertToConfig() {
return "##############################\n" +
"## PickShadow Server Plugin ##\n" +
"## Player data file ##\n" +
"##############################\n" +
"### DO NOT REMOVE THESE LINES OR THIS PLUGIN WILL BREAK ###\n" +
"!!de.pickshadow.plugin.classes.PlayerData\n" +
"version: " + version + "\n" +
"playerId: " + playerId + "\n" +
"### DO NOT REMOVE THESE LINES OR THIS PLUGIN WILL BREAK ###\n" +
"\n" +
"firstPlayed: " + firstPlayed + "\n" +
"lastPlayed: " + lastPlayed + "\n" +
"lastMessagedPlayer: " + lastMessagedPlayer;
}
// Convert data into debuggable string
public String convertToString() {
StringBuilder string = new StringBuilder();
boolean stringEmpty = true;
for (String var : new String[]{ "version", "playerId", "firstPlayed", "lastPlayed", "lastMessagedPlayer" }) {
if (stringEmpty) {
stringEmpty = false;
} else {
string.append("\n");
}
try {
string.append(var).append("=").append(this.getClass().getField(var).get(this));
} catch (NoSuchFieldException | IllegalAccessException e) {
ObjHolder.logger.crash(getClass(), "Couldn't convert player data for UUID '" + playerId + "' to string: Got exception: " + e.getMessage(), e.getStackTrace());
}
}
return string.toString();
}
}

View file

@ -1,26 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.classes;
public class Types {
public enum VersionType { RELEASE, RELEASECANDIDATE, BETA, ALPHA }
public enum LoggerLevel { ERROR, WARN, INFO, VERB, DIAG }
public enum FormatType { NONE, ERROR, NORMAL }
public enum SchedulerType { MINUTELY, HOURLY }
}

View file

@ -1,7 +0,0 @@
package de.pickshadow.plugin.classes.exceptions;
public class NotAPlayerException extends Exception {
public NotAPlayerException() {
super();
}
}

View file

@ -1,132 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.classes.logger;
import de.pickshadow.plugin.BuildConfiguration;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.Types;
import de.pickshadow.plugin.utils.Miscellaneous;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
// Logger base class implementing SOSLS version 1
public abstract class LoggerImpl {
// Configuration
public Types.LoggerLevel configLoggerLevel = Types.LoggerLevel.INFO;
public String configFormat = "[%level% %origin%] %message%";
// Instancing
public LoggerInstanceImpl getInstance(@NotNull Class<?> callerClass) {
return new LoggerInstanceImpl(this, callerClass);
}
// Abstract log functions
protected abstract void log(@NotNull Types.LoggerLevel level, @NotNull Class<?> callerClass, @NotNull String message);
public abstract void logCrash(String crashMessage);
// log() callers
public void diag(@NotNull Class<?> callerClass, @NotNull String message) {
log(Types.LoggerLevel.DIAG, callerClass, message);
}
public void verb(@NotNull Class<?> callerClass, @NotNull String message) {
log(Types.LoggerLevel.VERB, callerClass, message);
}
public void info(@NotNull Class<?> callerClass, @NotNull String message) {
log(Types.LoggerLevel.INFO, callerClass, message);
}
public void warn(@NotNull Class<?> callerClass, @NotNull String message) {
log(Types.LoggerLevel.WARN, callerClass, message);
}
public void error(@NotNull Class<?> callerClass, @NotNull String message) {
log(Types.LoggerLevel.ERROR, callerClass, message);
}
// Crash reporter
public void crash(@NotNull Class<?> callerClass, @NotNull String message) {
crash(callerClass, message, null, false);
}
public void crash(@NotNull Class<?> callerClass, @NotNull String message, boolean softCrash) {
crash(callerClass, message, null, softCrash);
}
public void crash(@NotNull Class<?> callerClass, @NotNull String message, StackTraceElement[] stackTrace) {
crash(callerClass, message, stackTrace, false);
}
public void crash(@NotNull Class<?> callerClass, @NotNull String message, StackTraceElement[] stackTrace, boolean softCrash) {
String crashMessage = "Generating crash report...\n";
crashMessage += "##################\n";
crashMessage += " PSSP crashed\n";
crashMessage += "++++++++++++++++++\n";
crashMessage += "Crash\n";
crashMessage += " -> Caller: " + getCallerInfo(callerClass).get("package.name") + "\n";
crashMessage += " -> Message: " + message + "\n";
crashMessage += "\n";
crashMessage += "PickShadow Server Plugin\n";
crashMessage += " -> Version: " + ObjHolder.main.getPluginMeta().getVersion() + "\n";
crashMessage += " -> API Version: " + ObjHolder.main.getPluginMeta().getAPIVersion() + "\n";
crashMessage += " -> Dependencies (hard): " + ObjHolder.main.getPluginMeta().getPluginDependencies() + "\n";
crashMessage += " -> Dependencies (soft): " + ObjHolder.main.getPluginMeta().getPluginSoftDependencies() + "\n";
crashMessage += " -> Authors: " + ObjHolder.main.getPluginMeta().getAuthors() + "\n";
crashMessage += " -> Contributors: " + ObjHolder.main.getPluginMeta().getContributors() + "\n";
crashMessage += "\n";
crashMessage += "Minecraft\n";
crashMessage += " -> Version: " + Bukkit.getMinecraftVersion() + "\n";
crashMessage += "\n";
crashMessage += "Server software\n";
crashMessage += " -> Name: " + Bukkit.getName() + "\n";
crashMessage += " -> Version: " + Bukkit.getVersion() + "\n";
crashMessage += "\n";
crashMessage += "Stack trace\n";
if (stackTrace == null) {
crashMessage += " -> No stack trace available\n";
} else {
crashMessage += Miscellaneous.convertStacktraceToString(stackTrace) + "\n";
}
crashMessage += "++++++++++++++++++\n";
crashMessage += " PSSP crashed\n";
crashMessage += "##################";
if (softCrash) {
crashMessage += "\nNote: Crash is soft, will not bring down server.";
}
logCrash(crashMessage);
if (!softCrash) Miscellaneous.shutdownPlugin();
}
// Utils
public boolean isLevelAllowed(@NotNull Types.LoggerLevel level) {
return configLoggerLevel.compareTo(level) <= 0;
}
public HashMap<String, String> getCallerInfo(@NotNull Class<?> callerClass) {
HashMap<String, String> callerInfo = new HashMap<>();
callerInfo.put("name", callerClass.getName().replace(callerClass.getPackage() + ".", ""));
callerInfo.put("package", String.valueOf(callerClass.getPackage()));
callerInfo.put("package.name", callerClass.getName());
return callerInfo;
}
public String getFinalFormat(@NotNull Types.LoggerLevel level, @NotNull Class<?> callerClass, @NotNull String message) {
return configFormat
.replace("%plugin%", BuildConfiguration.pluginName)
.replace("%level%", level.name())
.replace("%origin%", getCallerInfo(callerClass).get("package.name"))
.replace("%message%", message);
}
}

View file

@ -1,59 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.classes.logger;
import org.jetbrains.annotations.NotNull;
public class LoggerInstanceImpl {
private final LoggerImpl logger;
private final Class<?> callerClass;
public LoggerInstanceImpl(LoggerImpl newLogger, Class<?> newCallerClass) {
logger = newLogger;
callerClass = newCallerClass;
}
public void diag(@NotNull String message) {
logger.diag(callerClass, message);
}
public void verb(@NotNull String message) {
logger.verb(callerClass, message);
}
public void info(@NotNull String message) {
logger.info(callerClass, message);
}
public void warn(@NotNull String message) {
logger.warn(callerClass, message);
}
public void error(@NotNull String message) {
logger.error(callerClass, message);
}
public void crash(@NotNull String message) {
logger.crash(callerClass, message);
}
public void crash(@NotNull String message, boolean softCrash) {
logger.crash(callerClass, message, softCrash);
}
public void crash(@NotNull String message, StackTraceElement[] stackTrace) {
logger.crash(callerClass, message, stackTrace);
}
public void crash(@NotNull String message, StackTraceElement[] stackTrace, boolean softCrash) {
logger.crash(callerClass, message, stackTrace, softCrash);
}
}

View file

@ -1,64 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.classes.logger.implementations;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.Types;
import de.pickshadow.plugin.classes.logger.LoggerImpl;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
public class ExtendedBukkitLogger extends LoggerImpl {
public ExtendedBukkitLogger() {
super();
}
public boolean tryAlternativeLogging = false;
@Override
protected void log(Types.@NotNull LoggerLevel level, @NotNull Class<?> callerClass, @NotNull String message) throws IllegalArgumentException {
if (isLevelAllowed(level)) {
String finalFormat = getFinalFormat(level, callerClass, message);
if (tryAlternativeLogging) {
Bukkit.getConsoleSender().sendMessage(finalFormat);
} else {
switch (level) {
case DIAG:
case VERB:
case INFO:
ObjHolder.main.getLogger().info(finalFormat);
break;
case WARN:
ObjHolder.main.getLogger().warning(finalFormat);
break;
case ERROR:
ObjHolder.main.getLogger().severe(finalFormat);
break;
default:
throw new IllegalArgumentException("Invalid log level \"" + level + "\"");
}
}
}
}
@Override
public void logCrash(String crashMessage) {
ObjHolder.main.getLogger().severe(crashMessage);
}
}

View file

@ -1,52 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.commands;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.CommandBase;
import de.pickshadow.plugin.classes.Interactable;
import de.pickshadow.plugin.classes.Types;
import de.pickshadow.plugin.utils.Miscellaneous;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
public class BroadcastCommand extends CommandBase {
public BroadcastCommand() {
super();
commandNames = new String[]{ "broadcast" };
}
public void getCommand(@NotNull Interactable intact, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
StringBuilder message = new StringBuilder();
for (String arg : args) {
if (message.isEmpty()) {
message.append(arg);
} else {
message.append(" ").append(arg);
}
}
Bukkit.broadcast(Miscellaneous.format(String.valueOf(message), Types.FormatType.NONE, true));
}
public TabCompleter getCompletion() {
return ObjHolder.spellingHelper.getSpellingCompletion();
}
}

View file

@ -1,33 +0,0 @@
package de.pickshadow.plugin.commands;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.base.Translation;
import de.pickshadow.plugin.classes.CommandBase;
import de.pickshadow.plugin.classes.Interactable;
import de.pickshadow.plugin.utils.Miscellaneous;
import de.pickshadow.plugin.utils.TabCompletionHelper;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Random;
public class ClearChatCommand extends CommandBase {
public ClearChatCommand() {
commandNames = new String[]{ "clearchat" };
}
public void getCommand(@NotNull Interactable intact, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
String clearChatMessage = Translation.CLEARCHAT;
if (ObjHolder.config.allowChatClearMessageWithProfanity) clearChatMessage = Translation.CLEARCHAT_CURSES[new Random().nextInt(Translation.CLEARCHAT_CURSES.length)];
for (Player player : Bukkit.getOnlinePlayers()) player.sendMessage(MiniMessage.miniMessage().deserialize("\n".repeat(10000)).append(Miscellaneous.format(clearChatMessage.replace("%sender%", intact.getName()))));
}
@Override
public TabCompleter getCompletion() {
return TabCompletionHelper.createEmptyCompletion();
}
}

View file

@ -1,48 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.commands;
import de.pickshadow.plugin.classes.CommandBase;
import de.pickshadow.plugin.base.Translation;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.Interactable;
import de.pickshadow.plugin.classes.Types;
import de.pickshadow.plugin.utils.Miscellaneous;
import de.pickshadow.plugin.utils.TabCompletionHelper;
import org.bukkit.command.Command;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public class DiscordCommand extends CommandBase {
public DiscordCommand() {
commandNames = new String[]{ "discord" };
}
public void getCommand(@NotNull Interactable intact, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (Objects.equals(ObjHolder.config.inviteLink, "")) intact.message(Miscellaneous.format(Translation.DISCORD_UNAVAILABLE, Types.FormatType.ERROR));
else intact.message(Miscellaneous.format(Translation.DISCORD_INVITE.replace("%invite%", ObjHolder.config.inviteLink)));
}
public TabCompleter getCompletion() {
return TabCompletionHelper.createEmptyCompletion();
}
}

View file

@ -1,50 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.commands;
import de.pickshadow.plugin.classes.CommandBase;
import de.pickshadow.plugin.base.Translation;
import de.pickshadow.plugin.classes.Interactable;
import de.pickshadow.plugin.classes.Types;
import de.pickshadow.plugin.utils.Miscellaneous;
import de.pickshadow.plugin.utils.TabCompletionHelper;
import org.bukkit.Location;
import org.bukkit.command.*;
import org.jetbrains.annotations.NotNull;
public class HomeCommand extends CommandBase {
public HomeCommand() {
commandNames = new String[]{ "home"};
}
public void getCommand(@NotNull Interactable intact, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (Miscellaneous.isCommandSentByConsole(intact, true)) return;
Location coords = intact.getRespawnLocation();
if (coords == null) intact.message(Miscellaneous.format(Translation.HOME_MISSING, Types.FormatType.ERROR));
else {
intact.message(Miscellaneous.format(Translation.HOME_TELEPORT));
intact.setFallDistance(0f);
intact.teleport(coords);
}
}
public TabCompleter getCompletion() {
return TabCompletionHelper.createEmptyCompletion();
}
}

View file

@ -1,162 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.commands;
import de.pickshadow.plugin.BuildConfiguration;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.CommandBase;
import de.pickshadow.plugin.classes.Interactable;
import de.pickshadow.plugin.classes.PlayerData;
import de.pickshadow.plugin.base.Translation;
import de.pickshadow.plugin.classes.Types;
import de.pickshadow.plugin.utils.Miscellaneous;
import de.pickshadow.plugin.utils.TabCompletionHelper;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Objects;
public class MsgCommand extends CommandBase {
public MsgCommand() {
commandNames = new String[]{ "msg", "reply" };
}
@Override
public void getCommand(@NotNull Interactable intact, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (Miscellaneous.isCommandSentByConsole(intact, true)) return;
// Define shared variables
Player player = (Player) intact;
Player reciever;
StringBuilder message = new StringBuilder();
switch (label) {
case "msg":
case "whisper":
// Check args size
if (args.length < 2) {
player.sendMessage(Miscellaneous.format(Translation.GLOBAL_NOT_ENOUGH_ARGUMENTS.replace("%usage%", command.getUsage()), Types.FormatType.ERROR));
return;
}
// Get reciever and check if online
reciever = Bukkit.getPlayerExact(args[0]);
if (reciever == null) {
player.sendMessage(Miscellaneous.format(Translation.GLOBAL_PLAYER_NOT_ONLINE.replace("%player%", args[0])));
return;
}
// Check if performing self messaging
if (!BuildConfiguration.allowSelfMessaging && player.getUniqueId() == reciever.getUniqueId()) {
player.sendMessage(Miscellaneous.format(Translation.MSG_NO_SELF_MESSAGING, Types.FormatType.ERROR));
return;
}
// Update player data
ObjHolder.playerDataLoader.getPlayerData(player.getUniqueId()).lastMessagedPlayer = reciever.getUniqueId();
// Build message string from args
boolean messageRecieverSkipped = false;
for (String arg : args) {
if (!messageRecieverSkipped) {
messageRecieverSkipped = true;
continue;
}
if (message.isEmpty()) {
message.append(arg);
} else {
message.append(" ").append(arg);
}
}
// Send message
player.sendMessage(Miscellaneous.format(Translation.MSG_TO.replace("%intact%", player.getName()).replace("%reciever%", reciever.getName()).replace("%message%", message), Types.FormatType.NONE, true));
if (!(!BuildConfiguration.allowSelfMessaging && player.getUniqueId() == reciever.getUniqueId())) reciever.sendMessage(Miscellaneous.format(Translation.MSG_FROM.replace("%intact%", player.getName()).replace("%reciever%", reciever.getName()).replace("%message%", message), Types.FormatType.NONE, true));
break;
case "reply":
case "r":
// Check args size
if (args.length < 1) {
player.sendMessage(Miscellaneous.format(Translation.GLOBAL_NOT_ENOUGH_ARGUMENTS.replace("%usage%", command.getUsage()), Types.FormatType.ERROR));
return;
}
// Get last messaged player
PlayerData playerData = ObjHolder.playerDataLoader.getPlayerData(player.getUniqueId());
if (playerData.lastMessagedPlayer == null) {
player.sendMessage(Miscellaneous.format(Translation.MSG_NO_LAST_MESSAGED_PLAYER, Types.FormatType.ERROR));
return;
}
reciever = Bukkit.getPlayer(playerData.lastMessagedPlayer);
if (reciever == null) {
player.sendMessage(Miscellaneous.format(Translation.GLOBAL_EXCEPTION, Types.FormatType.ERROR));
}
if (!Objects.requireNonNull(reciever).isOnline()) {
player.sendMessage(Miscellaneous.format(Translation.GLOBAL_PLAYER_NOT_ONLINE.replace("%player%", reciever.getName()), Types.FormatType.ERROR));
}
// Check if performing self messaging
if (!BuildConfiguration.allowSelfMessaging && player.getUniqueId() == reciever.getUniqueId()) {
player.sendMessage(Miscellaneous.format(Translation.MSG_NO_SELF_MESSAGING, Types.FormatType.ERROR));
return;
}
// Build message string from args
for (String arg : args) {
if (message.isEmpty()) {
message.append(arg);
} else {
message.append(" ").append(arg);
}
}
// Send message
intact.message(Miscellaneous.format(Translation.MSG_TO.replace("%intact%", player.getName()).replace("%reciever%", reciever.getName()).replace("%message%", message), Types.FormatType.NONE, true));
if (!(!BuildConfiguration.allowSelfMessaging && player.getUniqueId() == reciever.getUniqueId())) reciever.sendMessage(Miscellaneous.format(Translation.MSG_FROM.replace("%intact%", player.getName()).replace("%reciever%", reciever.getName()).replace("%message%", message), Types.FormatType.NONE, true));
break;
default:
logger.crash("Invalid command '" + label + "' for " + getClass().getName());
}
}
public TabCompleter getCompletion() {
return (commandSender, command, name, args) -> {
if (name.equals("msg")) {
// Only apply workaround for /msg command
if (args.length == 0) {
// No tab completion available
return TabCompletionHelper.processEmptyCompletion(args);
} else if (args.length == 1) {
// Currently at argument one, insert player list
ArrayList<String[]> completion = new ArrayList<>();
completion.add(new String[]{"@@@@PLAYERLIST@@@@"});
return TabCompletionHelper.processDynamicCompletion(completion, args);
} else {
// Currently typing a message, insert spelling corrections
return ObjHolder.spellingHelper.getSpellingCompletionRaw(commandSender, name, args, 1);
}
} else {
// No workaround required, pass everything to getSpellingCompletionRaw as normal
return ObjHolder.spellingHelper.getSpellingCompletionRaw(commandSender, name, args, 0);
}
};
}
}

View file

@ -1,126 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.commands;
import de.pickshadow.plugin.classes.CommandBase;
import de.pickshadow.plugin.base.Translation;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.Interactable;
import de.pickshadow.plugin.classes.Types;
import de.pickshadow.plugin.classes.Configuration;
import de.pickshadow.plugin.utils.Miscellaneous;
import de.pickshadow.plugin.utils.TabCompletionHelper;
import org.bukkit.command.Command;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.UUID;
public class PluginCommand extends CommandBase {
public PluginCommand() {
commandNames = new String[]{ "pssp" };
}
@Override
public void getCommand(@NotNull Interactable intact, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (!intact.hasPermission("pickshadow.commands.pssp") || args.length < 1) {
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_INFO));
return;
}
switch (args[0]) {
case "reloadconfig":
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_RELOAD_CONFIG));
Configuration newConfig = ObjHolder.configLoader.loadConfig();
if (newConfig == null) {
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_RELOAD_CONFIG_FAIL, Types.FormatType.ERROR));
} else {
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_RELOAD_CONFIG_SUCCESS));
ObjHolder.config = newConfig;
}
break;
case "reloaddata":
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_RELOAD_DATA));
UUID[] failedReloads = ObjHolder.playerDataLoader.reloadPlayerData();
if (failedReloads.length == 0) {
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_RELOAD_DATA_SUCCESS));
} else {
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_RELOAD_DATA_FAIL.replace("%uuids%", Arrays.toString(failedReloads)), Types.FormatType.ERROR));
}
break;
case "gc":
Thread gcThread = new Thread(() -> {
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_GARBAGECOLLECT));
Miscellaneous.gc();
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_GARBAGECOLLECT_FINISHED));
});
gcThread.start();
break;
case "playerinfo":
if (Miscellaneous.isCommandSentByConsole(intact, true)) break;
Player player = (Player) intact;
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_PLAYERINFO.replace("%playerdata%", ObjHolder.playerDataLoader.getPlayerData(player.getUniqueId()).convertToString())));
break;
case "scheduler":
if (args.length < 2) {
intact.message(Miscellaneous.format(Translation.GLOBAL_NOT_ENOUGH_ARGUMENTS.replace("%usage%", command.getUsage()), Types.FormatType.ERROR));
return;
}
switch (args[1]) {
case "minutely":
case "minute":
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_SCHEDULER.replace("%timeframe%", "minutely")));
ObjHolder.scheduler.executeScheduler(Types.SchedulerType.MINUTELY);
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_SCHEDULER_DONE.replace("%timeframe%", "minutely")));
break;
case "hourly":
case "hour":
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_SCHEDULER.replace("%timeframe%", "hourly")));
ObjHolder.scheduler.executeScheduler(Types.SchedulerType.HOURLY);
intact.message(Miscellaneous.format(Translation.PLUGINCOMMAND_SCHEDULER_DONE.replace("%timeframe%", "hourly")));
break;
default: intact.message(Miscellaneous.format(Translation.GLOBAL_INVALID_ARGUMENT.replace("%usage%", command.getUsage()), Types.FormatType.ERROR));
}
break;
default: intact.message(Miscellaneous.format(Translation.GLOBAL_INVALID_ARGUMENT.replace("%usage%", command.getUsage()), Types.FormatType.ERROR));
}
}
public TabCompleter getCompletion() {
return (commandSender, command, name, args) -> {
if (commandSender.hasPermission("atc.commands.pickshadow")) {
ArrayList<String[]> completion = new ArrayList<>();
completion.add(new String[]{ "reloadconfig", "reloaddata", "gc", "scheduler", "playerinfo" });
if (args.length > 1) {
if (args[0].equals("scheduler")) {
completion.add(new String[]{"minutely", "hourly"});
}
}
return TabCompletionHelper.processDynamicCompletion(completion, args);
} else {
return TabCompletionHelper.processEmptyCompletion(args);
}
};
}
}

View file

@ -1,122 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.commands;
import de.pickshadow.plugin.classes.CommandBase;
import de.pickshadow.plugin.base.Translation;
import de.pickshadow.plugin.classes.Interactable;
import de.pickshadow.plugin.classes.Types;
import de.pickshadow.plugin.utils.Miscellaneous;
import de.pickshadow.plugin.utils.TabCompletionHelper;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Objects;
public class SystemInformationCommand extends CommandBase {
public SystemInformationCommand() {
commandNames = new String[]{ "sysinfo" };
}
@Override
public void getCommand(@NotNull Interactable intact, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
switch (label) {
case "sysinfo":
case "info":
case "stats":
if (args.length == 0) {
intact.message(Objects.requireNonNull(getMessage(0)));
} else {
switch (args[0]) {
case "memory":
intact.message(Objects.requireNonNull(getMessage(1)));
break;
case "performance":
intact.message(Objects.requireNonNull(getMessage(2)));
break;
default:
intact.message(Miscellaneous.format(Translation.GLOBAL_INVALID_ARGUMENT.replace("%usage%", command.getUsage())));
break;
}
}
break;
case "ram":
case "mem":
case "memory":
intact.message(Objects.requireNonNull(getMessage(1)));
break;
case "tps":
case "mspt":
case "perf":
intact.message(Objects.requireNonNull(getMessage(2)));
break;
default:
intact.message(Miscellaneous.format(Translation.GLOBAL_EXCEPTION, Types.FormatType.ERROR));
logger.error("Invalid label \"" + label + "\"");
break;
}
}
private Component getMessage(int messageType) {
String string;
switch (messageType) {
case 0:
string = Translation.SERVERINFO_SYSTEMINFO;
string = string.replace("%mem_free%", String.valueOf(Miscellaneous.byteToMib(Runtime.getRuntime().freeMemory(), true)));
string = string.replace("%mem_used%", String.valueOf(Miscellaneous.byteToMib(Runtime.getRuntime().maxMemory() - Runtime.getRuntime().freeMemory(), true)));
string = string.replace("%mem_usable%", String.valueOf(Miscellaneous.byteToMib(Runtime.getRuntime().totalMemory(), true)));
string = string.replace("%mem_max%", String.valueOf(Miscellaneous.byteToMib(Runtime.getRuntime().maxMemory(), true)));
string = string.replace("%tps%", String.valueOf(Miscellaneous.truncateNumber(Bukkit.getTPS()[0])));
string = string.replace("%mspt%", String.valueOf(Miscellaneous.truncateNumber(Bukkit.getAverageTickTime())));
return Miscellaneous.format(string);
case 1:
string = Translation.SERVERINFO_MEMORY;
string = string.replace("%mem_free%", String.valueOf(Miscellaneous.byteToMib(Runtime.getRuntime().freeMemory(), true)));
string = string.replace("%mem_used%", String.valueOf(Miscellaneous.byteToMib(Runtime.getRuntime().maxMemory() - Runtime.getRuntime().freeMemory(), true)));
string = string.replace("%mem_usable%", String.valueOf(Miscellaneous.byteToMib(Runtime.getRuntime().totalMemory(), true)));
string = string.replace("%mem_max%", String.valueOf(Miscellaneous.byteToMib(Runtime.getRuntime().maxMemory(), true)));
return Miscellaneous.format(string);
case 2:
string = Translation.SERVERINFO_PERF;
string = string.replace("%tps%", String.valueOf(Miscellaneous.truncateNumber(Bukkit.getTPS()[0])));
string = string.replace("%mspt%", String.valueOf(Miscellaneous.truncateNumber(Bukkit.getAverageTickTime())));
return Miscellaneous.format(string);
default:
logger.crash("Invalid messageType " + messageType);
return null;
}
}
public TabCompleter getCompletion() {
return (commandSender, command, name, args) -> {
if (commandSender.hasPermission("atc.commands.sysinfo")) {
if (name.equals("sysinfo") || name.equals("info") || name.equals("stats")) {
ArrayList<String[]> completion = new ArrayList<>();
completion.add(new String[]{ "mem", "tps", "mspt" });
return TabCompletionHelper.processDynamicCompletion(completion, args);
}
}
return TabCompletionHelper.processEmptyCompletion(args);
};
}
}

View file

@ -1,50 +0,0 @@
package de.pickshadow.plugin.commands;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.base.Translation;
import de.pickshadow.plugin.classes.CommandBase;
import de.pickshadow.plugin.classes.Interactable;
import de.pickshadow.plugin.classes.exceptions.NotAPlayerException;
import de.pickshadow.plugin.utils.Miscellaneous;
import de.pickshadow.plugin.utils.TabCompletionHelper;
import org.bukkit.command.Command;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import java.util.Locale;
import java.util.Random;
public class ToggleDownfallCommand extends CommandBase {
public ToggleDownfallCommand() {
commandNames = new String[]{ "toggledownfall" };
}
@Override
public void getCommand(@NotNull Interactable intact, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (Miscellaneous.isCommandSentByConsole(intact, true)) return;
try {
switch (intact.getWeather()) {
case DOWNFALL:
intact.getWorld().setClearWeatherDuration(new Random().nextInt(6000));
case CLEAR:
intact.getWorld().setThundering(true);
intact.getWorld().setThunderDuration(new Random().nextInt(6000));
default: logger.crash("Invalid weather type '" + String.valueOf(intact.getWeather()) + "'");
}
} catch (NotAPlayerException e) {
logger.crash("Tried to operate on console Interactable (THIS SHOULD BE IMPOSSIBLE!)", e.getStackTrace());
}
if (ObjHolder.config.useOldMcTranslationForToggleDownfall) {
if (intact.getLocale() == Locale.GERMANY) intact.message("Der Niederschlag wurde umgestellt.");
else intact.message("Toggled downfall.");
}
else intact.message(Miscellaneous.format(Translation.TOGGLEDOWNFALL));
}
@Override
public TabCompleter getCompletion() {
return TabCompletionHelper.createEmptyCompletion();
}
}

View file

@ -1,163 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.commands;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.CommandBase;
import de.pickshadow.plugin.base.Translation;
import de.pickshadow.plugin.classes.Interactable;
import de.pickshadow.plugin.classes.Types;
import de.pickshadow.plugin.utils.Miscellaneous;
import de.pickshadow.plugin.utils.TabCompletionHelper;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.title.Title;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.time.Duration;
import java.util.ArrayList;
public class TrollCommand extends CommandBase {
public TrollCommand() {
commandNames = new String[]{ "troll" };
}
@Override
public void getCommand(@NotNull Interactable intact, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
/*
TODO
========
The 'target' needs to be rewritten to be a Interactable at some point.
Player works, but Interactable would be better.
*/
if (Miscellaneous.isCommandSentByConsole(intact, true)) return;
if (args.length < 2) {
intact.message(Miscellaneous.format(Translation.GLOBAL_NOT_ENOUGH_ARGUMENTS.replace("%usage%", command.getUsage()), Types.FormatType.ERROR));
return;
}
Player target = Bukkit.getPlayerExact(args[0]);
if (target == null) {
intact.message(Miscellaneous.format(Translation.GLOBAL_PLAYER_NOT_ONLINE.replace("%player%", args[0]), Types.FormatType.ERROR));
return;
}
switch (args[1]) {
case "demo":
intact.message(Miscellaneous.format(Translation.TROLL_DEMO.replace("%target%", args[0])));
target.showDemoScreen();
break;
case "credits":
intact.message(Miscellaneous.format(Translation.TROLL_CREDITS.replace("%target%", args[0])));
target.showWinScreen();
break;
case "guardian":
intact.message(Miscellaneous.format(Translation.TROLL_GUARDIAN.replace("%target%", args[0])));
target.showElderGuardian();
break;
case "hack":
intact.message(Miscellaneous.format(Translation.TROLL_HACK.replace("%target%", args[0])));
String base = "<dark_red><bold><obfuscated>";
MiniMessage mm = MiniMessage.miniMessage();
target.showTitle(Title.title(mm.deserialize(base + "S=)E8tuv9ZM^P)TJZMVP);ZTP)MZIZM989pv(UZ;."), mm.deserialize(""), Title.Times.times(Duration.ofMillis(0L), Duration.ofSeconds(5L), Duration.ofMillis(0L))));
// Keine Ahnung wie ich das besser machen soll
// tl;dr der wartet 20 ticks und zeigt einen neuen Titel an
Bukkit.getScheduler().runTaskLater(ObjHolder.main, () -> {
target.showTitle(Title.title(mm.deserialize(base + "v89tp$MUPT)(98vtp9UASOEUVTP)("), mm.deserialize(""), Title.Times.times(Duration.ofMillis(0L), Duration.ofSeconds(5L), Duration.ofMillis(0L))));
Bukkit.getScheduler().runTaskLater(ObjHolder.main, () -> {
target.showTitle(Title.title(mm.deserialize(base + "t87ZJ(TW/$ZTVohufUS; PVT)()W$%ZV;"), mm.deserialize(""), Title.Times.times(Duration.ofMillis(0L), Duration.ofSeconds(5L), Duration.ofMillis(0L))));
Bukkit.getScheduler().runTaskLater(ObjHolder.main, () -> {
target.showTitle(Title.title(mm.deserialize(base + "tv)(Tuzv948SMZVEVRAOUERKV()REAK=(RK()AV=)§"), mm.deserialize(""), Title.Times.times(Duration.ofMillis(0L), Duration.ofSeconds(5L), Duration.ofMillis(0L))));
Bukkit.getScheduler().runTaskLater(ObjHolder.main, () -> {
target.showTitle(Title.title(mm.deserialize(base + "S=)E8tuv9ZM^P)TJZMVP);ZTP)MZIZM989pv(UZ;."), mm.deserialize(""), Title.Times.times(Duration.ofMillis(0L), Duration.ofSeconds(5L), Duration.ofMillis(0L))));
Bukkit.getScheduler().runTaskLater(ObjHolder.main, () -> {
target.showTitle(Title.title(mm.deserialize(base + "v89tp$MUPT)(98vtp9UASOEUVTP)("), mm.deserialize(""), Title.Times.times(Duration.ofMillis(0L), Duration.ofSeconds(5L), Duration.ofMillis(0L))));
Bukkit.getScheduler().runTaskLater(ObjHolder.main, () -> {
target.showTitle(Title.title(mm.deserialize(base + "t87ZJ(TW/$ZTVohufUS; PVT)()W$%ZV;"), mm.deserialize(""), Title.Times.times(Duration.ofMillis(0L), Duration.ofSeconds(5L), Duration.ofMillis(0L))));
Bukkit.getScheduler().runTaskLater(ObjHolder.main, () -> {
target.showTitle(Title.title(mm.deserialize(base + "tv)(Tuzv948SMZVEVRAOUERKV()REAK=(RK()AV=)§"), mm.deserialize(""), Title.Times.times(Duration.ofMillis(0L), Duration.ofSeconds(5L), Duration.ofMillis(0L))));
Bukkit.getScheduler().runTaskLater(ObjHolder.main, () -> target.showTitle(Title.title(mm.deserialize("<red>Zugriff gewährt."), mm.deserialize(""), Title.Times.times(Duration.ofSeconds(1L), Duration.ofSeconds(5L), Duration.ofSeconds(1L)))), 20L);
}, 20L);
}, 20L);
}, 20L);
}, 20L);
}, 20L);
}, 20L);
}, 20L);
break;
case "malware":
intact.message(Miscellaneous.format(Translation.TROLL_MALWARE.replace("%target%", args[0])));
for (int i = 0; i < 127; i++) {
int finalI = i;
if (finalI == 100) {
Bukkit.getScheduler().runTaskLater(ObjHolder.main, () -> target.sendMessage(Miscellaneous.format(Translation.TROLL_MALWARE_INFECTED, Types.FormatType.NORMAL, true)), 1L + i);
} else if (finalI == 101) {
Bukkit.getScheduler().runTaskLater(ObjHolder.main, () -> target.sendMessage(Miscellaneous.format(Translation.TROLL_MALWARE_PASSWORDS, Types.FormatType.NORMAL, true)), 1L + i);
} else if (finalI == 121) {
Bukkit.getScheduler().runTaskLater(ObjHolder.main, () -> target.sendMessage(Miscellaneous.format(Translation.TROLL_MALWARE_BANKING, Types.FormatType.NORMAL, true)), 1L + i);
} else if (finalI == 126) {
Bukkit.getScheduler().runTaskLater(ObjHolder.main, () -> target.sendMessage(Miscellaneous.format(Translation.TROLL_MALWARE_HACKED, Types.FormatType.NORMAL, true)), 1L + i);
} else {
if (!(finalI > 101 && finalI < 121 || finalI > 121 && finalI < 126)) Bukkit.getScheduler().runTaskLater(ObjHolder.main, () -> target.sendMessage(Miscellaneous.format(Translation.TROLL_MALWARE_PERCENT.replace("%percent%", String.valueOf(finalI)), Types.FormatType.NORMAL, true)), 1L + i);
}
}
break;
case "creeper":
intact.message(Miscellaneous.format(Translation.TROLL_CREEPER.replace("%target%", args[0])));
target.playSound(Sound.sound(Key.key("entity.creeper.primed"), Sound.Source.MASTER, 1f, 1f));
break;
case "heavens":
intact.message(Miscellaneous.format(Translation.TROLL_HEAVENS.replace("%target%", args[0])));
Location locationHeavens = target.getLocation();
locationHeavens.setY(10000);
target.teleport(locationHeavens);
break;
case "crash":
intact.message(Miscellaneous.format(Translation.TROLL_CRASH.replace("%target%", args[0])));
for (int i = 0; i < 100001; i++) {
target.spawnParticle(Particle.EXPLOSION_HUGE, target.getLocation(), 100000);
}
break;
default:
intact.message(Miscellaneous.format(Translation.GLOBAL_INVALID_ARGUMENT.replace("%usage%", command.getUsage()), Types.FormatType.ERROR));
break;
}
}
public TabCompleter getCompletion() {
return (commandSender, command, name, args) -> {
if (commandSender.hasPermission("atc.commands.troll")) {
ArrayList<String[]> completion = new ArrayList<>();
completion.add(new String[]{ "@@@@PLAYERLIST@@@@" });
completion.add(new String[]{ "demo", "credits", "guardian", "hack", "malware", "creeper", "heavens", "crash" });
return TabCompletionHelper.processDynamicCompletion(completion, args);
} else {
return TabCompletionHelper.processEmptyCompletion(args);
}
};
}
}

View file

@ -1,42 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.listeners;
import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
public class ChatMessageOverrideListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onChat(@NotNull AsyncChatEvent event) {
String messageBuilder = "<gold><bold>%player%<reset> <gold>» <white>";
messageBuilder = messageBuilder.replace("%player%", event.getPlayer().getName());
messageBuilder = messageBuilder.replace("%player_health%", String.valueOf(event.getPlayer().getHealth()));
messageBuilder = messageBuilder.replace("%player_world%", event.getPlayer().getWorld().getName());
messageBuilder = messageBuilder.replace("%player_brand%", String.valueOf(event.getPlayer().getClientBrandName()));
messageBuilder = messageBuilder.replace("%player_ping%", String.valueOf(event.getPlayer().getPing()));
Bukkit.broadcast(MiniMessage.miniMessage().deserialize(messageBuilder).append(event.originalMessage()));
event.setCancelled(true);
}
}

View file

@ -1,53 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.listeners;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.base.Translation;
import de.pickshadow.plugin.utils.Miscellaneous;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public class JoinLeaveMessagesListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onJoin(@NotNull PlayerJoinEvent event) {
Bukkit.broadcast(Miscellaneous.format(Translation.EVENT_JOIN.replace("%player%", event.getPlayer().getName())));
String dataLoadError = ObjHolder.playerDataLoader.loadPlayerData(event.getPlayer().getUniqueId());
if (!Objects.equals(dataLoadError, "")) {
event.getPlayer().kick(Miscellaneous.format(Translation.PLAYERDATA_LOAD_FAILED.replace("%uuid%", event.getPlayer().getUniqueId().toString()).replace("%error%", dataLoadError)));
}
ObjHolder.playerDataLoader.getPlayerData(event.getPlayer().getUniqueId()).lastPlayed = System.currentTimeMillis() / 1000L;
event.joinMessage(Component.empty());
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onQuit(@NotNull PlayerQuitEvent event) {
Bukkit.broadcast(Miscellaneous.format(Translation.EVENT_LEAVE.replace("%player%", event.getPlayer().getName())));
ObjHolder.playerDataLoader.unloadPlayerData(event.getPlayer().getUniqueId());
event.quitMessage(Component.empty());
}
}

View file

@ -1,143 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.loaders;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.Configuration;
import de.pickshadow.plugin.classes.logger.LoggerInstanceImpl;
import de.pickshadow.plugin.utils.FileOperations;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.composer.ComposerException;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.constructor.ConstructorException;
import org.yaml.snakeyaml.parser.ParserException;
import org.yaml.snakeyaml.scanner.ScannerException;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.Scanner;
public class ConfigLoader {
// Objects
private final LoggerInstanceImpl logger;
private final File configFile;
// Non-static
public final int configVersion = 0;
// Constructor
public ConfigLoader() {
logger = ObjHolder.logger.getInstance(getClass());
configFile = new File(ObjHolder.main.getDataFolder() + File.separator + "config.yml");
}
// Loads and returns a new configuration
public Configuration loadConfig() {
Configuration config;
logger.verb("Loading configuration file");
// Check existance of configuration directory
if (!ObjHolder.main.getDataFolder().exists()) {
logger.verb("Creating missing configuration directory");
if (!ObjHolder.main.getDataFolder().mkdir()) {
logger.crash("Could not create configuration directory: mkdir() returned false", true);
return null;
}
}
if (!configFile.exists()) {
logger.verb("Generating new configuration file");
if (!generateConfiguration()) {
return null;
}
}
// Read configuration file
logger.diag("Reading configuration file");
FileOperations operations = new FileOperations(configFile);
String configRaw;
try {
configRaw = operations.readUtf8();
} catch (IOException e) {
logger.crash("Reading configuration file failed", e.getStackTrace(), true);
return null;
}
// Mapping file to Configuration
logger.diag("Mapping file to Configuration");
LoaderOptions options = new LoaderOptions();
options.setTagInspector(tag -> tag.getClassName().equals(Configuration.class.getName()));
Yaml yaml = new Yaml(new Constructor(Configuration.class, options));
try {
config = yaml.load(configRaw);
} catch (ParserException | ScannerException | ComposerException | ConstructorException e) {
logger.crash("Unable to parse configuration file: " + e.getProblem(), e.getStackTrace(), true);
return null;
}
// Check config version
if (config.version == -1) {
logger.crash("Configuration file is invalid, cannot continue.", true);
} else if (config.version < configVersion) {
logger.crash("Configuration file is too old, cannot continue.", true);
} else if (config.version > configVersion) {
logger.crash("Configuration file is too new, cannot continue.", true);
} else {
return config;
}
return null;
}
// Generates a new configuration file
public boolean generateConfiguration() {
FileOperations operations = new FileOperations(configFile);
// Check if exists
try {
if (operations.exists()) {
logger.crash("Could not generate configuration file: A configuration file already exists", true);
return false;
}
} catch (IOException e) {
logger.crash("Could not generate player data file: Got IOException for exists(): " + e.getMessage(), true);
return false;
}
// Create file
try {
operations.createFile();
} catch (IOException e) {
logger.crash("Could not generate configuration file: Got IOException for createFile(): " + e.getMessage(), true);
return false;
}
// Write default configuration
Scanner scanner = new Scanner(Objects.requireNonNull(getClass().getResourceAsStream(File.separator + "config.yml"))).useDelimiter("\\A");
String defaultConfiguration = scanner.hasNext() ? scanner.next() : "";
try {
operations.writeUtf8(defaultConfiguration);
} catch (IOException e) {
logger.crash("Could not generate configuration file: Got IOException for writeUtf8(): " + e.getMessage(), true);
return false;
}
return true;
}
}

View file

@ -1,239 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.loaders;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.PlayerData;
import de.pickshadow.plugin.base.Translation;
import de.pickshadow.plugin.classes.Types;
import de.pickshadow.plugin.classes.logger.LoggerInstanceImpl;
import de.pickshadow.plugin.utils.FileOperations;
import de.pickshadow.plugin.utils.Miscellaneous;
import org.bukkit.Bukkit;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.composer.ComposerException;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.constructor.ConstructorException;
import org.yaml.snakeyaml.parser.ParserException;
import org.yaml.snakeyaml.scanner.ScannerException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
import java.util.UUID;
public class PlayerDataLoader {
// Objects
private final LoggerInstanceImpl logger;
// Non-static
private final String storageLocation;
public final int playerDataVersion = 0;
private HashMap<UUID, PlayerData> loadedPlayerData = new HashMap<>();
// Constructor
public PlayerDataLoader() {
logger = ObjHolder.logger.getInstance(getClass());
storageLocation = ObjHolder.main.getDataFolder() + File.separator + "playerdata" + File.separator;
}
// Loads player data
public String loadPlayerData(UUID uuid) {
PlayerData playerData;
logger.verb("Loading player data for UUID '" + uuid.toString() + "'");
// Check existance of player data directory
if (!new File(storageLocation).exists()) {
logger.verb("Creating missing player data directory");
if (!new File(storageLocation).mkdir()) {
logger.crash("Could not create player data directory: mkdir() returned false", true);
return "Could not create player data directory: mkdir() returned false";
}
}
File playerDataFile = new File(storageLocation + uuid + ".yml");
if (!playerDataFile.exists()) {
logger.verb("Generating new player data file");
String generationError = generatePlayerData(uuid);
if (!Objects.equals(generationError, "")) {
return generationError;
}
}
// Read configuration file
logger.diag("Reading player data file");
FileOperations operations = new FileOperations(playerDataFile);
String playerDataRaw;
try {
playerDataRaw = operations.readUtf8();
} catch (IOException e) {
logger.crash("Reading player data file failed for UUID '" + uuid + "'", e.getStackTrace(), true);
return "Reading player data file failed";
}
// Mapping file to PlayerData
logger.diag("Mapping file to PlayerData");
LoaderOptions options = new LoaderOptions();
options.setTagInspector(tag -> tag.getClassName().equals(PlayerData.class.getName()));
Yaml yaml = new Yaml(new Constructor(PlayerData.class, options));
try {
playerData = yaml.load(playerDataRaw);
} catch (ParserException | ScannerException | ComposerException | ConstructorException e) {
logger.crash("Unable to parse player data file for UUID '" + uuid + "': " + e.getProblem(), e.getStackTrace(), true);
return "Unable to parse player data file: " + e.getProblem();
}
// Check player data version
if (playerData.version == -1) {
logger.crash("Player data file is invalid, cannot continue.", true);
return "Player data file is invalid.";
} else if (playerData.version < playerDataVersion) {
logger.crash("Player data file for UUID '" + uuid + "' is too old, cannot continue.", true);
return "Player data file is too old.";
} else if (playerData.version > playerDataVersion) {
logger.crash("Player data file for UUID '" + uuid + "' is too new, cannot continue.", true);
return "Player data file is too new.";
} else {
loadedPlayerData.put(uuid, playerData);
return "";
}
}
// Generates a new configuration file
public String generatePlayerData(UUID uuid) {
FileOperations operations = new FileOperations(new File(storageLocation + uuid + ".yml"));
// Check if exists
try {
if (operations.exists()) {
logger.crash("Could not generate player data file for UUID '" + uuid + "': A player data file already exists", true);
return "Could not generate player data file: A player data file already exists";
}
} catch (IOException e) {
logger.crash("Could not generate player data file for UUID '" + uuid + "': Got IOException for exists(): " + e.getMessage(), true);
return "Could not generate player data file: Got IOException: " + e.getMessage();
}
// Create file
try {
operations.createFile();
} catch (IOException e) {
logger.crash("Could not generate player data file for UUID '" + uuid + "': Got IOException from creatFile(): " + e.getMessage(), true);
return "Could not generate player data file: createFile() was unsuccessful";
}
// Create new PlayerData object
PlayerData playerData = new PlayerData(uuid);
playerData.firstPlayed = System.currentTimeMillis() / 1000L;
playerData.version = playerDataVersion;
// Write default configuration
try {
operations.writeUtf8(playerData.convertToConfig());
} catch (IOException e) {
logger.crash("Could not generate player data file for UUID '" + uuid + "': Got IOException from writeUtf8(): " + e.getMessage(), true);
return "Could not generate player data file: writeUtf8() was unsuccessful";
}
return "";
}
// Unloads loaded player data
public void unloadPlayerData(UUID uuid) {
if (isPlayerDataLoaded(uuid)) {
savePlayerData(uuid);
loadedPlayerData.remove(uuid);
}
}
// Saves loaded player data
public void savePlayerData(UUID uuid) {
FileOperations operations = new FileOperations(new File(storageLocation + uuid + ".yml"));
// Check if loaded
if (!isPlayerDataLoaded(uuid)) {
logger.error("Could not save player data for UUID '" + uuid + "': Not loaded in memory");
}
// Check if exists
try {
if (!operations.exists()) {
try {
if (!operations.createFile()) logger.crash("Could not save player data for UUID '" + uuid + "': createFile() failed");
} catch (IOException e) {
logger.crash("Could not save player data file for UUID '" + uuid + "': Got IOException for createFile(): " + e.getMessage(), true);
}
}
} catch (IOException e) {
logger.crash("Could not save player data file for UUID '" + uuid + "': Got IOException for exists(): " + e.getMessage(), true);
}
// Write contents
try {
operations.writeUtf8(getPlayerData(uuid).convertToConfig());
} catch (IOException e) {
logger.crash("Could not save player data for UUID '" + uuid + "': Got IOException for writeUtf8(): " + e.getMessage());
}
}
// Reloads all loaded player data
// Returns the failed uuids
public UUID[] reloadPlayerData() {
return reloadPlayerData(true);
}
public UUID[] reloadPlayerData(boolean kickFailedUUIDs) {
logger.verb("Reloading player data");
ArrayList<UUID> failedReloads = new ArrayList<>();
for (UUID uuid : getLoadedUUIDs()) {
logger.diag("Reloading player data for UUID '" + uuid + "'");
unloadPlayerData(uuid);
String error = loadPlayerData(uuid);
if (!error.isEmpty()) {
logger.error("Could not reload player data for UUID '" + uuid + "': " + error);
failedReloads.add(uuid);
if (kickFailedUUIDs) {
try {
Objects.requireNonNull(Bukkit.getPlayer(uuid)).kick(Miscellaneous.format(Translation.PLAYERDATA_RELOAD_FAILED, Types.FormatType.NONE));
} catch (NullPointerException e) {
logger.crash("Could not kick player with UUID '" + uuid + "' (data reload failed): " + e.getMessage(), e.getStackTrace());
}
}
}
}
return failedReloads.toArray(new UUID[0]);
}
// Returns loaded player data
public PlayerData getPlayerData(UUID uuid) {
return loadedPlayerData.getOrDefault(uuid, null);
}
// Return if player is loaded
public boolean isPlayerDataLoaded(UUID uuid) {
return loadedPlayerData.containsKey(uuid);
}
// Return all loaded UUIDs
public UUID[] getLoadedUUIDs() {
return loadedPlayerData.keySet().toArray(new UUID[0]);
}
}

View file

@ -1,101 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.utils;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
public class FileOperations {
public FileOperations(@NotNull File newFile) {
file = newFile;
path = file.toPath();
}
private final File file;
private final Path path;
// Reading
public byte[] readBytes() throws IOException {
return Files.readAllBytes(path);
}
public String readUtf8() throws IOException {
StringBuilder string = new StringBuilder();
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
for (String line : lines) {
string.append(line).append("\n");
}
return string.toString();
}
// Writing
public void writeBytes(@NotNull byte[] data) throws IOException {
Files.write(path, data);
}
public void writeUtf8(@NotNull String data) throws IOException {
writeBytes(data.getBytes(StandardCharsets.UTF_8));
}
// File operations
public boolean createFile() throws IOException {
return file.createNewFile();
}
public boolean deleteFile() {
return file.delete();
}
public boolean exists() throws IOException {
return file.exists();
}
// Permissions
public boolean canRead() {
return file.canRead();
}
public boolean canWrite() {
return file.canWrite();
}
public boolean canExecute() {
return file.canExecute();
}
public String getUnixUserPermissions() {
String permissions;
if (canRead()) {
permissions = "r";
} else {
permissions = "-";
}
if (canWrite()) {
permissions = permissions + "w";
} else {
permissions = permissions + "-";
}
if (canExecute()) {
permissions = permissions + "x";
} else {
permissions = permissions + "-";
}
return permissions;
}
}

View file

@ -1,178 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.utils;
import de.pickshadow.plugin.base.Translation;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.Interactable;
import de.pickshadow.plugin.classes.Types;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.lang.ref.WeakReference;
import java.text.DecimalFormat;
import java.util.Objects;
public class Miscellaneous {
// Converts StackTraceElement[] to a String
public static String convertStacktraceToString(@NotNull StackTraceElement[] stacktrace) {
StringBuilder stringtrace = new StringBuilder();
for (int i = 1; i < stacktrace.length; i++) {
stringtrace.append("\tat ").append(stacktrace[i]).append("\n");
}
return stringtrace.toString();
}
// Disable plugin
public static void shutdownPlugin() {
try {
Bukkit.getPluginManager().disablePlugin(Objects.requireNonNull(Bukkit.getPluginManager().getPlugin("PickShadow")));
} catch (NullPointerException e) {
Bukkit.shutdown();
}
}
// Ensures garbage collection
// Stolen from JLibs
// https://github.com/santhosh-tekuri/jlibs/blob/e001fb7286c84f456125d1be00fc9a7e3b128881/core/src/main/java/jlibs/core/lang/RuntimeUtil.java#L148
public static void threadedGc(){
Thread gcThread = new Thread(Miscellaneous::gc);
gcThread.start();
}
public static void gc() {
ObjHolder.logger.warn(Miscellaneous.class, "Forcing garbage collection");
Object obj = new Object();
WeakReference<Object> ref = new WeakReference<>(obj);
obj = null;
while(ref.get() != null) System.gc();
ObjHolder.logger.warn(Miscellaneous.class, "Garbage collector finished");
}
// Check if command was sent by console
public static boolean isCommandSentByConsole(CommandSender sender) {
return isCommandSentByConsole(sender, false);
}
public static boolean isCommandSentByConsole(CommandSender sender, boolean issueError) {
return isCommandSentByConsole(new Interactable(sender), issueError);
}
public static boolean isCommandSentByConsole(Interactable intact) {
return isCommandSentByConsole(intact, false);
}
public static boolean isCommandSentByConsole(Interactable intact, boolean issueError) {
if (intact.isConsole()) {
if (issueError) intact.message(Miscellaneous.format(Translation.GLOBAL_NOT_A_PLAYER, Types.FormatType.ERROR));
return true;
}
return false;
}
// Data type conversion
/// Bytes <-> Mebibytes
public static double byteToMib(int bytes, boolean flatten) {
if (flatten) {
return truncateNumber((double) bytes / 1048576);
} else {
return (float) bytes / 1048576;
}
}
public static double byteToMib(double bytes, boolean flatten) {
if (flatten) {
return truncateNumber(bytes / 1048576);
} else {
return (float) bytes / 1048576;
}
}
public static double mibToByte(double mib, boolean flatten) {
if (flatten) {
return truncateNumber(mib * 1048576);
} else {
return mib * 1048576;
}
}
/// Mebibytes <-> Gebibytes
public static double mibToGib(double mib, boolean flatten) {
if (flatten) {
return truncateNumber(mib / 1024);
} else {
return mib / (float) 1024;
}
}
public static double gibToMib(double gib, boolean flatten) {
if (flatten) {
return truncateNumber(gib * 1024);
} else {
return gib * 1024;
}
}
// Truncate numbers
/// Double
public static double truncateNumber(double number, int keep) {
return Double.parseDouble(new DecimalFormat("#," + "#".repeat(keep)).format(number));
}
public static double truncateNumber(double number) {
return truncateNumber(number, 2);
}
/// Float
public static float truncateNumber(float number, int keep) {
return Float.parseFloat(new DecimalFormat("#," + "#".repeat(keep)).format(number));
}
public static float truncateNumber(float number) {
return truncateNumber(number, 2);
}
public static Component format(@NotNull String message, @NotNull Types.FormatType type) {
return format(message, type, false);
}
public static Component format(@NotNull String message, @NotNull Types.FormatType type, boolean disablePrefix) {
String prefix = "<reset>";
if (ObjHolder.config.enablePrefix && !disablePrefix) {
prefix = "<PREFIX>";
}
String formatted = prefix + message;
// Handle newlines
formatted = formatted.replace("\n", "\n" + "<reset>" + prefix);
// Format special effects
formatted = formatted.replace("<PREFIX>", Translation.GLOBAL_PREFIX);
formatted = formatted.replace("<BRANDING>", "<gradient:#FFFFFF:#A8A8A8>");
formatted = formatted.replace("<BRANDING_END>", "</gradient><reset>");
formatted = formatted.replace("<HIGHLIGHT>", "<aqua><bold>");
// Update color and reset tag
switch (type) {
case NORMAL:
formatted = formatted.replace("<reset>", "<reset><gold>");
case ERROR:
formatted = formatted.replace("<reset>", "<reset><red>");
}
// Jagen wir das Ding mal durch Kyori's Adventure // Run it through Kyori's Adventure
MiniMessage mm = MiniMessage.miniMessage();
return mm.deserialize(formatted);
}
public static Component format(@NotNull String translation) {
return format(translation, Types.FormatType.NORMAL);
}
}

View file

@ -1,193 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.utils;
import com.nikialeksey.hunspell.Hunspell;
import de.pickshadow.plugin.BuildConfiguration;
import de.pickshadow.plugin.base.ObjHolder;
import de.pickshadow.plugin.classes.logger.LoggerInstanceImpl;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
public class SpellingHelper {
// Objects
private final LoggerInstanceImpl logger;
private Hunspell speller = null;
// Non-static
public String activeLanguage = "none";
private final String spellingFilesPathExternal;
// Static
public final static String[] languages = new String[]{ "en_US", "de_DE" };
private final static String[] types = new String[]{ "dic", "aff" };
private final static String spellingFilesPathInternal = File.separator + "spelling" + File.separator;
private final static String[] spellingBlacklist = new String[]{ "<", ">" };
private final static int spellingMaxLength = 16;
// Constructor
public SpellingHelper() {
logger = ObjHolder.logger.getInstance(getClass());
spellingFilesPathExternal = ObjHolder.main.getDataFolder() + File.separator + "spelling" + File.separator;
}
// Extractor
public String extractFiles() {
logger.verb("Extracting spelling files");
File spellingDirectory = new File(ObjHolder.main.getDataFolder() + File.separator + "spelling");
if (!spellingDirectory.exists()) {
logger.diag("Creating missing 'spelling' directory");
if (!spellingDirectory.mkdirs()) {
logger.error("Couldn't spelling files: Could not create 'spelling' directory");
return "Couldn't spelling files: Could not create 'spelling' directory";
}
}
for (String lang : languages) {
for (String type : types) {
logger.diag("Extracting spelling/" + lang + "." + type);
FileOperations op = new FileOperations(new File(spellingFilesPathExternal + lang + "." + type));
try {
if (op.exists()) continue;
op.createFile();
op.writeBytes(Objects.requireNonNull(getClass().getResourceAsStream(spellingFilesPathInternal + lang + "." + type)).readAllBytes());
} catch (IOException e) {
logger.crash("Couldn't extract spelling files: Failed extracting language '" + lang + "': Got IOException: " + e.getMessage(), e.getStackTrace());
return "Couldn't extract spelling files: Failed extracting language '" + lang + "': Got IOException: " + e.getMessage();
}
}
}
return "";
}
// Returns the active spelling language
public String getActiveLanguage() {
return activeLanguage;
}
// Updates the active spelling language
public boolean setActiveLanguage(String newLang) {
boolean isValid = false;
// Determine if newLang is valid
for (String lang : languages) {
if (Objects.equals(lang, newLang)) {
isValid = true;
break;
}
}
if (isValid) {
if (speller != null) speller.close();
speller = new Hunspell(spellingFilesPathExternal + newLang + ".dic", spellingFilesPathExternal + newLang + ".aff");
activeLanguage = newLang;
} else if (newLang == null || Objects.equals(newLang, "none")) {
isValid = true;
if (speller != null) speller.close();
speller = null;
}
// Return success status
return isValid;
}
// Provide spelling for tab completion
public String[] getSpellingCorrections(@NotNull String word) {
if (Objects.equals(activeLanguage, "none")) {
// No language is active
if (BuildConfiguration.provideVerboseLoggingForSpellingHelpers) logger.diag("No language is active, can't provide corrections for '" + word + "'");
return new String[]{ word };
}
// Check word requirements
// -> Check word length
if (word.length() > spellingMaxLength) {
// Word is longer than spellingMaxLength allows
if (BuildConfiguration.provideVerboseLoggingForSpellingHelpers) logger.diag("Word '" + word + "' is longer than " + spellingMaxLength + " characters");
return new String[]{ word };
}
// -> Check blacklist
for (String blacklist : spellingBlacklist) {
if (word.contains(blacklist)) {
// Word contains something on the blacklist
if (BuildConfiguration.provideVerboseLoggingForSpellingHelpers) logger.diag("Word '" + word + "' contains a blacklisted keyword");
return new String[]{ word };
}
}
// Check spelling
if (speller.spell(word)) {
// Word is spelled correctly
if (BuildConfiguration.provideVerboseLoggingForSpellingHelpers) logger.diag("Word '" + word + "' is spelled correctly");
return new String[]{ word };
} else {
// Word is misspelled, return list of suggestions
if (BuildConfiguration.provideVerboseLoggingForSpellingHelpers) logger.diag("Word '" + word + "' is misspelled, providing corrections: " + speller.suggest(word).toString());
return speller.suggest(word).toArray(new String[0]);
}
}
public TabCompleter getSpellingCompletion() {
return getSpellingCompletion(0);
}
public TabCompleter getSpellingCompletion(int ignoreArguments) {
return (commandSender, command, name, args) -> getSpellingCompletionRaw(commandSender, name, args, ignoreArguments);
}
public ArrayList<String> getSpellingCompletionRaw(CommandSender commandSender, String name, String[] args, int ignoreArguments) {
if (ignoreArguments < 0) {
logger.crash("ignoreArguments cannot be negative (set to " + ignoreArguments + ")");
}
int ignoredArguments = 0;
ArrayList<String[]> completion = new ArrayList<>();
// Populate with arguments
for (int i = 0; i < args.length-1; i++) {
if (ignoredArguments == ignoreArguments) {
completion.add(new String[0]);
} else {
ignoredArguments++;
}
}
// Add result from getSpellingCorrections
completion.add(getSpellingCorrections(args[args.length-1]));
if (BuildConfiguration.provideVerboseLoggingForSpellingCompletions) logger.diag("Available spelling corrections for /" + name + " executed by " + commandSender.getName() + ": " + Arrays.toString(completion.get(completion.size() - 1)));
// Check if args needs to be updated
if (ignoreArguments != 0) {
ArrayList<String> newArgs = new ArrayList<>();
ignoredArguments = 0;
for (String arg : args) {
if (ignoredArguments == ignoreArguments) newArgs.add(arg);
else ignoredArguments++;
}
args = newArgs.toArray(new String[0]);
}
return TabCompletionHelper.processDynamicCompletion(completion, args);
}
}

View file

@ -1,83 +0,0 @@
/*
PICKSHADOW SERVER PLUGIN SOURCE FILE
Copyright (c) 2024 JeremyStarTM & Contributors
Licensed under the GNU Affero General Public License v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.pickshadow.plugin.utils;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TabCompletionHelper {
// Creates a TabCompleter from a list of arguments
public static TabCompleter createStaticCompletion(@NotNull ArrayList<String[]> completion) {
return (commandSender, command, name, args) -> processDynamicCompletion(completion, args);
}
// Creates a ArrayList<String> from a list of arguments
public static ArrayList<String> processDynamicCompletion(@NotNull ArrayList<String[]> completion, @NotNull String[] args) {
// Create new ArrayList<String>
ArrayList<String> completionOutput = new ArrayList<>();
// Reduces new allocations when comparing later in execution
String emptyStringArray = "[@@@@PLAYERLIST@@@@]";
// Get all online player names
ArrayList<String> playersTemporary = new ArrayList<>();
for (Player player : Bukkit.getOnlinePlayers()) {
playersTemporary.add(player.getName());
}
String[] players = playersTemporary.toArray(new String[0]);
// Replace all empty String[] with online players
for (int i = 0; i < completion.size(); i++) {
if (Arrays.toString(completion.get(i)).equals(emptyStringArray)) {
completion.set(i, players);
}
}
// Check if is out of bounce
if (args.length > completion.size()) {
// Is out of bounce, return empty completion
StringUtil.copyPartialMatches(args[args.length-1], List.of(new String[]{ " " }), completionOutput);
} else {
// Is in bounce, return completion
StringUtil.copyPartialMatches(args[args.length-1], List.of(completion.get(args.length-1)), completionOutput);
}
// Return processed completion
return completionOutput;
}
// Creates an empty TabCompleter
public static TabCompleter createEmptyCompletion() {
return (commandSender, command, name, args) -> StringUtil.copyPartialMatches(args[args.length-1], List.of(new String[]{ "" }), new ArrayList<>());
}
// Creates an empty ArrayList<String>
public static ArrayList<String> processEmptyCompletion(@NotNull String[] args) {
return StringUtil.copyPartialMatches(args[args.length-1], List.of(new String[]{ "" }), new ArrayList<>());
}
}

View file

@ -1,14 +0,0 @@
##############################
## PickShadow Server Plugin ##
## Configuration file ##
##############################
### DO NOT REMOVE THESE LINES OR THIS PLUGIN WILL BREAK ###
!!de.pickshadow.plugin.classes.Configuration
version: 0
### DO NOT REMOVE THESE LINES OR THIS PLUGIN WILL BREAK ###
enablePrefix: true
inviteLink: ""
defaultSpellingLanguage: "de_DE"
useOldMcTranslationForToggleDownfall: true
allowChatClearMessageWithProfanity: true

View file

@ -1,114 +0,0 @@
# PICKSHADOW SERVER PLUGIN SOURCE FILE
# Copyright (c) 2024 JeremyStarTM & Contributors
# Licensed under the GNU Affero General Public License v3
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
name: PSSP
version: '${version}'
main: de.pickshadow.plugin.base.Main
api-version: '1.20'
prefix: PSSP
depend: [ FreedomChat ]
authors: [ JeremyStarTM ]
commands:
discord:
description: Gibt den Link zum PickShadow Discord Server aus.
usage: /discord
aliases: [ dc ]
permission: pickshadow.commands.discord
home:
description: Teleportiert dich zu deinem Respawnpunkt.
usage: /home
aliases: [ bed, tph, tphome ]
permission: pickshadow.commands.home
pssp:
description: Verwaltet das PickShadow Server Plugin.
usage: /pssp <reloadconfig|reloaddata|gc <minutely|hourly>|playerinfo>
aliases: [ "pickshadow" ]
sysinfo:
description: Zeigt Informationen zum Server an.
usage: /sysinfo [memory, performance]
aliases: [ info, stats, tps, mspt, perf, mem, ram ]
permission: pickshadow.commands.sysinfo
troll:
description: Erlaubt es andere Spieler zu trollen.
usage: /troll <Spieler> <demo|credits|guardian|hack|malware|creeper|heavens|crash>
aliases: [ t ]
permission: pickshadow.commands.troll
broadcast:
description: Sendet eine Nachricht an alle Spieler.
usage: /broadcast <Nachricht>
aliases: [ bc, say, announce ]
permission: pickshadow.commands.broadcast
msg:
description: Sendet eine Nachricht an einen anderen Spieler.
usage: /msg <Spieler> <Nachricht>
aliases: [ "whisper", "w" ]
permission: pickshadow.commands.msg
reply:
description: Sendet eine Nachricht an den zuletzt kontaktierten Spieler.
usage: /reply <Nachricht>
aliases: [ "r" ]
permission: pickshadow.commands.reply
clearchat:
description: Löscht den Chatverlauf für den gesamten Server.
usage: /clearchat
aliases: [ "cc", "chatclear" ]
permission: pickshadow.commands.clearchat
toggledownfall:
description: Stellt den Niederschlag um. Erinnering an alte Zeiten.
usage: /toggledownfall
permission: pickshadow.commands.toggledownfall
permissions:
pickshadow.*:
default: op
description: Erlaubt Zugriff auf alles was PSSP zu bieten hat.
children:
- pickshadow.commands.*
pickshadow.commands.*:
default: op
description: Erlaubt Zugriff auf alle Befehle.
children:
- pickshadow.commands.discord
- pickshadow.commands.home
- pickshadow.commands.pssp
- pickshadow.commands.sysinfo
- pickshadow.commands.troll
- pickshadow.commands.broadcast
- pickshadow.commands.msg
- pickshadow.commands.reply
- pickshadow.commands.clearchat
- pickshadow.commands.toggledownfall
pickshadow.commands.discord:
default: not op
pickshadow.commands.home:
default: not op
pickshadow.commands.pssp:
default: op
pickshadow.commands.sysinfo:
default: op
pickshadow.commands.troll:
default: op
pickshadow.commands.broadcast:
default: op
pickshadow.commands.msg:
default: not op
pickshadow.commands.reply:
default: not op
pickshadow.commands.clearchat:
default: op
pickshadow.commands.toggledownfall:
default: not op

View file

@ -1,729 +0,0 @@
# this is the affix file of the de_DE Hunspell dictionary
# derived from the igerman98 dictionary
#
# Version: 20161207
#
# Copyright (C) 1998-2015 Bjoern Jacke <bjoern@j3e.de>
#
# License: GPLv2, GPLv3
# There should be a copy of both of this licenses included
# with every distribution of this dictionary. Modified
# versions using the GPL may only include the GPL
SET UTF-8
TRY esijanrtolcdugmphbyfvkwqxzäüößáéêàâñESIJANRTOLCDUGMPHBYFVKWQXZÄÜÖÉ-.
PFX U Y 1
PFX U 0 un .
PFX V Y 1
PFX V 0 ver .
SFX F Y 35
SFX F 0 nen in
SFX F e in e
SFX F e innen e
SFX F 0 in [^i]n
SFX F 0 innen [^i]n
SFX F 0 in [^enr]
SFX F 0 innen [^enr]
SFX F 0 in [^e]r
SFX F 0 innen [^e]r
SFX F 0 in [^r]er
SFX F 0 innen [^r]er
SFX F 0 in [^e]rer
SFX F 0 innen [^e]rer
SFX F 0 in ierer
SFX F 0 innen ierer
SFX F er in [^i]erer
SFX F er innen [^i]erer
SFX F in In in
SFX F in Innen in
SFX F e In e
SFX F e Innen e
SFX F 0 In [^i]n
SFX F 0 Innen [^i]n
SFX F 0 In [^en]
SFX F 0 Innen [^en]
SFX F 0 In [^e]r
SFX F 0 Innen [^e]r
SFX F 0 In [^r]er
SFX F 0 Innen [^r]er
SFX F 0 In [^e]rer
SFX F 0 Innen [^e]rer
SFX F 0 In ierer
SFX F 0 Innen ierer
SFX F er In [^i]erer
SFX F er Innen [^i]erer
#SFX F en innen en
#SFX F en Innen en
SFX L N 12
SFX L 0 tlich n
SFX L 0 tliche n
SFX L 0 tlicher n
SFX L 0 tliches n
SFX L 0 tlichem n
SFX L 0 tlichen n
SFX L 0 lich [^n]
SFX L 0 liche [^n]
SFX L 0 licher [^n]
SFX L 0 liches [^n]
SFX L 0 lichem [^n]
SFX L 0 lichen [^n]
#SFX H N 2
#SFX H 0 heit .
#SFX H 0 heiten .
#SFX K N 2
#SFX K 0 keit .
#SFX K 0 keiten .
SFX M N 10
SFX M 0 chen [^se]
SFX M 0 chens [^se]
SFX M ass ässchen ass
SFX M ass ässchens ass
SFX M oss össchen oss
SFX M oss össchens oss
SFX M uss üsschen uss
SFX M uss üsschens uss
SFX M e chen e
SFX M e chens e
SFX A Y 46
SFX A 0 r e
SFX A 0 n e
SFX A 0 m e
SFX A 0 s e
SFX A 0 e [^elr]
SFX A 0 er [^elr]
SFX A 0 en [^elr]
SFX A 0 em [^elr]
SFX A 0 es [^elr]
SFX A 0 e [^e][rl]
SFX A 0 er [^e][rl]
SFX A 0 en [^e][rl]
SFX A 0 em [^e][rl]
SFX A 0 es [^e][rl]
SFX A 0 e [^u]er
SFX A 0 er [^u]er
SFX A 0 en [^u]er
SFX A 0 em [^u]er
SFX A 0 es [^u]er
SFX A er re uer
SFX A er rer uer
SFX A er ren uer
SFX A er rem uer
SFX A er res uer
SFX A 0 e [eil]el
SFX A 0 er [eil]el
SFX A 0 en [eil]el
SFX A 0 em [eil]el
SFX A 0 es [eil]el
SFX A el le [^eil]el
SFX A el ler [^eil]el
SFX A el len [^eil]el
SFX A el lem [^eil]el
SFX A el les [^eil]el
SFX A lig elig [^aeiouhlräüö]lig
SFX A lig elige [^aeiouhlräüö]lig
SFX A lig eliger [^aeiouhlräüö]lig
SFX A lig eligen [^aeiouhlräüö]lig
SFX A lig eligem [^aeiouhlräüö]lig
SFX A lig eliges [^aeiouhlräüö]lig
SFX A erig rig [^hi]erig
SFX A erig rige [^hi]erig
SFX A erig riger [^hi]erig
SFX A erig rigen [^hi]erig
SFX A erig rigem [^hi]erig
SFX A erig riges [^hi]erig
SFX C Y 100
SFX C 0 ere [^elr]
SFX C 0 erer [^elr]
SFX C 0 eren [^elr]
SFX C 0 erem [^elr]
SFX C 0 eres [^elr]
SFX C 0 re e
SFX C 0 rer e
SFX C 0 ren e
SFX C 0 rem e
SFX C 0 res e
SFX C 0 ere [^e][lr]
SFX C 0 erer [^e][lr]
SFX C 0 eren [^e][lr]
SFX C 0 erem [^e][lr]
SFX C 0 eres [^e][lr]
SFX C el lere el
SFX C el lerer el
SFX C el leren el
SFX C el lerem el
SFX C el leres el
SFX C er rere uer
SFX C er rerer uer
SFX C er reren uer
SFX C er rerem uer
SFX C er reres uer
SFX C 0 ere [^u]er
SFX C 0 erer [^u]er
SFX C 0 eren [^u]er
SFX C 0 erem [^u]er
SFX C 0 eres [^u]er
SFX C lig eligere [^aeiouhlräüö]lig
SFX C lig eligerer [^aeiouhlräüö]lig
SFX C lig eligeren [^aeiouhlräüö]lig
SFX C lig eligerem [^aeiouhlräüö]lig
SFX C lig eligeres [^aeiouhlräüö]lig
SFX C erig rigere [^hi]erig
SFX C erig rigerer [^hi]erig
SFX C erig rigeren [^hi]erig
SFX C erig rigerem [^hi]erig
SFX C erig rigeres [^hi]erig
SFX C 0 est [kßsuxz]
SFX C 0 este [kßsuxz]
SFX C 0 ester [kßsuxz]
SFX C 0 esten [kßsuxz]
SFX C 0 estem [kßsuxz]
SFX C 0 estes [kßsuxz]
SFX C 0 st et
SFX C 0 ste et
SFX C 0 ster et
SFX C 0 sten et
SFX C 0 stem et
SFX C 0 stes et
SFX C 0 st igt
SFX C 0 ste igt
SFX C 0 ster igt
SFX C 0 sten igt
SFX C 0 stem igt
SFX C 0 stes igt
SFX C 0 est [^i]gt
SFX C 0 este [^i]gt
SFX C 0 ester [^i]gt
SFX C 0 esten [^i]gt
SFX C 0 estem [^i]gt
SFX C 0 estes [^i]gt
SFX C 0 est [^eg]t
SFX C 0 este [^eg]t
SFX C 0 ester [^eg]t
SFX C 0 esten [^eg]t
SFX C 0 estem [^eg]t
SFX C 0 estes [^eg]t
SFX C 0 st [^kßstxz]
SFX C 0 ste [^kßstxz]
SFX C 0 ster [^kßstxz]
SFX C 0 sten [^kßstxz]
SFX C 0 stem [^kßstxz]
SFX C 0 stes [^kßstxz]
SFX C 0 st nd
SFX C 0 ste nd
SFX C 0 ster nd
SFX C 0 sten nd
SFX C 0 stem nd
SFX C 0 stes nd
SFX C 0 est [^n]d
SFX C 0 este [^n]d
SFX C 0 ester [^n]d
SFX C 0 esten [^n]d
SFX C 0 estem [^n]d
SFX C 0 estes [^n]d
SFX C lig eligst [^aeiouhlräüö]lig
SFX C lig eligste [^aeiouhlräüö]lig
SFX C lig eligster [^aeiouhlräüö]lig
SFX C lig eligsten [^aeiouhlräüö]lig
SFX C lig eligstem [^aeiouhlräüö]lig
SFX C lig eligstes [^aeiouhlräüö]lig
SFX C erig rigst [^hi]erig
SFX C erig rigste [^hi]erig
SFX C erig rigster [^hi]erig
SFX C erig rigsten [^hi]erig
SFX C erig rigstem [^hi]erig
SFX C erig rigstes [^hi]erig
SFX E Y 1
SFX E 0 e .
SFX f Y 4
SFX f ph f ph
SFX f ph fen ph
SFX f phie fie phie
SFX f phie fien phie
SFX N Y 1
SFX N 0 n .
SFX P Y 1
SFX P 0 en .
SFX p Y 26
SFX p auf äufe auf
SFX p auf äufen auf
SFX p aus äuser [hH]aus
SFX p aus äusern [hH]aus
SFX p arkt ärkte [mM]arkt
SFX p arkt ärkten [mM]arkt
SFX p ang änge ang
SFX p ang ängen ang
SFX p uß üße uß
SFX p uß üßen uß
SFX p oß öße oß
SFX p oß ößen oß
SFX p aum äume aum
SFX p aum äumen aum
SFX p ag äge ag
SFX p ag ägen ag
SFX p ug üge ug
SFX p ug ügen ug
SFX p all älle all
SFX p all ällen all
SFX p ass ässe ass
SFX p ass ässen ass
SFX p uss üsse uss
SFX p uss üssen uss
SFX p oss össe oss
SFX p oss össen oss
# last ...oss rules are for swiss de_CH only - but do not affect de_DE
SFX R Y 3
SFX R 0 er [^e]
SFX R 0 ern [^e]
SFX R 0 r e
SFX S Y 1
SFX S 0 s .
SFX q Y 2
SFX q 0 se s
SFX q 0 sen s
SFX Q Y 1
SFX Q 0 ses s
#SFX Q 0 se s
#SFX Q 0 sen s
SFX T Y 1
SFX T 0 es .
SFX J Y 12
SFX J n ung [bgkpßsz]eln
SFX J n ungen [bgkpßsz]eln
SFX J eln lung eln
SFX J n ung ern
SFX J en ung en
SFX J eln lungen eln
SFX J n ungen ern
SFX J en ungen en
SFX J 0 ung [^n]
SFX J 0 ungen [^n]
SFX J el lung el
SFX J el lungen el
SFX B N 12
SFX B n bar e[lr]n
SFX B n bare e[lr]n
SFX B n baren e[lr]n
SFX B n barer e[lr]n
SFX B n bares e[lr]n
SFX B n barem e[lr]n
SFX B en bar en
SFX B en bare en
SFX B en baren en
SFX B en barer en
SFX B en bares en
SFX B en barem en
SFX D Y 6
SFX D 0 d n
SFX D 0 de n
SFX D 0 den n
SFX D 0 der n
SFX D 0 des n
SFX D 0 dem n
SFX W Y 5
SFX W en 0 en
SFX W n 0 [^e]n
SFX W st 0 [^s]st
SFX W t 0 sst
SFX W t 0 [^s]t
SFX I Y 16
SFX I n 0 en
SFX I eln le eln
SFX I n e eln
SFX I ern re ern
SFX I n e ern
SFX I n t e[lr]n
SFX I n t [dt]en
SFX I en t [^dimnt]en
SFX I en t eien
SFX I n t [^e]ien
SFX I n t chnen
SFX I en t [^c]h[mn]en
SFX I n t [^aäehilmnoöuür][mn]en
SFX I en t [aäeilmnoöuür][mn]en
SFX I n e un
SFX I n t un
SFX X Y 26
SFX X n t e[lr]n
SFX X n t [dtw]en
SFX X en t eien
SFX X n t [^e]ien
SFX X en t [^ditmnw]en
SFX X n t chnen
SFX X en t [^c]h[mn]en
SFX X n t [^aäehilmnoöuür][mn]en
SFX X en t [aäeilmnoöuür][mn]en
SFX X n t un
SFX X st 0 tst
SFX X n st e[lr]n
SFX X n st [dtw]en
SFX X en st [^dimnßstwzx]en
SFX X en st eien
SFX X n st [^e]ien
SFX X n st chnen
SFX X en st [^c]h[mn]en
SFX X n st [^aäehilmnoöuür][mn]en
SFX X en st [aäeilmnoöuür][mn]en
SFX X n st un
SFX X n st [ßsxz]en
SFX X n st ssen
SFX X n st schen
SFX X t st [^sz]t
SFX X t est zt
SFX Y Y 36
SFX Y n te e[lr]n
SFX Y n te [dtw]en
SFX Y en te [^dimntw]en
SFX Y en te eien
SFX Y n te [^e]ien
SFX Y n te chnen
SFX Y en te [^c]h[mn]en
SFX Y n te [^aäehilmnoöuür][mn]en
SFX Y en te [aäeilmnoöuür][mn]en
SFX Y n test e[lr]n
SFX Y n test [dtw]en
SFX Y en test [^dimntw]en
SFX Y en test eien
SFX Y n test [^e]ien
SFX Y n test chnen
SFX Y en test [^c]h[mn]en
SFX Y n test [^aäehilmnoöuür][mn]en
SFX Y en test [aäeilmnoöuür][mn]en
SFX Y n tet e[lr]n
SFX Y n tet [dtw]en
SFX Y en tet [^dimntw]en
SFX Y en tet eien
SFX Y n tet [^e]ien
SFX Y n tet chnen
SFX Y en tet [^c]h[mn]en
SFX Y n tet [^aäehilmnoöuür][mn]en
SFX Y en tet [aäeilmnoöuür][mn]en
SFX Y n ten e[lr]n
SFX Y n ten [dtw]en
SFX Y en ten [^dimntw]en
SFX Y en ten eien
SFX Y n ten [^e]ien
SFX Y n ten chnen
SFX Y en ten [^c]h[mn]en
SFX Y n ten [^aäehilmnoöuür][mn]en
SFX Y en ten [aäeilmnoöuür][mn]en
SFX Z Y 15
SFX Z 0 st [^hßsz]
SFX Z 0 st [^c]h
SFX Z 0 st [^s]ch
SFX Z 0 est [dfkstz]
SFX Z 0 est ch
SFX Z 0 est [au]ß
SFX Z 0 est ieß
SFX Z 0 est [io]ss
SFX Z 0 t [^dt]
SFX Z 0 et [dt]
SFX Z 0 n e
SFX Z 0 en ie
SFX Z 0 en [^e]
SFX Z 0 est iess
SFX Z 0 est [au]ss
# last two ...ss rules only used for swiss de_CH - but de_DE is unaffected
SFX O Y 21
SFX O n tes e[lr]n
SFX O n tes [dtw]en
SFX O en tes [^dmntw]en
SFX O n tes chnen
SFX O en tes [^c]h[mn]en
SFX O n tes [^aäehilmnoöuür][mn]en
SFX O en tes [aäeilmnoöuür][mn]en
SFX O n ter e[lr]n
SFX O n ter [dtw]en
SFX O en ter [^dmntw]en
SFX O n ter chnen
SFX O en ter [^c]h[mn]en
SFX O n ter [^aäehilmnoöuür][mn]en
SFX O en ter [aäeilmnoöuür][mn]en
SFX O n tem e[lr]n
SFX O n tem [dtw]en
SFX O en tem [^dmntw]en
SFX O n tem chnen
SFX O en tem [^c]h[mn]en
SFX O n tem [^aäehilmnoöuür][mn]en
SFX O en tem [aäeilmnoöuür][mn]en
REP 28
REP f ph
REP ph f
REP ß ss
REP ss ß
REP s ss
REP ss s
REP i ie
REP ie i
REP ee e
REP o oh
REP oh o
REP a ah
REP ah a
REP e eh
REP eh e
REP ae ä
REP oe ö
REP ue ü
REP Ae Ä
REP Oe Ö
REP Ue Ü
REP d t
REP t d
REP th t
REP t th
REP r rh
REP ch k
REP k ch
#REP eee ee-E
# this one will allow "-Eltern" - Hunspell 1.1.5 bug, but CHECKSHARPS obsoletes LANG de_DE
#LANG de_DE
CHECKSHARPS
COMPOUNDBEGIN x
COMPOUNDMIDDLE y
COMPOUNDEND z
FORBIDDENWORD d
# Prefixes are allowed at the beginning of compounds,
# suffixes are allowed at the end of compounds by default:
# (prefix)?(root)+(affix)?
# Affixes with COMPOUNDPERMITFLAG may be inside of compounds.
COMPOUNDPERMITFLAG c
ONLYINCOMPOUND o
# my PSEUDOROOT h(elper) flag
NEEDAFFIX h
# forbid uppercase characters at compound word bounds
# BUT I want to take care about it myself ;-)
# CHECKCOMPOUNDCASE
KEEPCASE w
# Affixes signed with CIRCUMFIX flag may be on a word when this word also has a prefix with CIRCUMFIX flag and vice versa.
# for decapitalizing nouns with fogemorphemes
CIRCUMFIX f
# this one would make a separate dict entry "Denkmalsschutz" invalidate the
# compound of "Denkmal"+"schutz". We do not want this feature here...
# CHECKCOMPOUNDREP
# make not all possible suggestions for typos of Flicken or some rare words
NOSUGGEST n
WORDCHARS ß-.
# - setting this to 2 decreases performance by 1/10 but is needed for "öl" and "ei"
# - setting this to 1 for handling Fuge-elements with dashes (Arbeits-) dash will
# be a special word but - is handled as a affix now
COMPOUNDMIN 2
# this ones are for Duden R36 (old orthography)
#CHECKCOMPOUNDPATTERN 2 #oldspell
#CHECKCOMPOUNDPATTERN ee e #oldspell
#CHECKCOMPOUNDPATTERN oo o #oldspell
# also need oo o
# this one needs to be flagable to be used for old orthography
#CHECKCOMPOUNDTRIPLE
PFX i Y 1
PFX i 0 -/coyf .
SFX j Y 3
SFX j 0 0/xoc .
SFX j 0 -/zocf .
SFX j 0 -/cz .
# Female forms for compound/Compound words:
# attention: [^e][^n] does also filter out "...er" !
SFX g Y 12
SFX g 0 innen/xyoc [^n]
SFX g en innen/xyoc en
SFX g 0 Innen/xyoc [^n]
SFX g en Innen/xyoc en
SFX g 0 innen/xyocf [^n]
SFX g en innen/xyocf en
SFX g 0 Innen/xyocf [^n]
SFX g en Innen/xyocf en
SFX g 0 innen-/cz [^n]
SFX g en innen-/cz en
SFX g 0 Innen-/cz [^n]
SFX g en Innen-/cz en
PFX k Y 2
PFX k 0 -/coxf .
PFX k 0 0/coy .
SFX e Y 2
SFX e 0 0/yoc .
SFX e 0 -/zc .
# for Uppercased end-words to prepend - and lowercase: (Tier/EPSm) (EX: Bettbezüge und *-laken*)
# AND
# for lowercased end-words to prepend - and re-uppercase : (tier/EPSozm) (EX: Arbeits*-Tier*)
#PFX m A -a/co A
#PFX m a -/ a
PFX m Y 58
PFX m A -a A
PFX m B -b B
PFX m C -c C
PFX m D -d D
PFX m E -e E
PFX m F -f F
PFX m G -g G
PFX m H -h H
PFX m I -i I
PFX m J -j J
PFX m K -k K
PFX m L -l L
PFX m M -m M
PFX m N -n N
PFX m O -o O
PFX m P -p P
PFX m Q -q Q
PFX m R -r R
PFX m S -s S
PFX m T -t T
PFX m U -u U
PFX m V -v V
PFX m W -w W
PFX m X -x X
PFX m Y -y Y
PFX m Z -z Z
PFX m Ä -ä Ä
PFX m Ö -ö Ö
PFX m Ü -ü Ü
PFX m a -A/co a
PFX m b -B/co b
PFX m c -C/co c
PFX m d -D/co d
PFX m e -E/co e
PFX m f -F/co f
PFX m g -G/co g
PFX m h -H/co h
PFX m i -I/co i
PFX m j -J/co j
PFX m k -K/co k
PFX m l -L/co l
PFX m m -M/co m
PFX m n -N/co n
PFX m o -O/co o
PFX m p -P/co p
PFX m q -Q/co q
PFX m r -R/co r
PFX m s -S/co s
PFX m t -T/co t
PFX m u -U/co u
PFX m v -V/co v
PFX m w -W/co w
PFX m x -X/co x
PFX m y -Y/co y
PFX m z -Z/co z
PFX m ä -Ä/co ä
PFX m ö -Ö/co ö
PFX m ü -Ü/co ü
# Decapitalizing: (not used ATM... )
# /co(f) : compound permit, in coumpount only, (decapitalizing with fogemorphemes)
#PFX l Y 29
#PFX l A a/co A
#PFX l Ä ä/co Ä
#PFX l B b/co B
#PFX l C c/co C
#PFX l D d/co D
#PFX l E e/co E
#PFX l F f/co F
#PFX l G g/co G
#PFX l H h/co H
#PFX l I i/co I
#PFX l J j/co J
#PFX l K k/co K
#PFX l L l/co L
#PFX l M m/co M
#PFX l N n/co N
#PFX l O o/co O
#PFX l Ö ö/co Ö
#PFX l P p/co P
#PFX l Q q/co Q
#PFX l R r/co R
#PFX l S s/co S
#PFX l T t/co T
#PFX l U u/co U
#PFX l Ü ü/co Ü
#PFX l V v/co V
#PFX l W w/co W
#PFX l X x/co X
#PFX l Y y/co Y
#PFX l Z z/co Z
# private hunspell flags:
# --x : not for capmain (rare words)
# With "BREAK -" some wrong forms are accepted but that is needed for US-Wirtschaft etc.
# So enabling this is the lesser evil. No perfect solution found so far...
BREAK 2
BREAK -
BREAK .

File diff suppressed because it is too large Load diff

View file

@ -1,205 +0,0 @@
SET UTF-8
TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ'
ICONV 1
ICONV '
NOSUGGEST !
# ordinal numbers
COMPOUNDMIN 1
# only in compounds: 1th, 2th, 3th
ONLYINCOMPOUND c
# compound rules:
# 1. [0-9]*1[0-9]th (10th, 11th, 12th, 56714th, etc.)
# 2. [0-9]*[02-9](1st|2nd|3rd|[4-9]th) (21st, 22nd, 123rd, 1234th, etc.)
COMPOUNDRULE 2
COMPOUNDRULE n*1t
COMPOUNDRULE n*mp
WORDCHARS 0123456789'
PFX A Y 1
PFX A 0 re .
PFX I Y 1
PFX I 0 in .
PFX U Y 1
PFX U 0 un .
PFX C Y 1
PFX C 0 de .
PFX E Y 1
PFX E 0 dis .
PFX F Y 1
PFX F 0 con .
PFX K Y 1
PFX K 0 pro .
SFX V N 2
SFX V e ive e
SFX V 0 ive [^e]
SFX N Y 3
SFX N e ion e
SFX N y ication y
SFX N 0 en [^ey]
SFX X Y 3
SFX X e ions e
SFX X y ications y
SFX X 0 ens [^ey]
SFX H N 2
SFX H y ieth y
SFX H 0 th [^y]
SFX Y Y 1
SFX Y 0 ly .
SFX G Y 2
SFX G e ing e
SFX G 0 ing [^e]
SFX J Y 2
SFX J e ings e
SFX J 0 ings [^e]
SFX D Y 4
SFX D 0 d e
SFX D y ied [^aeiou]y
SFX D 0 ed [^ey]
SFX D 0 ed [aeiou]y
SFX T N 4
SFX T 0 st e
SFX T y iest [^aeiou]y
SFX T 0 est [aeiou]y
SFX T 0 est [^ey]
SFX R Y 4
SFX R 0 r e
SFX R y ier [^aeiou]y
SFX R 0 er [aeiou]y
SFX R 0 er [^ey]
SFX Z Y 4
SFX Z 0 rs e
SFX Z y iers [^aeiou]y
SFX Z 0 ers [aeiou]y
SFX Z 0 ers [^ey]
SFX S Y 4
SFX S y ies [^aeiou]y
SFX S 0 s [aeiou]y
SFX S 0 es [sxzh]
SFX S 0 s [^sxzhy]
SFX P Y 3
SFX P y iness [^aeiou]y
SFX P 0 ness [aeiou]y
SFX P 0 ness [^y]
SFX M Y 1
SFX M 0 's .
SFX B Y 3
SFX B 0 able [^aeiou]
SFX B 0 able ee
SFX B e able [^aeiou]e
SFX L Y 1
SFX L 0 ment .
REP 90
REP a ei
REP ei a
REP a ey
REP ey a
REP ai ie
REP ie ai
REP alot a_lot
REP are air
REP are ear
REP are eir
REP air are
REP air ere
REP ere air
REP ere ear
REP ere eir
REP ear are
REP ear air
REP ear ere
REP eir are
REP eir ere
REP ch te
REP te ch
REP ch ti
REP ti ch
REP ch tu
REP tu ch
REP ch s
REP s ch
REP ch k
REP k ch
REP f ph
REP ph f
REP gh f
REP f gh
REP i igh
REP igh i
REP i uy
REP uy i
REP i ee
REP ee i
REP j di
REP di j
REP j gg
REP gg j
REP j ge
REP ge j
REP s ti
REP ti s
REP s ci
REP ci s
REP k cc
REP cc k
REP k qu
REP qu k
REP kw qu
REP o eau
REP eau o
REP o ew
REP ew o
REP oo ew
REP ew oo
REP ew ui
REP ui ew
REP oo ui
REP ui oo
REP ew u
REP u ew
REP oo u
REP u oo
REP u oe
REP oe u
REP u ieu
REP ieu u
REP ue ew
REP ew ue
REP uff ough
REP oo ieu
REP ieu oo
REP ier ear
REP ear ier
REP ear air
REP air ear
REP w qu
REP qu w
REP z ss
REP ss z
REP shun tion
REP shun sion
REP shun cion
REP size cise

File diff suppressed because it is too large Load diff