Updated too many things to count

This commit is contained in:
JeremyStar™ 2024-11-14 20:07:26 +01:00
parent 0f7029f1ee
commit 2d615d717d
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
60 changed files with 2642 additions and 456 deletions

178
.gitignore vendored
View file

@ -1,140 +1,50 @@
# User-specific stuff ### Gradle ###
.idea/
*.iml
*.ipr
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
.gradle .gradle
build/ build/
# Ignore Gradle GUI config
gradle-app.setting
# Cache of project
.gradletasknamecache
**/build/
# Common working directory
run/ run/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) ### IntelliJ IDEA ###
!gradle-wrapper.jar .idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
.idea/*
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
# Avoid committing large parts of the server ### Eclipse ###
server/.console_history .apt_generated
server/banned-ips.json .classpath
server/banned-players.json .factorypath
server/commands.yml .project
server/config .settings
server/help.yml .springBeans
server/logs .sts4-cache
server/ops.json bin/
server/permissions.yml !**/src/main/**/bin/
server/plugins/spark/tmp !**/src/test/**/bin/
server/usercache.json
server/version_history.json
server/whitelist.json
server/world
server/world_nether
server/world_the_end
# nothing to see here :3 ### NetBeans ###
NEVEREVERCOMMITTHIS.sh /nbproject/private/
uwu.txt /nbbuild/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store
### Java ###
hs_err_pid*.log
## Docker ##
dist/volumes

View file

@ -1,4 +1,4 @@
# PickShadow's server code # PickShadow Server Kit (PSSK)
This repository contains PickShadow's server-side code. This repository contains PickShadow's server-side code.
## Index ## Index

View file

@ -28,8 +28,8 @@ allprojects {
repositories { repositories {
mavenCentral() mavenCentral()
maven { maven {
name = "staropensource-sosengine" name = "staropensource-engine"
url = "https://mvn.staropensource.de/sosengine" url = "https://mvn.staropensource.de/engine"
} }
maven { maven {
name = "papermc-repo" name = "papermc-repo"

86
common/build.gradle Normal file
View file

@ -0,0 +1,86 @@
/*
* 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/>.
*/
import java.nio.file.Files
// Plugins
plugins {
id("java")
id("io.freefair.lombok") version("${pluginLombok}")
id("com.gorylenko.gradle-git-properties") version("${pluginGitProperties}")
}
// Dependencies
dependencies {
// Lombok
compileOnly("org.projectlombok:lombok:${dependencyLombok}")
annotationProcessor("org.projectlombok:lombok:${dependencyLombok}")
// JetBrains Annotations
compileOnly("org.jetbrains:annotations:${dependencyJetbrainsAnnotations}")
// Libraries
compileOnly("de.staropensource.engine:base:${dependencyStarOpenSourceEngine}")
}
// Set Java version
java {
toolchain.languageVersion.set(JavaLanguageVersion.of("${javaTarget}"))
}
// 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/pickshadow-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/pickshadow-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)

1
common/gradle Symbolic link
View file

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

1
common/gradlew vendored Symbolic link
View file

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

1
common/gradlew.bat vendored Symbolic link
View file

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

View file

@ -0,0 +1,66 @@
/*
* 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.common;
import de.staropensource.engine.base.logging.Logger;
import lombok.Getter;
/**
* Initializes and manages the PickShadow Common Library.
*
* @since v1-release0
*/
@SuppressWarnings({ "JavadocDeclaration" })
public final class CommonLibrary {
/**
* 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 CommonLibrary instance = null;
/**
* Creates and initializes an instance of this class.
*
* @since v1-release0
*/
private CommonLibrary() {
Logger.verb("Initializing the PickShadow Common Library");
PSSKInformation.update();
}
/**
* Initializes the common library,
* if it isn't already.
*
* @since v1-release0
*/
public static void initialize() {
if (instance == null)
instance = new CommonLibrary();
}
}

View file

@ -17,14 +17,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package de.jeremystartm.pickshadow.extension; package de.jeremystartm.pickshadow.common;
import de.staropensource.sosengine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.sosengine.base.type.VersionType; import de.staropensource.engine.base.type.VersionType;
import de.staropensource.sosengine.base.utility.PropertiesReader; import de.staropensource.engine.base.utility.PropertiesReader;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -42,15 +41,7 @@ import java.util.Properties;
* @since v1-alpha0 * @since v1-alpha0
*/ */
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class ExtensionInformation { public final class PSSKInformation {
/**
* 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. * Contains the extensions's version codename.
* *
@ -284,7 +275,7 @@ public final class ExtensionInformation {
* *
* @since v1-alpha6 * @since v1-alpha6
*/ */
private ExtensionInformation() {} private PSSKInformation() {}
/** /**
* Updates all variables. * Updates all variables.
@ -295,14 +286,14 @@ public final class ExtensionInformation {
* @since v1-alpha1 * @since v1-alpha1
*/ */
public static synchronized void update() { public static synchronized void update() {
logger.diag("Updating extension information"); Logger.diag("Updating extension information");
// Load properties from bundled gradle.properties // Load properties from bundled gradle.properties
Properties gradleProperties = new Properties(); Properties gradleProperties = new Properties();
InputStream gradleStream = ExtensionInformation.class.getClassLoader().getResourceAsStream("psse-gradle.properties"); InputStream gradleStream = PSSKInformation.class.getClassLoader().getResourceAsStream("psse-gradle.properties");
if (gradleStream == null) { if (gradleStream == null) {
logger.crash("Unable to load build information: The bundled gradle.properties file could not be found."); Logger.crash("Unable to load build information: The bundled gradle.properties file could not be found.");
return; return;
} }
@ -310,16 +301,16 @@ public final class ExtensionInformation {
gradleProperties.load(gradleStream); gradleProperties.load(gradleStream);
gradleStream.close(); gradleStream.close();
} catch (IOException exception) { } catch (IOException exception) {
logger.crash("Unable to load build information: InputStream 'gradleStream' failed", exception); Logger.crash("Unable to load build information: InputStream 'gradleStream' failed", exception);
return; return;
} }
// Load properties from bundled git.properties // Load properties from bundled git.properties
// or fill in blank information if file missing // or fill in blank information if file missing
Properties gitProperties = new Properties(); Properties gitProperties = new Properties();
InputStream gitStream = ExtensionInformation.class.getClassLoader().getResourceAsStream("psse-git.properties"); InputStream gitStream = PSSKInformation.class.getClassLoader().getResourceAsStream("psse-git.properties");
if (gitStream == null) { if (gitStream == null) {
logger.error("Unable to load build information: The bundled git.properties file could not be found. Did you download a tarball?"); Logger.error("Unable to load build information: The bundled git.properties file could not be found. Did you download a tarball?");
// Fake information // Fake information
gitProperties.setProperty("git.total.commit.count", "0"); gitProperties.setProperty("git.total.commit.count", "0");
@ -337,7 +328,7 @@ public final class ExtensionInformation {
gitProperties.load(gitStream); gitProperties.load(gitStream);
gitStream.close(); gitStream.close();
} catch (IOException exception) { } catch (IOException exception) {
logger.crash("Unable to load build information: InputStream 'gitStream' failed", exception); Logger.crash("Unable to load build information: InputStream 'gitStream' failed", exception);
return; return;
} }
} }
@ -369,7 +360,7 @@ public final class ExtensionInformation {
calendar.setTime(date); calendar.setTime(date);
gitCommitTime = calendar.toZonedDateTime(); gitCommitTime = calendar.toZonedDateTime();
} catch (ParseException exception) { } 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); 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"); gitCommitterName = gitParser.getString("git.commit.user.name");
gitCommitterEmail = gitParser.getString("git.commit.user.email"); gitCommitterEmail = gitParser.getString("git.commit.user.email");

View file

@ -0,0 +1,25 @@
/*
* 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/>.
*/
/**
* Code commonly used across PSSK's codebase.
*
* @since v1-release0
*/
package de.jeremystartm.pickshadow.common;

View file

@ -0,0 +1,25 @@
/*
* 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/>.
*/
/**
* Everything related to the PickShadow Server Kit.
*
* @since v1-release0
*/
package de.jeremystartm.pickshadow;

View file

@ -0,0 +1,15 @@
/**
* Code commonly used across PSSK's codebase.
*
* @since v1-release0
*/
module pickshadow.common {
// Libraries
requires sosengine.base;
// API access
exports de.jeremystartm.pickshadow.common;
// Reflection access
opens de.jeremystartm.pickshadow.common;
}

View file

@ -0,0 +1 @@
../../../../src/main/javadoc/theme.css

1
common/src/main/resources/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.properties

23
docker-compose.yml Normal file
View file

@ -0,0 +1,23 @@
services:
postgresql-dev:
container_name: postgresql-dev
image: bitnami/postgresql:latest
restart: always
stop_grace_period: 10s
user: 0:0
environment:
- ALLOW_EMPTY_PASSWORD=yes
- POSTGRESQL_USERNAME=postgres
- POSTGRESQL_PASSWORD=postgres
- POSTGRESQL_POSTGRES_PASSWORD=postgres
volumes:
- ./dist/volumes/postgresql-dev/data:/bitnami/postgresql/data
networks:
- development
ports:
- 127.0.0.1:5432:5432
networks:
development:
name: development
external: false

View file

@ -1,7 +1,3 @@
import io.papermc.paperweight.userdev.ReobfArtifactConfiguration
import java.nio.file.Files
/* /*
* PICKSHADOW SERVER KIT SOURCE FILE * PICKSHADOW SERVER KIT SOURCE FILE
* Copyright (c) 2024 The PickShadow Server Kit authors * Copyright (c) 2024 The PickShadow Server Kit authors
@ -21,13 +17,14 @@ import java.nio.file.Files
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import io.papermc.paperweight.userdev.ReobfArtifactConfiguration
// Plugins // Plugins
plugins { plugins {
id("java") id("java")
id("io.freefair.lombok") version("${pluginLombok}") id("io.freefair.lombok") version("${pluginLombok}")
id("io.papermc.paperweight.userdev") version("${pluginPaperweight}") id("io.papermc.paperweight.userdev") version("${pluginPaperweight}")
id("io.github.goooler.shadow") version("${pluginShadow}") id("io.github.goooler.shadow") version("${pluginShadow}")
id("com.gorylenko.gradle-git-properties") version("${pluginGitProperties}")
id("xyz.jpenilla.run-paper") version("${pluginRunTask}") id("xyz.jpenilla.run-paper") version("${pluginRunTask}")
} }
@ -41,7 +38,8 @@ dependencies {
compileOnly("org.jetbrains:annotations:${dependencyJetbrainsAnnotations}") compileOnly("org.jetbrains:annotations:${dependencyJetbrainsAnnotations}")
// Libraries // Libraries
compileOnly("de.staropensource.sosengine:base:${dependencyStarOpenSourceEngine}") compileOnly("de.staropensource.engine:base:${dependencyStarOpenSourceEngine}")
runtimeOnly("de.staropensource.enginemc:platform-bukkit:${dependencyStarOpenSourceEngineMC}")
implementation("com.google.code.gson:gson:${dependencyGson}") implementation("com.google.code.gson:gson:${dependencyGson}")
// Server // Server
@ -54,6 +52,9 @@ dependencies {
// Bukkit libraries // Bukkit libraries
implementation("fr.mrmicky:fastboard:${dependencyFastboard}") implementation("fr.mrmicky:fastboard:${dependencyFastboard}")
// Project
implementation(project(":common"))
} }
// Set Java version // Set Java version
@ -68,44 +69,6 @@ processResources {
} }
} }
// 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 // Configure paperweight
paperweight { paperweight {
reobfArtifactConfiguration = ReobfArtifactConfiguration.getMOJANG_PRODUCTION() reobfArtifactConfiguration = ReobfArtifactConfiguration.getMOJANG_PRODUCTION()
@ -114,14 +77,19 @@ paperweight {
// Configure server // Configure server
runServer { runServer {
minecraftVersion("${minecraftVersion}") minecraftVersion("${minecraftVersion}")
systemProperty("file.encoding", "UTF-8")
systemProperty("com.mojang.eula.agree", "true") jvmArguments.addAll(
systemProperty("sosengine.base.loggerLevel", "diagnostic") "-Dfile.encoding=UTF-8",
"-Dcom.mojang.eula.agree=true",
"-Dsosengine.base.logLevel=diagnostic",
"-Dpickshadow.extension.enabledModes=general,survival,survivalcheat"
)
downloadPlugins { downloadPlugins {
modrinth("freedomchat", "${downloadFreedomChat}")
url("${downloadEngineMC}") url("${downloadEngineMC}")
url("${downloadLuckPerms}") url("${downloadLuckPerms}")
url("${downloadSpark}")
modrinth("freedomchat", "${downloadFreedomChat}")
} }
doFirst { doFirst {

View file

@ -0,0 +1,108 @@
/*
* 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.extension;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Provides an ugly way to choose
* what to put into the final,
* compiled bytecode.
* <p>
* Seriously, why doesn't Java
* have a macro processor. It
* would've been so useful!
*
* @since v1-release0
*/
public final class BuildOptions {
// -----> Settings
/**
* Contains an array of all bad effects.
*
* @since v1-release0
*/
public static final @NotNull List<@NotNull PotionEffectType> SETTINGS_EFFECTS_BAD = List.of(
PotionEffectType.SLOWNESS,
PotionEffectType.MINING_FATIGUE,
PotionEffectType.INSTANT_DAMAGE,
PotionEffectType.NAUSEA,
PotionEffectType.BLINDNESS,
PotionEffectType.HUNGER,
PotionEffectType.WEAKNESS,
PotionEffectType.POISON,
PotionEffectType.UNLUCK,
PotionEffectType.BAD_OMEN,
PotionEffectType.DARKNESS,
PotionEffectType.TRIAL_OMEN,
PotionEffectType.RAID_OMEN,
PotionEffectType.INFESTED
);
/**
* Contains an array of all damaging effects.
*
* @since v1-release0
*/
public static final @NotNull List<@NotNull PotionEffectType> SETTINGS_EFFECTS_DAMAGING = List.of(
PotionEffectType.INSTANT_DAMAGE,
PotionEffectType.HUNGER,
PotionEffectType.POISON
);
// -----> Fixes and unfixes
/**
* Unfixes MC-212 (fixed in 24w45a),
* which allows players to avoid fall
* damage if they disconnect and then
* reconnect before hitting the ground.
*
* @see <a href="https://bugs.mojang.com/browse/MC-212">MC-212 on the Minecraft bug tracker</a>
* @see <a href="https://minecraft.wiki/w/Java_Edition_24w45a">24w45a on the Minecraft Wiki</a>
* @since v1-release0
*/
public static final boolean UNFIX_FALLDAMAGE_CANCELLING = true;
// -----> Small stuff
/**
* Hides all messages starting with {@code #}.
* <p>
* This allows commenting commands and
* messages easily. To circumvent it,
* just type {@code <reset>#} instead.
*
* @since v1-release0
*/
public static final boolean SMALLSTUFF_CHAT_COMMENTS = true;
/**
* Enables stonecutter damage.
* <p>
* I mean seriously, this thing has rotating blades.
* That Mojang decided not to add damage to it is
* embarrassing. Or can it cause animal cruelty,
* is it that Mojang?
*
* @since v1-release0
*/
public static final boolean SMALLSTUFF_STONECUTTER_DAMAGE = true;
}

View file

@ -19,14 +19,24 @@
package de.jeremystartm.pickshadow.extension; package de.jeremystartm.pickshadow.extension;
import de.jeremystartm.pickshadow.common.CommonLibrary;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory; import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.jeremystartm.pickshadow.extension.command.general.AnnounceCommand;
import de.jeremystartm.pickshadow.extension.command.general.replacement.GamemodeCommand;
import de.jeremystartm.pickshadow.extension.command.general.replacement.HelpCommand;
import de.jeremystartm.pickshadow.extension.command.general.replacement.MessageCommand;
import de.jeremystartm.pickshadow.extension.command.survivalcheat.FeedCommand;
import de.jeremystartm.pickshadow.extension.command.survivalcheat.HealCommand;
import de.jeremystartm.pickshadow.extension.command.survivalcheat.ToggleDownfallCommand;
import de.jeremystartm.pickshadow.extension.command.general.*; import de.jeremystartm.pickshadow.extension.command.general.*;
import de.jeremystartm.pickshadow.extension.command.survival.HomeCommand; import de.jeremystartm.pickshadow.extension.command.survival.HomeCommand;
import de.jeremystartm.pickshadow.extension.listener.ChatListener; import de.jeremystartm.pickshadow.extension.listener.ChatListener;
import de.jeremystartm.pickshadow.extension.listener.ConnectionListener; import de.jeremystartm.pickshadow.extension.listener.ConnectionListener;
import de.staropensource.sosengine.base.logging.LoggerInstance; import de.jeremystartm.pickshadow.extension.misc.BukkitLoggingAdapter;
import de.staropensource.sosengine.base.utility.Miscellaneous; import de.jeremystartm.pickshadow.extension.misc.Scheduler;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.utility.Miscellaneous;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
@ -51,13 +61,6 @@ public final class Extension extends JavaPlugin {
@Getter @Getter
private static Extension instance = null; 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. * Creates and initializes an instance of this class.
* *
@ -67,6 +70,7 @@ public final class Extension extends JavaPlugin {
instance = this; instance = this;
} }
// -----> Extension (de)initialization
/** /**
* Called after the plugin has been loaded. * Called after the plugin has been loaded.
* *
@ -74,25 +78,28 @@ public final class Extension extends JavaPlugin {
*/ */
@Override @Override
public void onLoad() { public void onLoad() {
logger.info("Bootstrapping"); // Fix logging adapter
Logger.setLoggingAdapter(new BukkitLoggingAdapter());
Logger.info("Bootstrapping");
// Check for NMS // Check for NMS
try { try {
Class.forName("net.minecraft.server.MinecraftServer"); Class.forName("net.minecraft.server.MinecraftServer");
} catch (Exception exception) { } 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 software.", 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 software.", exception);
return; return;
} }
// Load classes // Load classes
CommonLibrary.initialize();
new ExtensionConfiguration().loadConfiguration(); new ExtensionConfiguration().loadConfiguration();
ExtensionInformation.update();
TranslationManager.loadTranslations(); TranslationManager.loadTranslations();
TranslationManager.processTranslations(); TranslationManager.processTranslations();
//TabListHandler.initialize(); //TabListHandler.initialize();
PlayerDataFactory.initialize(); PlayerDataFactory.initialize();
logger.info("Bootstrapped in " + Miscellaneous.measureExecutionTime(() -> {}) + "ms"); Logger.info("Bootstrapped in " + Miscellaneous.measureExecutionTime(() -> {}) + "ms");
} }
/** /**
@ -102,25 +109,49 @@ public final class Extension extends JavaPlugin {
*/ */
@Override @Override
public void onEnable() { public void onEnable() {
logger.info("Initializing"); Logger.info("Initializing");
try { try {
logger.info("Initialized in " + Miscellaneous.measureExecutionTime(() -> { Logger.info("Initialized in " + Miscellaneous.measureExecutionTime(() -> {
logger.verb("Registering commands"); Logger.verb("Checking environment");
// Check for PaperMC
if (!isPaper())
Logger.crash("PaperMC classes weren't detected.\nYour server likely isn't running PaperMC or a fork of it.\nPSSE only supports PaperMC-based Minecraft servers.");
// Check for Folia
if (isFolia())
Logger.warn("Folia classes were detected.\nFolia support is experimental. Everything *should* work, but nothing is guaranteed. Here be dragons!");
else
Logger.verb("Folia classes weren't detected.\nFolia or a fork of it doesn't seem to be installed.");
Logger.verb("Registering commands");
new GamemodeCommand();
new HelpCommand();
new MessageCommand();
new AnnounceCommand(); new AnnounceCommand();
new ClearChatCommand(); new ClearChatCommand();
new ExtensionCommand(); new ExtensionCommand();
new HomeCommand(); new LanguageCommand();
new LinkCommand(); new LinkCommand();
new MessageCommand();
new ToggleDownfallCommand();
new TrollCommand(); new TrollCommand();
logger.verb("Registering listeners");
new HomeCommand();
new FeedCommand();
new HealCommand();
new ToggleDownfallCommand();
Logger.verb("Registering listeners");
Bukkit.getPluginManager().registerEvents(new ConnectionListener(), this); Bukkit.getPluginManager().registerEvents(new ConnectionListener(), this);
Bukkit.getPluginManager().registerEvents(new ChatListener(), this); Bukkit.getPluginManager().registerEvents(new ChatListener(), this);
Logger.verb("Starting schedulers");
Bukkit.getServer().getGlobalRegionScheduler().runAtFixedRate(Extension.getInstance(), Scheduler::server, 1L, 1L);
}) + "ms"); }) + "ms");
} catch (Exception exception) { } catch (Exception exception) {
logger.crash("Initialization failed", exception); Logger.crash("Initialization failed", exception);
} }
} }
@ -131,7 +162,41 @@ public final class Extension extends JavaPlugin {
*/ */
@Override @Override
public void onDisable() { public void onDisable() {
logger.info("Shutting down"); Logger.info("Shutting down");
logger.info("Shut down in " + Miscellaneous.measureExecutionTime(() -> {}) + "ms"); Logger.info("Shut down in " + Miscellaneous.measureExecutionTime(() -> {}) + "ms");
}
// -----> Utility methods
/**
* Checks if PaperMC's
* {@code PaperBootstrap}
* class is present.
*
* @return {@code true} if present, {@code false} otherwise
* @since v1-release0
*/
public static boolean isPaper() {
try {
Class.forName("io.papermc.paper.PaperBootstrap");
return true;
} catch (ClassNotFoundException exception) {
return false;
}
}
/**
* Checks if Folia's
* {@code RegionizedServer}
* class is present.
*
* @return {@code true} if present, {@code false} otherwise
* @since v1-release0
*/
public static boolean isFolia() {
try {
Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
return true;
} catch (ClassNotFoundException exception) {
return false;
}
} }
} }

View file

@ -20,8 +20,8 @@
package de.jeremystartm.pickshadow.extension; package de.jeremystartm.pickshadow.extension;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.staropensource.sosengine.base.implementable.Configuration; import de.staropensource.engine.base.implementable.Configuration;
import de.staropensource.sosengine.base.utility.PropertiesReader; import de.staropensource.engine.base.utility.PropertiesReader;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -56,33 +56,62 @@ public final class ExtensionConfiguration extends Configuration {
/** /**
* If enabled, allows for unintentional behaviour * Contains whether to allow unintentional behaviour
* and excess logging. Unless you want to debug or work * and excess logging.
* <p>
* Unless you want to debug or work
* on a sensitive part of the engine, don't enable this! * on a sensitive part of the engine, don't enable this!
* *
* @since v1-release0 * @since v1-release0
* -- GETTER -- * -- GETTER --
* Gets the value for {@link #debug}. * Returns whether to allow unintentional behaviour
* and excess logging.
* <p>
* Unless you want to debug or work
* on a sensitive part of the engine, don't enable this!
* *
* @return variable value * @return debugging flag state
* @see #debug
* @since v1-release0 * @since v1-release0
*/ */
private boolean debug; private boolean debug;
/** /**
* Causes {@link StaticTabCompletion} to print lots debugging information. * Contains whether or not the tab completioning process
* should be logged by {@link StaticTabCompletion}.
* *
* @since v1-release0 * @since v1-release0
* -- GETTER -- * -- GETTER --
* Gets the value for {@link #debugStaticCompletion}. * Contains whether or not the tab completioning process
* should be logged by {@link StaticTabCompletion}.
* *
* @return variable value * @return detailed tab completioning logging
* @see #debugStaticCompletion
* @since v1-release0 * @since v1-release0
*/ */
private boolean debugStaticCompletion; private boolean debugStaticCompletion;
/**
* Contains an array of all
* enabled extension modes.
* <p>
* Extension modes control what methods
* will be available and how the server
* will be controlled by the extension.
*
* @since v1-release0
* -- GETTER --
* Returns an array of all
* enabled extension modes.
* <p>
* Extension modes control what methods
* will be available and how the server
* will be controlled by the extension.
*
* @return enabled extension modes
* @since v1-release0
*/
private String[] enabledModes;
/** /**
* Creates and initializes an instance of this class. * Creates and initializes an instance of this class.
* *
@ -90,8 +119,6 @@ public final class ExtensionConfiguration extends Configuration {
* @since v1-release0 * @since v1-release0
*/ */
ExtensionConfiguration() { ExtensionConfiguration() {
super("PSSE");
instance = this; instance = this;
// Load default configuration // Load default configuration
@ -105,6 +132,8 @@ public final class ExtensionConfiguration extends Configuration {
switch (property) { switch (property) {
case "debug" -> debug = parser.getBoolean(group + property); case "debug" -> debug = parser.getBoolean(group + property);
case "debugStaticCompletion" -> debugStaticCompletion = parser.getBoolean(group + property); case "debugStaticCompletion" -> debugStaticCompletion = parser.getBoolean(group + property);
case "enabledModes" -> enabledModes = parser.getString(group + property).split(",");
} }
} catch (NullPointerException ignored) {} } catch (NullPointerException ignored) {}
} }
@ -123,6 +152,8 @@ public final class ExtensionConfiguration extends Configuration {
public void loadDefaultConfiguration() { public void loadDefaultConfiguration() {
debug = false; debug = false;
debugStaticCompletion = false; debugStaticCompletion = false;
enabledModes = new String[]{ "general" };
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@ -131,6 +162,8 @@ public final class ExtensionConfiguration extends Configuration {
return switch (setting) { return switch (setting) {
case "debug" -> debug; case "debug" -> debug;
case "debugStaticCompletion" -> debugStaticCompletion; case "debugStaticCompletion" -> debugStaticCompletion;
case "enabledModes" -> enabledModes;
default -> null; default -> null;
}; };
} }

View file

@ -19,48 +19,129 @@
package de.jeremystartm.pickshadow.extension.api.command; package de.jeremystartm.pickshadow.extension.api.command;
import de.jeremystartm.pickshadow.extension.ExtensionConfiguration;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.staropensource.engine.base.logging.Logger;
import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.*; import org.bukkit.command.*;
import org.bukkit.craftbukkit.command.ServerCommandSender;
import org.bukkit.util.StringUtil; import org.bukkit.util.StringUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
* Abstract class for implementing commands. * Abstract class for implementing commands.
*
* @since v1-release0
*/ */
@Getter
public abstract class CommandBase implements CommandExecutor { public abstract class CommandBase implements CommandExecutor {
/**
* Contains a list of all registered commands.
*
* @since v1-release0
*/
private static final @NotNull List<@NotNull CommandBase> REGISTERED = new ArrayList<>();
/**
* Contains a {@link CommandExecutor} implementation
* for disabled commands (caused by a disabled mode).
*
* @see ExtensionConfiguration#getEnabledModes()
* @since v1-release0
*/
public static final @NotNull CommandExecutor disallowedExecutor = (sender, command, alias, arguments) -> {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_INVALID_MODE, sender, true));
return true;
};
/**
* Contains a list of all {@link Command}s this
* command has been registered for.
*
* @since v1-release0
*/
private final @NotNull List<@NotNull PluginCommand> commands = new ArrayList<>();
/** /**
* Initializes this abstract class * Initializes this abstract class
* and registers the command. * and registers the command.
* *
* @param mode mode to register this command in
* @param commands all commands this class should handle * @param commands all commands this class should handle
* @throws IllegalArgumentException if a command does not exist * @throws IllegalArgumentException if a command does not exist
* @since v1-release0 * @since v1-release0
*/ */
public CommandBase(@NotNull String... commands) throws IllegalArgumentException { public CommandBase(@NotNull String mode, @NotNull String... commands) throws IllegalArgumentException {
boolean disallowedByMode = !Arrays.stream(ExtensionConfiguration.getInstance().getEnabledModes()).toList().contains(mode);
for (String command : commands) { for (String command : commands) {
PluginCommand pluginCommand = Bukkit.getPluginCommand(command); PluginCommand pluginCommand = Bukkit.getPluginCommand(command);
if (pluginCommand == null) if (pluginCommand == null)
throw new IllegalArgumentException("Command registration failed: The command \"" + command + "\" does not exist"); throw new IllegalArgumentException("Command registration failed: The command \"" + command + "\" does not exist");
pluginCommand.setExecutor(this); if (disallowedByMode) {
pluginCommand.setTabCompleter(new TabCompleter() { pluginCommand.setExecutor(disallowedExecutor);
@Override pluginCommand.setTabCompleter(null);
public @NotNull List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { } else {
return StringUtil.copyPartialMatches(args[args.length - 1], getCompletion().complete(sender, label, args), new ArrayList<>()); 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<>());
}
});
}
this.commands.add(pluginCommand);
} }
REGISTERED.add(this);
}
/**
* Initializes this abstract class
* and registers the command.
* <p>
* Using this constructor instead of
* {@link #CommandBase(String, String...)}
* causes the creation of a dummy command
* which must be registered manually.
* Not recommended, use only when needed.
*
* @since v1-release0
*/
public CommandBase() {
REGISTERED.add(this);
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { public final boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
invoke(sender, command, alias, args); try {
invoke(sender, command, alias, args);
} catch (Exception exception) {
Logger.crash(
"Command /"
+ command.getName()
+ " (under alias /"
+ alias
+ ") failed for sender "
+ sender.getName()
+ " (console="
+ (sender instanceof ConsoleCommandSender)
+ ") with the following arguments:\n"
+ Arrays.toString(args),
exception,
false);
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNKNOWN, sender, true));
}
return true; return true;
} }
@ -69,11 +150,13 @@ public abstract class CommandBase implements CommandExecutor {
* *
* @since v1-release0 * @since v1-release0
*/ */
@SuppressWarnings("NullableProblems") // intentional, see CommandBaseWithNull
public abstract void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments); public abstract void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments);
/** /**
* Provides tab completions for this command. * Provides tab completions for this command.
* *
* @return completion
* @since v1-release0 * @since v1-release0
*/ */
public abstract @NotNull TabCompletion getCompletion(); public abstract @NotNull TabCompletion getCompletion();
@ -85,10 +168,13 @@ public abstract class CommandBase implements CommandExecutor {
* *
* @param sender sender to check * @param sender sender to check
* @param permission permission to check for * @param permission permission to check for
* @return return? * @return {@code true} if the permission is missing, {@code false} otherwise
* @since v1-release0 * @since v1-release0
*/ */
protected static boolean checkPermission(@NotNull CommandSender sender, @NotNull String permission) { protected static boolean checkPermission(@NotNull CommandSender sender, @NotNull String permission) {
if (sender instanceof ServerCommandSender)
return false;
if (!sender.hasPermission(permission)) { if (!sender.hasPermission(permission)) {
sender.sendRichMessage( sender.sendRichMessage(
TranslationManager.get(LanguageString.ERROR_MISSING_PERM, sender, true) TranslationManager.get(LanguageString.ERROR_MISSING_PERM, sender, true)
@ -99,4 +185,14 @@ public abstract class CommandBase implements CommandExecutor {
return false; return false;
} }
/**
* Returns a list of all registered commands.
*
* @return list of registered commands
* @since v1-release0
*/
public static List<@NotNull CommandBase> getREGISTERED() {
return Collections.unmodifiableList(REGISTERED);
}
} }

View file

@ -0,0 +1,60 @@
/*
* 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.extension.api.command;
import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion;
import lombok.Getter;
import org.bukkit.command.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Abstract class for implementing commands
* without the {@code command} parameter.
*
* @since v1-release0
*/
@Getter
public abstract class CommandBaseWithNull extends CommandBase {
/**
* Initializes this abstract class
* and registers the command.
*
* @since v1-release0
*/
public CommandBaseWithNull() {}
/**
* Executes this command.
*
* @since v1-release0
*/
public abstract void invoke(@NotNull CommandSender sender, @Nullable Command command, @NotNull String alias, @NotNull String[] arguments);
/**
* Provides tab completions for this command.
*
* @return completion
* @since v1-release0
*/
public @NotNull TabCompletion getCompletion() {
return StubTabCompletion.completion();
}
}

View file

@ -21,7 +21,7 @@ package de.jeremystartm.pickshadow.extension.api.command.completion;
import de.jeremystartm.pickshadow.extension.ExtensionConfiguration; import de.jeremystartm.pickshadow.extension.ExtensionConfiguration;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.staropensource.sosengine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -37,13 +37,6 @@ import java.util.*;
* @since v1-release0 * @since v1-release0
*/ */
public final class StaticTabCompletion implements TabCompletion { 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. * Creates and initializes an instance of this class.
* *
@ -68,7 +61,7 @@ public final class StaticTabCompletion implements TabCompletion {
@Override @Override
public @NotNull List<@NotNull String> complete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) { public @NotNull List<@NotNull String> complete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] arguments) {
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion()) if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("complete(sender=" + sender.getName() + " alias=" + alias + " arguments=" + Arrays.toString(arguments) + ")"); Logger.diag("complete(sender=" + sender.getName() + " alias=" + alias + " arguments=" + Arrays.toString(arguments) + ")");
try { try {
// Get correct alias or return empty list // Get correct alias or return empty list
@ -79,26 +72,26 @@ public final class StaticTabCompletion implements TabCompletion {
return List.of(); return List.of();
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion() && alias.isEmpty()) if (ExtensionConfiguration.getInstance().isDebugStaticCompletion() && alias.isEmpty())
logger.diag("Alias has been corrected"); Logger.diag("Alias has been corrected");
// Get and add completions // Get and add completions
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion()) if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Compiling completions"); Logger.diag("Compiling completions");
List<@NotNull String> output = new ArrayList<>(getCompletions(sender, alias, arguments.length - 1)); List<@NotNull String> output = new ArrayList<>(getCompletions(sender, alias, arguments.length - 1));
// Get and add alias-wide completions // Get and add alias-wide completions
if (completions.get(alias).containsKey(-1)) { if (completions.get(alias).containsKey(-1)) {
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion()) if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Compiling alias-wide completions"); Logger.diag("Compiling alias-wide completions");
output.addAll(getCompletions(sender, alias, -1)); output.addAll(getCompletions(sender, alias, -1));
} }
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion()) if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("=== Completion finished"); Logger.diag("=== Completion finished");
return output; return output;
} catch (Exception exception) { } catch (Exception exception) {
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion()) if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Caught " + exception.getClass().getName() + ", returning error list"); Logger.diag("Caught " + exception.getClass().getName() + ", returning error list");
return Arrays.stream(new String[]{ "An error occurred" }).toList(); return Arrays.stream(new String[]{ "An error occurred" }).toList();
} }
} }
@ -116,7 +109,7 @@ public final class StaticTabCompletion implements TabCompletion {
List<@NotNull String> output = new ArrayList<>(); List<@NotNull String> output = new ArrayList<>();
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion()) if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("getCompletions(sender=" + sender.getName() + " alias=" + alias + " index=" + index + ")"); Logger.diag("getCompletions(sender=" + sender.getName() + " alias=" + alias + " index=" + index + ")");
if (!completions.get(alias).containsKey(index)) if (!completions.get(alias).containsKey(index))
return List.of(); return List.of();
@ -126,7 +119,7 @@ public final class StaticTabCompletion implements TabCompletion {
// Empty index, display player list // Empty index, display player list
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion()) if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Index is null, getting player list"); Logger.diag("Index is null, getting player list");
for (Player player : Bukkit.getOnlinePlayers()) for (Player player : Bukkit.getOnlinePlayers())
output.add(player.getName()); output.add(player.getName());
@ -136,15 +129,15 @@ public final class StaticTabCompletion implements TabCompletion {
// put these lines into Objects#requireNonNull so that the code is still fairly readable // put these lines into Objects#requireNonNull so that the code is still fairly readable
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion()) if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Index is map, getting arguments"); Logger.diag("Index is map, getting arguments");
for (String argument : completions.get(alias).get(index).keySet()) for (String argument : completions.get(alias).get(index).keySet())
if (sender.hasPermission(completions.get(alias).get(index).get(argument))) { if (sender.hasPermission(completions.get(alias).get(index).get(argument))) {
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion()) if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Adding completion argument \"" + argument + "\""); Logger.diag("Adding completion argument \"" + argument + "\"");
output.add(argument); output.add(argument);
} else if (ExtensionConfiguration.getInstance().isDebugStaticCompletion()) } else if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("Permission is missing, skipping completion argument \"" + argument + "\""); Logger.diag("Permission is missing, skipping completion argument \"" + argument + "\"");
} }
return output; return output;
@ -230,7 +223,7 @@ public final class StaticTabCompletion implements TabCompletion {
*/ */
private void createIndex(@NotNull String alias, @Range(from = -1, to = Integer.MAX_VALUE) int index) { private void createIndex(@NotNull String alias, @Range(from = -1, to = Integer.MAX_VALUE) int index) {
if (ExtensionConfiguration.getInstance().isDebugStaticCompletion()) if (ExtensionConfiguration.getInstance().isDebugStaticCompletion())
logger.diag("createIndex(alias=" + alias + " index=" + index + ")"); Logger.diag("createIndex(alias=" + alias + " index=" + index + ")");
try { try {
if (completions.get(alias).get(index) == null) if (completions.get(alias).get(index) == null)
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();

View file

@ -19,12 +19,11 @@
package de.jeremystartm.pickshadow.extension.api.entity.player; package de.jeremystartm.pickshadow.extension.api.entity.player;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import de.jeremystartm.pickshadow.extension.misc.TabListHandler; import de.jeremystartm.pickshadow.extension.misc.Scheduler;
import de.staropensource.sosengine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import fr.mrmicky.fastboard.adventure.FastBoard; import fr.mrmicky.fastboard.adventure.FastBoard;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
@ -33,6 +32,7 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@ -45,19 +45,16 @@ import static java.util.Map.entry;
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class PlayerData { public final class PlayerData {
/**
* Contains the logger instance for this instance.
*
* @since v1-release0
*/
private final LoggerInstance logger;
/** /**
* Contains the associated {@link Player}. * Contains the associated {@link Player}.
* <p>
* <b>Will be saved.</b>
* *
* @since v1-release0 * @since v1-release0
* -- GETTER -- * -- GETTER --
* Returns the associated {@link Player}. * Returns the associated {@link Player}.
* <p>
* <b>Will be saved.</b>
* *
* @return associated {@link Player} * @return associated {@link Player}
* @since v1-release0 * @since v1-release0
@ -67,15 +64,21 @@ public final class PlayerData {
/** /**
* Contains the player list scoreboard. * Contains the player list scoreboard.
* <p>
* <b>Will not be saved.</b>
* *
* @since v1-release0 * @since v1-release0
* -- GETTER -- * -- GETTER --
* Returns the player list scoreboard. * Returns the player list scoreboard.
* <p>
* <b>Will not be saved.</b>
* *
* @return player list scoreboard * @return player list scoreboard
* @since v1-release0 * @since v1-release0
* -- SETTER -- * -- SETTER --
* Sets the player list scoreboard. * Sets the player list scoreboard.
* <p>
* <b>Will not be saved.</b>
* *
* @param playerListScoreboard new player list scoreboard * @param playerListScoreboard new player list scoreboard
* @since v1-release0 * @since v1-release0
@ -83,20 +86,88 @@ public final class PlayerData {
@ApiStatus.Experimental @ApiStatus.Experimental
private @NotNull FastBoard playerListScoreboard; private @NotNull FastBoard playerListScoreboard;
/**
* Contains the preferred language
* the player has set.
* <p>
* <b>Will be saved.</b>
*
* @since v1-release0
* -- GETTER --
* Returns the preferred language
* the player has set.
* <p>
* <b>Will be saved.</b>
*
* @return preferred language
* @since v1-release0
* -- SETTER --
* Sets the preferred language
* the player has set.
* <p>
* <b>Will be saved.</b>
*
* @param language new preferred language
* @since v1-release0
*/
private String language;
/** /**
* Contains when the player has * Contains when the player has
* first been seen on the server. * first been seen on the server.
* <p>
* <b>Will be saved.</b>
* *
* @since v1-release0 * @since v1-release0
* -- GETTER -- * -- GETTER --
* Returns when the player has * Returns when the player has
* first been seen on the server. * first been seen on the server.
* <p>
* <b>Will be saved.</b>
* *
* @return first played date and time * @return first played date and time
* @since v1-release0 * @since v1-release0
*/ */
private ZonedDateTime firstSeen; private ZonedDateTime firstSeen;
/**
* Contains the UUID of the player
* this player has messaged last.
* <p>
* <b>Will be saved.</b>
*
* @since v1-release0
* -- GETTER --
* Returns the UUID of the player
* this player has messaged last.
* <p>
* <b>Will be saved.</b>
*
* @return UUID of the player last messaged
* @since v1-release0
*/
private UUID lastMessaged;
/**
* Contains the state for
* stone cutter damage, as
* assigned by the {@link Scheduler}.
* <p>
* <b>Will not be saved.</b>
*
* @since v1-release0
* -- GETTER --
* Returns the state for
* stone cutter damage, as
* assigned by the {@link Scheduler}.
* <p>
* <b>Will not be saved.</b>
*
* @return stone cutter damage state
* @since v1-release0
*/
private int stonecutterDamageState = -1;
/** /**
* Creates and initializes an instance of this class. * Creates and initializes an instance of this class.
* <p> * <p>
@ -107,11 +178,13 @@ public final class PlayerData {
* @since v1-release0 * @since v1-release0
*/ */
PlayerData(@NotNull Player player) { PlayerData(@NotNull Player player) {
this.player = player; Logger.info("Initializing fresh player data for player " + player.getName() + " [" + player.getUniqueId() + "]");
this.logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("PSSE").setMetadata(player.getName()).build();
this.player = player;
//TabListHandler.getInstance().initializeTabList(this); //TabListHandler.getInstance().initializeTabList(this);
language = "en";
firstSeen = ZonedDateTime.now(); firstSeen = ZonedDateTime.now();
lastMessaged = null;
} }
/** /**
@ -124,12 +197,14 @@ public final class PlayerData {
* @param firstSeen when the player was first seen * @param firstSeen when the player was first seen
* @since v1-release0 * @since v1-release0
*/ */
private PlayerData(@NotNull Player player, @NotNull ZonedDateTime firstSeen) { private PlayerData(@NotNull Player player, @NotNull String language, @NotNull ZonedDateTime firstSeen, @Nullable UUID lastMessaged) {
this.player = player; Logger.info("Initializing player data from existing data for player " + player.getName() + " [" + player.getUniqueId() + "]");
this.logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("PSSE").setMetadata(player.getName()).build();
TabListHandler.getInstance().initializeTabList(this); this.player = player;
//TabListHandler.getInstance().initializeTabList(this);
this.language = language;
this.firstSeen = firstSeen; this.firstSeen = firstSeen;
this.lastMessaged = lastMessaged;
} }
/** /**
@ -152,7 +227,9 @@ public final class PlayerData {
return new PlayerData( return new PlayerData(
player, player,
ZonedDateTime.parse(data.get("firstPlayed")) data.get("language"),
ZonedDateTime.parse(data.get("firstPlayed")),
data.get("lastMessaged").isBlank() ? null : UUID.fromString(data.get("lastMessaged"))
); );
} catch (Exception exception) { } catch (Exception exception) {
if (exception instanceof JsonSyntaxException) if (exception instanceof JsonSyntaxException)
@ -172,7 +249,9 @@ public final class PlayerData {
return new Gson().toJson( return new Gson().toJson(
Map.ofEntries( Map.ofEntries(
entry("playerUUID", player.getUniqueId().toString()), entry("playerUUID", player.getUniqueId().toString()),
entry("firstPlayed", firstSeen.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)) entry("language", language),
entry("firstPlayed", firstSeen.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)),
entry("lastMessaged", lastMessaged == null ? "" : lastMessaged.toString())
), ),
new TypeToken<Map<@NotNull String, @NotNull String>>(){}.getType()); new TypeToken<Map<@NotNull String, @NotNull String>>(){}.getType());
} }

View file

@ -19,7 +19,7 @@
package de.jeremystartm.pickshadow.extension.api.entity.player; package de.jeremystartm.pickshadow.extension.api.entity.player;
import de.staropensource.sosengine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import lombok.Getter; import lombok.Getter;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -29,7 +29,7 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
/** /**
* A factory for {@link Player}s. * A factory for {@link PlayerData} instances.
* *
* @since v1-release0 * @since v1-release0
*/ */
@ -48,13 +48,6 @@ public final class PlayerDataFactory {
@Getter @Getter
private static PlayerDataFactory instance; private static PlayerDataFactory instance;
/**
* Contains the logger instance of this instance.
*
* @since v1-release0
*/
private final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("PSSE").build();
/** /**
* Contains all registered {@link PlayerData} instances. * Contains all registered {@link PlayerData} instances.
* *
@ -136,12 +129,12 @@ public final class PlayerDataFactory {
* @since v1-release0 * @since v1-release0
*/ */
public void registerPlayer(@NotNull Player player) throws Exception { public void registerPlayer(@NotNull Player player) throws Exception {
logger.verb("Registering player " + player.getName() + " (" + player.getUniqueId() + ")"); Logger.verb("Registering player " + player.getName() + " (" + player.getUniqueId() + ")");
try { try {
playerList.add(new PlayerData(player)); playerList.add(new PlayerData(player));
} catch (Exception exception) { } catch (Exception exception) {
logger.crash("Unable to create PlayerData instance for player " + player.getName() + " (" + player.getUniqueId() + ")", exception, true); Logger.crash("Unable to create PlayerData instance for player " + player.getName() + " (" + player.getUniqueId() + ")", exception, true);
throw exception; throw exception;
} }
} }
@ -153,7 +146,7 @@ public final class PlayerDataFactory {
* @since v1-release0 * @since v1-release0
*/ */
public void unregisterPlayer(@NotNull PlayerData playerData) { public void unregisterPlayer(@NotNull PlayerData playerData) {
logger.verb("Unregistering player " + playerData.getPlayer().getName() + " (" + playerData.getPlayer().getUniqueId() + ")"); Logger.verb("Unregistering player " + playerData.getPlayer().getName() + " (" + playerData.getPlayer().getUniqueId() + ")");
playerList.remove(playerData); playerList.remove(playerData);
} }

View file

@ -43,6 +43,7 @@ public enum LanguageString {
// Errors // Errors
ERROR_UNKNOWN, ERROR_UNKNOWN,
ERROR_UNIMPLEMENTED, ERROR_UNIMPLEMENTED,
ERROR_INVALID_MODE,
ERROR_NOT_A_PLAYER, ERROR_NOT_A_PLAYER,
ERROR_MISSING_PERM, ERROR_MISSING_PERM,
ERROR_TOO_FEW_ARGUMENTS, ERROR_TOO_FEW_ARGUMENTS,
@ -56,6 +57,7 @@ public enum LanguageString {
CONNECTION_DISCONNECT, CONNECTION_DISCONNECT,
CONNECTION_ERROR_REGISTRATION, CONNECTION_ERROR_REGISTRATION,
CONNECTION_ERROR_TABLISTHANDLER, CONNECTION_ERROR_TABLISTHANDLER,
CONNECTION_ERROR_SCHEDULER,
// Command /psse // Command /psse
EXTENSIONCMD_GREETER, EXTENSIONCMD_GREETER,
@ -67,10 +69,13 @@ public enum LanguageString {
// Command group 'messaging' // Command group 'messaging'
MESSAGING_SERVER, MESSAGING_SERVER,
MESSAGING_DIRECT, MESSAGING_DIRECT,
MESSAGING_LASTCONTACT,
MESSAGING_ERROR_SELF, MESSAGING_ERROR_SELF,
MESSAGING_ERROR_NOLASTCONTACT,
// Command group 'links' // Command group 'links'
LINKS_WEBSITE, LINKS_WEBSITE,
LINKS_FORUM,
LINKS_DISCORD, LINKS_DISCORD,
LINKS_TEAMSPEAK, LINKS_TEAMSPEAK,
LINKS_MUMBLE, LINKS_MUMBLE,
@ -83,8 +88,9 @@ public enum LanguageString {
CLEARCHAT_CRINGE, CLEARCHAT_CRINGE,
// Command /home // Command /home
HOME,
HOME_NORESPAWN, HOME_NORESPAWN,
HOME_TELEPORTED, HOME_NORESPAWN_OTHER,
// Command /toggledownfall // Command /toggledownfall
TOGGLEDOWNFALL, TOGGLEDOWNFALL,
@ -99,6 +105,34 @@ public enum LanguageString {
TROLL_HACK_COMPLETE, TROLL_HACK_COMPLETE,
TROLL_HEAVENS, TROLL_HEAVENS,
// Command /language
LANGUAGE,
LANGUAGE_CURRENT,
LANGUAGE_INVALID,
// Command /heal
HEAL,
HEAL_REMOTE,
// Command /plugins
PLUGINS,
PLUGINS_FAKE,
PLUGINS_ENTRY_PREFIX,
PLUGINS_ENTRY_SUFFIX,
PLUGINS_ENTRY_NAME_PREFIX,
PLUGINS_ENTRY_NAME_SUFFIX,
// Command /reload
RELOAD,
// Command /gamemode
GAMEMODE,
GAMEMODE_REMOTE,
GAMEMODE_SURVIVAL,
GAMEMODE_CREATIVE,
GAMEMODE_ADVENTURE,
GAMEMODE_SPECTATOR,
// Event for chat commands // Event for chat commands
CHATCOMMAND_ERROR_NAMESPACE, CHATCOMMAND_ERROR_NAMESPACE,
} }

View file

@ -22,8 +22,10 @@ package de.jeremystartm.pickshadow.extension.api.translation;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import de.staropensource.sosengine.base.logging.LoggerInstance; import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory;
import de.staropensource.engine.base.logging.Logger;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -41,13 +43,6 @@ import java.util.Objects;
* @since v1-release0 * @since v1-release0
*/ */
public final class TranslationManager { 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. * Contains all translations.
* *
@ -55,6 +50,16 @@ public final class TranslationManager {
*/ */
private static final @NotNull Map<@NotNull String, @NotNull Map<@NotNull LanguageString, @NotNull String>> translations = new HashMap<>(); private static final @NotNull Map<@NotNull String, @NotNull Map<@NotNull LanguageString, @NotNull String>> translations = new HashMap<>();
/**
* Returns an array of all loaded languages.
*
* @return array of language names
* @since v1-release0
*/
public static @NotNull String @NotNull [] getLanguages() {
return translations.keySet().toArray(new String[0]);
}
/** /**
* Returns the translation for the specified language * Returns the translation for the specified language
* string for the specified {@link CommandSender}. * string for the specified {@link CommandSender}.
@ -65,18 +70,28 @@ public final class TranslationManager {
* @param placeholders placeholders * @param placeholders placeholders
* @since v1-release0 * @since v1-release0
*/ */
@SafeVarargs
public static @NotNull String get(@NotNull LanguageString languageString, @NotNull CommandSender sender, boolean includePrefix, @NotNull Map.Entry<@NotNull String, @NotNull String> @Nullable ... placeholders) { public static @NotNull String get(@NotNull LanguageString languageString, @NotNull CommandSender sender, boolean includePrefix, @NotNull Map.Entry<@NotNull String, @NotNull String> @Nullable ... placeholders) {
String temp = "en"; String temp = "en";
// Determine language to use
if (sender instanceof Player player)
try {
temp = PlayerDataFactory.getInstance().get(player).getLanguage();
} catch (NullPointerException ignored) {}
// Check if the prefix shall be included
if (includePrefix) if (includePrefix)
temp = get(LanguageString.PREFIX, "en") + get(languageString, temp).replace("\n", "\n" + get(LanguageString.PREFIX_NEWLINE, "en")); temp = get(LanguageString.PREFIX, "en") + get(languageString, temp).replace("\n", "\n" + get(LanguageString.PREFIX_NEWLINE, "en"));
else else
temp = get(languageString, temp); temp = get(languageString, temp);
// Replace placeholders
if (placeholders != null) if (placeholders != null)
for (Map.Entry<@NotNull String, @NotNull String> placeholder : placeholders) for (Map.Entry<@NotNull String, @NotNull String> placeholder : placeholders)
temp = temp.replace("%" + placeholder.getKey() + "%", placeholder.getValue()); temp = temp.replace("%" + placeholder.getKey() + "%", placeholder.getValue());
// Return
return temp; return temp;
} }
@ -89,12 +104,19 @@ public final class TranslationManager {
* @since v1-release0 * @since v1-release0
*/ */
public static @NotNull String get(@NotNull LanguageString languageString, @NotNull String language) { public static @NotNull String get(@NotNull LanguageString languageString, @NotNull String language) {
// Used for displaying '!MISSING_TRANSLATION!'
// when a translation is missing in 'en', the
// default language
if (language.equals("en")) if (language.equals("en"))
return translations.get(language).getOrDefault(languageString, "!" + languageString.name() + "!"); return translations.get(language).getOrDefault(languageString, "!" + languageString.name() + "!");
// If the translation key hasn't been translated
// in the specified language, request the
// translation using the standard language instead
if (!(translations.containsKey(language) && translations.get(language).containsKey(languageString))) if (!(translations.containsKey(language) && translations.get(language).containsKey(languageString)))
return get(languageString, "en"); return get(languageString, "en");
// Return translation string
return translations.get(language).get(languageString); return translations.get(language).get(languageString);
} }
@ -104,21 +126,21 @@ public final class TranslationManager {
* @since v1-release0 * @since v1-release0
*/ */
public static void loadTranslations() { public static void loadTranslations() {
LOGGER.verb("Loading translations"); Logger.verb("Loading translations");
Map<@NotNull String, @NotNull String> translationsLanguage; Map<@NotNull String, @NotNull String> translationsLanguage;
translations.clear(); translations.clear();
for (String language : new String[]{ "en", "de" }) { for (String language : new String[]{ "en", "de" }) {
LOGGER.diag("Loading translations for language \"" + language + "\""); Logger.diag("Loading translations for language \"" + language + "\"");
translations.put(language, new HashMap<>()); translations.put(language, new HashMap<>());
// Load, parse and store translations // Load, parse and store translations
try (InputStream stream = TranslationManager.class.getClassLoader().getResourceAsStream("translations/" + language.toLowerCase(Locale.ROOT) + ".json")) { 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()); 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) { } catch (IOException | NullPointerException exception) {
LOGGER.crash("Failed loading translations for language \"" + language + "\": IOException occurred", exception); Logger.crash("Failed loading translations for language \"" + language + "\": IOException occurred", exception);
return; return;
} catch (JsonSyntaxException exception) { } catch (JsonSyntaxException exception) {
LOGGER.crash("Failed loading translations for language \"" + language + "\": JSON Syntax does not match Map<LanguageString, String>", exception); Logger.crash("Failed loading translations for language \"" + language + "\": JSON Syntax does not match Map<LanguageString, String>", exception);
return; return;
} }
@ -134,7 +156,7 @@ public final class TranslationManager {
* @since v1-release0 * @since v1-release0
*/ */
public static void processTranslations() { public static void processTranslations() {
LOGGER.verb("Processing translations"); Logger.verb("Processing translations");
String tagBranding = get(LanguageString.TAG_BRANDING, "en"); String tagBranding = get(LanguageString.TAG_BRANDING, "en");
String tagGenericOpen = get(LanguageString.TAG_GENERIC_OPEN, "en"); String tagGenericOpen = get(LanguageString.TAG_GENERIC_OPEN, "en");
@ -147,7 +169,7 @@ public final class TranslationManager {
String tagLinkClose = get(LanguageString.TAG_LINK_CLOSE, "en"); String tagLinkClose = get(LanguageString.TAG_LINK_CLOSE, "en");
for (String language : translations.keySet()) { for (String language : translations.keySet()) {
LOGGER.diag("Processing translations for language \"" + language + "\""); Logger.diag("Processing translations for language \"" + language + "\"");
for (LanguageString languageString : translations.get(language).keySet()) for (LanguageString languageString : translations.get(language).keySet())
translations.get(language).put( translations.get(language).put(

View file

@ -0,0 +1,74 @@
/*
* 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.extension.command;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
/**
* Handles the {@code /cmd} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class TemplateCommand 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("cmd", -1, "--verbose", "pickshadow.command.cmd.verbose")
.add("cmd", 0, "arg1", "pickshadow.command.cmd")
.add("cmd", 0, "arg2", "pickshadow.command.cmd.arg2")
.add("cmd", 0, "arg3", "pickshadow.command.cmd.arg3")
.copy("cmd", "cmd2");
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public TemplateCommand() throws IllegalArgumentException {
super("mode", "cmd");
}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.cmd")) return;
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true));
}
}

View file

@ -24,7 +24,7 @@ import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabComp
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.staropensource.sosengine.base.utility.PlaceholderEngine; import de.staropensource.engine.base.utility.PlaceholderEngine;
import lombok.Getter; import lombok.Getter;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -51,7 +51,8 @@ public final class AnnounceCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
private final @NotNull TabCompletion completion = new StaticTabCompletion() private final @NotNull TabCompletion completion = new StaticTabCompletion()
.add("", -1, "--network", "pickshadow.command.announce.network"); .add("", -1, "--network", "pickshadow.command.announce.network")
.add("", -1, "--noprefix", "pickshadow.command.announce.network");
/** /**
* Creates and initializes an instance of * Creates and initializes an instance of
@ -60,7 +61,7 @@ public final class AnnounceCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public AnnounceCommand() throws IllegalArgumentException { public AnnounceCommand() throws IllegalArgumentException {
super("announce"); super("general", "announce");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@ -73,26 +74,38 @@ public final class AnnounceCommand extends CommandBase {
return; return;
} }
StringBuilder argumentsString = new StringBuilder(); StringBuilder argumentsBuilder = new StringBuilder();
String argumentsFinalized;
boolean networkwide = false; boolean networkwide = false;
boolean noprefix = false;
// Convert 'arguments' into a String // Convert 'arguments' into a String
for (String argument : arguments) { for (String argument : arguments) {
if (argument.equals("--network")) { if (argument.equals("--network")) {
networkwide = true; networkwide = true;
continue; continue;
} else if (argument.equals("--noprefix")) {
noprefix = true;
continue;
} }
if (!argumentsString.isEmpty()) if (!argumentsBuilder.isEmpty())
argumentsString.append(" "); argumentsBuilder.append(" ");
argumentsString.append(argument); argumentsBuilder.append(argument);
} }
argumentsFinalized = argumentsBuilder.toString();
if (noprefix)
argumentsFinalized = argumentsFinalized.replace("\\n", "\n");
else
argumentsFinalized = TranslationManager.get(LanguageString.PREFIX, sender, false) + argumentsFinalized.replace("\\n", "<reset>\n" + TranslationManager.get(LanguageString.PREFIX_NEWLINE, sender, false));
if (networkwide) { if (networkwide) {
if (!checkPermission(sender, "pickshadow.command.announce.network")) if (!checkPermission(sender, "pickshadow.command.announce.network"))
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true)); sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true));
} else } else
Bukkit.broadcast(MiniMessage.miniMessage().deserialize(PlaceholderEngine.getInstance().process(argumentsString.toString().replace("\\n", "\n")))); Bukkit.broadcast(MiniMessage.miniMessage().deserialize(PlaceholderEngine.getInstance().process(argumentsFinalized)));
} }
} }

View file

@ -68,7 +68,7 @@ public final class ClearChatCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public ClearChatCommand() throws IllegalArgumentException { public ClearChatCommand() throws IllegalArgumentException {
super("clearchat"); super("general", "clearchat");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */

View file

@ -19,7 +19,7 @@
package de.jeremystartm.pickshadow.extension.command.general; package de.jeremystartm.pickshadow.extension.command.general;
import de.jeremystartm.pickshadow.extension.ExtensionInformation; import de.jeremystartm.pickshadow.common.PSSKInformation;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.CommandBase;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
@ -67,30 +67,40 @@ public final class ExtensionCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public ExtensionCommand() throws IllegalArgumentException { public ExtensionCommand() throws IllegalArgumentException {
super("psse"); super("general", "psse", "pssp");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.extension")) return;
switch (alias) { switch (alias) {
case "psse", "pickshadow", "server" -> { case "psse", "pickshadow", "server" -> {
if (checkPermission(sender, "pickshadow.command.extension")) return;
if (arguments.length == 0) if (arguments.length == 0)
sender.sendRichMessage( sender.sendRichMessage(TranslationManager.get(LanguageString.EXTENSIONCMD_GREETER,
TranslationManager.get(LanguageString.EXTENSIONCMD_GREETER, sender,
sender, true,
true, entry("codename", PSSKInformation.getVersioningCodename()),
entry("codename", ExtensionInformation.getVersioningCodename()), entry("version", PSSKInformation.getVersioningString()),
entry("version", ExtensionInformation.getVersioningString()), entry("commit", PSSKInformation.getGitCommitIdentifierShort()),
entry("commit", ExtensionInformation.getGitCommitIdentifierShort()), entry("dirty", String.valueOf(PSSKInformation.isGitDirty()))
entry("%dirty%", String.valueOf(ExtensionInformation.isGitDirty())) ));
));
else { else {
switch (arguments[0]) { switch (arguments[0]) {
case "license" -> sender.sendRichMessage(TranslationManager.get(LanguageString.EXTENSIONCMD_LICENSE, sender, true)); case "license" -> sender.sendRichMessage(TranslationManager.get(
case "source" -> sender.sendRichMessage(TranslationManager.get(LanguageString.EXTENSIONCMD_SOURCE, sender, true, entry("source", "https://git.staropensource.de/JeremyStarTM/PSSE"))); LanguageString.EXTENSIONCMD_LICENSE,
sender,
true,
entry("license", "GNU Affero General Public License v3"),
entry("license_url", "https://gnu.org/licenses/agpl-3.0.en.html")
));
case "source" -> sender.sendRichMessage(TranslationManager.get(
LanguageString.EXTENSIONCMD_SOURCE,
sender,
true,
entry("source", "https://git.staropensource.de/JeremyStarTM/PSSE")
));
case "killjvm" -> { case "killjvm" -> {
if (checkPermission(sender, "pickshadow.command.extension.advanced")) return; if (checkPermission(sender, "pickshadow.command.extension.advanced")) return;
@ -111,7 +121,10 @@ public final class ExtensionCommand extends CommandBase {
Runtime.getRuntime().halt(0); Runtime.getRuntime().halt(0);
} }
} }
case "pssp" -> sender.sendRichMessage(TranslationManager.get(LanguageString.EXTENSIONCMD_ERROR_OLDCMD, sender, true)); case "pssp" -> {
if (!checkPermission(sender, "pickshadow.command.extension.legacy"))
sender.sendRichMessage(TranslationManager.get(LanguageString.EXTENSIONCMD_ERROR_OLDCMD, sender, true));
}
} }
} }
} }

View file

@ -0,0 +1,119 @@
/*
* 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.extension.command.general;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.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;
import java.util.Arrays;
import static java.util.Map.entry;
/**
* Handles the {@code /language} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class LanguageCommand 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;
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public LanguageCommand() throws IllegalArgumentException {
super("general", "language");
// Initialize completion
StaticTabCompletion staticTabCompletion = new StaticTabCompletion();
for (String language : TranslationManager.getLanguages())
staticTabCompletion.add("language", 0, language, "pickshadow.command.language");
staticTabCompletion
.copy("language", "lang")
.copy("language", "setlanguage")
.copy("language", "setlang");
completion = staticTabCompletion;
}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.language")) return;
if (sender instanceof Player player) {
// Check size of 'arguments'
if (arguments.length == 0)
sender.sendRichMessage(TranslationManager.get(
LanguageString.LANGUAGE_CURRENT,
sender,
true,
entry("language", PlayerDataFactory.getInstance().get(player).getLanguage())
));
else if (arguments.length == 1) {// Check if language is loaded
if (!Arrays.asList(TranslationManager.getLanguages()).contains(arguments[0])) {
sender.sendRichMessage(TranslationManager.get(
LanguageString.LANGUAGE_INVALID,
sender,
true,
entry("language", arguments[0])
));
}
// Change language
PlayerDataFactory.getInstance().get(player).setLanguage(arguments[0]);
// Send success message
sender.sendRichMessage(TranslationManager.get(
LanguageString.LANGUAGE,
sender,
true,
entry("language", arguments[0])
));
} else
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true));
} else
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true));
}
}

View file

@ -56,7 +56,7 @@ public final class LinkCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public LinkCommand() throws IllegalArgumentException { public LinkCommand() throws IllegalArgumentException {
super("discord", "teamspeak", "mumble", "website"); super("general", "website", "forum", "discord", "teamspeak", "mumble");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@ -66,6 +66,7 @@ public final class LinkCommand extends CommandBase {
switch (alias) { switch (alias) {
case "website" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_WEBSITE, sender, true)); case "website" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_WEBSITE, sender, true));
case "forum", "messageboard", "mb" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_FORUM, sender, true));
case "discord", "dc" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_DISCORD, 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 "teamspeak", "ts" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_TEAMSPEAK, sender, true));
case "mumble" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_MUMBLE, sender, true)); case "mumble" -> sender.sendRichMessage(TranslationManager.get(LanguageString.LINKS_MUMBLE, sender, true));

View file

@ -78,7 +78,7 @@ public final class TrollCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public TrollCommand() throws IllegalArgumentException { public TrollCommand() throws IllegalArgumentException {
super("troll"); super("general", "troll");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */

View file

@ -0,0 +1,183 @@
/*
* 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.extension.command.general.replacement;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import static java.util.Map.entry;
/**
* Handles the {@code /cmd} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class GamemodeCommand 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("gamemode", 0, "0", "pickshadow.command.gamemode.survival")
.add("gamemode", 0, "1", "pickshadow.command.gamemode.creative")
.add("gamemode", 0, "2", "pickshadow.command.gamemode.adventure")
.add("gamemode", 0, "3", "pickshadow.command.gamemode.spectator")
.add("gamemode", 0, "survival", "pickshadow.command.gamemode.survival")
.add("gamemode", 0, "creative", "pickshadow.command.gamemode.creative")
.add("gamemode", 0, "adventure", "pickshadow.command.gamemode.adventure")
.add("gamemode", 0, "spectator", "pickshadow.command.gamemode.spectator")
.players("gamemode", 1)
.copy("gamemode", "gm");
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public GamemodeCommand() throws IllegalArgumentException {
super("general", "gamemode");
}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.gamemode")) return;
// Check length of 'arguments'
if (arguments.length == 0) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_FEW_ARGUMENTS, sender, true));
return;
} else if (arguments.length > 2) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true));
return;
}
boolean onSelf;
GameMode gamemode;
LanguageString gamemodeTranslation;
Player target;
// Determine gamemode
switch (arguments[0]) {
case "0", "survival" -> {
gamemode = GameMode.SURVIVAL;
gamemodeTranslation = LanguageString.GAMEMODE_SURVIVAL;
}
case "1", "creative" -> {
gamemode = GameMode.CREATIVE;
gamemodeTranslation = LanguageString.GAMEMODE_CREATIVE;
}
case "2", "adventure" -> {
gamemode = GameMode.ADVENTURE;
gamemodeTranslation = LanguageString.GAMEMODE_ADVENTURE;
}
case "3", "spectator" -> {
gamemode = GameMode.SPECTATOR;
gamemodeTranslation = LanguageString.GAMEMODE_SPECTATOR;
}
default -> {
sender.sendRichMessage(TranslationManager.get(
LanguageString.ERROR_INVALID_ARGUMENT,
sender,
true,
entry("argument", arguments[0])
));
return;
}
}
// Get player
switch (arguments.length) {
case 1 -> {
onSelf = true;
// Check if command sender is a player
if (sender instanceof Player senderPlayer)
target = senderPlayer;
else {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true));
return;
}
}
case 2 -> {
target = Bukkit.getPlayer(arguments[1]);
try {
onSelf = Objects.requireNonNull(target).getName().equals(sender.getName());
} catch (NullPointerException exception) {
onSelf = false;
}
// Check if 'target' is null
if (target == null) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_PLAYER_NOT_FOUND,
sender,
true,
entry("player", arguments[1])
));
return;
}
}
default -> {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true));
return;
}
}
// Set game mode
target.setGameMode(gamemode);
// Send message
target.sendRichMessage(TranslationManager.get(
LanguageString.GAMEMODE,
target,
true,
entry("gamemode", TranslationManager.get(gamemodeTranslation, target, false))
));
if (!onSelf)
sender.sendRichMessage(TranslationManager.get(
LanguageString.GAMEMODE_REMOTE,
sender,
true,
entry("player", target.getName()),
entry("gamemode", TranslationManager.get(gamemodeTranslation, target, false))
));
}
}

View file

@ -0,0 +1,69 @@
/*
* 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.extension.command.general.replacement;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
/**
* Handles the {@code /help} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class HelpCommand 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 HelpCommand() throws IllegalArgumentException {
super("general", "help");
}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.help")) return;
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true));
}
}

View file

@ -17,11 +17,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package de.jeremystartm.pickshadow.extension.command.general; package de.jeremystartm.pickshadow.extension.command.general.replacement;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.CommandBase;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion; import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
@ -31,6 +32,8 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.UUID;
import static java.util.Map.entry; import static java.util.Map.entry;
/** /**
@ -64,12 +67,14 @@ public final class MessageCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public MessageCommand() throws IllegalArgumentException { public MessageCommand() throws IllegalArgumentException {
super("message", "reply"); super("general", "message", "reply");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.message")) return;
if (sender instanceof Player player) if (sender instanceof Player player)
switch (alias) { switch (alias) {
case "message", "msg", "whisper", "w" -> { case "message", "msg", "whisper", "w" -> {
@ -90,7 +95,7 @@ public final class MessageCommand extends CommandBase {
} }
// Check if the sender is the receiver // Check if the sender is the receiver
if (player.getUniqueId() == ((Player) sender).getUniqueId()) { if (player.getUniqueId().equals(receiver.getUniqueId())) {
player.sendRichMessage(TranslationManager.get(LanguageString.MESSAGING_ERROR_SELF, sender, true)); player.sendRichMessage(TranslationManager.get(LanguageString.MESSAGING_ERROR_SELF, sender, true));
return; return;
} }
@ -115,8 +120,33 @@ public final class MessageCommand extends CommandBase {
// Send message // Send message
player.sendRichMessage(output); player.sendRichMessage(output);
receiver.sendRichMessage(output); receiver.sendRichMessage(output);
// Mark receiver as last contact
PlayerDataFactory.getInstance().get(player).setLastMessaged(receiver.getUniqueId());
}
case "reply", "r" -> {
UUID lastMessaged = PlayerDataFactory.getInstance().get(player).getLastMessaged();
if (lastMessaged == null)
player.sendRichMessage(TranslationManager.get(LanguageString.MESSAGING_ERROR_NOLASTCONTACT, sender, true));
else {
String lastMessagedUsername = Bukkit.getOfflinePlayer(lastMessaged).getName();
if (lastMessagedUsername == null)
player.sendRichMessage(TranslationManager.get(LanguageString.MESSAGING_ERROR_NOLASTCONTACT, sender, true));
else {
if (arguments.length == 0)
player.sendRichMessage(
TranslationManager.get(LanguageString.MESSAGING_LASTCONTACT,
sender,
true,
entry("contact", lastMessagedUsername)
));
else
player.performCommand("message " + lastMessagedUsername + " " + String.join(" ", arguments));
}
}
} }
case "reply", "r" -> sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNIMPLEMENTED, sender, true));
} }
else else
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true)); sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true));

View file

@ -0,0 +1,94 @@
/*
* 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.extension.command.general.replacement;
import de.jeremystartm.pickshadow.extension.api.command.CommandBaseWithNull;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static java.util.Map.entry;
/**
* Handles the {@code /plugins} command.
*
* @since v1-release0
*/
@Getter
public final class PluginsCommand extends CommandBaseWithNull {
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public PluginsCommand() {}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @Nullable Command command, @NotNull String alias, @NotNull String[] arguments) {
if (sender.hasPermission("pickshadow.command.plugins.real")) {
StringBuilder output = new StringBuilder();
Plugin[] plugins = Bukkit.getPluginManager().getPlugins();
String prefixNewline = TranslationManager.get(LanguageString.PREFIX_NEWLINE, sender, false);
String entryPrefix = TranslationManager.get(LanguageString.PLUGINS_ENTRY_PREFIX, sender, false);
String entrySuffix = TranslationManager.get(LanguageString.PLUGINS_ENTRY_SUFFIX, sender, false);
String entryNamePrefix = TranslationManager.get(LanguageString.PLUGINS_ENTRY_NAME_PREFIX, sender, false);
String entryNameSuffix = TranslationManager.get(LanguageString.PLUGINS_ENTRY_NAME_SUFFIX, sender, false);
// Append header
output.append(TranslationManager.get(
LanguageString.PLUGINS,
sender,
true,
entry("count", String.valueOf(plugins.length))
));
// Append plugin list
for (Plugin plugin : plugins)
output
.append("\n")
.append(prefixNewline)
.append(entryPrefix)
.append(entryNamePrefix)
.append(plugin.getName())
.append(entryNameSuffix)
.append(" (")
.append(plugin.isEnabled() ? "enabled": "disabled")
.append(plugin.isNaggable() ? "": ", was nagged")
.append(")")
.append(entrySuffix)
;
sender.sendRichMessage(output.toString());
} else if (!checkPermission(sender, "pickshadow.command.plugins"))
sender.sendRichMessage(TranslationManager.get(
LanguageString.PLUGINS,
sender,
true
));
}
}

View file

@ -0,0 +1,53 @@
/*
* 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.extension.command.general.replacement;
import de.jeremystartm.pickshadow.extension.api.command.CommandBaseWithNull;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Handles the {@code /reload} command.
*
* @since v1-release0
*/
@Getter
public final class ReloadCommand extends CommandBaseWithNull {
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public ReloadCommand() {}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @Nullable Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.reload")) return;
sender.sendRichMessage(TranslationManager.get(LanguageString.RELOAD, sender, true));
}
}

View file

@ -0,0 +1,27 @@
/*
* 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/>.
*/
/**
* Replacement commands.
* <p>
* These replace various Minecraft or Bukkit commands.
*
* @since v1-release0
*/
package de.jeremystartm.pickshadow.extension.command.general.replacement;

View file

@ -25,11 +25,16 @@ import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Objects;
import static java.util.Map.entry;
/** /**
* Handles the {@code /home} command. * Handles the {@code /home} command.
* *
@ -57,7 +62,7 @@ public final class HomeCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public HomeCommand() throws IllegalArgumentException { public HomeCommand() throws IllegalArgumentException {
super("home"); super("survival", "home");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@ -65,14 +70,61 @@ public final class HomeCommand extends CommandBase {
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) { public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.home")) return; if (checkPermission(sender, "pickshadow.command.home")) return;
if (sender instanceof Player player) { boolean onSelf;
if (player.getRespawnLocation() == null) Player player;
player.sendRichMessage(TranslationManager.get(LanguageString.HOME_NORESPAWN, player, true));
else { // Get player
player.teleport(player.getRespawnLocation()); switch (arguments.length) {
player.setFallDistance(0f); case 0 -> {
player.sendRichMessage(TranslationManager.get(LanguageString.HOME_TELEPORTED, player, true)); onSelf = true;
// Check if command sender is a player
if (sender instanceof Player senderPlayer)
player = senderPlayer;
else {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true));
return;
}
} }
case 1 -> {
player = Bukkit.getPlayer(arguments[0]);
try {
onSelf = !Objects.requireNonNull(player).getName().equals(sender.getName());
} catch (NullPointerException exception) {
onSelf = false;
}
// Check if 'player' is null
if (player == null) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_PLAYER_NOT_FOUND,
sender,
true,
entry("player", arguments[0])
));
return;
}
}
default -> {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true));
return;
}
}
// Teleport player
if (player.getRespawnLocation() == null)
if (onSelf)
sender.sendRichMessage(TranslationManager.get(LanguageString.HOME_NORESPAWN, sender, true));
else
sender.sendRichMessage(TranslationManager.get(
LanguageString.HOME_NORESPAWN_OTHER,
sender,
true,
entry("player", player.getName())
));
else {
player.teleport(player.getRespawnLocation());
player.setFallDistance(0f);
sender.sendRichMessage(TranslationManager.get(LanguageString.HOME, sender, true));
} }
} }
} }

View file

@ -18,7 +18,8 @@
*/ */
/** /**
* Commands used by survival servers. * Commands most useful when
* playing in survival mode.
* *
* @since v1-release0 * @since v1-release0
*/ */

View file

@ -0,0 +1,128 @@
/*
* 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.extension.command.survivalcheat;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.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;
import java.util.Objects;
import static java.util.Map.entry;
/**
* Handles the {@code /feed} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class FeedCommand 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("feed", 0);
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public FeedCommand() throws IllegalArgumentException {
super("survivalcheat", "feed");
}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.feed")) return;
Player player;
boolean onSelf;
// Get player
switch (arguments.length) {
case 0 -> {
onSelf = true;
// Check if command sender is a player
if (sender instanceof Player senderPlayer)
player = senderPlayer;
else {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true));
return;
}
}
case 1 -> {
player = Bukkit.getPlayer(arguments[0]);
try {
onSelf = Objects.requireNonNull(player).getName().equals(sender.getName());
} catch (NullPointerException exception) {
onSelf = false;
}
// Check if 'player' is null
if (player == null) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_PLAYER_NOT_FOUND,
sender,
true,
entry("player", arguments[0])
));
return;
}
}
default -> {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true));
return;
}
}
// Heal player
player.setFoodLevel(20);
// Send success message
player.sendRichMessage(TranslationManager.get(LanguageString.HEAL, player, true));
if (!onSelf)
sender.sendRichMessage(TranslationManager.get(
LanguageString.HEAL_REMOTE,
sender,
true,
entry("player", player.getName())
));
}
}

View file

@ -0,0 +1,153 @@
/*
* 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.extension.command.survivalcheat;
import de.jeremystartm.pickshadow.extension.BuildOptions;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase;
import de.jeremystartm.pickshadow.extension.api.command.TabCompletion;
import de.jeremystartm.pickshadow.extension.api.command.completion.StaticTabCompletion;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.attribute.Attribute;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import static java.util.Map.entry;
/**
* Handles the {@code /heal} command.
*
* @since v1-release0
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public final class HealCommand 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("heal", 0)
.add("heal", -1, "--keep-effects", "pickshadow.command.heal")
.add("heal", -1, "--all-effects", "pickshadow.command.heal");
/**
* Creates and initializes an instance of
* this class and registers this command.
*
* @since v1-release0
*/
public HealCommand() throws IllegalArgumentException {
super("survivalcheat", "heal");
}
/** {@inheritDoc} */
@Override
public void invoke(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] arguments) {
if (checkPermission(sender, "pickshadow.command.heal")) return;
Player player;
List<@NotNull String> argumentsList = new ArrayList<>(Arrays.stream(arguments).toList());
boolean onSelf;
boolean keepEffects = argumentsList.remove("--keep-effects");
boolean allEffects = argumentsList.remove("--all-effects");
// Get player
switch (argumentsList.size()) {
case 0 -> {
onSelf = true;
// Check if command sender is a player
if (sender instanceof Player senderPlayer)
player = senderPlayer;
else {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_NOT_A_PLAYER, sender, true));
return;
}
}
case 1 -> {
player = Bukkit.getPlayer(argumentsList.getFirst());
try {
onSelf = Objects.requireNonNull(player).getName().equals(sender.getName());
} catch (NullPointerException exception) {
onSelf = false;
}
// Check if 'player' is null
if (player == null) {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_PLAYER_NOT_FOUND,
sender,
true,
entry("player", argumentsList.getFirst())
));
return;
}
}
default -> {
sender.sendRichMessage(TranslationManager.get(LanguageString.ERROR_TOO_MANY_ARGUMENTS, sender, true));
return;
}
}
// Heal player
player.heal(Objects.requireNonNull(player.getAttribute(Attribute.MAX_HEALTH)).getValue() - player.getHealth(), EntityRegainHealthEvent.RegainReason.MAGIC);
player.setFoodLevel(20);
player.setSaturation(20);
player.setRemainingAir(300);
// Reset bad or all effects
if (!keepEffects)
if (allEffects)
for (PotionEffect effect : player.getActivePotionEffects())
player.removePotionEffect(effect.getType());
else
for (PotionEffectType effectType : BuildOptions.SETTINGS_EFFECTS_DAMAGING)
player.removePotionEffect(effectType);
// Send success message
player.sendRichMessage(TranslationManager.get(LanguageString.HEAL, player, true));
if (!onSelf)
sender.sendRichMessage(TranslationManager.get(
LanguageString.HEAL_REMOTE,
sender,
true,
entry("player", player.getName())
));
}
}

View file

@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package de.jeremystartm.pickshadow.extension.command.general; package de.jeremystartm.pickshadow.extension.command.survivalcheat;
import de.jeremystartm.pickshadow.extension.api.command.CommandBase; import de.jeremystartm.pickshadow.extension.api.command.CommandBase;
import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion; import de.jeremystartm.pickshadow.extension.api.command.completion.StubTabCompletion;
@ -61,7 +61,7 @@ public final class ToggleDownfallCommand extends CommandBase {
* @since v1-release0 * @since v1-release0
*/ */
public ToggleDownfallCommand() throws IllegalArgumentException { public ToggleDownfallCommand() throws IllegalArgumentException {
super("toggledownfall"); super("survivalcheat", "toggledownfall");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */

View file

@ -0,0 +1,27 @@
/*
* 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/>.
*/
/**
* Commands which are generally used
* for cheating in survival mode.
*
* @since v1-release0
*/
package de.jeremystartm.pickshadow.extension.command.survivalcheat;

View file

@ -19,8 +19,13 @@
package de.jeremystartm.pickshadow.extension.listener; package de.jeremystartm.pickshadow.extension.listener;
import de.jeremystartm.pickshadow.extension.BuildOptions;
import de.jeremystartm.pickshadow.extension.api.command.CommandBaseWithNull;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.jeremystartm.pickshadow.extension.command.general.replacement.PluginsCommand;
import de.jeremystartm.pickshadow.extension.command.general.replacement.ReloadCommand;
import de.staropensource.engine.base.logging.Logger;
import io.papermc.paper.event.player.AsyncChatEvent; import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -30,12 +35,29 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
/** /**
* Listens on chat events. * Listens on chat events.
* *
* @since v1-release0 * @since v1-release0
*/ */
public final class ChatListener implements Listener { public final class ChatListener implements Listener {
/**
* Contains a static instance of
* the {@link PluginsCommand} class.
*
* @since v1-release0
*/
private static final @NotNull PluginsCommand pluginsCommand = new PluginsCommand();
/**
* Contains a static instance of
* the {@link ReloadCommand} class.
*
* @since v1-release0
*/
private static final @NotNull ReloadCommand reloadCommand = new ReloadCommand();
/** /**
* Handles chat messages. * Handles chat messages.
* *
@ -45,12 +67,14 @@ public final class ChatListener implements Listener {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void handleChatMessage(@NotNull AsyncChatEvent event) { public void handleChatMessage(@NotNull AsyncChatEvent event) {
event.setCancelled(true); event.setCancelled(true);
Bukkit.broadcast(
MiniMessage.miniMessage().deserialize( if (!BuildOptions.SMALLSTUFF_CHAT_COMMENTS || !MiniMessage.miniMessage().serialize(event.originalMessage()).startsWith("#"))
TranslationManager.get(LanguageString.MESSAGING_SERVER, event.getPlayer(), false) Bukkit.broadcast(
.replace("%sender%", event.getPlayer().getName()) MiniMessage.miniMessage().deserialize(
).append(MiniMessage.miniMessage().deserialize(MiniMessage.miniMessage().serialize(event.originalMessage()).replace("\\<", "<"))) TranslationManager.get(LanguageString.MESSAGING_SERVER, event.getPlayer(), false)
); .replace("%sender%", event.getPlayer().getName())
).append(MiniMessage.miniMessage().deserialize(MiniMessage.miniMessage().serialize(event.originalMessage()).replace("\\<", "<")))
);
} }
/** /**
@ -61,9 +85,35 @@ public final class ChatListener implements Listener {
*/ */
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void handleChatCommand(@NotNull PlayerCommandPreprocessEvent event) { public void handleChatCommand(@NotNull PlayerCommandPreprocessEvent event) {
if (event.getMessage().split(" ")[0].contains(":")) { try {
event.setCancelled(true); String[] arguments = event.getMessage().split(" ");
event.getPlayer().sendRichMessage(TranslationManager.get(LanguageString.CHATCOMMAND_ERROR_NAMESPACE, event.getPlayer(), true)); String command = arguments[0];
if (command.contains(":")) {
event.setCancelled(true);
event.getPlayer().sendRichMessage(TranslationManager.get(LanguageString.CHATCOMMAND_ERROR_NAMESPACE, event.getPlayer(), true));
}
// Override commands
forceOverrideCommand(event, arguments, pluginsCommand, "plugins", "pl");
forceOverrideCommand(event, arguments, reloadCommand, "reload", "rl");
} catch (Exception exception) {
event.getPlayer().sendRichMessage(TranslationManager.get(LanguageString.ERROR_UNKNOWN, event.getPlayer(), true));
Logger.crash("Failed to handle command:\n" + event.getMessage(), exception, false);
} }
} }
/**
* Forcefully overrides a command.
*
* @param event event information
* @since v1-release0
*/
private static void forceOverrideCommand(@NotNull PlayerCommandPreprocessEvent event, @NotNull String @NotNull [] arguments, @NotNull CommandBaseWithNull commandBase, @NotNull String... commands) {
for (String command : commands)
if (arguments[0].equals("/" + command)) {
event.setCancelled(true);
commandBase.invoke(event.getPlayer(), null, command.substring(1), Arrays.copyOf(arguments, 1));
}
}
} }

View file

@ -19,11 +19,14 @@
package de.jeremystartm.pickshadow.extension.listener; package de.jeremystartm.pickshadow.extension.listener;
import de.jeremystartm.pickshadow.extension.BuildOptions;
import de.jeremystartm.pickshadow.extension.Extension; import de.jeremystartm.pickshadow.extension.Extension;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory; import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString; import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager; import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.jeremystartm.pickshadow.extension.command.general.ClearChatCommand; import de.jeremystartm.pickshadow.extension.command.general.ClearChatCommand;
import de.jeremystartm.pickshadow.extension.misc.Scheduler;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -55,13 +58,26 @@ public final class ConnectionListener implements Listener {
// Register player // Register player
PlayerDataFactory.getInstance().registerPlayer(event.getPlayer()); PlayerDataFactory.getInstance().registerPlayer(event.getPlayer());
// Set join message // Reset fall distance
event.joinMessage(MiniMessage.miniMessage().deserialize(TranslationManager.get( // This effectively reintroduces MC-212,
LanguageString.CONNECTION_JOIN, // which was fixed in 24w45a.
event.getPlayer(), if (BuildOptions.UNFIX_FALLDAMAGE_CANCELLING)
false, event.getPlayer().setFallDistance(0f);
entry("player", event.getPlayer().getName())
))); // Launch scheduler
Scheduler.player(event.getPlayer());
// Empty join message
event.joinMessage(Component.empty());
// Broadcast our own join message
for (Player player : Bukkit.getOnlinePlayers())
player.sendRichMessage(TranslationManager.get(
LanguageString.CONNECTION_JOIN,
player,
false,
entry("player", event.getPlayer().getName())
));
// Schedule late join event // Schedule late join event
event.getPlayer().getScheduler().execute(Extension.getInstance(), () -> handlePlayerJoinLate(event.getPlayer()), null, 1); event.getPlayer().getScheduler().execute(Extension.getInstance(), () -> handlePlayerJoinLate(event.getPlayer()), null, 1);
@ -92,16 +108,21 @@ public final class ConnectionListener implements Listener {
* @since v1-release0 * @since v1-release0
*/ */
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
private void handlePlayerJoin(@NotNull PlayerQuitEvent event) { private void handlePlayerLeave(@NotNull PlayerQuitEvent event) {
// Unregister player // Unregister player
PlayerDataFactory.getInstance().unregisterPlayer(PlayerDataFactory.getInstance().get(event.getPlayer())); PlayerDataFactory.getInstance().unregisterPlayer(PlayerDataFactory.getInstance().get(event.getPlayer()));
// Set leave message // Empty quit message
event.quitMessage(MiniMessage.miniMessage().deserialize(TranslationManager.get( event.quitMessage(Component.empty());
LanguageString.CONNECTION_DISCONNECT,
event.getPlayer(), // Broadcast our own quit message
false, for (Player player : Bukkit.getOnlinePlayers())
entry("player", event.getPlayer().getName()) if (!player.getUniqueId().equals(event.getPlayer().getUniqueId()))
))); player.sendRichMessage(TranslationManager.get(
LanguageString.CONNECTION_DISCONNECT,
player,
false,
entry("player", event.getPlayer().getName())
));
} }
} }

View file

@ -0,0 +1,54 @@
/*
* STAROPENSOURCE ENGINEMC SOURCE FILE
* Copyright (c) 2024 The StarOpenSource EngineMC 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.extension.misc;
import de.jeremystartm.pickshadow.extension.Extension;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.implementable.LoggingAdapter;
import de.staropensource.engine.base.implementation.shortcode.EmptyShortcodeParser;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
/**
* EngineMC's {@code BukkitLoggingAdapter} class.
*
* @since v1-release0
*/
public final class BukkitLoggingAdapter implements LoggingAdapter {
/**
* Constructs this class.
*
* @since v1-alpha0
*/
public BukkitLoggingAdapter() {}
/** {@inheritDoc} */
@Override
public void print(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message, @NotNull String format) {
// Remove any tags
if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().getLogFeatures().contains("formatting"))
format = new EmptyShortcodeParser(format, true).getClean();
switch (level) {
case DIAGNOSTIC, VERBOSE, SILENT_WARNING, INFORMATIONAL, WARNING -> Extension.getInstance().getLogger().info(format.replace("\n", "\n "));
case ERROR, CRASH -> Extension.getInstance().getLogger().severe(format.replace("\n", "\n "));
}
}
}

View file

@ -0,0 +1,109 @@
/*
* 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.extension.misc;
import de.jeremystartm.pickshadow.extension.BuildOptions;
import de.jeremystartm.pickshadow.extension.Extension;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerData;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerDataFactory;
import de.jeremystartm.pickshadow.extension.api.translation.LanguageString;
import de.jeremystartm.pickshadow.extension.api.translation.TranslationManager;
import de.staropensource.engine.base.logging.Logger;
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* Responsible for periodically executing tasks.
*
* @since v1-release0
*/
public final class Scheduler {
/**
* Creates and initializes an
* instance of this class.
*
* @since v1-release0
*/
private Scheduler() {}
/**
* Invokes scheduler actions for the entire server.
*
* @param scheduledTask information about the scheduled task
* @since v1-release0
*/
public static void server(@NotNull ScheduledTask scheduledTask) {
for (World world : Bukkit.getServer().getWorlds())
world(world);
}
/**
* Invokes scheduler actions for a world.
*
* @since v1-release0
*/
public static void world(@NotNull World world) {
}
/**
* Invokes scheduler actions for a specified player.
*
* @param player player to invoke scheduler actions on
* @since v1-release0
*/
public static void player(@NotNull Player player) {
try {
PlayerData data = PlayerDataFactory.getInstance().get(player);
// Apply stonecutter damage
if (BuildOptions.SMALLSTUFF_STONECUTTER_DAMAGE)
switch (data.getStonecutterDamageState()) {
case -1 -> {
Location location = player.getLocation().clone();
location.setX((long) location.getX() - 1);
location.setY(((long) location.getY()));
location.setZ((long) location.getZ());
if (player.getWorld().getBlockAt(location).getType() == Material.STONECUTTER) {
data.setStonecutterDamageState(0);
player.damage(1);
}
}
case 11 -> data.setStonecutterDamageState(-1);
default -> data.setStonecutterDamageState(data.getStonecutterDamageState() + 1);
}
// Reschedule
player.getScheduler().execute(Extension.getInstance(), () -> player(player), null, 1L);
} catch (Exception exception) {
if (player.isOnline())
player.kick(MiniMessage.miniMessage().deserialize(TranslationManager.get(LanguageString.CONNECTION_ERROR_SCHEDULER, player, false)));
Logger.crash("Player scheduler failed for " + player.getName() + " [" + player.getUniqueId() + "]", exception, false);
}
}
}

View file

@ -21,7 +21,7 @@ package de.jeremystartm.pickshadow.extension.misc;
import de.jeremystartm.pickshadow.extension.Extension; import de.jeremystartm.pickshadow.extension.Extension;
import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerData; import de.jeremystartm.pickshadow.extension.api.entity.player.PlayerData;
import de.staropensource.sosengine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import fr.mrmicky.fastboard.adventure.FastBoard; import fr.mrmicky.fastboard.adventure.FastBoard;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import lombok.Getter; import lombok.Getter;
@ -55,13 +55,6 @@ public final class TabListHandler {
@Getter @Getter
private static TabListHandler instance = null; private static TabListHandler instance = null;
/**
* Contains the logger instance for this class.
*
* @since v1-release0
*/
private final LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("PSSE").build();
/** /**
* Contains the content of the tab list. * Contains the content of the tab list.
* Each entry represents one line. * Each entry represents one line.
@ -101,7 +94,7 @@ public final class TabListHandler {
* @since v1-release0 * @since v1-release0
*/ */
public void initializeTabList(@NotNull PlayerData playerData) { public void initializeTabList(@NotNull PlayerData playerData) {
logger.verb("Initializing player list for player " + playerData.getPlayer().getName() + " (" + playerData.getPlayer().getUniqueId() + ")"); Logger.verb("Initializing player list for player " + playerData.getPlayer().getName() + " (" + playerData.getPlayer().getUniqueId() + ")");
// Initialize FastBoard // Initialize FastBoard
FastBoard board = new FastBoard(playerData.getPlayer()); FastBoard board = new FastBoard(playerData.getPlayer());
@ -127,10 +120,10 @@ public final class TabListHandler {
if (justSchedule) if (justSchedule)
return; return;
logger.verb("Updating player list for player " + playerData.getPlayer().getName() + " (" + playerData.getPlayer().getUniqueId() + ")"); Logger.verb("Updating player list for player " + playerData.getPlayer().getName() + " (" + playerData.getPlayer().getUniqueId() + ")");
for (int line = 0; line < content.size(); line++) { for (int line = 0; line < content.size(); line++) {
logger.verb("Processing line " + line + " for player " + playerData.getPlayer().getName() + " (" + playerData.getPlayer().getUniqueId() + ")"); Logger.verb("Processing line " + line + " for player " + playerData.getPlayer().getName() + " (" + playerData.getPlayer().getUniqueId() + ")");
playerData.getPlayerListScoreboard().updateLine(line, MiniMessage.miniMessage().deserialize(content.get(line))); playerData.getPlayerListScoreboard().updateLine(line, MiniMessage.miniMessage().deserialize(content.get(line)));
} }
} }

View file

@ -12,6 +12,8 @@ depend:
- "LuckPerms" - "LuckPerms"
commands: commands:
# General
# -> AnnounceCommand
announce: announce:
description: "Announces a message and broadcasts it to all players on the subserver or the network." description: "Announces a message and broadcasts it to all players on the subserver or the network."
usage: "/announce [--network] <message>" usage: "/announce [--network] <message>"
@ -20,12 +22,14 @@ commands:
- broadcast - broadcast
- bcast - bcast
- bc - bc
# -> ClearChatCommand
clearchat: clearchat:
description: "Clears the chat for all players on the subserver or the entire network." description: "Clears the chat for all players on the subserver or the entire network."
usage: "/clearchat [--network]" usage: "/clearchat [--network]"
aliases: aliases:
- chatclear - chatclear
- cc - cc
# -> ExtensionCommand
psse: psse:
description: "Interface for players and administrators to PSSE and the PickShadow network." description: "Interface for players and administrators to PSSE and the PickShadow network."
usage: "/psse <license|source|killjvm>" usage: "/psse <license|source|killjvm>"
@ -35,31 +39,27 @@ commands:
pssp: pssp:
description: "Notifies you that PSSP is no more." description: "Notifies you that PSSP is no more."
usage: "/pssp" usage: "/pssp"
home: # -> LanguageCommand
description: "Teleports you to your respawn point." language:
usage: "/home" description: "Allows you to change the language of PSSE"
usage: "/language <language>"
aliases: aliases:
- bed - lang
- tphome - setlanguage
message: - setlang
description: "Messages another player." # -> LinkCommand
usage: "/message <player> <message...>"
aliases:
- msg
- whisper
- w
reply:
description: "Messages the last messaged player."
usage: "/reply <message>"
aliases:
- reply
- r
website: website:
description: "Displays the link to PickShadow's website." description: "Displays the link to PickShadow's website."
usage: "/website" usage: "/website"
aliases: aliases:
- web - web
- www - www
forum:
description: "Displays the link to PickShadow's forum."
usage: "/forum"
aliases:
- messageboard
- mb
discord: discord:
description: "Displays the link to PickShadow's Discord server." description: "Displays the link to PickShadow's Discord server."
usage: "/discord" usage: "/discord"
@ -74,11 +74,176 @@ commands:
description: "Displays the IP address to PickShadow's Mumble server." description: "Displays the IP address to PickShadow's Mumble server."
usage: "/mumble" usage: "/mumble"
aliases: [] aliases: []
toggledownfall: # -> TrollCommand
description: "A PSSE provided command."
usage: "/toggledownfall"
aliases: []
troll: troll:
description: "Various torturing methods for misbehaving players ;)" description: "Various torturing methods for misbehaving players ;)"
usage: "/troll <TODO>" usage: "/troll <TODO>"
aliases: [] aliases: []
# General (replacements)
# -> GamemodeCommand
gamemode:
description: "Changes the gamemode of the specified player."
usage: "/gamemode <gamemode> [player]"
aliases:
- gm
# -> HelpCommand
help:
description: "Provides information about the server."
usage: "/help"
aliases:
- h
# -> MessageCommand
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
# -> PluginsCommand
plugins:
description: "Lists all installed plugins."
usage: "/plugins"
aliases:
- pl
# -> ReloadCommand
reload:
description: "Warns about server reloads."
usage: "/reload"
aliases:
- rl
# Survival
# -> HomeCommand
home:
description: "Teleports you to your respawn point."
usage: "/home"
aliases:
- bed
- tphome
- tph
# Survival (Cheating)
# -> FeedCommand
feed:
description: "Feeds the specified player."
usage: "/feed [player]"
aliases: []
# -> HealCommand
heal:
description: "Heals the specified player."
usage: "/heal [player]"
aliases: []
# -> ToggleDownfallCommand
toggledownfall:
description: "A PSSE provided command."
usage: "/toggledownfall"
aliases: []
permissions:
# Commands
# -> General
# --> AnnounceCommand
pickshadow.command.announce:
description: "Provides access to the '/announce' command."
default: false
pickshadow.command.announce.network:
description: "Provides access to '/announce''s '--network' option."
default: false
# --> ClearChatCommand
pickshadow.command.clearchat:
description: "Provides access to the '/clearchat' command."
default: false
pickshadow.command.clearchat.network:
description: "Provides access to '/clearchat''s '--network' option."
default: false
# --> ExtensionCommand
pickshadow.command.extension:
description: "Provides access to the '/psse' command"
default: false
pickshadow.command.extension.advanced:
description: "Provides access to administrative operations."
default: false
pickshadow.command.extension.legacy:
description: "Provides access to the '/psse' command only."
default: false
# --> LanguageCommand
pickshadow.command.language:
description: "Provides access to the '/language' command."
default: false
# --> LinkCommand
pickshadow.command.link:
description: "Provides access to multiple commands returning hyperlinks."
default: false
# --> TrollCommand
pickshadow.command.troll:
description: "Provides access to the '/troll' command."
default: false
# -> General (replacements)
# --> GamemodeCommand
pickshadow.command.gamemode:
description: "Provides access to the '/gamemode' command."
default: false
pickshadow.command.gamemode.survival:
description: "Provides access to '/gamemode''s 'survival' option."
default: false
pickshadow.command.gamemode.creative:
description: "Provides access to '/gamemode''s 'creative' option."
default: false
pickshadow.command.gamemode.adventure:
description: "Provides access to '/gamemode''s 'adventure' option."
default: false
pickshadow.command.gamemode.spectator:
description: "Provides access to '/gamemode''s 'spectator' option."
default: false
# --> HelpCommand
pickshadow.command.help:
description: "Provides access to the '/help' command."
default: false
# --> MessageCommand
pickshadow.command.message:
description: "Provides access to the '/message' command."
default: false
# --> PluginsCommand
pickshadow.command.plugins:
description: "Provides access to the fake '/plugins' command."
default: false
pickshadow.command.plugins.real:
description: "Provides access to the real '/plugins' command."
default: false
# --> ReloadCommand
pickshadow.command.reload:
description: "Provides access to the '/reload' command."
default: false
# -> Survival
# --> HomeCommand
pickshadow.command.home:
description: "Provides access to the '/home' command."
default: false
# -> Survival (Cheating)
# --> FeedCommand
pickshadow.command.feed:
description: "Provides access to the '/feed' command."
default: false
# --> HealCommand
pickshadow.command.heal:
description: "Provides access to the '/heal' command."
default: false
# --> ToggleDownfallCommand
pickshadow.command.toggledownfall:
description: "Provides access to the '/toggledownfall' command :3"
default: false

View file

@ -1,6 +1,7 @@
{ {
"ERROR_UNKNOWN": "<error>Ein unbekannter Fehler ist aufgetreten. Bitte kontaktiere das Serverteam.</error>", "ERROR_UNKNOWN": "<error>Ein unbekannter Fehler ist aufgetreten. Bitte kontaktiere das Serverteam.</error>",
"ERROR_UNIMPLEMENTED": "<error>Diese Aktion wurde noch nicht implementiert.</error>", "ERROR_UNIMPLEMENTED": "<error>Diese Aktion wurde noch nicht implementiert.</error>",
"ERROR_INVALID_MODE": "<error>Diese Aktion ist nicht verfügbar, da sie deaktiviert wurde.</error>",
"ERROR_NOT_A_PLAYER": "<error>Ein Spieler ist für diese Aktion benötigt.</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_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_FEW_ARGUMENTS": "<error>Zu wenige Argumente.</error>",
@ -11,27 +12,34 @@
"CONNECTION_JOIN": "<generic><mention>%player%</mention> ist dem Spiel beigetreten</generic>", "CONNECTION_JOIN": "<generic><mention>%player%</mention> ist dem Spiel beigetreten</generic>",
"CONNECTION_JOIN_WELCOME": "<generic>Willkommen zu <branding/>, <mention>%player%</mention>!</generic>", "CONNECTION_JOIN_WELCOME": "<generic>Willkommen zu <branding/>, <mention>%player%</mention>!</generic>",
"CONNECTION_DISCONNECT": "<generic><mention>%player%</mention> hat das Spiel verlassen</generic>", "CONNECTION_DISCONNECT": "<generic><mention>%player%</mention> hat das Spiel verlassen</generic>",
"CONNECTION_ERROR_REGISTRATION": "<error>Anmeldung konnte nicht verarbeitet werden</error>",
"CONNECTION_ERROR_TABLISTHANDLER": "<error>Der TabListHandler schlug unerwartet fehl</error>",
"CONNECTION_ERROR_SCHEDULER": "<error>Der Player Scheduler schlug unerwartet fehl</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_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.</generic>",
"EXTENSIONCMD_KILLJVM": "<generic>Bye bye!", "EXTENSIONCMD_KILLJVM": "<generic>Bye bye!</generic>",
"EXTENSIONCMD_LICENSE": "<generic>PSSE ist lizensiert unter der <mention>GNU Affero General Public-Lizenz v3</mention>.", "EXTENSIONCMD_LICENSE": "<generic>PSSE ist lizensiert unter der <click:open_url:%license_url%><link>%license%</link></click>.</generic>",
"EXTENSIONCMD_SOURCE": "<generic>Du kannst PickShadow's serverseitigen Code auf <click:open_url:%source%><link>sos!git</link></click> finden.", "EXTENSIONCMD_SOURCE": "<generic>Du kannst PickShadow's serverseitigen Code auf <click:open_url:%source%><link>sos!git</link></click> finden.</generic>",
"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>", "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>",
"MESSAGING_LASTCONTACT": "<generic>Die letzte Person, die du angeschrieben hast ist <mention>%contact%</mention>.</generic>",
"MESSAGING_ERROR_SELF": "<error>Du kannst dich nicht selber anschreiben.</error>", "MESSAGING_ERROR_SELF": "<error>Du kannst dich nicht selber anschreiben.</error>",
"MESSAGING_ERROR_NOLASTCONTACT": "<error>Du hast in der letzten Zeit keinen angeschrieben.</error>",
"LINKS_WEBSITE": "<error>Das PickShadow Netzwerk hat aktuell keine Webseite.</error>", "LINKS_WEBSITE": "<error>Das PickShadow Netzwerk hat aktuell keine Webseite.</error>",
"LINKS_FORUM": "<error>Das PickShadow Netzwerk hat aktuell kein Forum.</error>",
"LINKS_DISCORD": "<error>Das PickShadow Netzwerk hat aktuell keine Discord Guilde.</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_TEAMSPEAK": "<error>Das PickShadow Netzwerk hat aktuell keinen TeamSpeak Server.</error>",
"LINKS_MUMBLE": "<error>Das PickShadow Netzwerk hat aktuell keinen Mumble Server.</error>", "LINKS_MUMBLE": "<error>Das PickShadow Netzwerk hat aktuell keinen Mumble Server.</error>",
"CLEARCHAT_GENERIC": "<generic>Der Chat wurde von %sender% geleert.", "CLEARCHAT_GENERIC": "<generic>Der Chat wurde von %sender% geleert.</generic>",
"CLEARCHAT_VOID": "<generic>Der Chat wurde von %sender% ins Void geschubst.", "CLEARCHAT_VOID": "<generic>Der Chat wurde von %sender% ins Void geschubst.</generic>",
"CLEARCHAT_SKILLISSUES": "<generic>Der Chat wurde von %sender% aufgrund von Skill Issues der Chatteilnehmer gelöscht.", "CLEARCHAT_SKILLISSUES": "<generic>Der Chat wurde von %sender% aufgrund von Skill Issues der Chatteilnehmer gelöscht.</generic>",
"CLEARCHAT_BRAINDAMAGE": "<generic>Um weitverbreitenden Gehirnschaden zu verhinden, hat %sender% den Chat geleert.", "CLEARCHAT_BRAINDAMAGE": "<generic>Um weitverbreitenden Gehirnschaden zu verhinden, hat %sender% den Chat geleert.</generic>",
"CLEARCHAT_CRINGE": "<generic>Aufgrund von Massen an Cringe musste %sender% den Chat leeren.", "CLEARCHAT_CRINGE": "<generic>Aufgrund von Massen an Cringe musste %sender% den Chat leeren.</generic>",
"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>", "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>",
"HOME_NORESPAWN_OTHER": "<error><mention>%player%</mention> hat keinen gültigen Respawnpunkt.</error>\n<error><mention>%player%</mention>'s Bett oder Respawn Anker wurde entweder abgebaut oder ist behindert.</error>",
"TOGGLEDOWNFALL": "Niederschlag umgestellt", "TOGGLEDOWNFALL": "Niederschlag umgestellt",
@ -44,5 +52,24 @@
"TROLL_HACK_COMPLETE": "Zugang gewährt.", "TROLL_HACK_COMPLETE": "Zugang gewährt.",
"TROLL_HEAVENS": "<generic><mention>%target%</mention> glaubt nun fliegen zu können.</generic>", "TROLL_HEAVENS": "<generic><mention>%target%</mention> glaubt nun fliegen zu können.</generic>",
"LANGUAGE": "<generic>Deine bevorzugte Sprache wurde auf <mention>%language%</mention> umgestellt.</generic>",
"LANGUAGE_CURRENT": "<generic>Deine bevorzugte Sprache ist <mention>%language%</mention>.</generic>",
"LANGUAGE_INVALID": "<error>Die Sprache <mention>%language%</mention> wird leider nicht von PickShadow unterstützt.</error>",
"HEAL": "<generic>Du wurdest geheilt.</generic>",
"HEAL_REMOTE": "<generic><mention>%player%</mention> wurde geheilt.</generic>",
"PLUGINS": "<generic><mention>%count%</mention> Erweiterungen sind auf diesem Subserver installiert, welche sind:</generic>",
"PLUGINS_FAKE": "<generic>Denkst du wirklich, dass du interne Informationen so einfach bekommen kannst?</generic>\n<generic>Glücklicherweise sind wir keine Arschlöcher und geben an was wir verwenden.\n<generic>Das PickShadow Netzwerk verwendet <click:open_url:%link_psse%><link>PSSE</link></click>, <click:open_url:%link_luckperms%><link>LuckPerms</link></click> und <click:open_url:%link_freedomchat%><link>FreedomChat</link></click> um Subserver zu verwalten.",
"RELOAD": "<error>Server reloads gelten als unsicher und werden daher von PSSE blockiert.</error>\n<error>Bitte starte den Subserver stattdessen neu.</error>\n<error>Für mehr Informationen, lese bitte den folgenden Blogartikel (Englisch):</error>\n<error>https://madelinemiller.dev/blog/problem-with-reload/</error>",
"GAMEMODE": "<generic>Dein Spielmodus wurde in den <mention>%gamemode%</mention> geändert.",
"GAMEMODE_REMOTE": "<generic>Der Spielmodus von <mention>%player%</mention> wurde in den <mention>%gamemode%</mention> geändert.",
"GAMEMODE_SURVIVAL": "Überlebensmodus",
"GAMEMODE_CREATIVE": "Kreativmodus",
"GAMEMODE_ADVENTURE": "Abenteuermodus",
"GAMEMODE_SPECTATOR": "Zuschauermodus",
"CHATCOMMAND_ERROR_NAMESPACE": "<error>Namespaces zu verwenden ist nicht erlaubt, da es verwendet werden kann um Sicherheitsmaßnahmen zu umgehen.</error>" "CHATCOMMAND_ERROR_NAMESPACE": "<error>Namespaces zu verwenden ist nicht erlaubt, da es verwendet werden kann um Sicherheitsmaßnahmen zu umgehen.</error>"
} }

View file

@ -13,6 +13,7 @@
"ERROR_UNKNOWN": "<error>An unknown error occurred. Please contact the server team.</error>", "ERROR_UNKNOWN": "<error>An unknown error occurred. Please contact the server team.</error>",
"ERROR_UNIMPLEMENTED": "<error>This action is not yet implemented.</error>", "ERROR_UNIMPLEMENTED": "<error>This action is not yet implemented.</error>",
"ERROR_INVALID_MODE": "<error>This action is unavailable due to it being disabled.</error>",
"ERROR_NOT_A_PLAYER": "<error>You must be a player to perform this action.</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_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_FEW_ARGUMENTS": "<error>Too few arguments.</error>",
@ -20,23 +21,27 @@
"ERROR_INVALID_ARGUMENT": "<error>Invalid argument(s) <mention>%argument%</mention>.</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>", "ERROR_PLAYER_NOT_FOUND": "<error>The player <mention>%player%</mention> could not be found.</error>",
"CONNECTION_JOIN": "<generic>%player% joined the game", "CONNECTION_JOIN": "<generic><mention>%player%</mention> joined the game</generic>",
"CONNECTION_JOIN_WELCOME": "<generic>Welcome to <branding/>, <mention>%player%</mention>!</generic>", "CONNECTION_JOIN_WELCOME": "<generic>Welcome to <branding/>, <mention>%player%</mention>!</generic>",
"CONNECTION_DISCONNECT": "<generic>%player% left the game", "CONNECTION_DISCONNECT": "<generic><mention>%player%</mention> left the game</generic>",
"CONNECTION_ERROR_REGISTRATION": "<error>Unable to process log in", "CONNECTION_ERROR_REGISTRATION": "<error>Unable to process log in</error>",
"CONNECTION_ERROR_TABLISTHANDLER": "<error>TabListHandler failed unexpectedly", "CONNECTION_ERROR_TABLISTHANDLER": "<error>The TabListHandler failed unexpectedly</error>",
"CONNECTION_ERROR_SCHEDULER": "<error>The player scheduler failed unexpectedly</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_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.</generic>",
"EXTENSIONCMD_KILLJVM": "<generic>Bye bye!", "EXTENSIONCMD_KILLJVM": "<generic>Bye bye!</generic>",
"EXTENSIONCMD_LICENSE": "<generic>PSSE is licensed under the <mention>GNU Affero General Public License v3</mention>.", "EXTENSIONCMD_LICENSE": "<generic>PSSE is licensed under the <click:open_url:%license_url%><link>%license%</link></click>.</generic>",
"EXTENSIONCMD_SOURCE": "<generic>You can find the source code of PickShadow's server-side code on <click:open_url:%source%><link>sos!git</link></click>.", "EXTENSIONCMD_SOURCE": "<generic>You can find the source code of PickShadow's server-side code on <click:open_url:%source%><link>sos!git</link></click>.</generic>",
"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>", "EXTENSIONCMD_ERROR_OLDCMD": "<error>What's <mention>PSSP</mention>...?</error>\n<error>The PickShadow Server <italic>Plugin</italic> (PSSP) has been renamed into PickShadow Server <italic>Extension</italic> (PSSE).</error>\n<error>Please use the new name from now on. Thank you.</error>",
"MESSAGING_SERVER": "<mention>%sender%</mention> <#d60532>»</#d60532> ", "MESSAGING_SERVER": "<mention>%sender%</mention> <#d60532>»</#d60532> ",
"MESSAGING_DIRECT": "<generic><bold>%from%</bold> » <bold>%to%</bold> » </generic>%message%", "MESSAGING_DIRECT": "<generic><mention>%from%</mention> » <mention>%to%</mention> » </generic>%message%",
"MESSAGING_LASTCONTACT": "<generic>The last person you've messaged is <mention>%contact%</mention>.</generic>",
"MESSAGING_ERROR_SELF": "<error>You can't message yourself.</error>", "MESSAGING_ERROR_SELF": "<error>You can't message yourself.</error>",
"MESSAGING_ERROR_NOLASTCONTACT": "<error>You haven't messaged anyone recently.</error>",
"LINKS_WEBSITE": "<error>The PickShadow Network doesn't currently have a website.</error>", "LINKS_WEBSITE": "<error>The PickShadow Network doesn't currently have a website.</error>",
"LINKS_FORUM": "<error>The PickShadow Network doesn't currently have a forum.</error>",
"LINKS_DISCORD": "<error>The PickShadow Network doesn't currently have a Discord guild.</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_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>", "LINKS_MUMBLE": "<error>The PickShadow Network doesn't currently have a Mumble server.</error>",
@ -47,8 +52,9 @@
"CLEARCHAT_BRAINDAMAGE": "<generic>To prevent widespread brain damage, the chat has been cleared by %sender%.</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>", "CLEARCHAT_CRINGE": "<generic>Due to masses of cringe, %sender% had to clear the chat.</generic>",
"HOME": "<generic><italic>... woosh ...</italic></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_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>", "HOME_NORESPAWN_OTHER": "<error><mention>%player%</mention> does not have a valid respawn point.</error>\n<error><mention>%player%</mention>'s bed or respawn anchor is either missing or obstructed.</error>",
"TOGGLEDOWNFALL": "Toggled downfall", "TOGGLEDOWNFALL": "Toggled downfall",
@ -61,5 +67,28 @@
"TROLL_HACK_COMPLETE": "Access granted.", "TROLL_HACK_COMPLETE": "Access granted.",
"TROLL_HEAVENS": "<generic><mention>%target%</mention> believes that they can fly.</generic>", "TROLL_HEAVENS": "<generic><mention>%target%</mention> believes that they can fly.</generic>",
"LANGUAGE": "<generic>Your preferred language was changed to <mention>%language%</mention>.</generic>",
"LANGUAGE_CURRENT": "<generic>Your preferred language is set to <mention>%language%</mention>.</generic>",
"LANGUAGE_INVALID": "<error>The language <mention>%language%</mention> is not supported by PickShadow, sorry.</error>",
"HEAL": "<generic>You have been healed.</generic>",
"HEAL_REMOTE": "<generic><mention>%player%</mention> has been healed.</generic>",
"PLUGINS": "<generic><mention>%count%</mention> extensions are installed on this subserver, these being:</generic>",
"PLUGINS_FAKE": "<generic>Do you really think you can get internal information so easily?</generic>\n<generic>Luckily, we aren't dicks and credit what we use.\n<generic>The PickShadow network uses <click:open_url:%link_psse%><link>PSSE</link></click>, <click:open_url:%link_luckperms%><link>LuckPerms</link></click> and <click:open_url:%link_freedomchat%><link>FreedomChat</link></click> to manage subservers.",
"PLUGINS_ENTRY_PREFIX": "<generic>- ",
"PLUGINS_ENTRY_SUFFIX": "</generic>",
"PLUGINS_ENTRY_NAME_PREFIX": "<mention>",
"PLUGINS_ENTRY_NAME_SUFFIX": "</mention>",
"RELOAD": "<error>Server reloads are considered unsafe and are consequently blocked by PSSE.</error>\n<error>Please restart the subserver instead.</error>\n<error>For more information, please read the following blog article:</error>\n<error>https://madelinemiller.dev/blog/problem-with-reload/</error>",
"GAMEMODE": "<generic>Your gamemode was changed to <mention>%gamemode%</mention>.",
"GAMEMODE_REMOTE": "<generic>The gamemode of <mention>%player%</mention> was changed to <mention>%gamemode%</mention>.",
"GAMEMODE_SURVIVAL": "Survival mode",
"GAMEMODE_CREATIVE": "Creative mode",
"GAMEMODE_ADVENTURE": "Adventure mode",
"GAMEMODE_SPECTATOR": "Spectator mode",
"CHATCOMMAND_ERROR_NAMESPACE": "<error>Using namespaces is not allowed, as it may be used to circumvent security measures.</error>" "CHATCOMMAND_ERROR_NAMESPACE": "<error>Using namespaces is not allowed, as it may be used to circumvent security measures.</error>"
} }

View file

@ -25,35 +25,37 @@ versioningTyperelease=0
versioningFork= versioningFork=
# Java # Java
javaSource=22 javaSource=21
javaTarget=22 javaTarget=21
# Plugins
pluginLombok=8.10.2
pluginShadow=8.1.8
pluginPaperweight=1.7.4
pluginGitProperties=2.4.2
pluginRunTask=2.3.1
# Dependencies # Dependencies
dependencyLombok=1.18.32 dependencyLombok=1.18.34
dependencyJetbrainsAnnotations=24.1.0 dependencyJetbrainsAnnotations=26.0.1
dependencyStarOpenSourceEngine=1-alpha5 dependencyStarOpenSourceEngine=1-alpha8
dependencyHikari=4.0.3 dependencyStarOpenSourceEngineMC=1-release2
dependencyHikari=6.1.0
dependencyGson=2.11.0 dependencyGson=2.11.0
dependencyPaper=R0.1 dependencyPaper=R0.1
dependencyAdventure=4.17.0 dependencyAdventure=4.17.0
dependencyLuckPerms=5.4 dependencyLuckPerms=5.4
dependencyFastboard=2.1.3 dependencyFastboard=2.1.3
# Plugins
pluginLombok=8.6
pluginShadow=8.1.7
pluginPaperweight=1.7.3
pluginGitProperties=2.4.2
pluginRunTask=2.3.0
# Minecraft # Minecraft
minecraftVersion=1.21 minecraftVersion=1.21.3
minecraftApi=1.21 minecraftApi=1.21
# Plugin download metadata # Plugin download metadata
downloadFreedomChat=x6xcBZtb downloadEngineMC=https://git.staropensource.de/StarOpenSource/EngineMC/releases/download/v1-release3/bukkit.jar
downloadEngineMC=https://git.staropensource.de/StarOpenSource/EngineMC/releases/download/v1-alpha1/bukkit.jar downloadLuckPerms=https://download.luckperms.net/1561/bukkit/loader/LuckPerms-Bukkit-5.4.146.jar
downloadLuckPerms=https://download.luckperms.net/1556/bukkit/loader/LuckPerms-Bukkit-5.4.141.jar downloadSpark=https://ci.lucko.me/job/spark/464/artifact/spark-bukkit/build/libs/spark-1.10.118-bukkit.jar
downloadFreedomChat=NdbpBqOZ
# etc # etc
group = de.staropensource.pickshadow group = de.staropensource.pickshadow

View file

@ -0,0 +1,96 @@
/*
* 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("application")
id("io.freefair.lombok") version("${pluginLombok}")
id("io.github.goooler.shadow") version("${pluginShadow}")
}
// Dependencies
dependencies {
// Lombok
compileOnly("org.projectlombok:lombok:${dependencyLombok}")
annotationProcessor("org.projectlombok:lombok:${dependencyLombok}")
// JetBrains Annotations
compileOnly("org.jetbrains:annotations:${dependencyJetbrainsAnnotations}")
// Libraries
implementation("de.staropensource.engine:base:${dependencyStarOpenSourceEngine}")
runtimeOnly("de.staropensource.engine:ansi:${dependencyStarOpenSourceEngine}")
implementation("com.google.code.gson:gson:${dependencyGson}")
// Project
implementation(project(":common"))
}
// Set Java version
java {
toolchain.languageVersion.set(JavaLanguageVersion.of("${javaTarget}"))
}
// Fix delombok task
delombok.doFirst {
File target = file("${project.projectDir}/src/main/module-info.java")
File source = file("${project.projectDir}/src/main/java/module-info.java")
target.delete()
source.renameTo(target)
}
delombok.doLast {
File target = file("${project.projectDir}/src/main/java/module-info.java")
File source = file("${project.projectDir}/src/main/module-info.java")
target.delete()
source.renameTo(target)
}
// Configure output jar
jar {
manifest {
attributes(
"Main-Class": "de.jeremystartm.pickshadow.servermanager.Main"
)
}
}
// Configure application run task
application {
mainClass.set("de.jeremystartm.pickshadow.servermanager.Main")
applicationDefaultJvmArgs = [
// Display GC log
"-Xlog:gc",
// Set log level to DIAGNOSTIC
"-Dsosengine.base.loggerLevel=diagnostic",
// Force writing to standard output
"-Dsosengine.base.loggerForceStandardOutput=true",
// Pass classes which should be included if
// reflective sclasspath scanning is disabled.
"-Dsosengine.base.initialIncludeSubsystemClasses=de.staropensource.engine.ansi.AnsiSubsystem",
// Force Jansi to write escape sequences
"-Djansi.mode=force",
]
}

1
servermanager/gradle Symbolic link
View file

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

1
servermanager/gradlew vendored Symbolic link
View file

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

1
servermanager/gradlew.bat vendored Symbolic link
View file

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

View file

@ -0,0 +1 @@
../../../../../src/main/javadoc/theme.css

View file

@ -17,6 +17,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
rootProject.name = "PSSE" rootProject.name = "PickShadow"
include("common")
include("extension") include("extension")
include("servermanager")