Add VelocityCore Module
This commit is contained in:
29
VelocityCore/Persistent/build.gradle.kts
Normal file
29
VelocityCore/Persistent/build.gradle.kts
Normal file
@@ -0,0 +1,29 @@
|
||||
plugins {
|
||||
id("java")
|
||||
}
|
||||
|
||||
group = "de.steamwar"
|
||||
|
||||
tasks.compileJava {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDirs("src/")
|
||||
}
|
||||
resources {
|
||||
srcDirs("src/")
|
||||
exclude("**/*.java", "**/*.kt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("org.projectlombok:lombok:1.18.32")
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.32")
|
||||
|
||||
compileOnly("de.steamwar:velocity:RELEASE")
|
||||
annotationProcessor("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT")
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.persistent;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class Arenaserver extends Subserver {
|
||||
|
||||
private final String mode;
|
||||
private final String map;
|
||||
private final boolean allowMerge;
|
||||
|
||||
public Arenaserver(String serverName, String mode, String map, boolean allowMerge, int port, ProcessBuilder processBuilder, Runnable shutdownCallback) {
|
||||
super(Servertype.ARENA, serverName, port, processBuilder, shutdownCallback, null);
|
||||
this.mode = mode;
|
||||
this.map = map;
|
||||
this.allowMerge = allowMerge;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.persistent;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Getter
|
||||
public class Bauserver extends Subserver {
|
||||
private static final Map<UUID, Bauserver> servers = new HashMap<>();
|
||||
public static Bauserver get(UUID owner) {
|
||||
synchronized (servers) {
|
||||
return servers.get(owner);
|
||||
}
|
||||
}
|
||||
|
||||
private final UUID owner;
|
||||
|
||||
public Bauserver(String serverName, UUID owner, int port, ProcessBuilder processBuilder, Runnable shutdownCallback){
|
||||
this(serverName, owner, port, processBuilder, shutdownCallback, null);
|
||||
}
|
||||
|
||||
public Bauserver(String serverName, UUID owner, int port, ProcessBuilder processBuilder, Runnable shutdownCallback, Consumer<Exception> failureCallback){
|
||||
super(Servertype.BAUSERVER, serverName, port, processBuilder, shutdownCallback, failureCallback);
|
||||
this.owner = owner;
|
||||
|
||||
synchronized (servers) {
|
||||
servers.put(owner, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregister() {
|
||||
synchronized (servers) {
|
||||
servers.remove(owner);
|
||||
}
|
||||
super.unregister();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.persistent;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Getter
|
||||
public class Builderserver extends Subserver {
|
||||
|
||||
private static final Map<String, Builderserver> servers = new HashMap<>();
|
||||
public static Builderserver get(String map) {
|
||||
synchronized (servers) {
|
||||
return servers.get(map);
|
||||
}
|
||||
}
|
||||
|
||||
private final String map;
|
||||
public Builderserver(String serverName, String map, int port, ProcessBuilder processBuilder, Runnable shutdownCallback){
|
||||
this(serverName, map, port, processBuilder, shutdownCallback, null);
|
||||
}
|
||||
|
||||
public Builderserver(String serverName, String map, int port, ProcessBuilder processBuilder, Runnable shutdownCallback, Consumer<Exception> failureCallback){
|
||||
super(Servertype.BUILDER, serverName, port, processBuilder, shutdownCallback, failureCallback);
|
||||
this.map = map;
|
||||
|
||||
synchronized (servers) {
|
||||
servers.put(map, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unregister() {
|
||||
synchronized (servers) {
|
||||
servers.remove(map);
|
||||
}
|
||||
super.unregister();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.persistent;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.name.Names;
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.velocitypowered.api.command.BrigadierCommand;
|
||||
import com.velocitypowered.api.command.CommandManager;
|
||||
import com.velocitypowered.api.command.CommandMeta;
|
||||
import com.velocitypowered.api.event.EventManager;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
import com.velocitypowered.api.plugin.PluginContainer;
|
||||
import com.velocitypowered.api.plugin.PluginDescription;
|
||||
import com.velocitypowered.api.plugin.PluginManager;
|
||||
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import com.velocitypowered.api.scheduler.ScheduledTask;
|
||||
import com.velocitypowered.proxy.plugin.PluginClassLoader;
|
||||
import com.velocitypowered.proxy.plugin.VelocityPluginManager;
|
||||
import com.velocitypowered.proxy.plugin.loader.VelocityPluginContainer;
|
||||
import com.velocitypowered.proxy.plugin.loader.java.JavaPluginLoader;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Plugin(
|
||||
id = "persistentvelocitycore",
|
||||
name = "PersistentVelocityCore"
|
||||
)
|
||||
public class Persistent {
|
||||
|
||||
private static final Reflection.Method<VelocityPluginManager> registerPlugin = new Reflection.Method<>(VelocityPluginManager.class, "registerPlugin", PluginContainer.class);
|
||||
|
||||
@Getter
|
||||
private static Persistent instance;
|
||||
|
||||
@Getter
|
||||
private final ProxyServer proxy;
|
||||
@Getter
|
||||
private final Logger logger;
|
||||
private final Path directory;
|
||||
|
||||
@Inject
|
||||
public Persistent(ProxyServer proxy, Logger logger, @DataDirectory Path dataDirectory) {
|
||||
instance = this;
|
||||
this.proxy = proxy;
|
||||
this.logger = logger;
|
||||
this.directory = dataDirectory;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onEnable(ProxyInitializeEvent event) {
|
||||
proxy.getCommandManager().register(
|
||||
new BrigadierCommand(
|
||||
BrigadierCommand.literalArgumentBuilder("softreload")
|
||||
.requires(commandSource -> commandSource.hasPermission("bungeecore.softreload"))
|
||||
.executes(commandContext -> softreload())
|
||||
.build()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onDisable(ProxyShutdownEvent event) {
|
||||
Subserver.shutdown();
|
||||
}
|
||||
|
||||
public int softreload() {
|
||||
PluginContainer container = null;
|
||||
ReloadablePlugin plugin = null;
|
||||
try {
|
||||
container = proxy.getPluginManager().getPlugin("velocitycore").orElseThrow();
|
||||
plugin = (ReloadablePlugin) container.getInstance().orElseThrow();
|
||||
} catch (NoSuchElementException e) {
|
||||
logger.log(Level.WARNING, "Could not find loaded VelocityCore, continuing without unloading.");
|
||||
}
|
||||
|
||||
PluginContainer newContainer;
|
||||
try {
|
||||
newContainer = prepareLoad();
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Could not instantiate new VelocityCore, aborting softreload.", e);
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
broadcast("§eNetwork update is starting§8.");
|
||||
try {
|
||||
if(container != null && plugin != null) {
|
||||
plugin.onProxyShutdown(new ProxyShutdownEvent());
|
||||
unload(container, plugin);
|
||||
}
|
||||
|
||||
registerPlugin.invoke((VelocityPluginManager) proxy.getPluginManager(), newContainer);
|
||||
((ReloadablePlugin) newContainer.getInstance().orElseThrow()).onProxyInitialization(new ProxyInitializeEvent());
|
||||
} catch (Throwable t) {
|
||||
logger.log(Level.SEVERE, "Error during softreload", t);
|
||||
broadcast("§cNetwork update failed§8, §cexpect network restart soon§8.");
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
broadcast("§eNetwork update complete§8.");
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
private void broadcast(String message) {
|
||||
Component component = LegacyComponentSerializer.legacySection().deserialize("§eSteam§8War» " + message);
|
||||
proxy.getAllPlayers().forEach(player -> player.sendMessage(component));
|
||||
proxy.getConsoleCommandSource().sendMessage(component);
|
||||
}
|
||||
|
||||
private PluginContainer prepareLoad() throws Exception {
|
||||
Path plugins = directory.getParent();
|
||||
JavaPluginLoader loader = new JavaPluginLoader(proxy, plugins);
|
||||
PluginDescription description = loader.createPluginFromCandidate(loader.loadCandidate(plugins.resolve("VelocityCore.jar")));
|
||||
PluginContainer container = new VelocityPluginContainer(description);
|
||||
|
||||
AbstractModule commonModule = new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
this.bind(ProxyServer.class).toInstance(proxy);
|
||||
this.bind(PluginManager.class).toInstance(proxy.getPluginManager());
|
||||
this.bind(EventManager.class).toInstance(proxy.getEventManager());
|
||||
this.bind(CommandManager.class).toInstance(proxy.getCommandManager());
|
||||
this.bind(PluginContainer.class).annotatedWith(Names.named(container.getDescription().getId())).toInstance(container);
|
||||
}
|
||||
};
|
||||
|
||||
Module module = loader.createModule(container);
|
||||
loader.createPlugin(container, module, commonModule);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
private void unload(PluginContainer container, Object plugin) throws InterruptedException, IOException {
|
||||
PluginClassLoader classLoader = ((PluginClassLoader) plugin.getClass().getClassLoader());
|
||||
|
||||
CommandManager commandManager = proxy.getCommandManager();
|
||||
for(String alias : commandManager.getAliases()) {
|
||||
CommandMeta meta = commandManager.getCommandMeta(alias);
|
||||
if(meta != null && meta.getPlugin() == plugin)
|
||||
commandManager.unregister(meta);
|
||||
}
|
||||
|
||||
proxy.getEventManager().unregisterListeners(plugin);
|
||||
proxy.getScheduler().tasksByPlugin(plugin).forEach(ScheduledTask::cancel);
|
||||
|
||||
container.getExecutorService().shutdown();
|
||||
if(!container.getExecutorService().awaitTermination(100, TimeUnit.MILLISECONDS))
|
||||
logger.log(Level.WARNING, "ExecutorService termination took longer than 100ms, continuing.");
|
||||
|
||||
for(Thread thread : Thread.getAllStackTraces().keySet()) {
|
||||
if(thread.getClass().getClassLoader() != classLoader)
|
||||
continue;
|
||||
|
||||
thread.interrupt();
|
||||
thread.join(100);
|
||||
|
||||
if (thread.isAlive())
|
||||
logger.log(Level.WARNING, "Could not stop thread %s of plugin %s. Still running".formatted(thread.getName(), container.getDescription().getId()));
|
||||
}
|
||||
|
||||
//TODO close all log handlers
|
||||
/*for (Handler handler : plugin.getLogger().getHandlers()) {
|
||||
handler.close();
|
||||
}*/
|
||||
|
||||
|
||||
//Clear resource bundle cache
|
||||
ResourceBundle.clearCache(classLoader);
|
||||
classLoader.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.persistent;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class Reflection {
|
||||
public static class Field<C, T> {
|
||||
private final java.lang.reflect.Field f;
|
||||
|
||||
public Field(Class<C> target, String name) {
|
||||
try {
|
||||
f = target.getDeclaredField(name);
|
||||
f.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new IllegalArgumentException("Cannot find field with name " + name, e);
|
||||
}
|
||||
}
|
||||
|
||||
public T get(C target) {
|
||||
try {
|
||||
return (T) f.get(target);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalArgumentException("Cannot access reflection.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void set(C target, T value) {
|
||||
try {
|
||||
f.set(target, value);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalArgumentException("Cannot access reflection.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Method<C> {
|
||||
private final java.lang.reflect.Method m;
|
||||
|
||||
public Method(Class<C> clazz, String methodName, Class<?>... params) {
|
||||
try {
|
||||
m = clazz.getDeclaredMethod(methodName, params);
|
||||
m.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new IllegalArgumentException("Cannot find method with name " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
public Object invoke(C target, Object... arguments) {
|
||||
try {
|
||||
return m.invoke(target, arguments);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Cannot invoke method " + m, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.persistent;
|
||||
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
||||
|
||||
public interface ReloadablePlugin {
|
||||
void onProxyInitialization(ProxyInitializeEvent event);
|
||||
default void onProxyShutdown(ProxyShutdownEvent event) {}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.persistent;
|
||||
|
||||
public enum Servertype {
|
||||
BAUSERVER,
|
||||
ARENA,
|
||||
BUILDER
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.persistent;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfoPacket;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@UtilityClass
|
||||
public class Storage {
|
||||
public static final Map<Player, List<Player>> challenges = new HashMap<>();
|
||||
|
||||
public static final Map<Player, Player> lastChats = new HashMap<>();
|
||||
|
||||
public static final Map<Integer, List<Integer>> teamInvitations = new HashMap<>(); // UserID -> List<TeamIDs>
|
||||
|
||||
public static final Map<Player, Timestamp> sessions = new HashMap<>(); // Contains session start timestamp
|
||||
|
||||
public static final Map<Integer, Subserver> eventServer = new HashMap<>(); // TeamID -> Subserver map
|
||||
|
||||
public static final Map<Player, Integer> fabricCheckedPlayers = new HashMap<>();
|
||||
|
||||
public static final Map<Player, Long> fabricExpectPluginMessage = new HashMap<>();
|
||||
|
||||
public static final Map<Integer, ServerInfo> teamServers = new HashMap<>(); // TeamID -> ServerInfo map
|
||||
|
||||
public static final Map<Player, Map<UUID, UpsertPlayerInfoPacket.Entry>> directTabItems = new HashMap<>();
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.persistent;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class Subserver {
|
||||
|
||||
private static final Component PREFIX = Component
|
||||
.text("Steam").color(NamedTextColor.YELLOW)
|
||||
.append(Component.text("War» ").color(NamedTextColor.DARK_GRAY));
|
||||
|
||||
private static final Logger logger = Persistent.getInstance().getLogger();
|
||||
|
||||
@Getter
|
||||
private static final List<Subserver> serverList = new LinkedList<>();
|
||||
private static final Map<ServerInfo, Subserver> infoToServer = new HashMap<>();
|
||||
|
||||
public static Subserver getSubserver(Player p) {
|
||||
synchronized (serverList) {
|
||||
for (int i = serverList.size() - 1; i >= 0; i--) {
|
||||
if (serverList.get(i).onServer(p))
|
||||
return serverList.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Subserver getSubserver(ServerInfo server) {
|
||||
synchronized (serverList) {
|
||||
return infoToServer.get(server);
|
||||
}
|
||||
}
|
||||
|
||||
static void shutdown() {
|
||||
while (!serverList.isEmpty()) {
|
||||
Subserver server = serverList.get(0);
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private final String serverName;
|
||||
private final boolean checkpoint;
|
||||
private final Runnable shutdownCallback;
|
||||
private final Consumer<Exception> failureCallback;
|
||||
private final Process process;
|
||||
private final PrintWriter writer;
|
||||
@Getter
|
||||
private final ServerInfo server;
|
||||
@Getter
|
||||
private RegisteredServer registeredServer;
|
||||
@Getter
|
||||
private final Servertype type;
|
||||
private final Thread thread;
|
||||
@Getter
|
||||
private boolean started;
|
||||
|
||||
private final List<Player> cachedPlayers = new LinkedList<>();
|
||||
@Getter
|
||||
private final Map<Player, String> tablistNames = new HashMap<>();
|
||||
|
||||
protected Subserver(Servertype type, String serverName, int port, ProcessBuilder processBuilder, Runnable shutdownCallback, Consumer<Exception> failureCallback) {
|
||||
this.started = false;
|
||||
this.serverName = serverName;
|
||||
this.type = type;
|
||||
this.shutdownCallback = shutdownCallback;
|
||||
this.failureCallback = failureCallback == null ? this::fatalError : failureCallback;
|
||||
this.checkpoint = processBuilder.command().contains("criu");
|
||||
|
||||
try {
|
||||
this.process = processBuilder.start();
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Server could not be started", e);
|
||||
}
|
||||
|
||||
InetSocketAddress address = new InetSocketAddress("127.0.0.1", port);
|
||||
this.server = new ServerInfo(serverName, address);
|
||||
this.writer = new PrintWriter(process.getOutputStream(), true);
|
||||
|
||||
this.thread = new Thread(this::run, "Subserver " + serverName);
|
||||
this.thread.start();
|
||||
}
|
||||
|
||||
public void sendPlayer(Player p) {
|
||||
if (!started) {
|
||||
p.sendActionBar(generateBar(0));
|
||||
cachedPlayers.add(p);
|
||||
} else {
|
||||
p.createConnectionRequest(registeredServer).connect();
|
||||
}
|
||||
}
|
||||
|
||||
public void execute(String command) {
|
||||
writer.println(command);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
try {
|
||||
long pid = process.pid();
|
||||
if (checkpoint)
|
||||
pid = process.children().findAny().map(ProcessHandle::pid).orElse(pid);
|
||||
|
||||
Runtime.getRuntime().exec(new String[]{"kill", "-SIGUSR1", Long.toString(pid)});
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, "Failed to send SIGUSR1 to subserver.", e);
|
||||
}
|
||||
|
||||
try {
|
||||
if (!process.waitFor(1, TimeUnit.MINUTES)) {
|
||||
logger.log(Level.SEVERE, () -> serverName + " did not stop correctly, forcibly stopping!");
|
||||
process.destroyForcibly();
|
||||
}
|
||||
|
||||
thread.join();
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.SEVERE, "Subserver stop interrupted!", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean onServer(Player p) {
|
||||
return cachedPlayers.contains(p) || (registeredServer != null && registeredServer.getPlayersConnected().contains(p));
|
||||
}
|
||||
|
||||
private void fatalError(Exception e) {
|
||||
logger.log(Level.SEVERE, e, () -> serverName + " did not run correctly!");
|
||||
|
||||
for (Player cached : cachedPlayers)
|
||||
cached.sendMessage(PREFIX.append(Component.text("Unexpected error during server startup.").color(NamedTextColor.RED)));
|
||||
if (registeredServer != null) {
|
||||
for (Player player : registeredServer.getPlayersConnected())
|
||||
player.sendMessage(PREFIX.append(Component.text("Lost connection to server.").color(NamedTextColor.RED)));
|
||||
}
|
||||
}
|
||||
|
||||
private void start(InputStream stream, Predicate<String> test) throws IOException {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
|
||||
String line = "";
|
||||
while (!started && (line = reader.readLine()) != null) {
|
||||
started = test.test(line);
|
||||
}
|
||||
|
||||
if (line == null)
|
||||
throw new IOException(serverName + " did not start correctly!");
|
||||
}
|
||||
}
|
||||
|
||||
protected void register() {
|
||||
if (Persistent.getInstance().getProxy().getServer(serverName).isPresent()) {
|
||||
SecurityException e = new SecurityException("Server already registered: " + serverName);
|
||||
stop();
|
||||
failureCallback.accept(e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
synchronized (serverList) {
|
||||
registeredServer = Persistent.getInstance().getProxy().registerServer(server);
|
||||
serverList.add(this);
|
||||
infoToServer.put(server, this);
|
||||
}
|
||||
}
|
||||
|
||||
protected void unregister() {
|
||||
synchronized (serverList) {
|
||||
infoToServer.remove(server);
|
||||
serverList.remove(this);
|
||||
Persistent.getInstance().getProxy().unregisterServer(server);
|
||||
registeredServer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void run() {
|
||||
register();
|
||||
|
||||
Exception ex = null;
|
||||
try {
|
||||
if (checkpoint) {
|
||||
start(process.getErrorStream(), line -> line.contains("Restore finished successfully."));
|
||||
} else {
|
||||
start(process.getInputStream(), line -> {
|
||||
if (line.contains("Loading libraries, please wait"))
|
||||
sendProgress(2);
|
||||
else if (line.contains("Starting Minecraft server on"))
|
||||
sendProgress(4);
|
||||
else if (line.contains("Preparing start region"))
|
||||
sendProgress(6);
|
||||
return line.contains("Finished mapping loading");
|
||||
});
|
||||
}
|
||||
|
||||
if (!started)
|
||||
return;
|
||||
|
||||
sendProgress(8);
|
||||
|
||||
Thread.sleep(300);
|
||||
|
||||
sendProgress(10);
|
||||
for (Player cachedPlayer : cachedPlayers) {
|
||||
sendPlayer(cachedPlayer);
|
||||
}
|
||||
cachedPlayers.clear();
|
||||
|
||||
process.waitFor();
|
||||
} catch (IOException e) {
|
||||
ex = e;
|
||||
} catch (InterruptedException e) {
|
||||
ex = e;
|
||||
Thread.currentThread().interrupt();
|
||||
} finally {
|
||||
unregister();
|
||||
shutdownCallback.run();
|
||||
if (ex != null)
|
||||
failureCallback.accept(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Component generateBar(int progress) {
|
||||
return Component.text("⬛".repeat(Math.max(0, progress))).color(NamedTextColor.YELLOW)
|
||||
.append(Component.text("⬛".repeat(Math.max(0, 10 - progress))).color(NamedTextColor.DARK_GRAY));
|
||||
}
|
||||
|
||||
private void sendProgress(int progress) {
|
||||
Component tc = generateBar(progress);
|
||||
for (Player cached : cachedPlayers)
|
||||
cached.sendActionBar(tc);
|
||||
}
|
||||
}
|
||||
60
VelocityCore/build.gradle.kts
Normal file
60
VelocityCore/build.gradle.kts
Normal file
@@ -0,0 +1,60 @@
|
||||
plugins {
|
||||
id("java")
|
||||
id("com.github.johnrengelman.shadow")
|
||||
}
|
||||
|
||||
group = "de.steamwar"
|
||||
|
||||
tasks.shadowJar {
|
||||
exclude("META-INF/*")
|
||||
exclude("org/sqlite/native/FreeBSD/**', 'org/sqlite/native/Mac/**', 'org/sqlite/native/Windows/**', 'org/sqlite/native/Linux-Android/**', 'org/sqlite/native/Linux-Musl/**")
|
||||
exclude("org/sqlite/native/Linux/aarch64/**', 'org/sqlite/native/Linux/arm/**', 'org/sqlite/native/Linux/armv6/**', 'org/sqlite/native/Linux/armv7/**', 'org/sqlite/native/Linux/ppc64/**', 'org/sqlite/native/Linux/x86/**")
|
||||
exclude("org/slf4j/**")
|
||||
//https://imperceptiblethoughts.com/shadow/configuration/minimizing/
|
||||
minimize {
|
||||
exclude(project(":VelocityCore"))
|
||||
exclude(dependency("mysql:mysql-connector-java:.*"))
|
||||
}
|
||||
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||
}
|
||||
|
||||
tasks.compileJava {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDirs("src/")
|
||||
}
|
||||
resources {
|
||||
srcDirs("src/")
|
||||
exclude("**/*.java", "**/*.kt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("org.projectlombok:lombok:1.18.32")
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.32")
|
||||
|
||||
annotationProcessor("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT")
|
||||
compileOnly("de.steamwar:velocity:RELEASE")
|
||||
|
||||
implementation(project(":CommonCore"))
|
||||
implementation(project(":CommandFramework"))
|
||||
|
||||
compileOnly(project(":VelocityCore:Persistent"))
|
||||
|
||||
implementation("org.xerial:sqlite-jdbc:3.46.0.0")
|
||||
implementation("mysql:mysql-connector-java:8.0.33")
|
||||
|
||||
implementation("net.dv8tion:JDA:4.4.0_352") {
|
||||
exclude(module = "opus-java")
|
||||
}
|
||||
|
||||
implementation("org.msgpack:msgpack-core:0.9.8")
|
||||
|
||||
implementation("com.lunarclient:apollo-api:1.1.0")
|
||||
implementation("com.lunarclient:apollo-common:1.1.0")
|
||||
}
|
||||
29
VelocityCore/src/GDPRQueryREADME.md
Normal file
29
VelocityCore/src/GDPRQueryREADME.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# SteamWar GDPR report
|
||||
|
||||
## Copyright notice
|
||||
The provided build worlds contain the world design of SteamWar contributors and is subject to their copyright.
|
||||
The build worlds are therefore provided for personal use only.
|
||||
|
||||
## Categories of personal data processed
|
||||
- IP address
|
||||
- Minecraft account
|
||||
- E-Mail address (if using a website account)
|
||||
|
||||
## Processing purposes of personal data and person-related data
|
||||
- Provision of SteamWar user functionality (Minecraft account, IP address, BuildWorlds, BuildInventories, BuildMembers, Elo, IgnoredPlayers, SchematicMembers, SchematicChecksessions, Schematics, PersonalKits, UserData, UserConfigs)
|
||||
- Manual analysis and punishment of player misbehaviour (BannedIPs, log files, Punishments)
|
||||
- Statistical analysis (Sessions, Fights, SchematicChecksessions)
|
||||
- Historical data storage (Fights)
|
||||
- Technical error analysis (log files)
|
||||
- Provision of the SteamWar website functionality (IP address, E-Mail address)
|
||||
|
||||
## Data Accessors
|
||||
- SteamWar software
|
||||
- SteamWar Administration
|
||||
- SteamWar Development
|
||||
- SteamWar Moderation (limited to Punishments and SchematicChecksessions)
|
||||
|
||||
## Storage duration
|
||||
- Data for provision of functionality is stored until user triggered deletion
|
||||
- Log file storage duration is targeted at one month, but might differ due to technical reasons
|
||||
- Historical and statistical data deletion is not intended
|
||||
183
VelocityCore/src/de/steamwar/command/SWCommand.java
Normal file
183
VelocityCore/src/de/steamwar/command/SWCommand.java
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.command;
|
||||
|
||||
import com.velocitypowered.api.command.SimpleCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.discord.DiscordBot;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class SWCommand extends AbstractSWCommand<Chatter> {
|
||||
|
||||
static {
|
||||
TypeUtils.init();
|
||||
}
|
||||
|
||||
private final String name;
|
||||
@Getter
|
||||
private final UserPerm permission;
|
||||
private final String[] aliases;
|
||||
|
||||
private SimpleCommand command;
|
||||
|
||||
private final List<String> defaultHelpMessages = new ArrayList<>();
|
||||
|
||||
protected SWCommand(String command, String... aliases) {
|
||||
this(command, null, aliases);
|
||||
}
|
||||
|
||||
protected SWCommand(String command, UserPerm permission, String... aliases) {
|
||||
super(Chatter.class, command, aliases);
|
||||
this.name = command;
|
||||
this.permission = permission;
|
||||
this.aliases = aliases;
|
||||
create = true;
|
||||
createAndSafeCommand(command, aliases);
|
||||
unregister();
|
||||
register();
|
||||
}
|
||||
|
||||
public void execute(Chatter sender, String[] args) {
|
||||
execute(sender, null, args);
|
||||
}
|
||||
|
||||
private boolean create = false;
|
||||
|
||||
@Override
|
||||
protected void createAndSafeCommand(String command, String[] aliases) {
|
||||
if (!create) return;
|
||||
this.command = new SimpleCommand() {
|
||||
|
||||
@Override
|
||||
public void execute(Invocation invocation) {
|
||||
SWCommand.this.execute(Chatter.of(invocation.source()), invocation.alias(), invocation.arguments());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> suggest(Invocation invocation) {
|
||||
String[] args = invocation.arguments();
|
||||
if(args.length == 0)
|
||||
args = new String[]{""};
|
||||
|
||||
return SWCommand.this.tabComplete(Chatter.of(invocation.source()), invocation.alias(), args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Invocation invocation) {
|
||||
return permission == null || Chatter.of(invocation.source()).user().perms().contains(permission);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister() {
|
||||
if (command == null)
|
||||
return;
|
||||
|
||||
VelocityCore.getProxy().getCommandManager().unregister(name);
|
||||
DiscordBot.getCommands().remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register() {
|
||||
if (command == null)
|
||||
return;
|
||||
|
||||
VelocityCore.getProxy().getCommandManager().register(VelocityCore.getProxy().getCommandManager().metaBuilder(name).aliases(aliases).plugin(VelocityCore.get()).build(), command);
|
||||
DiscordBot.getCommands().put(name, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void commandSystemError(Chatter sender, CommandFrameworkException e) {
|
||||
VelocityCore.getLogger().log(Level.SEVERE, e.getMessage(), e);
|
||||
sender.prefixless("COMMAND_SYSTEM_ERROR");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void commandSystemWarning(Supplier<String> message) {
|
||||
VelocityCore.getLogger().log(Level.WARNING, message);
|
||||
}
|
||||
|
||||
public void addDefaultHelpMessage(String message) {
|
||||
defaultHelpMessages.add(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(Chatter sender, String message, Object[] args) {
|
||||
sender.system(message, args);
|
||||
}
|
||||
|
||||
@Register(noTabComplete = true)
|
||||
public void internalHelp(Chatter sender, String... args) {
|
||||
try {
|
||||
sender.prefixless("COMMAND_HELP_HEAD", name);
|
||||
defaultHelpMessages.forEach(sender::prefixless);
|
||||
} catch (Exception e) {
|
||||
VelocityCore.getLogger().log(Level.WARNING, "Failed to send help message", e);
|
||||
return;
|
||||
}
|
||||
AtomicInteger atomicInteger = new AtomicInteger();
|
||||
if (args.length != 0) {
|
||||
commandList.forEach(subCommand -> {
|
||||
List<String> tabCompletes = subCommand.tabComplete(sender, args);
|
||||
if (tabCompletes == null || tabCompletes.isEmpty()) {
|
||||
atomicInteger.incrementAndGet();
|
||||
return;
|
||||
}
|
||||
boolean hasTabCompletes = tabCompletes.stream()
|
||||
.anyMatch(s -> s.toLowerCase().startsWith(args[args.length - 1].toLowerCase()));
|
||||
if (hasTabCompletes) {
|
||||
send(sender, subCommand);
|
||||
} else {
|
||||
atomicInteger.incrementAndGet();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (args.length == 0 || atomicInteger.get() == commandList.size()) {
|
||||
commandList.forEach(subCommand -> {
|
||||
if (subCommand.validator == null || subCommand.validator.validate(sender, sender, (s, args1) -> {})) {
|
||||
send(sender, subCommand);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void send(Chatter chatter, SubCommand<Chatter> subCommand) {
|
||||
try {
|
||||
for (String s : subCommand.description) {
|
||||
String hover = "§8/§e" + name + " " + String.join(" ", subCommand.subCommand);
|
||||
chatter.prefixless(s, new Message("PLAIN_STRING", hover), ClickEvent.suggestCommand("/" + name + " " + String.join(" ", subCommand.subCommand)));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
VelocityCore.getLogger().log(Level.WARNING, "Failed to send description of registered method '%s' with description '%s'".formatted(subCommand.method, Arrays.toString(subCommand.description)), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
VelocityCore/src/de/steamwar/command/TypeMapper.java
Normal file
29
VelocityCore/src/de/steamwar/command/TypeMapper.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.command;
|
||||
|
||||
import de.steamwar.messages.Chatter;
|
||||
|
||||
public interface TypeMapper<T> extends AbstractTypeMapper<Chatter, T> {
|
||||
/**
|
||||
* The CommandSender can be null!
|
||||
*/
|
||||
T map(Chatter sender, PreviousArguments previousArguments, String s);
|
||||
}
|
||||
75
VelocityCore/src/de/steamwar/command/TypeUtils.java
Normal file
75
VelocityCore/src/de/steamwar/command/TypeUtils.java
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.command;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.steamwar.velocitycore.ServerVersion;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.commands.TypeMappers;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.Team;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@UtilityClass
|
||||
public class TypeUtils {
|
||||
|
||||
static void init() {
|
||||
SWCommandUtils.addMapper(Player.class, SWCommandUtils.createMapper(s -> VelocityCore.getProxy().getPlayer(s).orElse(null), s -> VelocityCore.getProxy().getAllPlayers().stream().map(Player::getUsername).collect(Collectors.toList())));
|
||||
SWCommandUtils.addMapper(SteamwarUser.class, SWCommandUtils.createMapper(SteamwarUser::get, s -> VelocityCore.getProxy().getAllPlayers().stream().map(Player::getUsername).collect(Collectors.toList())));
|
||||
SWCommandUtils.addMapper(ServerVersion.class, new TypeMapper<>() {
|
||||
@Override
|
||||
public ServerVersion map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
Player player = sender.getPlayer();
|
||||
if (player != null && s.isEmpty()) {
|
||||
ProtocolVersion version = player.getProtocolVersion();
|
||||
if (version.greaterThan(ProtocolVersion.MINECRAFT_1_19_4)) {
|
||||
return ServerVersion.PAPER_20;
|
||||
} else if (version.greaterThan(ProtocolVersion.MINECRAFT_1_15_2)) {
|
||||
return ServerVersion.PAPER_19;
|
||||
} else if (version.greaterThan(ProtocolVersion.MINECRAFT_1_12_2)) {
|
||||
return ServerVersion.SPIGOT_15;
|
||||
} else {
|
||||
return ServerVersion.SPIGOT_12;
|
||||
}
|
||||
}
|
||||
|
||||
return ServerVersion.get(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return ServerVersion.chatVersions();
|
||||
}
|
||||
});
|
||||
|
||||
AbstractTypeMapper<Object, Team> teamMapper = SWCommandUtils.createMapper(Team::get, s -> Team.getAll().stream().flatMap(team -> Stream.of(team.getTeamKuerzel(), team.getTeamName())).collect(Collectors.toList()));
|
||||
TabCompletionCache.add(teamMapper, true, 10, TimeUnit.SECONDS);
|
||||
SWCommandUtils.addMapper(Team.class, teamMapper);
|
||||
|
||||
TypeMappers.init();
|
||||
}
|
||||
}
|
||||
24
VelocityCore/src/de/steamwar/command/TypeValidator.java
Normal file
24
VelocityCore/src/de/steamwar/command/TypeValidator.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.command;
|
||||
|
||||
import de.steamwar.messages.Chatter;
|
||||
|
||||
public interface TypeValidator<T> extends AbstractValidator<Chatter, T> {}
|
||||
730
VelocityCore/src/de/steamwar/messages/BungeeCore.properties
Normal file
730
VelocityCore/src/de/steamwar/messages/BungeeCore.properties
Normal file
@@ -0,0 +1,730 @@
|
||||
COMMAND_SYSTEM_ERROR = §cError executing the command!
|
||||
COMMAND_HELP_HEAD=§7---=== (§e{0}§7) ===---
|
||||
|
||||
PREFIX=§eSteam§8War»
|
||||
SPACER=
|
||||
TIMEFORMAT=dd.MM.yyyy HH:mm
|
||||
PLAIN_STRING={0}
|
||||
|
||||
UNKNOWN_COMMAND=§cUnknown command.
|
||||
UNKNOWN_PLAYER=§cUnknown player.
|
||||
UNKNOWN_TEAM=§cUnknown team.
|
||||
UNKNOWN_EVENT=$cUnknown event.
|
||||
INVALID_TIME=§cInvalid time.
|
||||
|
||||
STEAMWAR_BRAND=§eSteam§8War.de §7({0}) §r<- §e{1} §7({2})§r
|
||||
|
||||
DEV_NO_SERVER=§cThe server is currently not available.
|
||||
DEV_UNKNOWN_SERVER=§cPlease specify a dev server.
|
||||
|
||||
DISABLED=§cCurrently disabled.
|
||||
|
||||
SERVER_START_OVERLOAD=§cServer start cancelled due to overload. Please try again later.
|
||||
UPDATE_INTERRUPTION=§cPlease try again. A software update has interrupted this action.
|
||||
|
||||
#Help command
|
||||
HELP_LOBBY=§7Return from anywhere to the lobby using §8/§el§7!
|
||||
HELP_LOBBY_HOVER=§eBack to the lobby
|
||||
HELP_BAU=§7Join your build server using §8/§ebuild§7!
|
||||
HELP_BAU_HOVER=§eTo your build server
|
||||
HELP_BAUSERVER=§7Get help regarding the build server with §8/§ehelp build§7!
|
||||
HELP_BAUSERVER_HOVER=§eHelp for the build server
|
||||
HELP_FIGHT=§7Start a new fight using §8/§efight§7!
|
||||
HELP_FIGHT_HOVER=§eTo the fighting system
|
||||
HELP_CHALLENGE=§7Challenge someone directly using §8/§echallenge§7!
|
||||
HELP_CHALLENGE_HOVER=§eChallenge
|
||||
HELP_HISTORIC=§7Start a historic fight using §8/§ehistoric§7!
|
||||
HELP_HISTORIC_HOVER=§eHistoric fights
|
||||
HELP_TEAM=§8/§eteam§7 for the team system!
|
||||
HELP_TEAM_HOVER=§eTeam management
|
||||
HELP_JOIN=§7Join a fight using §8/§ejoin §8[§eplayer§8]§7!
|
||||
HELP_JOIN_HOVER=§eSJoin a player
|
||||
HELP_LOCAL=§7Send chat messages only on your current server using §8/§elocal§7!
|
||||
HELP_LOCAL_HOVER=§eLocal chat
|
||||
|
||||
HELP_TNT=§8/§7tnt §8- §7(de)activates explosion damage
|
||||
HELP_FIRE=§8/§7fire §8- §7(de)activates fire damage
|
||||
HELP_TESTBLOCK=§8/§7testblock §8- §7Resets the dummy
|
||||
HELP_RESET=§8/§7reset §8- §7Resets the current region
|
||||
HELP_SPEED=§8/§7speed §8- §7Changes flight and walking speed
|
||||
HELP_NV=§8/§7nv §8- §7(de)activates night vision
|
||||
HELP_TRACE=§8/§7trace §8- §7Gives help regarding the tnt tracer
|
||||
HELP_TPSLIMIT=§8/§7tpslimit §8- §7Gives help regarding the TPS limiter
|
||||
HELP_LOADER=§8/§7loader §8- §7Use the automatic cannon loader
|
||||
HELP_PROTECT=§8/§7protect §8- §7Protects the floor of the (M)WG region
|
||||
HELP_FREEZE=§8/§7freeze §8- §7Stops block updates
|
||||
HELP_SKULL=§8/§7skull §8- §7Gives you a player head
|
||||
HELP_DEBUGSTICK=§8/§7debugstick §8- §7Gives you a debugstick
|
||||
HELP_BAUINFO=§8/§7buildinfo §8- §7Information about the current build server
|
||||
HELP_SCHEMSUBMIT=§7For a Tutorial about submitting your AirShip§8/§7MiniWarGear§8/§7WarGear§8/§7WarShip click §ehere§8!
|
||||
HELP_SCHEMSUBMIT_HOVER=§ehttps://www.youtube.com/watch?v=9QrQ3UBWveE
|
||||
|
||||
HELP_WE_POS1=§8//§71 §7» §8//§7pos1
|
||||
HELP_WE_POS2=§8//§72 §7» §8//§7pos2
|
||||
HELP_WE_COPY=§8//§7c §7» §8//§7copy
|
||||
HELP_WE_PASTE=§8//§7p §7» §8//§7paste
|
||||
HELP_WE_FLOPY=§8//§7flopy §7» §8//§7copy §7& §8//§7flip
|
||||
HELP_WE_FLOPYP=§8//§7flopyp §7» §8//§7copy §7& §8//§7flip §7& §8//§7paste
|
||||
HELP_WE_ROTATE_90=§8//§790 §7» §8//§7rotate §e90
|
||||
HELP_WE_ROTATE_180=§8//§7180 §7» §8//§7rotate §e180
|
||||
HELP_WE_ROTATE_N90=§8//§7-90 §7» §8//§7rotate §e-90
|
||||
|
||||
HELP_BAU_GROUP_ADMIN=§7Build server management commands
|
||||
HELP_BAU_GROUP_ADMIN_HOVER=§eAll management commands
|
||||
HELP_BAU_GROUP_ADMIN_TITLE=§7All management commands§8:
|
||||
HELP_BAU_GROUP_OTHER=§7Additional management commands
|
||||
HELP_BAU_GROUP_OTHER_HOVER=§eAdditional build server commands
|
||||
HELP_BAU_GROUP_OTHER_TITLE=§7Additional build server commands§8:
|
||||
HELP_BAU_GROUP_WE=§7WorldEdit shortcuts
|
||||
HELP_BAU_GROUP_WE_HOVER=§eWorldEdit shortcuts
|
||||
HELP_BAU_GROUP_WE_TITLE=§7WorldEdit shortcuts§8:
|
||||
HELP_BAU_GROUP_PLAYER=§7Player commands
|
||||
HELP_BAU_GROUP_PLAYER_HOVER=§ePlayer commands
|
||||
HELP_BAU_GROUP_PLAYER_TITLE=§7Player commands§8:
|
||||
HELP_BAU_GROUP_WORLD=§7World changing build server commands
|
||||
HELP_BAU_GROUP_WORLD_HOVER=§eWorld changing build server commands
|
||||
HELP_BAU_GROUP_WORLD_TITLE=§7World changing build server commands§8:
|
||||
|
||||
HELP_BAU_TP=§8/§ebuild tp §8- §7Join the build server of friends!
|
||||
HELP_BAU_TP_HOVER=§eto another build server
|
||||
HELP_BAU_ADDMEMBER=§8/§ebuild addmember §8- §7Allows a friend on your build server
|
||||
HELP_BAU_ADDMEMBER_HOVER=§eAdd a friend
|
||||
HELP_BAU_DELMEMBER=§8/§ebuild delmember §8- §7Removes a player
|
||||
HELP_BAU_DELMEMBER_HOVER=§eRemoves a player
|
||||
HELP_BAU_SET_SPECTATOR=§8/§ebuild setspectator §8- §7Spectate build server
|
||||
HELP_BAU_SET_SPECTATOR_HOVER=§eSets the Role to Spectator
|
||||
HELP_BAU_SET_BUILDER=§8/§ebuild setbuilder §8- §7Building, WorldEdit, BauSystem features
|
||||
HELP_BAU_SET_BUILDER_HOVER=§eSets the Role to Builder
|
||||
HELP_BAU_SET_SUPERVISOR=§8/§ebuild supervisor §8- §7Starting build server. Saving schematics
|
||||
HELP_BAU_SET_SUPERVISOR_HOVER=§eSets the Role to Supervisor
|
||||
HELP_BAU_DELETE=§8/§ebuild delete §8- §7Reset your entire build server
|
||||
HELP_BAU_DELETE_HOVER=§eReset build server
|
||||
HELP_BAU_TESTARENA=§8/§ebuild testarena §8- §7Start a test arena
|
||||
HELP_BAU_TESTARENA_HOVER=§eStart test arena
|
||||
HELP_BAU_LOCK=§8/§ebuild lock §8- §7Locks the build server for a specified group of players
|
||||
HELP_BAU_LOCK_HOVER=§eLock your build server
|
||||
HELP_BAU_UNLOCK=§8/§ebuild unlock §8- §7Unlocks the buildserver for added users
|
||||
HELP_BAU_UNLOCK_HOVER=§eUnlock your build server
|
||||
|
||||
#Usage description of various commands
|
||||
USAGE_ALERT=§8/§7alert §8[§emessage§8]
|
||||
USAGE_IGNORE=§8/§7ignore §8[§eplayer§8]
|
||||
|
||||
#ModListener
|
||||
MOD_RED_SING=Attempted use of mod {0}
|
||||
MOD_RED_PLUR=Attempted use of mods:\n{0}
|
||||
MOD_YELLOW_SING=§7Deactivate the mod §e{0}§7 to continue playing on §eSteam§8War§7.
|
||||
MOD_YELLOW_PLUR=§7Deactivate the mods\n§e{0}\n§7to continue playing on §eSteam§8War§7.
|
||||
MODS_CHECKED=§7Your Mods have been checked.\n§aYou can join §eSteam§8War §anow§8.
|
||||
|
||||
#Various commands
|
||||
ALERT=§f{0}
|
||||
STAT_SERVER=§7Server §e{0}§8: §7Below limit §e{1} §7Server count §e{2}
|
||||
|
||||
#Ban&Mute-Command
|
||||
PUNISHMENT_USAGE=§8/§7{0} §8[§eplayer§8] [§edd§8.§emm§8.§eyyyy §7or §edd§8.§emm§8.§eyyyy§8_§ehh§8:§emm §7or §enumber§8[§eh§7our|§ed§7ay|§ew§7eek|§em§7onth|§ey§7ear§8] §7or §eperma§8] [§ereason§8]
|
||||
PUNISHMENT_USAGE_REASON=§cPlease enter a reason.
|
||||
UNPUNISHMENT_USAGE=§8/§7{0} §8[§eplayer§8]
|
||||
|
||||
PUNISHMENT_UNTIL=until {0}
|
||||
PUNISHMENT_PERMA=permanent
|
||||
|
||||
BAN_TEAM={0} §e{1} §7was §e§lbanned§7 by §e{2} {3}§8: §f{4}
|
||||
BAN_PERMA=§7You are §e§lbanned §epermanently§8: §e{0}
|
||||
BAN_UNTIL=§7You are §e§lbanned §euntil {0}§8: §e{1}
|
||||
UNBAN_ERROR=§cThe player isn't banned.
|
||||
UNBAN=§7You have §e§lunbanned §e{0}.
|
||||
|
||||
BAN_AVOIDING_ALERT=§cPotential ban bypass by §r{0}§c: {1}
|
||||
BAN_AVOIDING_LIST=§c{0} §e{1}
|
||||
BAN_AVOIDING_BAN_HOVER=§cBan player because of bann bypass.
|
||||
|
||||
MUTE_TEAM={0} §e{1} §7was §e§lmuted§7 by §e{2} {3}§8: §f{4}
|
||||
MUTE_PERMA=§7You are §epermanently §e§lmuted§8: §e{0}
|
||||
MUTE_UNTIL=§7You are §e§lmuted §euntil {0}§8: §e{1}
|
||||
UNMUTE_ERROR=§cThe player isn't muted.
|
||||
UNMUTE=§7You have §e§lunmuted §e{0}.
|
||||
|
||||
NOSCHEMRECEIVING_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lrecieving schematics§8: §f{4}
|
||||
NOSCHEMRECEIVING_PERMA=§7You are §epermanently§7 excluded from receiving §e§lschematics§8: §e{0}
|
||||
NOSCHEMRECEIVING_UNTIL=§7You are excluded from receiving §e§lschematics §euntil {0}§8: §e{1}
|
||||
UNNOSCHEMRECEIVING_ERROR=§cThe player is not excluded from receiving schematics.
|
||||
UNNOSCHEMRECEIVING=§e{0} §7may now receive §e§lschematics§7 again§8.
|
||||
|
||||
NOSCHEMSHARING_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lsharing schematics§8: §f{4}
|
||||
NOSCHEMSHARING_PERMA=§7You are §epermanently§7 excluded from sharing §e§lschematics§8: §e{0}
|
||||
NOSCHEMSHARING_UNTIL=§7You are excluded from sharing §e§lschematics §euntil {0}§8: §e{1}
|
||||
UNNOSCHEMSHARING_ERROR=§cThe player is not excluded from sharing schematics.
|
||||
UNNOSCHEMSHARING=§e{0} §7may now share §e§lschematics§7 again§8.
|
||||
|
||||
NOSCHEMSUBMITTING_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lsubmitting schematics§8: §f{4}
|
||||
NOSCHEMSUBMITTING_PERMA=§7You are §epermanently§7 excluded from submitting §e§lschematics§8: §e{0}
|
||||
NOSCHEMSUBMITTING_UNTIL=§7You are excluded from submitting §e§lschematics §euntil {0}§8: §e{1}
|
||||
UNNOSCHEMSUBMITTING_ERROR=§cThe player is not excluded from submitting schematics.
|
||||
UNNOSCHEMSUBMITTING=§e{0} §7may now submit §e§lschematics§7 again§8.
|
||||
|
||||
NODEVSERVER_TEAM={0} §e{1} §7has annoyed §e{2} §7with reason §f{4}§7 and therefore has received §e§ldev server prohibition§7§8, §f{3}
|
||||
NODEVSERVER_PERMA=§7You are §epermanently§7 excluded from §e§ldev servers§8: §e{0}
|
||||
NODEVSERVER_UNTIL=§7You are excluded from §e§ldev servers§7 §euntil {0}§8: §e{1}
|
||||
UNNODEVSERVER_ERROR=§cThe player is not excluded from dev servers.
|
||||
UNNODEVSERVER=§e{0} §7may now join §e§ldev servers§7 again§8.
|
||||
|
||||
NOFIGHTSERVER_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lfighting§8: §f{4}
|
||||
NOFIGHTSERVER_PERMA=§7You are §epermanently§7 excluded from §e§lfighting§8: §e{0}
|
||||
NOFIGHTSERVER_UNTIL=§7You are excluded from §e§lfighting§7 §euntil {0}§8: §e{1}
|
||||
UNNOFIGHTSERVER_ERROR=§cThe player is not excluded from fighting.
|
||||
UNNOFIGHTSERVER=§e{0} §7may now join §e§lfights§7 again§8.
|
||||
|
||||
NOTEAMSERVER_TEAM={0} §e{1} §7was excluded from §e{2} {3} §7from §e§lteam servers§8: §f{4}
|
||||
NOTEAMSERVER_PERMA=§7You are §epermanently§7 excluded from §e§lteam servers§8: §e{0}
|
||||
NOTEAMSERVER_UNTIL=§7You are excluded from §e§lteam servers§7 §euntil {0}§8: §e{1}
|
||||
UNNOTEAMSERVER_ERROR=§cThe player is not excluded from team servers.
|
||||
UNNOTEAMSERVER=§e{0} §7may now set §e§lteam servers§7 again§8.
|
||||
|
||||
NOTE_TEAM={0} §e{1} §7received a §e§lnote§7 from §e{2} {3}: §f{4}
|
||||
|
||||
#BugCommand
|
||||
BUG_MESSAGE=§7Please describe the issue in a Discord ticket with the bug ID §e{0} §7further§8.
|
||||
|
||||
#IgnoreCommand
|
||||
IGNORE_YOURSELF=§cHow are you going to ignore yourself?
|
||||
IGNORE_ALREADY=§cYou are already ignoring this player.
|
||||
IGNORE_MESSAGE=§7You are now ignoring §e{0}§8.
|
||||
|
||||
#PollresultCommand
|
||||
POLLRESULT_NOPOLL=§cThere is currently no ongoing poll.
|
||||
POLLRESULT_HEADER=§e{0} players have voted on the question: §7{1}
|
||||
POLLRESULT_LIST=§e{0}§8: §7{1}
|
||||
|
||||
#BauCommand
|
||||
BAU_ADDMEMBER_USAGE=§8/§7build addmember §8[§eplayer§8]
|
||||
BAU_ADDMEMBER_SELFADD=§cYou don't have to add yourself!
|
||||
BAU_ADDMEMBER_ISADDED=§cThis player is already a member of your world.
|
||||
BAU_ADDMEMBER_ADDED=§aThe player was added to your world.
|
||||
BAU_ADDMEMBER_ADDED_TARGET=§aYou have been added to the world of §e{0}§a.
|
||||
BAU_TP_USAGE=§8/§7build tp §8[§eplayer§8]
|
||||
BAU_TP_NOALLOWED=§cYou are not allowed to teleport to this player's world.
|
||||
BAU_LOCKED_NOALLOWED=§cThe build server is currently locked.
|
||||
BAU_LOCK_BLOCKED=§cYour build lock has prevented §e{0} §cfrom joining.
|
||||
BAU_LOCKED_OPTIONS=§7Build server lock options§8: §cnobody§8, §eserverteam§8, §eteam_and_serverteam§8, §eteam§8, §aopen
|
||||
BAU_LOCKED_NOBODY=§7You have locked your build server for all players.
|
||||
BAU_LOCKED_SERVERTEAM=§7You have locked your build server for all players except added server team members.
|
||||
BAU_LOCKED_TEAM_AND_SERVERTEAM=§7You have locked your build server for all players except added team members and server team members.
|
||||
BAU_LOCKED_TEAM=§7You have locked your build server for all players except added team members.
|
||||
BAU_LOCKED_OPEN=§7You have opened your build server for all added players.
|
||||
BAU_DELMEMBER_USAGE=§8/§7build delmember §8[§eplayer§8]
|
||||
BAU_DELMEMBER_SELFDEL=§cYou cannot remove yourself!
|
||||
BAU_DELMEMBER_DELETED=§cPlayer was removed.
|
||||
BAU_DELMEMBER_DELETED_TARGET=§cYou were removed from the world of §e{0}.
|
||||
BAU_DELETE_DELETED=§aYour world is being reset.
|
||||
BAU_DELETE_GUI_NAME=§eDo you really want to delete the world?
|
||||
BAU_DELETE_GUI_CANCEL=§cCancel
|
||||
BAU_DELETE_GUI_DELETE=§aDelete
|
||||
BAU_START_ALREADY=§cThis server is already starting.
|
||||
BAU_MEMBER_NOMEMBER=§cThis player is no member of your world!
|
||||
BAU_MEMBER_SET_USAGE=§8/§7build {0} §8[§eplayer§8]
|
||||
BAU_MEMBER_SET_TARGET=§7You are now a §e{1}§7 on the world of §e{0}§7.
|
||||
BAU_MEMBER_SET=§7The player is now a §e{0}§7.
|
||||
BAU_MEMBER_SET_SPECTATOR = spectator
|
||||
BAU_MEMBER_SET_BUILDER = builder
|
||||
BAU_MEMBER_SET_SUPERVISOR = supervisor
|
||||
BAU_START_NOT_ALLOWED = §cYou are not allowed to start this build server.
|
||||
|
||||
#ChallengeCommand
|
||||
CHALLENGE_USAGE=§8/§7challenge §8[§eplayer§8]
|
||||
CHALLENGE_OFFLINE=§cThe challenged player isn\'t online.
|
||||
CHALLENGE_SELF=§cSchizophrenia?
|
||||
CHALLENGE_IGNORED=§cThe challenged player has blocked you.
|
||||
CHALLENGE_INARENA=§cThe challenged player is already in an arena.
|
||||
CHALLENGE_BROADCAST=§e{0} duel§7: §e{1} §7vs §e{2}
|
||||
CHALLENGE_BROADCAST_HOVER=§aWatch
|
||||
CHALLENGE_CHALLENGED=§7You have challenged §e{0} §7to a §e{1} fight§7!
|
||||
CHALLENGE_CHALLENGED_TARGET=§e{0} §7 has challenged you to a §e{1} fight §7{2}!
|
||||
CHALLENGE_CHALLENGED_MAP=on §e{0} §7
|
||||
CHALLENGE_ACCEPT=§7Click §ehere§7 to accept
|
||||
CHALLENGE_ACCEPT_HOVER=§aAccept challenge
|
||||
|
||||
#EventCommand
|
||||
EVENT_TIME_FORMAT=HH:mm
|
||||
EVENT_DATE_FORMAT=dd.MM.
|
||||
EVENT_USAGE=§8/§7event §8[§eTeam§8] - §7To teleport to a fight
|
||||
EVENT_NO_TEAM=§cThis team does not exist
|
||||
EVENT_NO_FIGHT_TEAM=§cThis team has no current fight
|
||||
EVENT_NO_CURRENT=§cThere is no event taking place currently
|
||||
EVENT_COMING=§eUpcoming events§8:
|
||||
EVENT_COMING_EVENT=§7{0}§8-§7{1}§8: §e{2}
|
||||
EVENT_COMING_DEADLINE=§7 Registration deadline§8: §7{0}
|
||||
EVENT_COMING_SCHEM_DEADLINE=§7 Submission deadline§8: §7{0}
|
||||
EVENT_COMING_TEAMS=§7 With§8: {0}
|
||||
EVENT_COMING_TEAM= §{0}{1}
|
||||
EVENT_CURRENT_EVENT=§e§l{0}
|
||||
EVENT_CURRENT_FIGHT=§7{0} §{1}{2}§8 vs §{3}{4}
|
||||
EVENT_CURRENT_FIGHT_WIN=§8: §7Victory §{0}{1}
|
||||
EVENT_CURRENT_FIGHT_DRAW=§8: §7Draw
|
||||
|
||||
#EventRescheduleCommand
|
||||
EVENTRESCHEDULE_USAGE=§8/§7eventreschedule §8[§eTeam1§8] [§eTeam2§8]
|
||||
EVENTRESCHEDULE_UNKNOWN_TEAM=§cA team is unknown / No current event
|
||||
EVENTRESCHEDULE_NO_FIGHT="§cNo fight found between the teams"
|
||||
EVENTRESCHEDULE_STARTING=§aFight starts in 30s
|
||||
|
||||
#FightCommand
|
||||
FIGHT_UNKNOWN_GAMEMODE=§cUnknown gamemode: {0}
|
||||
FIGHT_UNKNOWN_ARENA=§cThe desired arena does not exist.
|
||||
FIGHT_IN_ARENA=§cYou are already in an arena.
|
||||
FIGHT_BROADCAST=§7Click §ehere§7 to fight §e{0} §7against §e{1}!
|
||||
FIGHT_BROADCAST_HOVER=§aFight §eagainst §7{1}
|
||||
|
||||
#CheckCommand
|
||||
CHECK_REMINDER=§7There are §e{0} §7schematics left for review§8!
|
||||
CHECK_REMINDER_HOVER=§eSchematics to review
|
||||
CHECK_NOT_CHECKING=§cYou are currently not reviewing any schematic.
|
||||
CHECK_HELP_LIST=§8/§7check list §8- §7Shows the list of unreviewed schematics
|
||||
CHECK_HELP_NEXT=§8/§7check next §8- §7Next review question§8/§7accept
|
||||
CHECK_HELP_DECLINE=§8/§7check decline §8[§ereason§8] - §7Decline schematic
|
||||
CHECK_HELP_CANCEL=§8/§7check cancel §8- §7Cancels reviewing process
|
||||
CHECK_LIST_HEADER=§e§l{0} schematics are left to review
|
||||
CHECK_LIST_TO_CHECK={0} §8{1} §7{2} §e{3}
|
||||
CHECK_LIST_WAIT=§{0}{1}:{2}
|
||||
CHECK_LIST_TO_CHECK_HOVER=§eCheck schematic
|
||||
CHECK_LIST_CHECKING={0} §8{1} §7{2} §e{3} §7is being reviewed by §e{4}
|
||||
CHECK_LIST_CHECKING_HOVER=§eTo the reviewer
|
||||
CHECK_SCHEMATIC_ALREADY_CHECKING=§cYou are already reviewing a schematic!
|
||||
CHECK_SCHEMATIC_OWN=§cYou cannot review your own schematics.
|
||||
CHECK_SCHEMATIC_OWN_TEAM=§cYou cannot review your team schematics.
|
||||
CHECK_SCHEMATIC_PREVIOUS=§7{0} from {1}§8: §e{2}
|
||||
CHECK_INVALID_RANK=§cUnknown schematic rank.
|
||||
CHECK_ABORT=§aThe test operation was canceled!
|
||||
CHECK_NEXT=Next question
|
||||
CHECK_ACCEPT=Accept
|
||||
CHECK_DECLINE=Decline
|
||||
CHECK_RANK=§aRank {0}: {1}
|
||||
CHECK_RANK_HOVER=§aAccept with given rank
|
||||
CHECK_ACCEPTED=§aYour §e{0} {1} §ewas accepted§8!
|
||||
CHECK_ACCEPTED_TEAM=§7The schematic §e{0} §7from §e{1} §7is now approved!
|
||||
CHECK_DECLINED=§cYour §e{0} {1} §cwas declined§8: §c{2}
|
||||
CHECK_DECLINED_TEAM=§7The schematic §e{0} §7from §e{1} §7is now declined because §e{2}§7!
|
||||
|
||||
#HistoricCommand
|
||||
HISTORIC_BROADCAST=§7Historic §e{0} §7fight by §e{1}§8!
|
||||
HISTORIC_BROADCAST_HOVER=§afight against §7{1}
|
||||
|
||||
#JoinCommand
|
||||
JOIN_PLAYER_BLOCK=§cYou currently cannot follow this player.
|
||||
|
||||
#JoinmeCommand
|
||||
JOINME_USAGE=§8/§7join §8[§eplayer§8].
|
||||
JOINME_BROADCAST=§7Click §ehere§8 §7to join §e{0} §7on §e{1}§8!
|
||||
JOINME_BROADCAST_HOVER=§aJoin player
|
||||
JOINME_PLAYER_OFFLINE=§cThis player is offline.
|
||||
JOINME_PLAYER_SELF=§cBe one with yourself!
|
||||
|
||||
#KickCommand
|
||||
KICK_USAGE=§8/§7kick §8[§ePlayer§8] [§eMessage§8]
|
||||
KICK_OFFLINE=§cThis player is currently not online!
|
||||
KICK_CONFIRM=The player {0} was kicked.
|
||||
KICK_NORMAL=§cYou were kicked.
|
||||
KICK_CUSTOM=§c{0}
|
||||
|
||||
#MsgCommand
|
||||
MSG_USAGE=§8/§7msg §8[§euser§8] [§emessage§8]
|
||||
MSG_OFFLINE=§cPlayer is offline!
|
||||
MSG_IGNORED=§cThis player has blocked you!
|
||||
|
||||
#PingCommand
|
||||
PING_RESPONSE=§7Your ping is §c{0}§7 ms!
|
||||
|
||||
#PollCommand
|
||||
POLL_NO_POLL=§cThere is no ongoing poll.
|
||||
POLL_NO_ANSWER=§cThis is not an option
|
||||
POLL_ANSWER_REFRESH=§aYour answer was updated.
|
||||
POLL_ANSWER_NEW=§aYour answer was registered.
|
||||
|
||||
#RCommand
|
||||
R_USAGE=§8/§7r §8[§eanswer§8]
|
||||
|
||||
#RegelnCommand
|
||||
REGELN_RULES=§7§lRules
|
||||
REGELN_AS=§eAirShip §7Rules
|
||||
REGELN_AS_HOVER=§7https://steamwar.de/spielmodi/airship-regelwerk/
|
||||
REGELN_AS_URL=https://steamwar.de/spielmodi/airship-regelwerk/
|
||||
REGELN_MWG=§eMiniWarGear §7Rules
|
||||
REGELN_MWG_HOVER=§7https://steamwar.de/spielmodi/miniwargear-regelwerk/
|
||||
REGELN_MWG_URL=https://steamwar.de/spielmodi/miniwargear-regelwerk/
|
||||
REGELN_WG=§eWarGear §7Rules
|
||||
REGELN_WG_HOVER=§7https://steamwar.de/spielmodi/wargear-regelwerk/
|
||||
REGELN_WG_URL=https://steamwar.de/spielmodi/wargear-regelwerk/
|
||||
REGELN_WS=§eWarShip §7Rules
|
||||
REGELN_WS_HOVER=§7https://steamwar.de/spielmodi/warship-regelwerk/
|
||||
REGELN_WS_URL=https://steamwar.de/spielmodi/warship-regelwerk/
|
||||
REGELN_QG=§eQuickGear §7Rules
|
||||
REGELN_QG_HOVER=§7https://steamwar.de/spielmodi/quickgear-regelwerk/
|
||||
REGELN_QG_URL=https://steamwar.de/spielmodi/quickgear-regelwerk/
|
||||
REGELN_CONDUCT=§eCode of conduct
|
||||
REGELN_CONDUCT_HOVER=§7https://steamwar.de/verhaltensrichtlinien/
|
||||
REGELN_CONDUCT_URL=https://steamwar.de/verhaltensrichtlinien/
|
||||
|
||||
#ReplayCommand
|
||||
REPLAY_TITLE=Most recent fights
|
||||
REPLAY_UNAVAILABLE=§cReplay unavailable
|
||||
REPLAY_SOLO_WINNER=§e§l{0}
|
||||
REPLAY_WINNER=§e§l{0} §7+§e{1}
|
||||
REPLAY_SOLO_LOSER=§e{0}
|
||||
REPLAY_LOSER=§e{0} §7+§e{1}
|
||||
REPLAY_TIME=§7{0}
|
||||
REPLAY_SERVER=§7{0}
|
||||
|
||||
#TutorialCommand
|
||||
TUTORIAL_TITLE=Tutorials
|
||||
TUTORIAL_NAME=§e{0}
|
||||
TUTORIAL_BY=§8von §7{0}
|
||||
TUTORIAL_STARS=§e{0} §7Stars
|
||||
TUTORIAL_RATE_TITLE=Rate tutorial
|
||||
TUTORIAL_RATE=§e{0} §7Star(s)
|
||||
TUTORIAL_DELETE=§cDelete with Shift+Right-Click
|
||||
TUTORIAL_CREATE_HELP=§8/§7tutorial create §8[§ematerial§8] §8[§ename§8]
|
||||
TUTORIAL_CREATE_MISSING=§cA tutorial can only be created on a tutorial server!
|
||||
TUTORIAL_CREATED=§7Tutorial created§8.
|
||||
TUTORIAL_OWN_HELP=§8/§7tutorial own §8- §7List your own tutorials
|
||||
|
||||
#ServerTeamchatCommand
|
||||
STC_USAGE=§8/§7stc §8[§emessage to team§8]
|
||||
|
||||
#TeamchatCommand
|
||||
TC_USAGE=§8/§7tc §8[§eMessage to the team§8]
|
||||
TC_NO_TEAM=§cYou are currently in no team.
|
||||
|
||||
#TeamCommand
|
||||
TEAM_IN_TEAM=§cYou are already in a team.
|
||||
TEAM_NOT_IN_TEAM=§cYou are currently in no team.
|
||||
TEAM_NOT_LEADER=§cYou are not a leader of your team.
|
||||
TEAM_NOT_IN_EVENT=§cThis is not possible during an event.
|
||||
TEAM_HELP_HEADER=§7Manage your team with §e/team.
|
||||
TEAM_HELP_LIST=§8/§7team list §8- §7List all teams.
|
||||
TEAM_HELP_INFO=§8/§7team info §8- §7Get information on a team.
|
||||
TEAM_HELP_TP=§8/§7team tp §8(§7Team§8) §8- §7Teleport to a team server.
|
||||
TEAM_HELP_CREATE=§8/§7team create §8- §7Create your own team.
|
||||
TEAM_HELP_JOIN=§8/§7team join §8- §7Join a team.
|
||||
TEAM_HELP_CHAT=§8/§7teamchat §8- §7Send messages to your team.
|
||||
TEAM_HELP_EVENT=§8/§7team event §8- §7Take part in an event.
|
||||
TEAM_HELP_LEAVE=§8/§7team leave §8- §7Leave your team.
|
||||
TEAM_HELP_INVITE=§8/§7team invite §8- §7Invite someone to join your team.
|
||||
TEAM_HELP_REMOVE=§8/§7team remove §8- §7Remove somebody out of your team.
|
||||
TEAM_HELP_KUERZEL=§8/§7team changekuerzel §8- §7Change your team shortcut.
|
||||
TEAM_HELP_NAME=§8/§7team changename §8- §7Change your team name.
|
||||
TEAM_HELP_COLOR=§8/§7team changecolor §8- §7Change your team color.
|
||||
TEAM_HELP_LEADER=§8/§7team promote §8- §7Promote someone to leader.
|
||||
TEAM_HELP_STEP_BACK=§8/§7team stepback §8- §7Demote yourself from leader.
|
||||
TEAM_HELP_SERVER=§8/§7team server §8[§eIP/address§8] §8(§7port§8) §8- §7Set the address for your teamserver.
|
||||
|
||||
#Team Create
|
||||
TEAM_CREATE_USAGE=§8/§7team create §8[§eteam shortcut§8] §8[§eteam name§8]
|
||||
TEAM_CREATE_CREATED=§7You have created the team §e{0}§7!
|
||||
|
||||
#Team Join
|
||||
TEAM_JOIN_NO_INVITE=§7You have no pending invitation.
|
||||
TEAM_JOIN_USAGE=§8/§7team join §8[§eteam§8]
|
||||
TEAM_JOIN_INVITED=§7You were invited by the following teams§8: §e{0}
|
||||
TEAM_JOIN_NOT_BY_TEAM=§cYou have no pending invitation from this team.
|
||||
TEAM_JOIN_JOINED=§7You joined the team §e{0}§7!
|
||||
|
||||
#Team Leave
|
||||
TEAM_OTHER_LEADER_REQUIRED=§cPlease appoint another leader first!
|
||||
TEAM_LEAVE_LEFT=§7You left the team!
|
||||
|
||||
#Team Step Back
|
||||
TEAM_STEP_BACK=§7You have stepped back from your position as leader§8!
|
||||
|
||||
#Team Invite
|
||||
TEAM_INVITE_USAGE=§8/§7team invite §8[§eplayer§8]
|
||||
TEAM_INVITE_NO_PLAYER=§cThis player is unknown.
|
||||
TEAM_INVITE_IN_TEAM=§cThis player is already in a team.
|
||||
TEAM_INVITE_ALREADY_INVITED=§cAn invitation is already pending.
|
||||
TEAM_INVITE_INVITED=§7You have invited §e{0} §7in your team!
|
||||
TEAM_INVITE_INVITED_TARGET=§7You were invited into the team §{0}{1}§7!
|
||||
|
||||
#Team Remove
|
||||
TEAM_REMOVE_USAGE=§8/§7team remove §8[§eplayer§8]
|
||||
TEAM_REMOVE_NOT_PLAYER=§cThis player does not exist.
|
||||
TEAM_REMOVE_NOT_LEADER=§cA leader can not be kicked.
|
||||
TEAM_REMOVE_INVITE=§7The invitation was retracted.
|
||||
TEAM_REMOVE_NO_INVITE=§cNo pending invitation is due for this player.
|
||||
TEAM_REMOVE_NOT_IN_TEAM=§cThis player is not in your team.
|
||||
TEAM_REMOVE_REMOVED=§7You removed this player from the team.
|
||||
TEAM_REMOVE_REMOVED_TARGET=§cYou were removed from the team.
|
||||
|
||||
#Team Kuerzel
|
||||
TEAM_KUERZEL_USAGE=§8/§7team changekuerzel §8[§eshortcut§8]
|
||||
TEAM_KUERZEL_CHANGED=§7You changed your teams shortcut!
|
||||
TEAM_KUERZEL_LENGTH=§cA team shortcut has to consist of 2 to 4 characters.
|
||||
TEAM_KUERZEL_TAKEN=§cThere is already a team with that shortcut.
|
||||
|
||||
#Team Name
|
||||
TEAM_NAME_USAGE=§8/§7team changename §8[§eteam name§8]
|
||||
TEAM_NAME_CHANGED=§7You have renamed your team!
|
||||
TEAM_NAME_LENGTH=§cA team name has to consist of 4 to 15 characters.
|
||||
TEAM_NAME_TAKEN=§cThere is already a team with that name.
|
||||
|
||||
#Team Leader
|
||||
TEAM_LEADER_USAGE=§8/§7team promote §8[§emember§8]
|
||||
TEAM_LEADER_NOT_USER=§cUnknown player.
|
||||
TEAM_LEADER_NOT_MEMBER=§cThis player is not in your team.
|
||||
TEAM_LEADER_PROMOTED=§7You made §e{0} §7a leader!
|
||||
|
||||
#Team Info
|
||||
TEAM_INFO_USAGE=§8/§7team info §8[§eTeamname§8]
|
||||
TEAM_INFO_TEAM=§7Team §e{0} §8[§{1}{2}§8]
|
||||
TEAM_INFO_LEADER=§7Leader ({0})§8: {1}
|
||||
TEAM_INFO_MEMBER=§7Member ({0})§8: {1}
|
||||
TEAM_INFO_EVENTS=§7Events§8: §e{0}
|
||||
|
||||
#Team List
|
||||
TEAM_LIST_NOT_PAGE=§cNo page number entered
|
||||
TEAM_LIST_UNKNOWN_PAGE=§cInvalid page entered
|
||||
TEAM_LIST_HEADER=§7§lTeam list §7{0}§8/§7{1}
|
||||
TEAM_LIST_TEAM=§{0}{1} §e{2}
|
||||
TEAM_LIST_TEAM_HOVER=§7Team info
|
||||
TEAM_LIST_PAGE=Page »»
|
||||
TEAM_LIST_NEXT=§eNext page
|
||||
TEAM_LIST_PREV=§ePrevious page
|
||||
|
||||
#Team Event
|
||||
TEAM_EVENT_USAGE=§8/§7team event §8[§eEvent§8] - §7to take part
|
||||
TEAM_EVENT_HEADER=§7Your team takes part in the following events§8:
|
||||
TEAM_EVENT_EVENT=§7{0}§8: §e{1}
|
||||
TEAM_EVENT_NO_EVENT=§cThis event does not exist
|
||||
TEAM_EVENT_OVER=§cThe registration period for this event is already over
|
||||
TEAM_EVENT_LEFT=§7Your team no longer takes part in this event
|
||||
TEAM_EVENT_JOINED=§7Your team now takes part in the event §e{0}§7!
|
||||
TEAM_EVENT_HOW_TO_LEAVE=§7To cancel the participation repeat the command.
|
||||
|
||||
#Team Color
|
||||
TEAM_COLOR_TITLE=Choose color
|
||||
|
||||
#Team Server
|
||||
TEAM_SERVER_USAGE=§8/§7team server §8[§eIP/address§8] §8(§7port§8) §8- §7Sets the address of the team server.
|
||||
TEAM_SERVER_SET=§7You changed the team server address§8!
|
||||
TEAM_SERVER_PORT_INVALID=§cInvalid port number.
|
||||
TEAM_SERVER_ADDRESS_INVALID=§cInvalid address.
|
||||
TEAM_NO_ADDRESS=§cNo team server address set.
|
||||
TEAM_OFFLINE=§cTeam server may be offline.
|
||||
TEAM_TP_NO_TEAM=§cUnknown team.
|
||||
|
||||
#TpCommand
|
||||
TP_USAGE=§8/§7tp §8[§eplayer§8]
|
||||
TP_USAGE_EVENT=§8/§7tp §8[§ePlayer §7or §eteam§8]
|
||||
|
||||
#UnignoreCommand
|
||||
UNIGNORE_USAGE=§8/§7unignore §8[§eplayer§8]
|
||||
UNIGNORE_NOT_PLAYER=§cThis player does not exist!
|
||||
UNIGNORE_NOT_IGNORED=§cYou are not ignoring this player.
|
||||
UNIGNORE_UNIGNORED=§7You ignored §e{0}§8.
|
||||
|
||||
#WebregisterCommand
|
||||
WEB_USAGE=§8/§7webpassword §8[§epassword§8]
|
||||
WEB_UPDATED=§7Your password was updated.
|
||||
WEB_CREATED=§7Your webaccount was created.
|
||||
WEB_PASSWORD_LENGTH=§cYour password is shorter than 8 characters.
|
||||
|
||||
#ChatListener
|
||||
CHAT_LIXFEL_ACTION_BAR=§4§lTechnical problems?
|
||||
CHAT_LIXFEL_1=You called me!
|
||||
CHAT_LIXFEL_2=Unfortunately I am only human and do not hear everything.
|
||||
CHAT_LIXFEL_3=Therefore I ask you to deposit the problem or the error in the forum in the category §eReport error §7with a sufficient description
|
||||
CHAT_LIXFEL_4=Thank you.
|
||||
CHAT_LIXFEL_5=I wish you still a smooth gaming experience.
|
||||
CHAT_YOYONOW_1=You called me!
|
||||
CHAT_YOYONOW_2=I would like to recommend you the command "/bug <MESSAGE>"..
|
||||
CHAT_YOYONOW_3=Thank you.
|
||||
CHAT_YOYONOW_4=I wish you still a smooth gaming experience.
|
||||
CHAT_CHAOSCAOT_1=You called me!
|
||||
CHAT_CHAOSCAOT_2=If something is broken, just say it\'s a feature.
|
||||
CHAT_CHAOSCAOT_3=And if it is a feature, just then it can\'t be broken.
|
||||
CHAT_CHAOSCAOT_4=Broken is just a definition. So if you define it as a feature, it\'s not broken.
|
||||
CHAT_CHAOSCAOT_5=And if you define it as broken, then tell us using the command "/bug <MESSAGE>".
|
||||
CHAT_CHAOSCAOT_6=Thank you and goodbye.
|
||||
CHAT_RECEIVE=§cTo be able to send chat messages, you must also receive them!
|
||||
CHAT_NO_LINKS=§cYou may not send links.
|
||||
CHAT_BC_USAGE=§8/§7bc §8[§emessage§8]
|
||||
CHAT_NO_RECEIVER=§cNobody receives your message
|
||||
CHAT_EMPTY=§cDon\'t write meaningless empty messages.
|
||||
|
||||
CHAT_SERVERTEAM=§8STC §e{0}§8» §f{2}
|
||||
CHAT_GLOBAL={3}{4}{5}{6}{0}§8» {7}{2}
|
||||
CHAT_DISCORD_GLOBAL=§8Dc {5}{6}{0}§8» {7}{2}
|
||||
CHAT_TEAM=§8TC §e{0}§8» §f{2}
|
||||
CHAT_MSG=§e{0}§8»§e{1} §7{2}
|
||||
|
||||
#CheckListner
|
||||
CHECK_UNCHECKED=§7You still have §e{0} §7unchecked schematic§8(§7s§8)!
|
||||
CHECK_CHECKING=§cYou are checking a Schematic!
|
||||
|
||||
#ConnectionListener
|
||||
JOIN_ARENA=§7Click §ehere§7 to join §e{0}
|
||||
JOIN_ARENA_HOVER=§eJoin Arena
|
||||
JOIN_FIRST=§7Please greet §e{0}§7 on the server§8!
|
||||
|
||||
#EventModeListener
|
||||
EVENTMODE_KICK=§cYou are not an event participant.
|
||||
|
||||
#PollSystem
|
||||
POLL_HEADER=§e§lPoll
|
||||
POLL_HEADER2=§7Click the answer you like!
|
||||
POLL_QUESTION=§e{0}
|
||||
POLL_ANSWER=§7{0}
|
||||
POLL_ANSWER_HOVER=§eChoose {0}
|
||||
|
||||
#TablistManager
|
||||
TABLIST_PHASE_WEBSITE=§8Website: https://§eSteam§8War.de
|
||||
TABLIST_PHASE_DISCORD=§8Discord: https://§eSteam§8War.de/discord
|
||||
TABLIST_FOOTER=§e{0} {1}§8ms §ePlayers§8: §7{2}
|
||||
TABLIST_BAU=§7§lBuild
|
||||
LIST_COMMAND=§e{0}§8: §7{1}
|
||||
|
||||
#EventStarter
|
||||
EVENT_FIGHT_BROADCAST=§eClick here §7for the fight §{0}{1} §8vs §{2}{3}
|
||||
EVENT_FIGHT_BROADCAST_HOVER=§eJoin Event
|
||||
|
||||
#SubserverSystem
|
||||
SERVER_IGNORED=§cThis player has blocked you!
|
||||
SERVER_ADD_MEMBER=§e{0} §7wants to join your Build server.
|
||||
SERVER_ADD_MESSAGE=§7Click §ehere §7if you want to allow this.
|
||||
SERVER_ADD_MESSAGE_HOVER=§8/§7build addmember §e{0}
|
||||
SERVER_WORLD_ERROR=§cCreating the world failed.
|
||||
|
||||
|
||||
#WhoisCommand
|
||||
WHOIS_USAGE=§c/whois [player/ID] [-a/-m]
|
||||
WHOIS_USERNAME=§7Username§8: §e{0}
|
||||
WHOIS_PREFIX=§7Chat-Prefix§8: {0}
|
||||
WHOIS_UUID=§7UUID§8: §e{0}
|
||||
WHOIS_UUID_HOVER=§eCopy UUID
|
||||
WHOIS_ID=§7ID§8: §e{0}
|
||||
WHOIS_PERMS=§7Perms§8: §7{0}
|
||||
WHOIS_DISCORD_ID=§7Discord-ID§8: §e{0}
|
||||
WHOIS_JOINED_FIRST=§7Joined on§8: §e{0}
|
||||
WHOIS_HOURS_PLAYED=§7Online Time§8: §e{0}h
|
||||
WHOIS_CURRENT_PLAYED=§7Current Online Time§8: §e{0}m
|
||||
WHOIS_CURRENT_SERVER=§7Current Server§8: §e{0}
|
||||
WHOIS_CURRENT_PROTOCOL=§7Current Protocol§8: §e{0}
|
||||
WHOIS_TEAM=§7Team§8: §e[§{0}{1}§e] {2}
|
||||
WHOIS_TEAM_HOVER=§eShow {0}
|
||||
WHOIS_PUNISHMENTS=§7Punishments:
|
||||
WHOIS_PUNISHMENT=§7{0}§8» §f§l{1}: §e{2} - {3} §f{4}
|
||||
WHOIS_NO_PUNISHMENT=§a✓ §7This player has no active punishment.
|
||||
WHOIS_NO_ALL_PUNISHMENT=§a✓ §7The player has not done anything yet.
|
||||
WHOIS_ACTIVE_MODS=§7Active Mods ({0}): {1}
|
||||
WHOIS_NO_ACTIVE_MODS=§7This player has no active mods.
|
||||
WHOIS_PLATFORM=§7Modloader: §e{0}
|
||||
|
||||
#VerifyCommand
|
||||
VERIFY_USAGE=§c/verify [Code]
|
||||
VERIFY_INVALID=§cInvalid Code
|
||||
VERIFY_SUCCESS=§7Successfully linked to the Discord account §e{0}
|
||||
|
||||
#Discord
|
||||
DISCORD_TICKET_HOVER=§eTo the message
|
||||
DISCORD_TICKET_MESSAGE=§7Ticket §e{0}§7» §f§l{1}: §7{2}
|
||||
DISCORD_TICKET_NEW=§7Ticket §e{0}§7» §aTicket was created!
|
||||
DISCORD_TICKET_CLOSED=§7Ticket §e{0}§7» §cTicket was closed!
|
||||
|
||||
#GDPR Query
|
||||
GDPR_STATUS_WEBSITE=§7Website cannot be packed automatically and therefore must be added manually.
|
||||
GDPR_STATUS_WORLD=§7Packing Build worlds...
|
||||
GDPR_STATUS_INVENTORIES=§7Searching and packing inventories...
|
||||
GDPR_STATUS_DATABASE=§7Packing database contents...
|
||||
GDPR_STATUS_LOGS=§7Searching and packing logs...
|
||||
GDPR_STATUS_FINISHED=§7Packing complete
|
||||
|
||||
#Playtime Command
|
||||
HOURS_PLAYED=§7Your playtime is§8: §e{0}h
|
||||
|
||||
#Arena command
|
||||
ARENA_NOT_FOUND=§cThe specified arena could not be found
|
||||
|
||||
#Rank
|
||||
RANK_PLAYER_NOT_FOUND=§cPlayer not found
|
||||
RANK_PLAYER_FOUND=§eRank §7of §e{0}
|
||||
RANK_HEADER=§e{0} {1}
|
||||
RANK_UNPLACED=§7unranked
|
||||
RANK_PLACED=§e{0}§8. §7with §e{1} §7Elo§8.
|
||||
RANK_EMBLEM=§7Emblem§8: {0}
|
||||
|
||||
#Fabric Mod Sender
|
||||
MODIFICATION_BAN_MESSAGE=You tried to bypass / modify the FabricModSender!
|
||||
MODIFICATION_BAN_LOG={0} has tried to edit / bypass the FabricModSender! Reason: {1}
|
||||
|
||||
#Arena Merging
|
||||
FIGHT_MERGE_TITLE=Equal fight found!
|
||||
FIGHT_MERGE_DECLINE=§cLaunch new arena
|
||||
FIGHT_MERGE_ACCEPT=§aJoin fight
|
||||
FIGHT_MERGE_INFO_LORE_1=§8By: §e{0}
|
||||
FIGHT_MERGE_OFFLINE=§7The proposed arena has been terminated in the meantime, a new arena will be started.
|
||||
FIGHT_MERGE_INFO=§e{0}§8: §e{1}
|
||||
|
||||
#Locale Locking
|
||||
LOCK_LOCALE_CHANGED=§aLanguage saved
|
||||
|
||||
#Builder Cloud
|
||||
BUILDERCLOUD_USAGE=§8/§7buildercloud §8[§eversion§8] §8[§emap§8]
|
||||
BUILDERCLOUD_CREATE_USAGE=§8/§7buildercloud create §8[§eversion§8] §8[§emap§8] §8<§7generator§8>
|
||||
BUILDERCLOUD_RENAME_USAGE=§8/§7buildercloud rename §8[§eversion§8] §8[§emap§8] §8[§enew name§8]
|
||||
BUILDERCLOUD_DEPLOY_USAGE=§8/§7deployarena §8[§egamemode§8] §8[§eversion§8] §8[§emap§8]
|
||||
BUILDERCLOUD_DEPLOY_FINISHED=§7Map deployment finished.
|
||||
BUILDERCLOUD_VERSION=§cUnknown version.
|
||||
BUILDERCLOUD_EXISTING_MAP=§cMap already exists.
|
||||
BUILDERCLOUD_UNKNOWN_MAP=§cUnknown map.
|
||||
BUILDERCLOUD_RENAMED=§7Map rename successful.
|
||||
|
||||
# Advent Calendar
|
||||
ADVENT_CALENDAR_TITLE=§eAdvent Calendar
|
||||
ADVENT_CALENDAR_DAY=§7Day§8: §e{0}
|
||||
ADVENT_CALENDAR_MESSAGE=§eDid you already open your advent calendar?
|
||||
ADVENT_CALENDAR_MESSAGE_HOVER=§eClick to open!
|
||||
ADVENT_CALENDAR_OPEN=§7You got §e{0} §7from the advent calendar!
|
||||
|
||||
#Mod Command
|
||||
MOD_COMMAND_SET_USAGE=§7/mod set [mod name] [platform] [ModType 1-4]
|
||||
MOD_COMMAND_GET_USAGE=§7/mod get [mod name] [platform]
|
||||
MOD_CHANGED_TYPE=§7Successfully reclassified mod {0} on platform {1} to type {2}!
|
||||
MOD_NO_MORE_UNCLASSIFIED_MODS=§7No more unclassified mods found in databank!
|
||||
MOD_FOUND_NEXT_MOD=§7Next unclassified mod is {0} on platform {1}!
|
||||
MOD_COMMAND_NOT_FOUND_IN_DATABASE=§7The Mod {0} on platform {1} was§c not §7found in the database!
|
||||
MOD_COMMAND_INFO=§7The mod {0} on platform {1} is of the type {2}.
|
||||
MOD_COMMAND_GUI_TITLE=Unclassified Mods
|
||||
MOD_COMMAND_CLASSICIATION_GUI=Mod Type Changer
|
||||
MOD_OPEN_GUI=§7Open Gui
|
||||
MOD_TITLE_FILTER=Filter
|
||||
MOD_UNCLASSIFIED=§7Unclassified
|
||||
MOD_ALLOWED=§aAllowed
|
||||
MOD_FORBIDDEN=§eForbidden
|
||||
MOD_AUTOBAN=§cAutoban
|
||||
MOD_YT=§5YT Only
|
||||
MOD_ITEM_BACK=§7Back
|
||||
|
||||
#StreamInv
|
||||
INV_PAGE_BACK=§{0}Seite zurück
|
||||
INV_PAGE_NEXT=§{0}Seite vor
|
||||
|
||||
#Discord
|
||||
DC_UNLINKED=For this action your Discord account has to be linked to your Minecraft account. To link your accounts go onto the SteamWar Discord to the `regeln-infos` Channel and click on `Minecraft Verknüpfen`.
|
||||
DC_TITLE_SCHEMINFO=Schematic Info
|
||||
DC_SCHEM_ACCEPT=Your schematic **{0}** has been accepted.
|
||||
DC_SCHEM_DECLINE=Your schematic **{0}** has been declined.\n**Reason:**{1}
|
||||
DC_AUTH_SUCCESS=:white_check_mark: You\'re Discord account has been linked with **{0}**.
|
||||
DC_ROLE_ADDED=:tada: Your getting {0} now.
|
||||
DC_ROLE_REMOVED=Your not getting {0} anymore.
|
||||
DC_TICKET_CREATED=Your Ticket {0} has been created.
|
||||
DC_TICKET_TITLE=SteamWar Ticket
|
||||
DC_TICKETINTRO_REPORT=Please answer for the punishment of the misconduct the following questions as accurately as possible and attach evidence whenever possible:\n - Which player(s)?\n - On which Server?\n - At what time?\n - Type and nature of the misconduct?
|
||||
DC_TICKETINTRO_IDEA=Describe your idea as detailed as possible. Hereto belongs: What, Why, How, Where?
|
||||
DC_TICKETINTRO_BUG=Please describe the observed unexpected or incorrect behaviour of our software. If necessary describe steps to reproduce the error.
|
||||
DC_TICKETINTRO_QUESTION=Please ask your question. A staff member will address the question soon.
|
||||
DC_TICKETINTRO_APPEAL=Asking creates wonders.
|
||||
DC_TICKET_CLOSE=Close
|
||||
|
||||
DC_SCHEMUPLOAD_NOPERM=You\'re not allowed to upload schematics.
|
||||
DC_SCHEMUPLOAD_IGNORED=Skipping `{0}`, not a schematic file.
|
||||
DC_SCHEMUPLOAD_INVCHAR=`{0}` has invalid characters in its name.
|
||||
DC_SCHEMUPLOAD_SUCCESS=`{0}` was uploaded successfully.
|
||||
DC_SCHEMUPLOAD_ERROR=An error has occured during the upload of `{0}`. For more information ask a Developer.
|
||||
683
VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties
Normal file
683
VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties
Normal file
@@ -0,0 +1,683 @@
|
||||
COMMAND_SYSTEM_ERROR = §cFehler beim Ausführen des Befehls!
|
||||
|
||||
PREFIX=§eSteam§8War»
|
||||
SPACER=
|
||||
TIMEFORMAT=dd.MM.yyyy HH:mm
|
||||
|
||||
UNKNOWN_COMMAND=§cUnbekannter Befehl.
|
||||
UNKNOWN_PLAYER=§cDiesen Spieler gibt es nicht.
|
||||
UNKNOWN_TEAM=§cDieses Team gibt es nicht.
|
||||
UNKNOWN_EVENT=$cDieses Event gibt es nicht.
|
||||
INVALID_TIME=§cUngültige Zeitangabe.
|
||||
|
||||
DEV_NO_SERVER=§cDer Server ist derzeit nicht erreichbar.
|
||||
DEV_UNKNOWN_SERVER=§cBitte gib einen DevServer an.
|
||||
|
||||
DISABLED=§cDerzeit deaktiviert.
|
||||
|
||||
SERVER_START_OVERLOAD=§cDer Serverstart wurde aufgrund von Überlastung abgebrochen. Versuche es später erneut.
|
||||
UPDATE_INTERRUPTION=§cBitte erneut versuchen. Ein Softwareupdate hat die Aktion unterbrochen.
|
||||
|
||||
#Help command
|
||||
HELP_LOBBY=§7Kehre von überall mit §8/§el §7zur Lobby zurück!
|
||||
HELP_LOBBY_HOVER=§eZurück zur Lobby
|
||||
HELP_BAU=§7Komme mit §8/§ebau §7auf den Bauserver!
|
||||
HELP_BAU_HOVER=§eZum Bauserver
|
||||
HELP_BAUSERVER=§7Erhalte mit §8/§ehelp bau §7Hilfe zum Bauserver!
|
||||
HELP_BAUSERVER_HOVER=§eHilfe zum Bauserver
|
||||
HELP_FIGHT=§7Starte mit §8/§efight §7einen neuen Kampf!
|
||||
HELP_FIGHT_HOVER=§eZum Kampfsystem
|
||||
HELP_CHALLENGE=§7Tippe §8/§echallenge§7, um jemanden herauszufordern!
|
||||
HELP_CHALLENGE_HOVER=§eHerausfordern
|
||||
HELP_HISTORIC=§7Starte mit §8/§ehistoric §7einen historischen Kampf!
|
||||
HELP_HISTORIC_HOVER=§eHistorische Kämpfe
|
||||
HELP_TEAM=§8/§eteam§7 für das Teamsystem!
|
||||
HELP_TEAM_HOVER=§eTeamverwaltung
|
||||
HELP_JOIN=§7Trete mit §8/§ejoin §8[§eSpieler§8] §7einem Kampf bei!
|
||||
HELP_JOIN_HOVER=§eSpieler beitreten
|
||||
HELP_LOCAL=§7Schreibe mit §8/§elocal §7nur auf dem lokalen Server!
|
||||
HELP_LOCAL_HOVER=§eLokaler Chat
|
||||
|
||||
HELP_TNT=§8/§7tnt §8- §7(de)aktiviert Explosionsschaden
|
||||
HELP_FIRE=§8/§7fire §8- §7(de)aktiviert Feuerschaden
|
||||
HELP_TESTBLOCK=§8/§7testblock §8- §7Erneuert den nächsten Testblock
|
||||
HELP_RESET=§8/§7reset §8- §7Setzt die derzeitige Region zurück
|
||||
HELP_SPEED=§8/§7speed §8- §7Ändert deine Fluggeschwindigkeit
|
||||
HELP_NV=§8/§7nv §8- §7(de)aktiviert Nachtsicht
|
||||
HELP_TRACE=§8/§7trace §8- §7Gibt einen Überblick über den TNT-Tracer
|
||||
HELP_TPSLIMIT=§8/§7tpslimit §8- §7Gibt einen Überblick über den TPS-Limiter
|
||||
HELP_LOADER=§8/§7loader §8- §7Nutze den automatischen Kanonenlader
|
||||
HELP_PROTECT=§8/§7protect §8- §7Schützt den Boden der (M)WG-Region
|
||||
HELP_FREEZE=§8/§7freeze §8- §7Unterbindet Blockupdates
|
||||
HELP_SKULL=§8/§7skull §8- §7Gibt dir den Kopf eines Spielers
|
||||
HELP_DEBUGSTICK=§8/§7debugstick §8- §7Gibt dir einen Debugstick (1.15+)
|
||||
HELP_BAUINFO=§8/§7bauinfo §8- §7Gibt dir Informationen über den Bauserver
|
||||
HELP_SCHEMSUBMIT=§7Für ein Tutorial über das Freischalten deines AirShips§8/§7MiniWarGear§8/§7WarGear§8/§7WarShips klicke §ehier§8!
|
||||
|
||||
HELP_BAU_GROUP_ADMIN=§7Bauserver-Verwaltungsbefehle
|
||||
HELP_BAU_GROUP_ADMIN_HOVER=§eAlle Verwaltungsbefehle
|
||||
HELP_BAU_GROUP_ADMIN_TITLE=§7Alle Verwaltungsbefehle§8:
|
||||
HELP_BAU_GROUP_OTHER=§7Weitere Bauserverbefehle
|
||||
HELP_BAU_GROUP_OTHER_HOVER=§eWeitere Bauserverbefehle
|
||||
HELP_BAU_GROUP_OTHER_TITLE=§7Weitere Bauserverbefehle§8:
|
||||
HELP_BAU_GROUP_WE=§7WorldEdit-Abkürzungen
|
||||
HELP_BAU_GROUP_WE_HOVER=§eWorldEdit-Abkürzungen
|
||||
HELP_BAU_GROUP_WE_TITLE=§7WorldEdit-Abkürzungen§8:
|
||||
HELP_BAU_GROUP_PLAYER=§7Spielerbefehle
|
||||
HELP_BAU_GROUP_PLAYER_HOVER=§eSpielerbefehle
|
||||
HELP_BAU_GROUP_PLAYER_TITLE=§7Spielerbefehle§8:
|
||||
HELP_BAU_GROUP_WORLD=§7Weltverändernde Bauserverbefehle
|
||||
HELP_BAU_GROUP_WORLD_HOVER=§eWeltverändernde Bauserverbefehle
|
||||
HELP_BAU_GROUP_WORLD_TITLE=§7Weltverändernde Bauserverbefehle§8:
|
||||
|
||||
HELP_BAU_TP=§8/§ebau tp §8- §7Gehe auf Bauserver von Freunden!
|
||||
HELP_BAU_TP_HOVER=§eZu einem anderen Bauserver
|
||||
HELP_BAU_ADDMEMBER=§8/§ebau addmember §8- §7Fügt einen Freund hinzu
|
||||
HELP_BAU_ADDMEMBER_HOVER=§eFüge einen Freund hinzu
|
||||
HELP_BAU_DELMEMBER=§8/§ebau delmember §8- §7Entfernt einen Spieler
|
||||
HELP_BAU_DELMEMBER_HOVER=§eEntfernt einen Spieler
|
||||
HELP_BAU_SET_SPECTATOR=§8/§ebau setspectator §8- §7Zuschauen auf dem Bauserver
|
||||
HELP_BAU_SET_SPECTATOR_HOVER=§eSetzt die Rolle Spectator
|
||||
HELP_BAU_SET_BUILDER=§8/§ebau setbuilder §8- §7Bauen, WorldEdit, BauSystem Features
|
||||
HELP_BAU_SET_BUILDER_HOVER=§eSetzt die Rolle Builder
|
||||
HELP_BAU_SET_SUPERVISOR=§8/§ebuild setsupervisor §8- §7Starten des Baus. Schematics erstellen
|
||||
HELP_BAU_SET_SUPERVISOR_HOVER=§eSetzt die Rolle Supervisor
|
||||
HELP_BAU_DELETE=§8/§ebau delete §8- §7Setzt deine Bauwelt zurück
|
||||
HELP_BAU_DELETE_HOVER=§eBauwelt zurücksetzen
|
||||
HELP_BAU_TESTARENA=§8/§ebau testarena §8- §7Starte eine Testarena
|
||||
HELP_BAU_TESTARENA_HOVER=§eTestarena starten
|
||||
HELP_BAU_LOCK=§8/§ebau lock §8- §7Sperre deinen Bauserver für bestimmte Spielergruppen
|
||||
HELP_BAU_LOCK_HOVER=§eSperre deinen Bau
|
||||
HELP_BAU_UNLOCK=§8/§ebau unlock §8- §7Öffne deinen Bauserver für alle hinzugefügten Spieler
|
||||
HELP_BAU_UNLOCK_HOVER=§eÖffne deinen Bau
|
||||
|
||||
#Usage description of various commands
|
||||
USAGE_ALERT=§8/§7alert §8[§eNachricht§8]
|
||||
USAGE_IGNORE=§8/§7ignore §8[§eSpieler§8]
|
||||
|
||||
#ModListener
|
||||
MOD_RED_SING=Versuchte Benutzung des Mods {0}
|
||||
MOD_RED_PLUR=Versuchte Benutzung der Mods:\n{0}
|
||||
MOD_YELLOW_SING=§7Deaktiviere den Mod §e{0}§7, um weiter auf §eSteam§8War §7spielen zu können.
|
||||
MOD_YELLOW_PLUR=§7Deaktiviere die Mods\n§e{0}\n§7um weiter auf §eSteam§8War §7spielen zu können.
|
||||
MODS_CHECKED=§7Deine installierten Mods wurden überprüft.\n§aDu kannst nun §eSteam§8War §abetreten§8.
|
||||
|
||||
#Various commands
|
||||
STAT_SERVER=§7Server §e{0}§8: §7Startfähig §e{1} §7Serveranzahl §e{2}
|
||||
|
||||
#Ban&Mute-Command
|
||||
PUNISHMENT_USAGE=§8/§7{0} §8[§eSpieler§8] [§edd§8.§emm§8.§eyyyy §7oder §edd§8.§emm§8.§eyyyy§8_§ehh§8:§emm §7oder §ezahl§8[§eh§7our|§ed§7ay|§ew§7eek|§em§7onth|§ey§7ear§8] §7oder §eperma§8] [§eGrund§8]
|
||||
PUNISHMENT_USAGE_REASON=§cBitte gib einen Grund an.
|
||||
UNPUNISHMENT_USAGE=§8/§7{0} §8[§eSpieler§8]
|
||||
|
||||
PUNISHMENT_UNTIL=bis zum {0}
|
||||
PUNISHMENT_PERMA=permanent
|
||||
|
||||
BAN_TEAM={0} §e{1} §7wurde von §e{2} {3} §e§lgebannt§8. §7Grund§8: §f{4}
|
||||
BAN_PERMA=§7Du bist §epermanent §e§lgebannt§8. §7Grund§8: §e{0}
|
||||
BAN_UNTIL=§7Du bist §ebis zum {0} §e§lgebannt§8. §7Grund§8: §e{1}
|
||||
UNBAN_ERROR=§cDer Spieler ist nicht gebannt.
|
||||
UNBAN=§7Du hast §e{0} §e§lentbannt.
|
||||
|
||||
BAN_AVOIDING_ALERT=§cMögliche Bannumgehung durch §r{0}§c: {1}
|
||||
BAN_AVOIDING_LIST=§c{0} §e{1}
|
||||
BAN_AVOIDING_BAN_HOVER=§cBanne Spieler wegen Bannumgehung
|
||||
|
||||
MUTE_TEAM={0} §e{1} §7wurde von §e{2} {3} §e§lgemuted§8. §7Grund§8: §f{4}
|
||||
MUTE_PERMA=§7Du bist §epermanent §e§lgemuted§8. §7Grund§8: §e{0}
|
||||
MUTE_UNTIL=§7Du bist §ebis zum {0} §e§lgemuted§8. §7Grund§8: §e{1}
|
||||
UNMUTE_ERROR=§cDer Spieler ist nicht gemuted.
|
||||
UNMUTE=§7Du hast §e{0} §e§lentmuted.
|
||||
|
||||
NOSCHEMRECEIVING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematicerhalten§7 ausgeschlossen§8: §f{4}
|
||||
NOSCHEMRECEIVING_PERMA=§7Du bist §epermanent §7vom Erhalten von §e§lSchematics§7 ausgeschlossen§8: §e{0}
|
||||
NOSCHEMRECEIVING_UNTIL=§7Du bist §ebis zum {0} §7vom Erhalten von §e§lSchematics§7 ausgeschlossen§8: §e{1}
|
||||
UNNOSCHEMRECEIVING_ERROR=§cDer Spieler ist nicht vom Erhalten von Schematics ausgeschlossen.
|
||||
UNNOSCHEMRECEIVING=§e{0} §7darf nun wieder §e§lSchematics§7 erhalten§8.
|
||||
|
||||
NOSCHEMSHARING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematicverteilen§7 ausgeschlossen§8: §f{4}
|
||||
NOSCHEMSHARING_PERMA=§7Du bist §epermanent §7vom §e§lVerteilen von Schematics§7 ausgeschlossen§8: §e{0}
|
||||
NOSCHEMSHARING_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lVerteilen von Schematics§7 ausgeschlossen§8: §e{1}
|
||||
UNNOSCHEMSHARING_ERROR=§cDer Spieler ist nicht vom Verteilen von Schematics ausgeschlossen.
|
||||
UNNOSCHEMSHARING=§e{0} §7darf nun wieder §e§lSchematics§7 verteilen§8.
|
||||
|
||||
NOSCHEMSUBMITTING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematiceinsenden§7 ausgeschlossen§8: §f{4}
|
||||
NOSCHEMSUBMITTING_PERMA=§7Du bist §epermanent §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{0}
|
||||
NOSCHEMSUBMITTING_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{1}
|
||||
UNNOSCHEMSUBMITTING_ERROR=§cDer Spieler ist nicht vom Einsenden von Schematics ausgeschlossen.
|
||||
UNNOSCHEMSUBMITTING=§e{0} §7darf nun wieder §e§lSchematis§7 einsenden§8.
|
||||
|
||||
NODEVSERVER_TEAM={0} §e{1} §7hat §e{2} §7mit Grund §f{4}§7 zu genervt und hat daher §e§lDevserververbot§7 erhalten§8, §f{3}
|
||||
NODEVSERVER_PERMA=§7Du bist §epermanent §7vom §e§lDevserver§7 ausgeschlossen§8: §e{0}
|
||||
NODEVSERVER_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lDevserver§7 ausgeschlossen§8: §e{1}
|
||||
UNNODEVSERVER_ERROR=§cDer Spieler ist nicht vom Devserver ausgeschlossen.
|
||||
UNNODEVSERVER=§e{0} §7darf nun wieder dem §e§lDevserver§7 beitreten§8.
|
||||
|
||||
NOFIGHTSERVER_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lKämpfen§7 ausgeschlossen§8: §f{4}
|
||||
NOFIGHTSERVER_PERMA=§7Du bist §epermanent §7vom §e§lKämpfen§7 ausgeschlossen§8: §e{0}
|
||||
NOFIGHTSERVER_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lKämpfen§7 ausgeschlossen§8: §e{1}
|
||||
UNNOFIGHTSERVER_ERROR=§cDer Spieler ist nicht vom Kämpfen ausgeschlossen.
|
||||
UNNOFIGHTSERVER=§e{0} §7darf nun wieder §e§lKämpfen§7 beitreten§8.
|
||||
|
||||
NOTEAMSERVER_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §f{4}
|
||||
NOTEAMSERVER_PERMA=§7Du bist §epermanent §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §e{0}
|
||||
NOTEAMSERVER_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lTeamserver§7 setzen ausgeschlossen§8: §e{1}
|
||||
UNNOTEAMSERVER_ERROR=§cDer Spieler ist nicht vom Teamserver setzten ausgeschlossen.
|
||||
UNNOTEAMSERVER=§e{0} §7darf nun wieder §e§lTeamserver§7 setzen§8.
|
||||
|
||||
NOTE_TEAM={0} §e{1} §7erhielt von §e{2} {3} §7die §e§lNotiz§7§8: §f{4}
|
||||
|
||||
#BugCommand
|
||||
BUG_MESSAGE=§7Bitte beschreibe das Problem in einem Discordticket genauer und gebe dabei die Bug-ID §e{0} §7an§8.
|
||||
|
||||
#IgnoreCommand
|
||||
IGNORE_YOURSELF=§cWie willst du dich selber ignorieren?
|
||||
IGNORE_ALREADY=§cDu ignorierst diesen Spieler bereits.
|
||||
IGNORE_MESSAGE=§7Du ignorierst nun §e{0}§8.
|
||||
|
||||
#PollresultCommand
|
||||
POLLRESULT_NOPOLL=§cDerzeit läuft keine Umfrage.
|
||||
POLLRESULT_HEADER=§eEs haben {0} abgestimmt auf die Frage: §7{1}
|
||||
|
||||
#BauCommand
|
||||
BAU_ADDMEMBER_USAGE=§8/§7bau addmember §8[§eSpieler§8]
|
||||
BAU_ADDMEMBER_SELFADD=§cDu brauchst dich nicht selbst hinzufügen!
|
||||
BAU_ADDMEMBER_ISADDED=§cDieser Spieler ist bereits Mitglied auf deiner Welt.
|
||||
BAU_ADDMEMBER_ADDED=§aDer Spieler wurde zu deiner Welt hinzugefügt.
|
||||
BAU_ADDMEMBER_ADDED_TARGET=§aDu wurdest zu der Welt von §e{0} §ahinzugefügt.
|
||||
BAU_TP_USAGE=§8/§7bau tp §8[§eSpieler§8]
|
||||
BAU_TP_NOALLOWED=§cDu darfst dich nicht auf diese Welt teleportieren.
|
||||
BAU_LOCKED_NOALLOWED=§cDer Bauserver ist momentan gesperrt.
|
||||
BAU_LOCK_BLOCKED=§cDeine Bausperre hat den Beitritt von §e{0} §cverhindert.
|
||||
BAU_LOCKED_OPTIONS=§7Bauserver-Sperroptionen§8: §cnobody§8, §eserverteam§8, §eteam_and_serverteam§8, §eteam§8, §aopen
|
||||
BAU_LOCKED_NOBODY=§7Du hast deinen Bau für alle Spieler geschlossen.
|
||||
BAU_LOCKED_SERVERTEAM=§7Du hast deinen Bau für alle außer hinzugefügte Serverteammitglieder gesperrt.
|
||||
BAU_LOCKED_TEAM_AND_SERVERTEAM=§7Du hast deinen Bau für alle außer hinzugefügte Teammitglieder und Serverteammitglieder gesperrt.
|
||||
BAU_LOCKED_TEAM=§7Du hast deinen Bau für alle außer hinzugefügte Teammitglieder gesperrt.
|
||||
BAU_LOCKED_OPEN=§7Du hast deinen Bau für alle hinzugefügten Spieler geöffnet.
|
||||
BAU_DELMEMBER_USAGE=§8/§7bau delmember §8[§eSpieler§8]
|
||||
BAU_DELMEMBER_SELFDEL=§cDu kannst dich nicht selbst entfernen!
|
||||
BAU_DELMEMBER_DELETED=§cDer Spieler wurde entfernt.
|
||||
BAU_DELMEMBER_DELETED_TARGET=§cDu wurdest von der Welt von §e{0} §centfernt.
|
||||
BAU_DELETE_DELETED=§aDeine Welt wird zurückgesetzt.
|
||||
BAU_DELETE_GUI_NAME=§eWirklich Welt löschen?
|
||||
BAU_DELETE_GUI_CANCEL=§cAbbrechen
|
||||
BAU_DELETE_GUI_DELETE=§aLöschen
|
||||
BAU_START_ALREADY=§cDer Server startet bereits.
|
||||
BAU_MEMBER_NOMEMBER=§cDer Spieler ist kein Mitglied deiner Welt!
|
||||
BAU_MEMBER_SET_USAGE=§8/§7bau {0} §8[§eSpieler§8]
|
||||
BAU_MEMBER_SET_TARGET=§7Du bist nun ein §e{1}§7 auf der Welt von §e{0}§7.
|
||||
BAU_MEMBER_SET=§7Der Spieler ist nun §e{0}§7.
|
||||
BAU_MEMBER_SET_SPECTATOR = Zuschauer
|
||||
BAU_MEMBER_SET_BUILDER = Builder
|
||||
BAU_MEMBER_SET_SUPERVISOR = Supervisor
|
||||
BAU_START_NOT_ALLOWED = §cDu darfst diesen Bauserver nicht starten.
|
||||
|
||||
#ChallengeCommand
|
||||
CHALLENGE_USAGE=§8/§7challenge §8[§eSpieler§8]
|
||||
CHALLENGE_OFFLINE=§cDer Herausgeforderte ist nicht online.
|
||||
CHALLENGE_SELF=§cSchizophren?
|
||||
CHALLENGE_IGNORED=§cDer Herausgeforderte hat dich geblockt.
|
||||
CHALLENGE_INARENA=§cDer Herausgeforderte ist bereits in einer Arena.
|
||||
CHALLENGE_BROADCAST=§e{0}§7-§eDuell§7: §e{1} §7vs §e{2}
|
||||
CHALLENGE_BROADCAST_HOVER=§aZuschauen
|
||||
CHALLENGE_CHALLENGED=§7Du hast §e{0} §7zu einem §e{1}-Kampf §7herausgefordert!
|
||||
CHALLENGE_CHALLENGED_TARGET=§e{0} §7 hat dich zu einem §e{1}-Kampf §7{2}herausgefordert!
|
||||
CHALLENGE_CHALLENGED_MAP=auf §e{0} §7
|
||||
CHALLENGE_ACCEPT=§7Klicke §ehier§7, um die Herausforderung anzunehmen
|
||||
CHALLENGE_ACCEPT_HOVER=§aHerausforderung annehmen
|
||||
|
||||
#EventCommand
|
||||
EVENT_TIME_FORMAT=HH:mm
|
||||
EVENT_DATE_FORMAT=dd.MM.
|
||||
EVENT_USAGE=§8/§7event §8[§eTeam§8] - §7Um dich zum Kampf zu teleportieren
|
||||
EVENT_NO_TEAM=§cDieses Team gibt es nicht
|
||||
EVENT_NO_FIGHT_TEAM=§cDas Team kämpft derzeit nicht
|
||||
EVENT_NO_CURRENT=§cDerzeit findet kein Event statt
|
||||
EVENT_COMING=§eKommende Events§8:
|
||||
EVENT_COMING_EVENT=§7{0}§8-§7{1}§8: §e{2}
|
||||
EVENT_COMING_DEADLINE=§7 Anmeldeschluss§8: §7{0}
|
||||
EVENT_COMING_SCHEM_DEADLINE=§7 Einsendeschluss§8: §7{0}
|
||||
EVENT_COMING_TEAMS=§7 Mit§8: {0}
|
||||
EVENT_COMING_TEAM= §{0}{1}
|
||||
EVENT_CURRENT_EVENT=§e§l{0}
|
||||
EVENT_CURRENT_FIGHT=§7{0} §{1}{2}§8 vs §{3}{4}
|
||||
EVENT_CURRENT_FIGHT_WIN=§8: §7Sieg §{0}{1}
|
||||
EVENT_CURRENT_FIGHT_DRAW=§8: §7Unentschieden
|
||||
|
||||
#EventRescheduleCommand
|
||||
EVENTRESCHEDULE_USAGE=§8/§7eventreschedule §8[§eTeam1§8] [§eTeam2§8]
|
||||
EVENTRESCHEDULE_UNKNOWN_TEAM=§cEin Team ist unbekannt / Derzeit kein Event
|
||||
EVENTRESCHEDULE_NO_FIGHT="§cKein Kampf zwischen den Teams gefunden"
|
||||
EVENTRESCHEDULE_STARTING=§aKampf startet in 30s
|
||||
|
||||
#FightCommand
|
||||
FIGHT_UNKNOWN_GAMEMODE=§cUnbekannter Spielmodus: {0}
|
||||
FIGHT_UNKNOWN_ARENA=§cDie gewünschte Arena gibt es nicht.
|
||||
FIGHT_IN_ARENA=§cDu befindest dich bereits in einer Arena.
|
||||
FIGHT_BROADCAST=§7Klicke §ehier§7, um §e{0} §7gegen §e{1} §7zu §7kämpfen!
|
||||
FIGHT_BROADCAST_HOVER=§aGegen §7{1} §ekämpfen
|
||||
|
||||
#CheckCommand
|
||||
CHECK_REMINDER=§7Es sind §e{0} §7Schematics zu prüfen§8!
|
||||
CHECK_REMINDER_HOVER=§eZu prüfende Schematics
|
||||
CHECK_NOT_CHECKING=§cDu prüfst derzeit nicht.
|
||||
CHECK_HELP_LIST=§8/§7check list §8- §7Zeigt die Liste der ungeprüften Schematics
|
||||
CHECK_HELP_NEXT=§8/§7check next §8- §7Nächste Prüffrage§8/§7freigeben
|
||||
CHECK_HELP_DECLINE=§8/§7check decline §8[§eGrund§8] - §7Schematic ablehnen
|
||||
CHECK_HELP_CANCEL=§8/§7check cancel §8- §7Bricht den Prüfvorgang ab
|
||||
CHECK_LIST_HEADER=§e§lZu prüfen sind {0} Schematics
|
||||
CHECK_LIST_TO_CHECK={0} §8{1} §7{2} §e{3}
|
||||
CHECK_LIST_TO_CHECK_HOVER=§eSchematic prüfen
|
||||
CHECK_LIST_CHECKING={0} §8{1} §7{2} §e{3} §7wird geprüft von §e{4}
|
||||
CHECK_LIST_CHECKING_HOVER=§eZum Prüfer
|
||||
CHECK_SCHEMATIC_ALREADY_CHECKING=§cDu prüfst schon eine Schematic!
|
||||
CHECK_SCHEMATIC_OWN=§cDu kannst nicht deine eigenen Schematics prüfen.
|
||||
CHECK_SCHEMATIC_OWN_TEAM=§cDu kannst nicht Schematics deines Teams prüfen.
|
||||
CHECK_SCHEMATIC_PREVIOUS=§7{0} von {1}§8: §e{2}
|
||||
CHECK_INVALID_RANK=§cUnbekannter Schematicrang.
|
||||
CHECK_ABORT=§aDer Prüfvorgang wurde abgebrochen!
|
||||
CHECK_NEXT=Nächste Frage
|
||||
CHECK_ACCEPT=Annehmen
|
||||
CHECK_DECLINE=Ablehnen
|
||||
CHECK_RANK=§aRang {0}: {1}
|
||||
CHECK_RANK_HOVER=§aMit diesem Rang freigeben
|
||||
CHECK_ACCEPTED=§aDein §e{0} {1} §ewurde freigegeben§8!
|
||||
CHECK_ACCEPTED_TEAM=§7Die Schematic §e{0} §7von §e{1} §7ist nun freigegeben!
|
||||
CHECK_DECLINED=§cDein §e{0} {1} §cwurde abgelehnt§8: §c{2}
|
||||
CHECK_DECLINED_TEAM=§7Die Schematic §e{0} §7von §e{1} §7wurde aufgrund von §e{2} §7abgelehnt!
|
||||
|
||||
#HistoricCommand
|
||||
HISTORIC_BROADCAST=§7Historischer §e{0}§8-§7Kampf von §e{1}§8!
|
||||
HISTORIC_BROADCAST_HOVER=§aGegen §7{1} §ekämpfen
|
||||
|
||||
#JoinCommand
|
||||
JOIN_PLAYER_BLOCK=§cDu kannst diesem Spieler derzeit nicht folgen.
|
||||
|
||||
#JoinmeCommand
|
||||
JOINME_USAGE=§8/§7join §8[§eSpieler§8].
|
||||
JOINME_BROADCAST=§7Klicke §ehier§8, §7um zu §e{0} §7auf §e{1} §7zu kommen§8!
|
||||
JOINME_BROADCAST_HOVER=§aSpieler folgen
|
||||
JOINME_PLAYER_OFFLINE=§cDieser Spieler ist offline.
|
||||
JOINME_PLAYER_SELF=§cSei eins mit dir selbst!
|
||||
|
||||
#KickCommand
|
||||
KICK_USAGE=§8/§7kick §8[§eSpieler§8] [§eNachricht§8]
|
||||
KICK_OFFLINE=§cDieser Spieler ist derzeit nicht online!
|
||||
KICK_CONFIRM=Der Spieler {0} wurde gekickt.
|
||||
KICK_NORMAL=§cDu wurdest gekickt.
|
||||
|
||||
#MsgCommand
|
||||
MSG_USAGE=§8/§7msg §8[§eBenutzer§8] [§eNachricht§8]
|
||||
MSG_OFFLINE=§cKein Gesprächspartner verfügbar!
|
||||
MSG_IGNORED=§cDieser Spieler hat dich geblockt!
|
||||
|
||||
#PingCommand
|
||||
PING_RESPONSE=§7Dein Ping beträgt §c{0}§7 ms!
|
||||
|
||||
#PollCommand
|
||||
POLL_NO_POLL=§cDerzeit läuft keine Umfrage.
|
||||
POLL_NO_ANSWER=§cDas ist keine Antwortmöglichkeit!
|
||||
POLL_ANSWER_REFRESH=§aDeine Antwort wurde aktualisiert.
|
||||
POLL_ANSWER_NEW=§aDeine Antwort wurde registriert.
|
||||
|
||||
#RCommand
|
||||
R_USAGE=§8/§7r §8[§eAntwort§8]
|
||||
|
||||
#RegelnCommand
|
||||
REGELN_RULES=§7§lRegelwerke
|
||||
REGELN_AS=§eAirShip§8-§7Regelwerk
|
||||
REGELN_AS_HOVER=§7https://steamwar.de/spielmodi/airship-regelwerk/
|
||||
REGELN_AS_URL=https://steamwar.de/spielmodi/airship-regelwerk/
|
||||
REGELN_MWG=§eMiniWarGear§8-§7Regelwerk
|
||||
REGELN_MWG_HOVER=§7https://steamwar.de/spielmodi/miniwargear-regelwerk/
|
||||
REGELN_MWG_URL=https://steamwar.de/spielmodi/miniwargear-regelwerk/
|
||||
REGELN_WG=§eWarGear§8-§7Regelwerk
|
||||
REGELN_WG_HOVER=§7https://steamwar.de/spielmodi/wargear-regelwerk/
|
||||
REGELN_WG_URL=https://steamwar.de/spielmodi/wargear-regelwerk/
|
||||
REGELN_WS=§eWarShip§8-§7Regelwerk
|
||||
REGELN_WS_HOVER=§7https://steamwar.de/spielmodi/warship-regelwerk/
|
||||
REGELN_WS_URL=https://steamwar.de/spielmodi/warship-regelwerk/
|
||||
REGELN_QG=§eQuickGear§8-§7Regelwerk
|
||||
REGELN_QG_HOVER=§7https://steamwar.de/spielmodi/quickgear-regelwerk/
|
||||
REGELN_QG_URL=https://steamwar.de/spielmodi/quickgear-regelwerk/
|
||||
REGELN_CONDUCT=§eVerhaltensrichtlinien
|
||||
REGELN_CONDUCT_HOVER=§7https://steamwar.de/verhaltensrichtlinien/
|
||||
REGELN_CONDUCT_URL=https://steamwar.de/verhaltensrichtlinien/
|
||||
|
||||
#ReplayCommand
|
||||
REPLAY_TITLE=Letzte Kämpfe
|
||||
REPLAY_UNAVAILABLE=§cReplay nicht möglich
|
||||
|
||||
#TutorialCommand
|
||||
TUTORIAL_TITLE=Tutorials
|
||||
TUTORIAL_NAME=§e{0}
|
||||
TUTORIAL_BY=§8von §7{0}
|
||||
TUTORIAL_STARS=§e{0} §7Sterne
|
||||
TUTORIAL_RATE_TITLE=Tutorial bewerten
|
||||
TUTORIAL_RATE=§e{0} §7Stern(e)
|
||||
TUTORIAL_DELETE=§cMit Shift+Rechtsklick löschen
|
||||
TUTORIAL_CREATE_HELP=§8/§7tutorial create §8[§eMaterial§8] §8[§eName§8]
|
||||
TUTORIAL_CREATE_MISSING=§cEin Tutorial kann nur von einem Tutorialserver aus erstellt werden!
|
||||
TUTORIAL_CREATED=§7Das Tutorial wurde erstellt§8.
|
||||
TUTORIAL_OWN_HELP=§8/§7tutorial own §8- §7Liste der eigenen Tutorials
|
||||
|
||||
#ServerTeamchatCommand
|
||||
STC_USAGE=§8/§7stc §8[§eNachricht an das Team§8]
|
||||
|
||||
#TeamchatCommand
|
||||
TC_USAGE=§8/§7tc §8[§eNachricht an das Team§8]
|
||||
TC_NO_TEAM=§cDu bist in keinem Team.
|
||||
|
||||
#TeamCommand
|
||||
TEAM_IN_TEAM=§cDu bist bereits in einem Team.
|
||||
TEAM_NOT_IN_TEAM=§cDu bist in keinem Team.
|
||||
TEAM_NOT_LEADER=§cDu bist nicht der Teamleader.
|
||||
TEAM_NOT_IN_EVENT=§cDies ist während eines Events nicht möglich.
|
||||
TEAM_HELP_HEADER=§7Mit §e/team §7verwaltest du dein Team.
|
||||
TEAM_HELP_LIST=§8/§7team list §8- §7Liste alle Teams auf.
|
||||
TEAM_HELP_INFO=§8/§7team info §8- §7Informiere dich über ein Team.
|
||||
TEAM_HELP_TP=§8/§7team tp §8(§7Team§8) §8- §7Teleportiert zum Teamserver.
|
||||
TEAM_HELP_CREATE=§8/§7team create §8- §7Erstelle dein eigenes Team.
|
||||
TEAM_HELP_JOIN=§8/§7team join §8- §7Trete einem Team bei.
|
||||
TEAM_HELP_CHAT=§8/§7teamchat §8- §7Sende Nachrichten an dein Team.
|
||||
TEAM_HELP_EVENT=§8/§7team event §8- §7Nehme an Events teil.
|
||||
TEAM_HELP_LEAVE=§8/§7team leave §8- §7Verlasse dein Team.
|
||||
TEAM_HELP_INVITE=§8/§7team invite §8- §7Lade jemanden in dein Team ein.
|
||||
TEAM_HELP_REMOVE=§8/§7team remove §8- §7Entferne jemanden aus deinem Team.
|
||||
TEAM_HELP_KUERZEL=§8/§7team changekuerzel §8- §7Ändere dein Teamkürzel.
|
||||
TEAM_HELP_NAME=§8/§7team changename §8- §7Ändere deinen Teamnamen.
|
||||
TEAM_HELP_COLOR=§8/§7team changecolor §8- §7Ändere deine Teamfarbe.
|
||||
TEAM_HELP_LEADER=§8/§7team promote §8- §7Ernenne jemanden zum Teamleader.
|
||||
TEAM_HELP_STEP_BACK=§8/§7team stepback §8- §7Tritt als Leader zurück.
|
||||
TEAM_HELP_SERVER=§8/§7team server §8[§eIP/Adresse§8] §8(§7Port§8) §8- §7Setzt Adresse des Teamservers.
|
||||
|
||||
#Team Create
|
||||
TEAM_CREATE_USAGE=§8/§7team create §8[§eTeamkürzel§8] §8[§eTeamname§8]
|
||||
TEAM_CREATE_CREATED=§7Du hast das Team §e{0} §7gegründet!
|
||||
|
||||
#Team Join
|
||||
TEAM_JOIN_NO_INVITE=§7Du hast keine Einladungen erhalten.
|
||||
TEAM_JOIN_USAGE=§8/§7team join §8[§eTeam§8]
|
||||
TEAM_JOIN_INVITED=§7Du wurdest von diesen Teams eingeladen§8: §e{0}
|
||||
TEAM_JOIN_NOT_BY_TEAM=§cVon diesem Team wurdest du nicht eingeladen.
|
||||
TEAM_JOIN_JOINED=§7Du bist dem Team §e{0} §7beigetreten!
|
||||
|
||||
#Team Leave
|
||||
TEAM_OTHER_LEADER_REQUIRED=§cBitte ernenne zunächst ein anderes Teammitglied zum Leader!
|
||||
TEAM_LEAVE_LEFT=§7Du hast dein Team verlassen!
|
||||
|
||||
#Team Step Back
|
||||
TEAM_STEP_BACK=§7Du hast deinen Posten als Teamleader abgegeben§8!
|
||||
|
||||
#Team Invite
|
||||
TEAM_INVITE_USAGE=§8/§7team invite §8[§eSpieler§8]
|
||||
TEAM_INVITE_NO_PLAYER=§cDiesen Spieler gibt es nicht.
|
||||
TEAM_INVITE_IN_TEAM=§cDieser Spieler ist bereits in einem Team.
|
||||
TEAM_INVITE_ALREADY_INVITED=§cDu hast diesen Spieler bereits eingeladen.
|
||||
TEAM_INVITE_INVITED=§7Du hast §e{0} §7in das Team eingeladen!
|
||||
TEAM_INVITE_INVITED_TARGET=§7Du wurdest in das Team §{0}{1} §7eingeladen!
|
||||
|
||||
#Team Remove
|
||||
TEAM_REMOVE_USAGE=§8/§7team remove §8[§eSpieler§8]
|
||||
TEAM_REMOVE_NOT_PLAYER=§cDiesen Spieler gibt es nicht.
|
||||
TEAM_REMOVE_NOT_LEADER=§cLeader können nicht rausgeworfen werden.
|
||||
TEAM_REMOVE_INVITE=§7Die Einladung wurde zurückgezogen.
|
||||
TEAM_REMOVE_NO_INVITE=§cDieser Spieler hat keine Einladung erhalten.
|
||||
TEAM_REMOVE_NOT_IN_TEAM=§cDieser Spieler ist nicht in deinem Team.
|
||||
TEAM_REMOVE_REMOVED=§7Der Spieler wurde aus dem Team entfernt.
|
||||
TEAM_REMOVE_REMOVED_TARGET=§cDu wurdest aus dem Team entfernt.
|
||||
|
||||
#Team Kuerzel
|
||||
TEAM_KUERZEL_USAGE=§8/§7team changekuerzel §8[§eTeamkürzel§8]
|
||||
TEAM_KUERZEL_CHANGED=§7Du hast das Kürzel des Teams geändert!
|
||||
TEAM_KUERZEL_LENGTH=§cEin Teamkürzel muss aus 2 bis 4 Buchstaben bestehen.
|
||||
TEAM_KUERZEL_TAKEN=§cEs gibt bereits ein Team mit diesem Namen.
|
||||
|
||||
#Team Name
|
||||
TEAM_NAME_USAGE=§8/§7team changename §8[§eTeamname§8]
|
||||
TEAM_NAME_CHANGED=§7Du hast das Team umbenannt!
|
||||
TEAM_NAME_LENGTH=§cEin Teamname muss aus 4 bis 15 Buchstaben bestehen.
|
||||
TEAM_NAME_TAKEN=§cEs gibt bereits ein Team mit diesem Namen.
|
||||
|
||||
#Team Leader
|
||||
TEAM_LEADER_USAGE=§8/§7team promote §8[§eMember§8]
|
||||
TEAM_LEADER_NOT_USER=§cUnbekannter Spieler.
|
||||
TEAM_LEADER_NOT_MEMBER=§cDer Spieler ist nicht in deinem Team.
|
||||
TEAM_LEADER_PROMOTED=§7Du hast den Spieler §e{0} §7zum Leader gemacht!
|
||||
|
||||
#Team Info
|
||||
TEAM_INFO_USAGE=§8/§7team info §8[§eTeamname§8]
|
||||
TEAM_INFO_TEAM=§7Team §e{0} §8[§{1}{2}§8]
|
||||
TEAM_INFO_LEADER=§7Leader ({0})§8: {1}
|
||||
TEAM_INFO_MEMBER=§7Member ({0})§8: {1}
|
||||
TEAM_INFO_EVENTS=§7Events§8: §e{0}
|
||||
|
||||
#Team List
|
||||
TEAM_LIST_NOT_PAGE=§cKeine Seitenzahl angegeben
|
||||
TEAM_LIST_UNKNOWN_PAGE=§cUngültige Seitenzahl angegeben
|
||||
TEAM_LIST_HEADER=§7§lTeamliste §7{0}§8/§7{1}
|
||||
TEAM_LIST_TEAM=§{0}{1} §e{2}
|
||||
TEAM_LIST_TEAM_HOVER=§7Teaminfo
|
||||
TEAM_LIST_PAGE=Seite »»
|
||||
TEAM_LIST_NEXT=§eNächste Seite
|
||||
TEAM_LIST_PREV=§eVorherige Seite
|
||||
|
||||
#Team Event
|
||||
TEAM_EVENT_USAGE=§8/§7team event §8[§eEvent§8] - §7um daran teilzunehmen
|
||||
TEAM_EVENT_HEADER=§7Dein Team nimmt an folgenden Events teil§8:
|
||||
TEAM_EVENT_EVENT=§7{0}§8: §e{1}
|
||||
TEAM_EVENT_NO_EVENT=§cDieses Event gibt es nicht
|
||||
TEAM_EVENT_OVER=§cDie Anmeldephase für dieses Event ist bereits vorbei
|
||||
TEAM_EVENT_LEFT=§7Dein Team nimmt nicht mehr am Event teil
|
||||
TEAM_EVENT_JOINED=§7Dein Team nimmt nun am Event §e{0} §7 teil!
|
||||
TEAM_EVENT_HOW_TO_LEAVE=§7Um die Teilnahme abzusagen, wiederhole den Befehl.
|
||||
|
||||
#Team Color
|
||||
TEAM_COLOR_TITLE=Farbe wählen
|
||||
|
||||
#Team Server
|
||||
TEAM_SERVER_USAGE=§8/§7team server §8[§eIP/Adresse§8] §8(§7Port§8) §8- §7Setzt Adresse des Teamservers.
|
||||
TEAM_SERVER_SET=§7Du hast die Teamserveradresse geändert§8!
|
||||
TEAM_SERVER_PORT_INVALID=§cUnmögliche Portnummer.
|
||||
TEAM_SERVER_ADDRESS_INVALID=§cUngültige Adresse.
|
||||
TEAM_NO_ADDRESS=§cTeamserveradresse nicht gesetzt.
|
||||
TEAM_OFFLINE=§cTeamserver scheint offline zu sein.
|
||||
TEAM_UNKNOWN=§cEin unwerwarteter Fehler ist aufgetreten beim verbinden zum Teamserver.
|
||||
TEAM_TP_NO_TEAM=§cUnbekanntes Team.
|
||||
|
||||
#TpCommand
|
||||
TP_USAGE=§8/§7tp §8[§eSpieler§8]
|
||||
TP_USAGE_EVENT=§8/§7tp §8[§eSpieler §7oder §eTeam§8]
|
||||
|
||||
#UnignoreCommand
|
||||
UNIGNORE_USAGE=§8/§7unignore §8[§eSpieler§8]
|
||||
UNIGNORE_NOT_PLAYER=§cDiesen Spieler gibt es nicht!
|
||||
UNIGNORE_NOT_IGNORED=§cDu ignorierst diesen Spieler nicht.
|
||||
UNIGNORE_UNIGNORED=§7Du empfängst nun wieder Nachrichten von §e{0}§8.
|
||||
|
||||
#WebregisterCommand
|
||||
WEB_USAGE=§8/§7webpassword §8[§ePasswort§8]
|
||||
WEB_UPDATED=§7Dein Passwort wurde aktualisiert.
|
||||
WEB_CREATED=§7Dein Webaccount wurde erstellt.
|
||||
WEB_PASSWORD_LENGTH=§cDein Passwort ist kürzer als 8 Zeichen.
|
||||
|
||||
#ChatListener
|
||||
CHAT_LIXFEL_ACTION_BAR=§4§lTechnische Probleme?
|
||||
CHAT_LIXFEL_1=Du hast mich gerufen!
|
||||
CHAT_LIXFEL_2=Leider bin ich nur ein Mensch und höre nicht alles.
|
||||
CHAT_LIXFEL_3=Daher bitte ich dich, das Problem bzw. den Fehler im Forum in der Kategorie §eFehler melden §7mit einer ausreichenden Beschreibung zu hinterlegen.
|
||||
CHAT_LIXFEL_4=Vielen Dank.
|
||||
CHAT_LIXFEL_5=Ich wünsche dir noch weiterhin ein reibungsloses Spielerlebnis.
|
||||
CHAT_YOYONOW_1=Du hast mich gerufen!
|
||||
CHAT_YOYONOW_2=Ich würde dir gerne den Befehl "/bug <MESSAGE>" ans Herz legen.
|
||||
CHAT_YOYONOW_3=Vielen Dank.
|
||||
CHAT_YOYONOW_4=Ich wünsche dir noch weiterhin ein reibungsloses Spielerlebnis.
|
||||
CHAT_CHAOSCAOT_1=Du hast mich gerufen!
|
||||
CHAT_CHAOSCAOT_2=Wenn etwas nicht funktioniert, dann nen es einfach ein Feature.
|
||||
CHAT_CHAOSCAOT_3=Und wenn es ein Feature ist, dann kann es nicht kaputt.
|
||||
CHAT_CHAOSCAOT_4=Kaputt ist nur eine Definition. Wenn du es als Feature definiert, dann kann es nicht kaputt sein.
|
||||
CHAT_CHAOSCAOT_5=Und wenn du es als kaputt definiert, dann sag uns bescheid mit dem Befehl "/bug <MESSAGE>".
|
||||
CHAT_CHAOSCAOT_6=Vielen Dank.
|
||||
CHAT_RECEIVE=§cUm Chatnachrichten versenden zu können, musst du auch welche empfangen!
|
||||
CHAT_NO_LINKS=§cDu darfst keine Links versenden.
|
||||
CHAT_BC_USAGE=§8/§7bc §8[§eNachricht§8]
|
||||
CHAT_NO_RECEIVER=§cNiemand empfängt deine Nachricht
|
||||
CHAT_EMPTY=§cSchreibe keine inhaltslosen Nachrichten.
|
||||
|
||||
CHAT_SERVERTEAM=§8STC §e{0}§8» §f{2}
|
||||
CHAT_GLOBAL={3}{4}{5}{6}{0}§8» {7}{2}
|
||||
CHAT_DISCORD_GLOBAL=§8Dc {5}{6}{0}§8» {7}{2}
|
||||
CHAT_TEAM=§8TC §e{0}§8» §f{2}
|
||||
CHAT_MSG=§e{0}§8»§e{1} §7{2}
|
||||
|
||||
#CheckListner
|
||||
CHECK_UNCHECKED=§7Du hast noch §e{0} §7ungeprüfte Schematic§8(§7s§8)!
|
||||
CHECK_CHECKING=§cDu prüfst gerade eine Schematic!
|
||||
|
||||
#ConnectionListener
|
||||
JOIN_ARENA=§7Klicke §ehier§7, um §e{0} §7beizutreten
|
||||
JOIN_ARENA_HOVER=§eArena beitreten
|
||||
JOIN_FIRST=§7Begrüßt alle mal §e{0} §7auf dem Server§8!
|
||||
|
||||
#EventModeListener
|
||||
EVENTMODE_KICK=§cDu bist kein Eventteilnehmer.
|
||||
|
||||
#PollSystem
|
||||
POLL_HEADER=§e§lUmfrage
|
||||
POLL_HEADER2=§7Klicke die Antwort an, die dir gefällt!
|
||||
POLL_QUESTION=§e{0}
|
||||
POLL_ANSWER=§7{0}
|
||||
POLL_ANSWER_HOVER=§e{0} §ewählen
|
||||
|
||||
#TablistManager
|
||||
TABLIST_PHASE_WEBSITE=§8Website: https://§eSteam§8War.de
|
||||
TABLIST_PHASE_DISCORD=§8Discord: https://§eSteam§8War.de/discord
|
||||
TABLIST_FOOTER=§e{0} {1}§8ms §eSpieler§8: §7{2}
|
||||
TABLIST_BAU=§7§lBau
|
||||
LIST_COMMAND=§e{0}§8: §7{1}
|
||||
|
||||
#EventStarter
|
||||
EVENT_FIGHT_BROADCAST=§7Hier §eklicken §7für den Kampf §{0}{1} §8vs §{2}{3}
|
||||
EVENT_FIGHT_BROADCAST_HOVER=§eEvent beitreten
|
||||
|
||||
#SubserverSystem
|
||||
SERVER_IGNORED=§cDieser Spieler hat dich geblockt!
|
||||
SERVER_ADD_MEMBER=§e{0} §7möchte auf deine Bauwelt.
|
||||
SERVER_ADD_MESSAGE=§7Klicke §ehier§7, wenn du das erlauben möchtest.
|
||||
SERVER_ADD_MESSAGE_HOVER=§8/§7bau addmember §e{0}
|
||||
SERVER_WORLD_ERROR=§cDas Erstellen der Welt ist fehlgeschlagen.
|
||||
|
||||
|
||||
#WhoisCommand
|
||||
WHOIS_USAGE=§c/whois [Spieler/ID] [-a/-m]
|
||||
WHOIS_USERNAME=§7Username§8: §e{0}
|
||||
WHOIS_PREFIX=§7Chat-Präfix§8: {0}
|
||||
WHOIS_PERMS=§7Rechte§8: §7{0}
|
||||
WHOIS_UUID=§7UUID§8: §e{0}
|
||||
WHOIS_UUID_HOVER=§eUUID Kopieren
|
||||
WHOIS_ID=§7ID§8: §e{0}
|
||||
WHOIS_DISCORD_ID=§7Discord-ID§8: §e{0}
|
||||
WHOIS_JOINED_FIRST=§7Beigetreten am§8: §e{0}
|
||||
WHOIS_HOURS_PLAYED=§7Spielzeit§8: §e{0}h
|
||||
WHOIS_CURRENT_PLAYED=§7Aktuell online§8: §e{0}m
|
||||
WHOIS_CURRENT_SERVER=§7Aktueller Server§8: §e{0}
|
||||
WHOIS_CURRENT_PROTOCOL=§7Aktuelle Version§8: §e{0}
|
||||
WHOIS_TEAM=§7Team§8: §e[§{0}{1}§e] {2}
|
||||
WHOIS_TEAM_HOVER=§e{0} anzeigen
|
||||
WHOIS_PUNISHMENTS=§7Strafen:
|
||||
WHOIS_PUNISHMENT=§7{0}§8» §f§l{1}: §e{2} - {3} §f{4}
|
||||
WHOIS_NO_PUNISHMENT=§a✓ §7Der Spieler hat keine aktiven Strafen.
|
||||
WHOIS_NO_ALL_PUNISHMENT=§a✓ §7Der Spieler hat noch nichts getan.
|
||||
WHOIS_ACTIVE_MODS=§7Aktive Mods ({0}): {1}
|
||||
WHOIS_NO_ACTIVE_MODS=§7Der Spieler hat keine aktiven Mods.
|
||||
|
||||
#VerifyCommand
|
||||
VERIFY_USAGE=§c/verify [Code]
|
||||
VERIFY_INVALID=§cInvalider Code
|
||||
VERIFY_SUCCESS=§7Erfolgreich mit dem Discord Account §e{0} §7verknüpft
|
||||
|
||||
#Discord
|
||||
DISCORD_TICKET_HOVER=§eZur Nachricht
|
||||
DISCORD_TICKET_MESSAGE=§7Ticket §e{0}§7» §f§l{1}: §7{2}
|
||||
DISCORD_TICKET_NEW=§7Ticket §e{0}§7» §aTicket wurde geöffnet!
|
||||
DISCORD_TICKET_CLOSED=§7Ticket §e{0}§7» §cTicket wurde geschlossen!
|
||||
|
||||
#GDPR Query
|
||||
GDPR_STATUS_WEBSITE=§7Website kann nicht automatisiert gepackt werden und muss daher manuell hinzugefügt werden.
|
||||
GDPR_STATUS_WORLD=§7Packe Bauwelten...
|
||||
GDPR_STATUS_INVENTORIES=§7Suche und packe Inventare...
|
||||
GDPR_STATUS_DATABASE=§7Packe Datenbankinhalte...
|
||||
GDPR_STATUS_LOGS=§7Suche und packe logs...
|
||||
GDPR_STATUS_FINISHED=§7Packen abgeschlossen
|
||||
|
||||
#Playtime Command
|
||||
HOURS_PLAYED=§7Deine Spielzeit beträgt§8: §e{0}h
|
||||
|
||||
#Arena command
|
||||
ARENA_NOT_FOUND=§cDie angegebene Arena konnte nicht gefunden werden
|
||||
|
||||
#Rank
|
||||
RANK_PLAYER_NOT_FOUND=§cSpieler nicht gefunden
|
||||
RANK_PLAYER_FOUND=§eRang §7von §e{0}
|
||||
RANK_HEADER=§e{0} {1}
|
||||
RANK_UNPLACED=§7unplatziert
|
||||
RANK_PLACED=§e{0}§8. §7mit §e{1} §7Elo§8.
|
||||
RANK_EMBLEM=§7Emblem§8: {0}
|
||||
|
||||
#Fabric Mod Sender
|
||||
MODIFICATION_BAN_MESSAGE=Du hast probiert den FabricModSender zu umgehen / zu modifizieren!
|
||||
MODIFICATION_BAN_LOG={0} hat probiert den Fabric Mod Sender zu editieren / umzugehen! Grund: {1}
|
||||
|
||||
#Arena Merging
|
||||
FIGHT_MERGE_TITLE=Gleicher Kampf gefunden!
|
||||
FIGHT_MERGE_DECLINE=§cNeue Arena starten
|
||||
FIGHT_MERGE_ACCEPT=§aKampf beitreten
|
||||
FIGHT_MERGE_INFO_LORE_1=§8Von: §e{0}
|
||||
FIGHT_MERGE_OFFLINE=§7Die vorgeschlagene Arena wurde in der Zwischenzeit beendet, es wird eine neue Arena gestartet.
|
||||
|
||||
#Locale Locking
|
||||
LOCK_LOCALE_CHANGED=§aSprache gespeichert
|
||||
|
||||
#Builder Cloud
|
||||
BUILDERCLOUD_USAGE=§8/§7buildercloud §8[§eVersion§8] §8[§eWelt§8]
|
||||
BUILDERCLOUD_CREATE_USAGE=§8/§7buildercloud create §8[§eVersion§8] §8[§eWelt§8] §8<§7Generator§8>
|
||||
BUILDERCLOUD_RENAME_USAGE=§8/§7buildercloud rename §8[§eVersion§8] §8[§eWElt§8] §8[§eNeuer Name§8]
|
||||
BUILDERCLOUD_VERSION=§cUnbekannte Version.
|
||||
BUILDERCLOUD_EXISTING_MAP=§cWelt existiert bereits.
|
||||
BUILDERCLOUD_UNKNOWN_MAP=§cUnbekannte Welt.
|
||||
BUILDERCLOUD_RENAMED=§7Umbenennung erfolgreich.
|
||||
|
||||
# Advent Calendar
|
||||
ADVENT_CALENDAR_TITLE=§eAdventskalender
|
||||
ADVENT_CALENDAR_DAY=§7Tag§8: §e{0}
|
||||
ADVENT_CALENDAR_MESSAGE=§eHast du heute schon dein Geschenk geholt?
|
||||
ADVENT_CALENDAR_MESSAGE_HOVER=§eKlicken zum öffnen!
|
||||
ADVENT_CALENDAR_OPEN=§7Du hast §e{0}§7 aus dem Adventskalender erhalten!
|
||||
|
||||
#StreamInv
|
||||
INV_PAGE_BACK=§{0}Page back
|
||||
INV_PAGE_NEXT=§{0}Next page
|
||||
|
||||
#Discord
|
||||
DC_UNLINKED=Für diese Aktion muss dein Minecraftaccount mit deinem Discordaccount verknüpft sein, gehe dazu auf dem SteamWar-Discord in den `regeln-infos` Channel und Klicke auf `Minecraft Verknüpfen`.
|
||||
DC_TITLE_SCHEMINFO=Schematicinfo
|
||||
DC_SCHEM_ACCEPT=Deine Schematic **{0}** wurde angenommen.
|
||||
DC_SCHEM_DECLINE=Deine Schematic **{0}** wurde abgelehnt. **Grund:** \n{1}
|
||||
DC_AUTH_SUCCESS=:white_check_mark: Dein Discordaccount wurde mit **{0}** verknüpft.
|
||||
DC_ROLE_ADDED=:tada: Du bekommst nun {0}.
|
||||
DC_ROLE_REMOVED=Du bekommst nun keine {0} mehr.
|
||||
|
||||
DC_TICKET_CREATED=Dein Ticket {0} wurde erstellt.
|
||||
DC_TICKETINTRO_REPORT=Bitte beantworte für die Ahndung des Fehlverhaltens möglichst genau folgende Fragen und füge nach Möglichkeit Beweismaterial hinzu:\n - Welche(r) Spieler?\n - Auf welchem Server?\n - Zu welchem Zeitpunkt?\n - Art und Natur des Fehlverhaltens?
|
||||
DC_TICKETINTRO_IDEA=Beschreibe deine Idee möglichst detailiert. Hierzu gehört: Was, Warum, Wie, Wo?
|
||||
DC_TICKETINTRO_BUG=Bitte beschreibe das beobachtete unerwartete bzw. inkorrekte Verhalten der Serversoftware. Falls notwendig, beschreibe die Schritte, mit denen der Fehler reproduziert werden kann.
|
||||
DC_TICKETINTRO_QUESTION=Bitte stelle deine Frage, ein Serverteammitglied wird sich dieser zeitnah annehmen.
|
||||
DC_TICKETINTRO_APPEAL=Fragen wirkt Wunder!
|
||||
DC_TICKET_CLOSE=Schließen
|
||||
|
||||
DC_SCHEMUPLOAD_NOPERM=Du darfst keine Schematics hochladen.
|
||||
DC_SCHEMUPLOAD_IGNORED=`{0}` wird ignoriert, da die Datei keine Schematic ist.
|
||||
DC_SCHEMUPLOAD_INVCHAR=`{0}` hat unzulässige Buchstaben im Namen.
|
||||
DC_SCHEMUPLOAD_SUCCESS=`{0}` wurde erfolgreich hochgeladen.
|
||||
DC_SCHEMUPLOAD_ERROR=Ein Fehler ist beim Hochladen von `{0}` aufgetreten. Für nähere Informationen wende dich an einen Developer.
|
||||
276
VelocityCore/src/de/steamwar/messages/Chatter.java
Normal file
276
VelocityCore/src/de/steamwar/messages/Chatter.java
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.messages;
|
||||
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.event.ResultedEvent;
|
||||
import com.velocitypowered.api.event.connection.LoginEvent;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
import de.steamwar.persistent.Servertype;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public interface Chatter {
|
||||
|
||||
static Stream<Player> allPlayers() {
|
||||
return VelocityCore.getProxy().getAllPlayers().stream();
|
||||
}
|
||||
|
||||
static Stream<Chatter> allStream() {
|
||||
return Stream.concat(Stream.of(Chatter.console()), allPlayers().map(Chatter::of));
|
||||
}
|
||||
|
||||
static ChatterGroup broadcast() {
|
||||
return new ChatterGroup(allStream());
|
||||
}
|
||||
|
||||
static ChatterGroup globalChat() {
|
||||
return new ChatterGroup(Stream.concat(Stream.of(Chatter.console()), allPlayers().filter(player -> {
|
||||
Subserver subserver = Subserver.getSubserver(player);
|
||||
return subserver == null || !(subserver.getType() == Servertype.ARENA && subserver.getServer() == player.getCurrentServer().map(ServerConnection::getServerInfo).orElse(null));
|
||||
}).map(Chatter::of)));
|
||||
}
|
||||
|
||||
static ChatterGroup serverteam() {
|
||||
return new ChatterGroup(allStream().filter(player -> player.user().hasPerm(UserPerm.TEAM)));
|
||||
}
|
||||
|
||||
SteamwarUser user();
|
||||
|
||||
Locale getLocale();
|
||||
boolean chatShown();
|
||||
void sendMessage(Component msg);
|
||||
Player getPlayer();
|
||||
|
||||
default <T> T withPlayerOrOffline(Function<Player, T> withPlayer, Supplier<T> withOffline) {
|
||||
Player player = getPlayer();
|
||||
if(player == null)
|
||||
return withOffline.get();
|
||||
else
|
||||
return withPlayer.apply(player);
|
||||
}
|
||||
default void withPlayerOrOffline(Consumer<Player> withPlayer, Runnable withOffline) {
|
||||
Player player = getPlayer();
|
||||
if(player == null)
|
||||
withOffline.run();
|
||||
else
|
||||
withPlayer.accept(player);
|
||||
}
|
||||
default void withPlayer(Consumer<Player> function) {
|
||||
withPlayerOrOffline(function, () -> {});
|
||||
}
|
||||
|
||||
default void system(String format, Object... params) {
|
||||
system(new Message(format, params));
|
||||
}
|
||||
|
||||
default void system(Message message) {
|
||||
send(true, null, null, message);
|
||||
}
|
||||
|
||||
default void system(String format, Message onHover, ClickEvent onClick, Object... params) {
|
||||
send(true, onHover, onClick, new Message(format, params));
|
||||
}
|
||||
|
||||
default void prefixless(String format, Object... params) {
|
||||
prefixless(format, null, null, params);
|
||||
}
|
||||
|
||||
default void prefixless(String format, Message onHover, ClickEvent onClick, Object... params) {
|
||||
send(false, onHover, onClick, new Message(format, params));
|
||||
}
|
||||
|
||||
default void send(boolean prefixed, Message onHover, ClickEvent onClick, Message message) {
|
||||
Component msg = parse(prefixed, message);
|
||||
if(onHover != null)
|
||||
msg = msg.hoverEvent(HoverEvent.showText(parse(false, onHover)));
|
||||
if(onClick != null)
|
||||
msg = msg.clickEvent(onClick);
|
||||
sendMessage(msg);
|
||||
}
|
||||
|
||||
default String parseToPlain(String format, Object... params) {
|
||||
return parseToPlain(new Message(format, params));
|
||||
}
|
||||
|
||||
default String parseToPlain(Message message) {
|
||||
return PlainTextComponentSerializer.plainText().serialize(parse(message));
|
||||
}
|
||||
|
||||
default String parseToLegacy(String format, Object... params) {
|
||||
return parseToLegacy(new Message(format, params));
|
||||
}
|
||||
|
||||
default String parseToLegacy(Message message) {
|
||||
return LegacyComponentSerializer.legacySection().serialize(parse(message));
|
||||
}
|
||||
|
||||
default Component parse(String format, Object... params) {
|
||||
return parse(false, new Message(format, params));
|
||||
}
|
||||
|
||||
default Component parse(Message message) {
|
||||
return parse(false, message);
|
||||
}
|
||||
|
||||
default Component parse(boolean prefixed, String format, Object... params) {
|
||||
return parse(prefixed, new Message(format, params));
|
||||
}
|
||||
|
||||
default Component parse(boolean prefixed, Message message) {
|
||||
Locale locale = getLocale();
|
||||
ResourceBundle resourceBundle = SteamwarResourceBundle.getResourceBundle(locale);
|
||||
String pattern = "";
|
||||
if(prefixed)
|
||||
pattern = resourceBundle.getObject("PREFIX") + " ";
|
||||
pattern += (String)resourceBundle.getObject(message.format());
|
||||
|
||||
MessageFormat format = new MessageFormat(pattern, locale);
|
||||
Object[] params = message.params();
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
if(params[i] instanceof Message msg) {
|
||||
params[i] = parseToLegacy(msg);
|
||||
} else if(params[i] instanceof Date date) {
|
||||
params[i] = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale).format(date);
|
||||
} else if(params[i] instanceof SteamwarUser user) {
|
||||
params[i] = user.getUserName();
|
||||
} else if(params[i] instanceof Player player) {
|
||||
params[i] = player.getUsername();
|
||||
} else if(params[i] instanceof Chatter chatter) {
|
||||
params[i] = chatter.user().getUserName();
|
||||
} else if(params[i] instanceof Function func) {
|
||||
params[i] = func.apply(this);
|
||||
}
|
||||
}
|
||||
return LegacyComponentSerializer.legacySection().deserialize(format.format(params));
|
||||
}
|
||||
|
||||
static PlayerChatter of(Player player) {
|
||||
return new PlayerChatter(player, player::sendMessage);
|
||||
}
|
||||
|
||||
static PlayerChatter disconnect(Player player) {
|
||||
return new PlayerChatter(player, player::disconnect);
|
||||
}
|
||||
|
||||
static Chatter of(CommandSource sender) {
|
||||
if(sender instanceof Player player)
|
||||
return of(player);
|
||||
|
||||
//Console
|
||||
return new PlayerlessChatter() {
|
||||
@Override
|
||||
public SteamwarUser user() {
|
||||
return SteamwarUser.get(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chatShown() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Component msg) {
|
||||
sender.sendMessage(msg);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static Chatter of(SteamwarUser user) {
|
||||
return of(user.getUUID());
|
||||
}
|
||||
|
||||
static Chatter of(UUID uuid) {
|
||||
Player player = VelocityCore.getProxy().getPlayer(uuid).orElse(null);
|
||||
if(player != null)
|
||||
return Chatter.of(player);
|
||||
|
||||
return new PlayerlessChatter() {
|
||||
@Override
|
||||
public SteamwarUser user() {
|
||||
return SteamwarUser.get(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chatShown() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Component msg) {
|
||||
// Nowhere to send
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static Chatter console() {
|
||||
return of(VelocityCore.getProxy().getConsoleCommandSource());
|
||||
}
|
||||
|
||||
static Chatter of(LoginEvent event) {
|
||||
return new PlayerlessChatter() {
|
||||
@Override
|
||||
public SteamwarUser user() {
|
||||
return SteamwarUser.get(event.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chatShown() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Component msg) {
|
||||
event.setResult(ResultedEvent.ComponentResult.denied(msg));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
abstract class PlayerlessChatter implements Chatter {
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return user().getLocale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
return VelocityCore.getProxy().getPlayer(user().getUUID()).orElse(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
63
VelocityCore/src/de/steamwar/messages/ChatterGroup.java
Normal file
63
VelocityCore/src/de/steamwar/messages/ChatterGroup.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.messages;
|
||||
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Getter
|
||||
public class ChatterGroup extends Chatter.PlayerlessChatter {
|
||||
|
||||
final Chatter[] chatters;
|
||||
|
||||
public ChatterGroup(Stream<Chatter> stream) {
|
||||
chatters = stream.toArray(Chatter[]::new);
|
||||
}
|
||||
|
||||
public ChatterGroup(Chatter... chatters) {
|
||||
this.chatters = chatters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chatShown() {
|
||||
return Arrays.stream(chatters).allMatch(Chatter::chatShown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(boolean prefixed, Message onHover, ClickEvent onClick, Message message) {
|
||||
for(Chatter sender : chatters)
|
||||
sender.send(prefixed, onHover, onClick, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SteamwarUser user() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Component msg) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
22
VelocityCore/src/de/steamwar/messages/Message.java
Normal file
22
VelocityCore/src/de/steamwar/messages/Message.java
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.messages;
|
||||
|
||||
public record Message(String format, Object... params) { }
|
||||
64
VelocityCore/src/de/steamwar/messages/PlayerChatter.java
Normal file
64
VelocityCore/src/de/steamwar/messages/PlayerChatter.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.messages;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.player.PlayerSettings;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class PlayerChatter implements Chatter {
|
||||
|
||||
private final Player player;
|
||||
private final Consumer<Component> sendMessage;
|
||||
|
||||
@Override
|
||||
public SteamwarUser user() {
|
||||
return SteamwarUser.get(player.getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return user().getLocale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chatShown() {
|
||||
if(!player.hasSentPlayerSettings())
|
||||
return false;
|
||||
|
||||
return player.getPlayerSettings().getChatMode() == PlayerSettings.ChatMode.SHOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Component msg) {
|
||||
sendMessage.accept(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.messages;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
public class SteamwarResourceBundle extends PropertyResourceBundle {
|
||||
|
||||
private static final String BASE_PATH = "/" + "de.steamwar.messages.BungeeCore".replace('.', '/');
|
||||
|
||||
private static final Map<String, ResourceBundle> bundles = new HashMap<>();
|
||||
|
||||
public static ResourceBundle getResourceBundle(Locale locale) {
|
||||
return getResourceBundle(locale.toString(), getResourceBundle(locale.getLanguage(), getResourceBundle( "", null)));
|
||||
}
|
||||
|
||||
private static synchronized ResourceBundle getResourceBundle(String locale, ResourceBundle parent) {
|
||||
return bundles.computeIfAbsent(locale, locale1 -> {
|
||||
InputStream inputStream = Message.class.getResourceAsStream(BASE_PATH + ("".equals(locale) ? "" : "_" + locale) + ".properties");
|
||||
if(inputStream == null)
|
||||
return parent;
|
||||
try {
|
||||
return new SteamwarResourceBundle(inputStream, parent);
|
||||
} catch (IOException e) {
|
||||
return parent;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private SteamwarResourceBundle(InputStream stream, ResourceBundle parent) throws IOException {
|
||||
super(stream);
|
||||
setParent(parent);
|
||||
}
|
||||
}
|
||||
37
VelocityCore/src/de/steamwar/sql/SQLConfigImpl.java
Normal file
37
VelocityCore/src/de/steamwar/sql/SQLConfigImpl.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.sql;
|
||||
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.sql.internal.SQLConfig;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class SQLConfigImpl implements SQLConfig {
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return VelocityCore.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int maxConnections() {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
83
VelocityCore/src/de/steamwar/sql/SQLWrapperImpl.java
Normal file
83
VelocityCore/src/de/steamwar/sql/SQLWrapperImpl.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.sql;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import de.steamwar.velocitycore.GameModeConfig;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.commands.CheckCommand;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SQLWrapperImpl implements SQLWrapper {
|
||||
private static final SimpleDateFormat deadlineFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm");
|
||||
private static Date parseDeadline(String deadline) {
|
||||
if(deadline == null)
|
||||
return null;
|
||||
|
||||
try {
|
||||
return deadlineFormat.parse(deadline);
|
||||
} catch (ParseException e) {
|
||||
throw new SecurityException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSchemTypes(List<SchematicType> tmpTypes, Map<String, SchematicType> tmpFromDB) {
|
||||
GameModeConfig.loadAll(GameModeConfig.class, (file, config) -> {
|
||||
if(config.getSchematic() == null || tmpFromDB.containsKey(config.getSchemType().toLowerCase()))
|
||||
return;
|
||||
|
||||
String shortcut = config.getSchematic().getShortcut();
|
||||
String material = config.getSchematic().getMaterial();
|
||||
|
||||
SchematicType checktype = null;
|
||||
if(!config.getCheckQuestions().isEmpty()) {
|
||||
checktype = new SchematicType("C" + config.getSchemType(), "C" + shortcut, SchematicType.Type.CHECK_TYPE, null, material, true);
|
||||
tmpTypes.add(checktype);
|
||||
tmpFromDB.put(checktype.toDB(), checktype);
|
||||
CheckCommand.setCheckQuestions(checktype, config.getCheckQuestions());
|
||||
}
|
||||
|
||||
SchematicType current = new SchematicType(config.getSchemType(), shortcut, config.getServer() != null ? SchematicType.Type.FIGHT_TYPE : SchematicType.Type.NORMAL, checktype, material, parseDeadline(config.getDeadline()), config.getSchematic().isManualCheck());
|
||||
tmpTypes.add(current);
|
||||
tmpFromDB.put(config.getSchemType().toLowerCase(), current);
|
||||
if(checktype != null)
|
||||
CheckCommand.addFightType(checktype, current);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void additionalExceptionMetadata(StringBuilder builder) {
|
||||
builder.append("\nServers: ");
|
||||
for(RegisteredServer server : VelocityCore.getProxy().getAllServers()) {
|
||||
builder.append(server.getServerInfo().getName()).append("(");
|
||||
for(Player player : server.getPlayersConnected()) {
|
||||
builder.append(player.getUsername()).append(" ");
|
||||
}
|
||||
builder.append(") ");
|
||||
}
|
||||
}
|
||||
}
|
||||
121
VelocityCore/src/de/steamwar/velocitycore/ArenaMode.java
Normal file
121
VelocityCore/src/de/steamwar/velocitycore/ArenaMode.java
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore;
|
||||
|
||||
import de.steamwar.sql.SchematicType;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ArenaMode extends GameModeConfig {
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
private static final Map<String, ArenaMode> byChat = new HashMap<>();
|
||||
private static final Map<String, ArenaMode> byInternal = new HashMap<>();
|
||||
private static final Map<SchematicType, ArenaMode> bySchemType = new HashMap<>();
|
||||
@Getter
|
||||
private static final List<ArenaMode> allModes = new LinkedList<>();
|
||||
|
||||
static {
|
||||
init();
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
byChat.clear();
|
||||
byInternal.clear();
|
||||
bySchemType.clear();
|
||||
allModes.clear();
|
||||
|
||||
GameModeConfig.loadAll(ArenaMode.class, (file, mode) -> {
|
||||
if(mode.getServer() == null)
|
||||
return;
|
||||
|
||||
mode.config = file.getName();
|
||||
mode.internalName = file.getName().replace(".yml", "");
|
||||
mode.getMaps().forEach(map -> mode.lowerToRealMapNames.put(map.toLowerCase(), map));
|
||||
if(mode.getGameName() == null)
|
||||
mode.setGameName(mode.internalName);
|
||||
|
||||
allModes.add(mode);
|
||||
byInternal.put(mode.internalName, mode);
|
||||
for(String name : mode.getServer().getChatNames()){
|
||||
byChat.put(name.toLowerCase(), mode);
|
||||
}
|
||||
|
||||
if(mode.getSchematic() != null && mode.getSchemType() != null)
|
||||
bySchemType.put(SchematicType.fromDB(mode.getSchemType()), mode);
|
||||
});
|
||||
}
|
||||
|
||||
public static ArenaMode getByChat(String name){
|
||||
return byChat.get(name.toLowerCase());
|
||||
}
|
||||
|
||||
public static ArenaMode getByInternal(String name){
|
||||
return byInternal.get(name);
|
||||
}
|
||||
|
||||
public static List<String> getAllChatNames(boolean historic) {
|
||||
List<String> chatNames = new LinkedList<>();
|
||||
for(ArenaMode mode : byInternal.values()){
|
||||
if(historic == mode.isHistoric())
|
||||
chatNames.addAll(mode.getServer().getChatNames());
|
||||
}
|
||||
return chatNames;
|
||||
}
|
||||
|
||||
public static ArenaMode getBySchemType(SchematicType schemType){
|
||||
return bySchemType.get(schemType);
|
||||
}
|
||||
|
||||
|
||||
private final Map<String, String> lowerToRealMapNames = new HashMap<>();
|
||||
|
||||
@Getter
|
||||
private String internalName;
|
||||
@Getter
|
||||
private String config;
|
||||
|
||||
public String hasMap(String map){
|
||||
for(String m : getMaps()) {
|
||||
if(m.equalsIgnoreCase(map))
|
||||
return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getRandomMap(){
|
||||
return getMaps().get(random.nextInt(getMaps().size()));
|
||||
}
|
||||
|
||||
public String convertToRealMapName(String map){
|
||||
return lowerToRealMapNames.get(map.toLowerCase());
|
||||
}
|
||||
|
||||
public String getChatName(){
|
||||
return getServer().getChatNames().get(0);
|
||||
}
|
||||
|
||||
public boolean withoutChatName(){
|
||||
return getServer().getChatNames().isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
44
VelocityCore/src/de/steamwar/velocitycore/Broadcaster.java
Normal file
44
VelocityCore/src/de/steamwar/velocitycore/Broadcaster.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore;
|
||||
|
||||
import de.steamwar.messages.Chatter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
class Broadcaster {
|
||||
|
||||
private final List<String> broadcasts = VelocityCore.get().getConfig().getBroadcasts();
|
||||
private int lastBroadCast = 0;
|
||||
|
||||
Broadcaster() {
|
||||
if(!broadcasts.isEmpty())
|
||||
VelocityCore.schedule(this::broadcast).repeat(10, TimeUnit.MINUTES).schedule();
|
||||
}
|
||||
|
||||
private void broadcast() {
|
||||
if(!VelocityCore.getProxy().getAllPlayers().isEmpty())
|
||||
Chatter.broadcast().system("PLAIN_STRING", broadcasts.get(lastBroadCast++));
|
||||
|
||||
if(lastBroadCast == broadcasts.size())
|
||||
lastBroadCast = 0;
|
||||
}
|
||||
}
|
||||
88
VelocityCore/src/de/steamwar/velocitycore/Config.java
Normal file
88
VelocityCore/src/de/steamwar/velocitycore/Config.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore;
|
||||
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import lombok.Getter;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
import org.yaml.snakeyaml.TypeDescription;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
import org.yaml.snakeyaml.introspector.BeanAccess;
|
||||
import org.yaml.snakeyaml.representer.Representer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Getter
|
||||
public class Config {
|
||||
|
||||
public static <T> T load(Class<T> clazz, File file, Consumer<TypeDescription> description) {
|
||||
TypeDescription typeDescription = new TypeDescription(Config.class);
|
||||
description.accept(typeDescription);
|
||||
|
||||
Constructor constructor = new Constructor(clazz, new LoaderOptions());
|
||||
constructor.addTypeDescription(typeDescription);
|
||||
|
||||
Representer representer = new Representer();
|
||||
representer.getPropertyUtils().setSkipMissingProperties(true);
|
||||
|
||||
Yaml yaml = new Yaml(constructor, representer);
|
||||
yaml.setBeanAccess(BeanAccess.FIELD);
|
||||
|
||||
try{
|
||||
return yaml.load(new FileInputStream(file));
|
||||
}catch(IOException e){
|
||||
VelocityCore.getProxy().shutdown();
|
||||
throw new SecurityException("Could not load config", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Config load() {
|
||||
return load(Config.class, new File(VelocityCore.get().getDataDirectory().toFile(), "config.yml"), description -> description.addPropertyParameters("servers", String.class, Config.Server.class));
|
||||
}
|
||||
|
||||
private String lobbyserver;
|
||||
private boolean eventmode = false;
|
||||
private Map<String, Server> servers = Collections.emptyMap();
|
||||
private List<String> broadcasts = Collections.emptyList();
|
||||
private Poll poll = null;
|
||||
|
||||
public RegisteredServer lobbyserver() {
|
||||
return VelocityCore.getProxy().getServer(lobbyserver).orElseThrow();
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class Poll {
|
||||
private String question;
|
||||
private List<String> answers;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class Server {
|
||||
private int spectatePort = 0;
|
||||
private List<String> commands;
|
||||
}
|
||||
}
|
||||
83
VelocityCore/src/de/steamwar/velocitycore/ErrorLogger.java
Normal file
83
VelocityCore/src/de/steamwar/velocitycore/ErrorLogger.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore;
|
||||
|
||||
import de.steamwar.sql.SWException;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.core.LogEvent;
|
||||
import org.apache.logging.log4j.core.LoggerContext;
|
||||
import org.apache.logging.log4j.core.appender.AbstractAppender;
|
||||
import org.apache.logging.log4j.core.config.AbstractConfiguration;
|
||||
import org.apache.logging.log4j.core.config.Property;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.List;
|
||||
|
||||
public class ErrorLogger extends AbstractAppender {
|
||||
|
||||
ErrorLogger() {
|
||||
super("SW ErrorLogger", null, null, false, Property.EMPTY_ARRAY);
|
||||
start();
|
||||
|
||||
LoggerContext context = (LoggerContext) LogManager.getContext(false);
|
||||
context.getConfiguration().addAppender(this);
|
||||
context.getRootLogger().addAppender(this);
|
||||
context.updateLoggers();
|
||||
}
|
||||
|
||||
void unregister() {
|
||||
LoggerContext context = (LoggerContext) LogManager.getContext(false);
|
||||
((AbstractConfiguration) context.getConfiguration()).removeAppender(getName());
|
||||
context.getRootLogger().removeAppender(this);
|
||||
context.updateLoggers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void append(LogEvent event) {
|
||||
if(event.getLevel().isLessSpecificThan(Level.WARN))
|
||||
return;
|
||||
|
||||
String message = event.getMessage().getFormattedMessage();
|
||||
for(String reason : filteredMessages)
|
||||
if(message.contains(reason))
|
||||
return;
|
||||
|
||||
ByteArrayOutputStream stacktraceOutput = new ByteArrayOutputStream();
|
||||
if(event.getThrown() != null)
|
||||
event.getThrown().printStackTrace(new PrintStream(stacktraceOutput));
|
||||
String stacktrace = stacktraceOutput.toString();
|
||||
for(String reason : filteredStacktraces)
|
||||
if (stacktrace.contains(reason))
|
||||
return;
|
||||
|
||||
SWException.log(message, stacktrace);
|
||||
}
|
||||
|
||||
private static final List<String> filteredMessages = List.of(
|
||||
"read timed out",
|
||||
"disconnected while connecting to Lobby"
|
||||
);
|
||||
private static final List<String> filteredStacktraces = List.of(
|
||||
"ErrorLogger",
|
||||
"Connection reset by peer"
|
||||
);
|
||||
}
|
||||
90
VelocityCore/src/de/steamwar/velocitycore/EventStarter.java
Normal file
90
VelocityCore/src/de/steamwar/velocitycore/EventStarter.java
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore;
|
||||
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.sql.EventFight;
|
||||
import de.steamwar.sql.Team;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static de.steamwar.persistent.Storage.eventServer;
|
||||
|
||||
public class EventStarter {
|
||||
|
||||
private static final Map<Integer, String> spectatePorts = new HashMap<>();
|
||||
|
||||
public static void addSpectateServer(int port, String command) {
|
||||
spectatePorts.put(port, command);
|
||||
}
|
||||
|
||||
public EventStarter() {
|
||||
EventFight.loadAllComingFights();
|
||||
VelocityCore.schedule(this::run).delay(10, TimeUnit.SECONDS).schedule();
|
||||
}
|
||||
|
||||
public static Map<Integer, Subserver> getEventServer() {
|
||||
return eventServer;
|
||||
}
|
||||
|
||||
private void run() {
|
||||
eventServer.entrySet().removeIf(entry -> Subserver.getSubserver(entry.getValue().getServer()) == null);
|
||||
Queue<EventFight> fights = EventFight.getFights();
|
||||
|
||||
EventFight next;
|
||||
while((next = nextFight(fights)) != null){
|
||||
Team blue = Team.get(next.getTeamBlue());
|
||||
Team red = Team.get(next.getTeamRed());
|
||||
|
||||
//Don't start EventServer if not the event bungee
|
||||
String command;
|
||||
if(VelocityCore.get().getConfig().isEventmode() || next.getSpectatePort() == 0) {
|
||||
ServerStarter starter = new ServerStarter().event(next);
|
||||
|
||||
starter.callback(subserver -> {
|
||||
eventServer.put(blue.getTeamId(), subserver);
|
||||
eventServer.put(red.getTeamId(), subserver);
|
||||
}).start();
|
||||
|
||||
command = "/event " + blue.getTeamKuerzel();
|
||||
} else {
|
||||
command = "/" + spectatePorts.get(next.getSpectatePort());
|
||||
}
|
||||
Chatter.broadcast().system("EVENT_FIGHT_BROADCAST", "EVENT_FIGHT_BROADCAST_HOVER", ClickEvent.runCommand(command), blue.getTeamColor(), blue.getTeamName(), red.getTeamColor(), red.getTeamName());
|
||||
}
|
||||
}
|
||||
|
||||
private EventFight nextFight(Queue<EventFight> fights){
|
||||
EventFight next = fights.peek();
|
||||
if(next == null)
|
||||
return null;
|
||||
|
||||
if(!next.getStartTime().before(new Timestamp(System.currentTimeMillis())))
|
||||
return null;
|
||||
|
||||
return fights.poll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@Getter
|
||||
public class GameModeConfig {
|
||||
|
||||
public static <T extends GameModeConfig> void loadAll(Class<T> config, BiConsumer<File, T> consumer) {
|
||||
File folder = new File(VelocityCore.get().getDataDirectory().getParent().toFile(), "FightSystem");
|
||||
if(!folder.exists())
|
||||
return;
|
||||
|
||||
for(File file : Arrays.stream(folder.listFiles((file, name) -> name.endsWith(".yml") && !name.endsWith(".kits.yml"))).sorted().toList()) {
|
||||
consumer.accept(file, Config.load(config, file, description -> {}));
|
||||
}
|
||||
}
|
||||
|
||||
private Server Server = null;
|
||||
private List<String> CheckQuestions = Collections.emptyList();
|
||||
private String deadline = null;
|
||||
private Schematic Schematic = null;
|
||||
@Setter
|
||||
private String GameName;
|
||||
|
||||
@Getter
|
||||
public static class Server {
|
||||
private String Folder;
|
||||
private String ServerJar;
|
||||
private List<String> ChatNames = Collections.emptyList();
|
||||
private List<String> Maps;
|
||||
private boolean Ranked = false;
|
||||
private boolean Historic = false;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class Schematic {
|
||||
private String Type;
|
||||
private String Shortcut;
|
||||
private String Material;
|
||||
private boolean ManualCheck = true;
|
||||
}
|
||||
|
||||
public String getServerJar() {
|
||||
return getServer().getServerJar();
|
||||
}
|
||||
|
||||
public String getFolder() {
|
||||
return getServer().getFolder();
|
||||
}
|
||||
|
||||
public List<String> getMaps() {
|
||||
return getServer().getMaps();
|
||||
}
|
||||
|
||||
public boolean isHistoric() {
|
||||
return getServer().isHistoric();
|
||||
}
|
||||
|
||||
public boolean isRanked() {
|
||||
return getServer().isRanked();
|
||||
}
|
||||
|
||||
public String getSchemType() {
|
||||
return getSchematic().getType();
|
||||
}
|
||||
}
|
||||
218
VelocityCore/src/de/steamwar/velocitycore/Node.java
Normal file
218
VelocityCore/src/de/steamwar/velocitycore/Node.java
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.file.Files;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public abstract class Node {
|
||||
|
||||
//-Xquickstart Langzeitperformance testen!
|
||||
private static final List<String> OPENJ9_ARGS = Arrays.asList(
|
||||
"-XX:+EnableCRIUSupport", "-XX:-CRIURestoreNonPortableMode",
|
||||
"-Xgc:excessiveGCratio=80", "-Xdisableexplicitgc", "-Xnoclassgc", "-Xmos128M", "-Xmns48M", "-XX:+ExitOnOutOfMemoryError", // initial heap half values of memory observed by 1.19 spectate server
|
||||
"-Xsyslog:none", "-Xtrace:none", "-Xverify:none", "-Xdump:system:none", "-Xdump:jit:none", "-Xdump:snap:none",
|
||||
"-XX:+EnableDynamicAgentLoading", "-Dlog4j.configurationFile=log4j2.xml"
|
||||
);
|
||||
private static final Set<String> JAVA_8 = new HashSet<>();
|
||||
static {
|
||||
JAVA_8.add("paper-1.8.8.jar");
|
||||
JAVA_8.add("paper-1.10.2.jar");
|
||||
JAVA_8.add("spigot-1.8.8.jar");
|
||||
JAVA_8.add("spigot-1.9.4.jar");
|
||||
JAVA_8.add("spigot-1.10.2.jar");
|
||||
}
|
||||
|
||||
private static final long MIN_FREE_MEM = 4 * 1024 * 1024L; // 4 GiB
|
||||
|
||||
private static final List<Node> nodes = new ArrayList<>();
|
||||
|
||||
public static Node getNode() {
|
||||
for(Node node : nodes) {
|
||||
if(node.belowLoadLimit)
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void forEach(Consumer<Node> consumer) {
|
||||
nodes.forEach(consumer);
|
||||
}
|
||||
|
||||
public abstract ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams);
|
||||
|
||||
protected abstract ProcessBuilder prepareExecution(String... command);
|
||||
protected abstract void calcLoadLimit();
|
||||
|
||||
protected final String hostname;
|
||||
protected volatile boolean belowLoadLimit = true;
|
||||
|
||||
protected Node(String hostname) {
|
||||
this.hostname = hostname;
|
||||
nodes.add(this);
|
||||
VelocityCore.schedule(this::calcLoadLimit).repeat(2, TimeUnit.SECONDS).schedule();
|
||||
}
|
||||
|
||||
public void execute(String... command) {
|
||||
try {
|
||||
prepareExecution(command).start().waitFor();
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not execute command", e);
|
||||
} catch (InterruptedException e) {
|
||||
VelocityCore.getLogger().log(Level.SEVERE, "Interrupted during execution", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean belowLoadLimit() {
|
||||
return belowLoadLimit;
|
||||
}
|
||||
public String getName() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
protected void constructServerstart(File directory, List<String> cmd, String serverJar, String worldDir, String levelName, int port, String xmx, String... dParams) {
|
||||
if (JAVA_8.contains(serverJar))
|
||||
cmd.add("/usr/lib/jvm/java-8-openj9-amd64/bin/java");
|
||||
else
|
||||
cmd.add("/usr/lib/jvm/java-21-openj9-amd64/bin/java");
|
||||
|
||||
for(String param : dParams){
|
||||
cmd.add("-D" + param);
|
||||
}
|
||||
cmd.add("-Xshareclasses:nonfatal,name=" + directory.getName());
|
||||
cmd.add("-Xmx" + xmx);
|
||||
cmd.addAll(OPENJ9_ARGS);
|
||||
if (!JAVA_8.contains(serverJar)) {
|
||||
cmd.add("--add-opens");
|
||||
cmd.add("java.base/jdk.internal.misc=ALL-UNNAMED");
|
||||
cmd.add("-XX:-CRIUSecProvider");
|
||||
}
|
||||
cmd.add("-jar");
|
||||
cmd.add("/binarys/" + serverJar);
|
||||
cmd.add("--log-strip-color");
|
||||
cmd.add("--world-dir");
|
||||
cmd.add(worldDir);
|
||||
cmd.add("--level-name");
|
||||
cmd.add(levelName);
|
||||
cmd.add("--port");
|
||||
cmd.add(String.valueOf(port));
|
||||
cmd.add("nogui");
|
||||
}
|
||||
|
||||
protected void calcLoadLimit(BufferedReader meminfo) throws IOException {
|
||||
String line = meminfo.readLine();
|
||||
while(!line.startsWith("MemAvailable")) {
|
||||
line = meminfo.readLine();
|
||||
}
|
||||
|
||||
long availableMem = Long.parseLong(line.replaceAll(" +", " ").split(" ")[1]);
|
||||
belowLoadLimit = availableMem >= MIN_FREE_MEM;
|
||||
}
|
||||
|
||||
public static class LocalNode extends Node {
|
||||
private static final File MEMINFO = new File("/proc/meminfo");
|
||||
|
||||
public LocalNode() {
|
||||
super("sw");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams) {
|
||||
List<String> cmd = new ArrayList<>();
|
||||
constructServerstart(directory, cmd, serverJar, worldDir, levelName, port, xmx, dParams);
|
||||
ProcessBuilder builder = new ProcessBuilder(cmd);
|
||||
builder.directory(directory);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calcLoadLimit() {
|
||||
try (BufferedReader meminfo = new BufferedReader(new InputStreamReader(Files.newInputStream(MEMINFO.toPath())))) {
|
||||
calcLoadLimit(meminfo);
|
||||
} catch (IOException e) {
|
||||
VelocityCore.getLogger().log(Level.SEVERE, "Could not read local load", e);
|
||||
belowLoadLimit = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProcessBuilder prepareExecution(String... command) {
|
||||
return new ProcessBuilder(command);
|
||||
}
|
||||
}
|
||||
|
||||
public static class RemoteNode extends Node {
|
||||
|
||||
public RemoteNode(String hostname) {
|
||||
super(hostname);
|
||||
VelocityCore.getLogger().log(Level.INFO, "Added node {0}", hostname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams) {
|
||||
List<String> cmd = new ArrayList<>();
|
||||
cmd.add("ssh");
|
||||
cmd.add("-L");
|
||||
cmd.add(port + ":localhost:" + port);
|
||||
cmd.add(hostname);
|
||||
cmd.add("cd");
|
||||
cmd.add(directory.getPath());
|
||||
cmd.add(";");
|
||||
constructServerstart(directory, cmd, serverJar, worldDir, levelName, port, xmx, dParams);
|
||||
return new ProcessBuilder(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProcessBuilder prepareExecution(String... command) {
|
||||
List<String> cmd = new ArrayList<>();
|
||||
cmd.add("ssh");
|
||||
cmd.add(hostname);
|
||||
cmd.addAll(Arrays.asList(command));
|
||||
return new ProcessBuilder(cmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calcLoadLimit() {
|
||||
try {
|
||||
Process process = prepareExecution("cat /proc/meminfo").start();
|
||||
if(!process.waitFor(1, TimeUnit.SECONDS))
|
||||
throw new IOException(hostname + " timeout");
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
|
||||
calcLoadLimit(reader);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if(belowLoadLimit)
|
||||
VelocityCore.getLogger().log(Level.SEVERE, "Could read remote load", e);
|
||||
belowLoadLimit = false;
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
belowLoadLimit = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
373
VelocityCore/src/de/steamwar/velocitycore/ServerStarter.java
Normal file
373
VelocityCore/src/de/steamwar/velocitycore/ServerStarter.java
Normal file
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.persistent.Arenaserver;
|
||||
import de.steamwar.persistent.Bauserver;
|
||||
import de.steamwar.persistent.Builderserver;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.sql.*;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ServerStarter {
|
||||
|
||||
private static final Portrange BAU_PORTS = VelocityCore.MAIN_SERVER ? new Portrange(10100, 20000) : new Portrange(2100, 2200);
|
||||
private static final Portrange ARENA_PORTS = VelocityCore.MAIN_SERVER ? new Portrange(3000, 3100) : (VelocityCore.get().getConfig().isEventmode() ? new Portrange(4000, 5000) : BAU_PORTS);
|
||||
|
||||
public static final String SERVER_PATH = "/servers/";
|
||||
private static final String USER_HOME = System.getProperty("user.home") + "/";
|
||||
private static final String EVENT_PATH = USER_HOME + "event/";
|
||||
public static final String TEMP_WORLD_PATH = USER_HOME + "arenaserver/";
|
||||
public static final String TUTORIAL_PATH = USER_HOME + "tutorials/";
|
||||
|
||||
public static final String WORLDS_BASE_PATH = USER_HOME + "userworlds";
|
||||
public static final String BUILDER_BASE_PATH = USER_HOME + "builder";
|
||||
|
||||
private File directory = null;
|
||||
private String worldDir = null;
|
||||
|
||||
private Node node = null;
|
||||
private String serverJar = "spigot-1.15.2.jar";
|
||||
private String xmx = "768M";
|
||||
private Portrange portrange = BAU_PORTS;
|
||||
private Function<Integer, String> serverNameProvider = port -> node.getName() + port;
|
||||
private BooleanSupplier startCondition = () -> true;
|
||||
private Runnable worldSetup = () -> {};
|
||||
private String worldName = null;
|
||||
private Runnable worldCleanup = () -> {};
|
||||
private boolean allowMerge = false;
|
||||
private String fightMap = null;
|
||||
private String gameMode = null;
|
||||
private boolean checkpoint = false;
|
||||
private ServerConstructor constructor = (serverName, port, builder, shutdownCallback, failureCallback) -> new Arenaserver(serverName, gameMode, fightMap, allowMerge, port, builder, shutdownCallback);
|
||||
private Consumer<Subserver> callback = subserver -> {};
|
||||
|
||||
private final Set<Player> playersToSend = new HashSet<>();
|
||||
private final Map<String, String> arguments = new HashMap<>();
|
||||
|
||||
public ServerStarter arena(ArenaMode mode, String map) {
|
||||
portrange = ARENA_PORTS;
|
||||
serverNameProvider = port -> mode.getGameName() + (port - portrange.start);
|
||||
serverJar = mode.getServerJar();
|
||||
allowMerge = true;
|
||||
fightMap = map;
|
||||
gameMode = mode.getInternalName();
|
||||
directory = new File(SERVER_PATH, mode.getFolder());
|
||||
arguments.put("config", mode.getConfig());
|
||||
tempWorld(SERVER_PATH + mode.getFolder() + "/arenas/" + map);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerStarter event(EventFight eventFight) {
|
||||
arena(ArenaMode.getByInternal(eventFight.getSpielmodus()), eventFight.getMap());
|
||||
node = VelocityCore.local;
|
||||
worldDir = EVENT_PATH;
|
||||
worldCleanup = () -> {};
|
||||
arguments.put("fightID", String.valueOf(eventFight.getFightID()));
|
||||
fightMap = eventFight.getMap();
|
||||
gameMode = eventFight.getSpielmodus();
|
||||
|
||||
String serverName = Team.get(eventFight.getTeamBlue()).getTeamKuerzel() + " vs " + Team.get(eventFight.getTeamRed()).getTeamKuerzel();
|
||||
serverNameProvider = port -> serverName;
|
||||
worldName = serverToWorldName(serverName + eventFight.getStartTime().toLocalDateTime().format(DateTimeFormatter.ISO_TIME));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerStarter test(ArenaMode mode, String map, Player owner) {
|
||||
arena(mode, map);
|
||||
buildWithTemp(owner);
|
||||
portrange = BAU_PORTS;
|
||||
arguments.put("fightID", String.valueOf(-1));
|
||||
return send(owner);
|
||||
}
|
||||
|
||||
public ServerStarter blueLeader(Player player) {
|
||||
arguments.put("blueLeader", player.getUniqueId().toString());
|
||||
return send(player);
|
||||
}
|
||||
|
||||
public ServerStarter redLeader(Player player) {
|
||||
arguments.put("redLeader", player.getUniqueId().toString());
|
||||
return send(player);
|
||||
}
|
||||
|
||||
public ServerStarter check(int schemID) {
|
||||
arguments.put("checkSchemID", String.valueOf(schemID));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerStarter prepare(int schemID) {
|
||||
arguments.put("prepareSchemID", String.valueOf(schemID));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerStarter replay(int replayID) {
|
||||
arguments.put("replay", String.valueOf(replayID));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerStarter build(ServerVersion version, UUID owner) {
|
||||
directory = version.getServerDirectory("Bau");
|
||||
serverJar = version.getServerJar();
|
||||
worldDir = version.getWorldFolder(WORLDS_BASE_PATH);
|
||||
worldName = version != ServerVersion.SPIGOT_12 ? String.valueOf(SteamwarUser.get(owner).getId()) : owner.toString();
|
||||
checkpoint = true;
|
||||
|
||||
build(owner);
|
||||
|
||||
worldSetup = () -> {
|
||||
File world = new File(worldDir, worldName);
|
||||
if (!world.exists())
|
||||
copyWorld(node, new File(directory, "Bauwelt").getPath(), world.getPath());
|
||||
};
|
||||
|
||||
// Send players to existing server
|
||||
startCondition = () -> {
|
||||
Bauserver subserver = Bauserver.get(owner);
|
||||
if(subserver != null) {
|
||||
for(Player p : playersToSend)
|
||||
SubserverSystem.sendPlayer(subserver, p);
|
||||
return false;
|
||||
}
|
||||
boolean atLeastOneSupervisor = playersToSend.stream().anyMatch(player -> {
|
||||
if (player.getUniqueId().equals(owner)) return true;
|
||||
BauweltMember bauweltMember = BauweltMember.getBauMember(owner, player.getUniqueId());
|
||||
return bauweltMember.isSupervisor();
|
||||
});
|
||||
if (!atLeastOneSupervisor) {
|
||||
for (Player p : playersToSend) {
|
||||
Chatter.of(p).system("BAU_START_NOT_ALLOWED");
|
||||
}
|
||||
}
|
||||
return atLeastOneSupervisor;
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerStarter tutorial(Player owner, Tutorial tutorial) {
|
||||
directory = new File(SERVER_PATH, "Tutorial");
|
||||
buildWithTemp(owner);
|
||||
tempWorld(TUTORIAL_PATH + tutorial.getTutorialId());
|
||||
arguments.put("tutorial", String.valueOf(tutorial.getTutorialId()));
|
||||
return send(owner);
|
||||
}
|
||||
|
||||
private void tempWorld(String template) {
|
||||
worldDir = TEMP_WORLD_PATH;
|
||||
worldSetup = () -> copyWorld(node, template, worldDir + worldName);
|
||||
worldCleanup = () -> SubserverSystem.deleteFolder(node, worldDir + worldName);
|
||||
}
|
||||
|
||||
private void buildWithTemp(Player owner) {
|
||||
build(owner.getUniqueId());
|
||||
|
||||
// Stop existing build server
|
||||
startCondition = () -> {
|
||||
if(startingBau(owner))
|
||||
return false;
|
||||
|
||||
Bauserver subserver = Bauserver.get(owner.getUniqueId());
|
||||
if(subserver != null && subserver.isStarted())
|
||||
subserver.stop();
|
||||
|
||||
return !startingBau(owner);
|
||||
};
|
||||
}
|
||||
|
||||
private void build(UUID owner) {
|
||||
constructor = (serverName, port, builder, shutdownCallback, failureCallback) -> new Bauserver(serverName, owner, port, builder, shutdownCallback, failureCallback);
|
||||
serverNameProvider = port -> bauServerName(SteamwarUser.get(owner));
|
||||
}
|
||||
|
||||
public ServerStarter builder(ServerVersion version, String map, File generator) {
|
||||
serverJar = version.getServerJar();
|
||||
directory = version.getServerDirectory("Builder");
|
||||
worldDir = version.getWorldFolder(BUILDER_BASE_PATH);
|
||||
worldName = map;
|
||||
serverNameProvider = port -> "*" + map;
|
||||
checkpoint = true;
|
||||
constructor = (serverName, port, builder, shutdownCallback, failureCallback) -> new Builderserver(serverName, worldName, port, builder, shutdownCallback, failureCallback);
|
||||
|
||||
// Send players to existing server
|
||||
startCondition = () -> {
|
||||
Builderserver subserver = Builderserver.get(worldName);
|
||||
if (subserver != null) {
|
||||
for(Player p : playersToSend)
|
||||
SubserverSystem.sendPlayer(subserver, p);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if(generator != null) {
|
||||
worldSetup = () -> {
|
||||
File leveldat = new File(new File(worldDir, worldName), "level.dat");
|
||||
try {
|
||||
Files.copy(generator.toPath(), leveldat.toPath());
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerStarter send(Player player) {
|
||||
playersToSend.add(player);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerStarter callback(Consumer<Subserver> callback) {
|
||||
this.callback = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean start() {
|
||||
if(!startCondition.getAsBoolean())
|
||||
return false;
|
||||
|
||||
int port = portrange.freePort();
|
||||
String serverName = serverNameProvider.apply(port);
|
||||
|
||||
if(node == null) {
|
||||
node = Node.getNode();
|
||||
if(node == null) {
|
||||
for (Player p : playersToSend)
|
||||
Chatter.of(p).system("SERVER_START_OVERLOAD");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(worldName == null)
|
||||
worldName = serverToWorldName(serverName);
|
||||
|
||||
worldSetup.run();
|
||||
arguments.put("logPath", worldName);
|
||||
|
||||
File checkpointDir = new File("/tmp/" + System.getProperty("user.name") + ".checkpoints/" + directory.getName() + "/" + worldName);
|
||||
if(checkpoint)
|
||||
arguments.put("checkpoint", checkpointDir.getPath());
|
||||
|
||||
if(checkpoint && checkpointDir.exists()) {
|
||||
try(DataOutputStream out = new DataOutputStream(Files.newOutputStream(new File(checkpointDir, "port").toPath()))) {
|
||||
out.writeInt(port);
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException(e);
|
||||
}
|
||||
|
||||
postStart(constructor.construct(serverName, port, node.prepareExecution(
|
||||
"criu", "restore", "-D", checkpointDir.getPath(), "--auto-dedup", "--shell-job", "-v"
|
||||
), worldCleanup, e -> regularStart(serverName, port)));
|
||||
} else {
|
||||
regularStart(serverName, port);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void regularStart(String serverName, int port) {
|
||||
postStart(constructor.construct(serverName, port, node.startServer(
|
||||
serverJar, directory, worldDir, worldName, port, xmx, arguments.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).toArray(String[]::new)
|
||||
), worldCleanup, null));
|
||||
}
|
||||
|
||||
private void postStart(Subserver subserver) {
|
||||
for(Player p : playersToSend)
|
||||
SubserverSystem.sendPlayer(subserver, p);
|
||||
|
||||
callback.accept(subserver);
|
||||
}
|
||||
|
||||
private static boolean startingBau(Player p) {
|
||||
Bauserver subserver = Bauserver.get(p.getUniqueId());
|
||||
if(subserver != null && !subserver.isStarted()) {
|
||||
Chatter.of(p).system("BAU_START_ALREADY");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String bauServerName(SteamwarUser user) {
|
||||
return user.getUserName() + "s Bau";
|
||||
}
|
||||
|
||||
public static String serverToWorldName(String serverName) {
|
||||
return serverName.replace(' ', '_').replace("[", "").replace("]", "");
|
||||
}
|
||||
|
||||
public static void copyWorld(Node node, String template, String target) {
|
||||
node.execute("cp", "-r", template, target);
|
||||
}
|
||||
|
||||
private interface ServerConstructor {
|
||||
Subserver construct(String serverName, int port, ProcessBuilder builder, Runnable shutdownCallback, Consumer<Exception> failureCallback);
|
||||
}
|
||||
|
||||
private static class Portrange {
|
||||
|
||||
private final int start;
|
||||
private final int end;
|
||||
private int current;
|
||||
|
||||
private Portrange(int start, int end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
current = start;
|
||||
}
|
||||
|
||||
private void increment() {
|
||||
current++;
|
||||
|
||||
if(current == end)
|
||||
current = start;
|
||||
}
|
||||
|
||||
private synchronized int freePort() {
|
||||
Set<Integer> usedPorts;
|
||||
|
||||
synchronized (Subserver.getServerList()) {
|
||||
usedPorts = Subserver.getServerList().stream().map(server -> server.getServer().getAddress().getPort()).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
while(usedPorts.contains(current)) {
|
||||
increment();
|
||||
}
|
||||
|
||||
int result = current;
|
||||
increment();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
87
VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java
Normal file
87
VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@Getter
|
||||
public enum ServerVersion {
|
||||
SPIGOT_12("spigot-1.12.2.jar", 12),
|
||||
SPIGOT_15("spigot-1.15.2.jar", 15),
|
||||
PAPER_19("paper-1.19.3.jar", 19),
|
||||
PAPER_20("paper-1.20.1.jar", 20);
|
||||
|
||||
private static final Map<String, ServerVersion> chatMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
chatMap.put("20", ServerVersion.PAPER_20);
|
||||
chatMap.put("1.20", ServerVersion.PAPER_20);
|
||||
chatMap.put("1.20.1", ServerVersion.PAPER_20);
|
||||
chatMap.put("as", ServerVersion.PAPER_20);
|
||||
chatMap.put("airship", ServerVersion.PAPER_20);
|
||||
chatMap.put("wg", ServerVersion.PAPER_20);
|
||||
chatMap.put("wargear", ServerVersion.PAPER_20);
|
||||
chatMap.put("ws", ServerVersion.PAPER_20);
|
||||
chatMap.put("warship", ServerVersion.PAPER_20);
|
||||
chatMap.put("mwg", ServerVersion.PAPER_20);
|
||||
chatMap.put("miniwargear", ServerVersion.PAPER_20);
|
||||
|
||||
chatMap.put("19", ServerVersion.PAPER_19);
|
||||
chatMap.put("1.19", ServerVersion.PAPER_19);
|
||||
chatMap.put("1.19.2", ServerVersion.PAPER_19);
|
||||
|
||||
chatMap.put("15", ServerVersion.SPIGOT_15);
|
||||
chatMap.put("1.15", ServerVersion.SPIGOT_15);
|
||||
chatMap.put("1.15.2", ServerVersion.SPIGOT_15);
|
||||
|
||||
chatMap.put("12", ServerVersion.SPIGOT_12);
|
||||
chatMap.put("1.12", ServerVersion.SPIGOT_12);
|
||||
chatMap.put("1.12.2", ServerVersion.SPIGOT_12);
|
||||
}
|
||||
|
||||
public static ServerVersion get(String chat) {
|
||||
return chatMap.get(chat.toLowerCase());
|
||||
}
|
||||
|
||||
public static Set<String> chatVersions() {
|
||||
return chatMap.keySet();
|
||||
}
|
||||
|
||||
private final String serverJar;
|
||||
private final int versionSuffix;
|
||||
|
||||
ServerVersion(String serverJar, int versionSuffix) {
|
||||
this.serverJar = serverJar;
|
||||
this.versionSuffix = versionSuffix;
|
||||
}
|
||||
|
||||
public String getWorldFolder(String base) {
|
||||
return base + versionSuffix + "/";
|
||||
}
|
||||
|
||||
public File getServerDirectory(String base) {
|
||||
return new File(ServerStarter.SERVER_PATH, base + versionSuffix);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.steamwar.velocitycore.network.NetworkSender;
|
||||
import de.steamwar.velocitycore.network.handlers.FightInfoHandler;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.network.packets.server.StartingServerPacket;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.sql.IgnoreSystem;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SubserverSystem {
|
||||
private SubserverSystem(){}
|
||||
|
||||
public static void deleteFolder(Node node, String worldName) {
|
||||
node.execute("rm", "-r", worldName);
|
||||
}
|
||||
|
||||
public static void sendDeniedMessage(Chatter p, UUID owner) {
|
||||
if(IgnoreSystem.isIgnored(owner, p.user().getUUID())){
|
||||
p.system("SERVER_IGNORED");
|
||||
return;
|
||||
}
|
||||
|
||||
Chatter o = Chatter.of(owner);
|
||||
o.system("SERVER_ADD_MEMBER", p);
|
||||
o.prefixless("SERVER_ADD_MESSAGE", new Message("SERVER_ADD_MESSAGE_HOVER"), ClickEvent.runCommand("/bau addmember " + p.user().getUserName()));
|
||||
}
|
||||
|
||||
public static void sendPlayer(Subserver subserver, Player player) {
|
||||
subserver.sendPlayer(player);
|
||||
if(!subserver.isStarted() && FightInfoHandler.onLobby(player))
|
||||
NetworkSender.send(player, new StartingServerPacket(SteamwarUser.get(player.getUniqueId()).getId()));
|
||||
}
|
||||
}
|
||||
282
VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java
Normal file
282
VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
||||
import com.velocitypowered.api.plugin.Dependency;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import com.velocitypowered.api.scheduler.Scheduler;
|
||||
import de.steamwar.command.*;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.network.packets.PacketHandler;
|
||||
import de.steamwar.persistent.ReloadablePlugin;
|
||||
import de.steamwar.sql.Punishment;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.Team;
|
||||
import de.steamwar.sql.UserElo;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import de.steamwar.velocitycore.commands.*;
|
||||
import de.steamwar.velocitycore.discord.DiscordBot;
|
||||
import de.steamwar.velocitycore.discord.DiscordConfig;
|
||||
import de.steamwar.velocitycore.listeners.*;
|
||||
import de.steamwar.velocitycore.mods.*;
|
||||
import de.steamwar.velocitycore.network.handlers.*;
|
||||
import de.steamwar.velocitycore.tablist.TablistManager;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Plugin(
|
||||
id = "velocitycore",
|
||||
name = "VelocityCore",
|
||||
dependencies = { @Dependency(id = "persistentvelocitycore") }
|
||||
)
|
||||
public class VelocityCore implements ReloadablePlugin {
|
||||
|
||||
public static boolean MAIN_SERVER;
|
||||
|
||||
private static VelocityCore instance;
|
||||
public static VelocityCore get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static Node local;
|
||||
|
||||
public static Scheduler.TaskBuilder schedule(Runnable runnable) {
|
||||
return instance.proxyServer.getScheduler().buildTask(instance, runnable);
|
||||
}
|
||||
|
||||
public static ProxyServer getProxy() {
|
||||
return instance.proxyServer;
|
||||
}
|
||||
|
||||
public static Logger getLogger() {
|
||||
return instance.logger;
|
||||
}
|
||||
|
||||
private final ProxyServer proxyServer;
|
||||
private final Logger logger;
|
||||
@Getter
|
||||
private final Path dataDirectory;
|
||||
|
||||
private Driver sqlDriver;
|
||||
@Getter
|
||||
private Config config;
|
||||
private ErrorLogger errorLogger;
|
||||
private TablistManager tablistManager;
|
||||
|
||||
@Getter
|
||||
private TeamCommand teamCommand;
|
||||
|
||||
@Inject
|
||||
public VelocityCore(ProxyServer proxyServer, Logger logger, @DataDirectory Path dataDirectory) {
|
||||
this.proxyServer = proxyServer;
|
||||
this.logger = logger;
|
||||
this.dataDirectory = dataDirectory;
|
||||
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@Override
|
||||
public void onProxyInitialization(ProxyInitializeEvent event) {
|
||||
instance = this;
|
||||
config = Config.load();
|
||||
MAIN_SERVER = proxyServer.getBoundAddress().getPort() == 25565;
|
||||
|
||||
try {
|
||||
sqlDriver = Statement.mysqlMode() ? new com.mysql.cj.jdbc.Driver() : new org.sqlite.JDBC();
|
||||
DriverManager.registerDriver(sqlDriver);
|
||||
} catch (SQLException e) {
|
||||
throw new SecurityException(e);
|
||||
}
|
||||
|
||||
errorLogger = new ErrorLogger();
|
||||
|
||||
SWCommandUtils.init((SWTypeMapperCreator<TypeMapper<Object>, Chatter, Object>) (mapper, tabCompleter) -> new TypeMapper<>() {
|
||||
@Override
|
||||
public Object map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return mapper.apply(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return tabCompleter.apply(sender, s);
|
||||
}
|
||||
});
|
||||
schedule(TabCompletionCache::invalidateOldEntries).repeat(1, TimeUnit.SECONDS).schedule();
|
||||
|
||||
initStaticServers();
|
||||
PollSystem.init();
|
||||
|
||||
new Hostname();
|
||||
new PluginMessage();
|
||||
new Schematica();
|
||||
new Badlion();
|
||||
new FabricModSender();
|
||||
new ReplayMod();
|
||||
new FML2();
|
||||
|
||||
new ConnectionListener();
|
||||
new ChatListener();
|
||||
new BanListener();
|
||||
new CheckListener();
|
||||
new IPSanitizer();
|
||||
|
||||
local = new Node.LocalNode();
|
||||
if(MAIN_SERVER) {
|
||||
//new Node.RemoteNode("lx");
|
||||
}
|
||||
|
||||
new TeamchatCommand();
|
||||
new MsgCommand();
|
||||
new RCommand();
|
||||
new PingCommand();
|
||||
new AlertCommand();
|
||||
new KickCommand();
|
||||
new JoinmeCommand();
|
||||
new TpCommand();
|
||||
HelpCommand helpCommand = new HelpCommand();
|
||||
teamCommand = new TeamCommand();
|
||||
new ServerTeamchatCommand();
|
||||
new DevCommand();
|
||||
new EventCommand();
|
||||
new EventreloadCommand();
|
||||
new EventRescheduleCommand();
|
||||
new PollCommand();
|
||||
new BugCommand();
|
||||
new WhoisCommand();
|
||||
new RulesCommand();
|
||||
new IgnoreCommand();
|
||||
new UnIgnoreCommand();
|
||||
new PollresultCommand();
|
||||
new ListCommand();
|
||||
new StatCommand();
|
||||
new VerifyCommand();
|
||||
new GDPRQuery();
|
||||
new PlaytimeCommand();
|
||||
new ArenaCommand();
|
||||
new RankCommand();
|
||||
new LocalCommand();
|
||||
new SetLocaleCommand();
|
||||
new BuilderCloudCommand();
|
||||
new CheckCommand();
|
||||
|
||||
new ModCommand();
|
||||
|
||||
// Punishment Commands:
|
||||
new PunishmentCommand("ban", Punishment.PunishmentType.Ban);
|
||||
new PunishmentCommand("mute", Punishment.PunishmentType.Mute);
|
||||
new PunishmentCommand("noschemreceiving", Punishment.PunishmentType.NoSchemReceiving);
|
||||
new PunishmentCommand("noschemsharing", Punishment.PunishmentType.NoSchemSharing);
|
||||
new PunishmentCommand("noschemsubmitting", Punishment.PunishmentType.NoSchemSubmitting);
|
||||
new PunishmentCommand("nodev", Punishment.PunishmentType.NoDevServer);
|
||||
new PunishmentCommand("nofight", Punishment.PunishmentType.NoFightServer);
|
||||
new PunishmentCommand("noteamserver", Punishment.PunishmentType.NoTeamServer);
|
||||
new PunishmentCommand("note", Punishment.PunishmentType.Note);
|
||||
|
||||
if(!config.isEventmode()){
|
||||
new BauCommand(helpCommand);
|
||||
new WebpasswordCommand();
|
||||
new FightCommand();
|
||||
new ChallengeCommand();
|
||||
new HistoricCommand();
|
||||
new ReplayCommand();
|
||||
new TutorialCommand();
|
||||
|
||||
new Broadcaster();
|
||||
}else{
|
||||
new EventModeListener();
|
||||
}
|
||||
|
||||
for(PacketHandler handler : new PacketHandler[] {
|
||||
new EloPlayerHandler(), new EloSchemHandler(), new ExecuteCommandHandler(), new FightInfoHandler(),
|
||||
new ImALobbyHandler(), new InventoryCallbackHandler(), new PrepareSchemHandler()
|
||||
})
|
||||
handler.register();
|
||||
|
||||
new EventStarter();
|
||||
new SessionManager();
|
||||
tablistManager = new TablistManager();
|
||||
new SettingsChangedListener();
|
||||
|
||||
schedule(() -> {
|
||||
SteamwarUser.clear();
|
||||
UserElo.clear();
|
||||
Team.clear();
|
||||
}).repeat(1, TimeUnit.HOURS).schedule();
|
||||
|
||||
DiscordConfig discordConfig = DiscordConfig.load();
|
||||
if (discordConfig != null) {
|
||||
try {
|
||||
new DiscordBot(discordConfig);
|
||||
} catch (Throwable e) {
|
||||
logger.log(Level.SEVERE, "Could not initialize discord bot", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@Override
|
||||
public void onProxyShutdown(ProxyShutdownEvent event) {
|
||||
try {
|
||||
DiscordBot.withBot(bot -> bot.getJda().shutdownNow());
|
||||
} catch (Throwable e) {
|
||||
logger.log(Level.SEVERE, "Could not shutdown discord bot", e);
|
||||
}
|
||||
|
||||
if(tablistManager != null)
|
||||
tablistManager.disable();
|
||||
errorLogger.unregister();
|
||||
Statement.closeAll();
|
||||
|
||||
try {
|
||||
DriverManager.deregisterDriver(sqlDriver);
|
||||
} catch (SQLException e) {
|
||||
throw new SecurityException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void initStaticServers() {
|
||||
for (Map.Entry<String, Config.Server> entry : config.getServers().entrySet()) {
|
||||
Config.Server server = entry.getValue();
|
||||
List<String> cmds = server.getCommands();
|
||||
String cmd = cmds.remove(0);
|
||||
|
||||
if(server.getSpectatePort() != 0)
|
||||
EventStarter.addSpectateServer(server.getSpectatePort(), cmd);
|
||||
|
||||
new ServerSwitchCommand(cmd, entry.getKey(), cmds.toArray(new String[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.discord.DiscordBot;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
|
||||
public class AlertCommand extends SWCommand {
|
||||
|
||||
public AlertCommand() {
|
||||
super("alert", UserPerm.MODERATION, "broadcast", "bbc");
|
||||
}
|
||||
|
||||
@Register(description = "USAGE_ALERT")
|
||||
public void broadcast(Chatter sender, @OptionalValue("") @StaticValue("-discord") String sendToDiscord, String... message) {
|
||||
if (message.length == 0) {
|
||||
sender.system("USAGE_ALERT");
|
||||
return;
|
||||
}
|
||||
|
||||
String s = String.join(" ", message);
|
||||
Chatter.broadcast().system("ALERT", s.replace('&', '§'));
|
||||
|
||||
if ("-discord".equals(sendToDiscord))
|
||||
DiscordBot.withBot(bot -> bot.getAnnouncementChannel().send(s));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import de.steamwar.persistent.Servertype;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.command.PreviousArguments;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ArenaCommand extends SWCommand {
|
||||
|
||||
public ArenaCommand() {
|
||||
super("arena");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void arenaJoin(PlayerChatter sender, Subserver server) {
|
||||
TpCommand.teleport(sender, server.getRegisteredServer());
|
||||
}
|
||||
|
||||
@ClassMapper(value = Subserver.class, local = true)
|
||||
public TypeMapper<Subserver> serverInfoTypeMapper() {
|
||||
return new TypeMapper<>() {
|
||||
@Override
|
||||
public Subserver map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return Subserver.getSubserver(VelocityCore.getProxy().getServer(s).map(RegisteredServer::getServerInfo).orElse(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(Chatter sender, Subserver value, MessageSender messageSender) {
|
||||
if (value == null || value.getType() != Servertype.ARENA) {
|
||||
sender.system("ARENA_NOT_FOUND");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
List<Subserver> subserverList = Subserver.getServerList();
|
||||
synchronized (subserverList) {
|
||||
return subserverList.stream().filter(subserver -> subserver.getType() == Servertype.ARENA).map(subserver -> subserver.getServer().getName()).toList();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.*;
|
||||
import de.steamwar.velocitycore.inventory.SWInventory;
|
||||
import de.steamwar.velocitycore.inventory.SWItem;
|
||||
import de.steamwar.velocitycore.network.NetworkSender;
|
||||
import de.steamwar.velocitycore.util.BauLock;
|
||||
import de.steamwar.velocitycore.util.BauLockState;
|
||||
import de.steamwar.command.PreviousArguments;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
import de.steamwar.command.TypeValidator;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.network.packets.server.BaumemberUpdatePacket;
|
||||
import de.steamwar.persistent.Bauserver;
|
||||
import de.steamwar.sql.BauweltMember;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class BauCommand extends SWCommand {
|
||||
|
||||
private final HelpCommand command;
|
||||
|
||||
public BauCommand(HelpCommand command) {
|
||||
super("bau", "b", "build", "gs");
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
@Register(noTabComplete = true)
|
||||
public void genericHelp(Chatter sender, String... args) {
|
||||
this.command.sendBauHelp(sender);
|
||||
}
|
||||
|
||||
@Register
|
||||
public void toBau(PlayerChatter sender, @OptionalValue(value = "", onlyUINIG = true) ServerVersion version) {
|
||||
new ServerStarter().build(version, sender.user().getUUID()).send(sender.getPlayer()).start();
|
||||
}
|
||||
|
||||
@Register(value = "addmember", description = "BAU_ADDMEMBER_USAGE")
|
||||
public void addmember(Chatter sender, @Validator("addMemberTarget") SteamwarUser target) {
|
||||
BauweltMember.addMember(sender.user().getUUID(), target.getUUID());
|
||||
sender.system("BAU_ADDMEMBER_ADDED");
|
||||
Chatter.of(target.getUUID()).system("BAU_ADDMEMBER_ADDED_TARGET", sender);
|
||||
}
|
||||
|
||||
@Validator(value = "addMemberTarget", local = true)
|
||||
public TypeValidator<SteamwarUser> addMemberTargetValidator() {
|
||||
return (sender, value, messageSender) -> {
|
||||
if (value == null) {
|
||||
messageSender.send("UNKNOWN_PLAYER");
|
||||
return false;
|
||||
}
|
||||
if (sender.user().getUUID().equals(value.getUUID())) {
|
||||
messageSender.send("BAU_ADDMEMBER_SELFADD");
|
||||
return false;
|
||||
}
|
||||
if (BauweltMember.getBauMember(sender.user().getId(), value.getId()) != null) {
|
||||
messageSender.send("BAU_ADDMEMBER_ISADDED");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
@Register(value = "tp", description = "BAU_TP_USAGE")
|
||||
@Register("teleport")
|
||||
public void teleport(PlayerChatter sender, @Validator("teleportTarget") SteamwarUser worldOwner, @OptionalValue(value = "", onlyUINIG = true) ServerVersion version) {
|
||||
new ServerStarter().build(version, worldOwner.getUUID()).send(sender.getPlayer()).start();
|
||||
}
|
||||
|
||||
@Validator(value = "teleportTarget", local = true)
|
||||
public TypeValidator<SteamwarUser> teleportTargetValidator() {
|
||||
return (sender, owner, messageSender) -> {
|
||||
if (owner == null) {
|
||||
messageSender.send("UNKNOWN_PLAYER");
|
||||
return false;
|
||||
}
|
||||
if (sender.user().getId() != owner.getId() && BauweltMember.getBauMember(owner.getId(), sender.user().getId()) == null) {
|
||||
SubserverSystem.sendDeniedMessage(sender, owner.getUUID());
|
||||
messageSender.send("BAU_TP_NOALLOWED");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (BauLock.isLocked(owner, sender.user())) {
|
||||
messageSender.send("BAU_LOCKED_NOALLOWED");
|
||||
Chatter.of(owner.getUUID()).system("BAU_LOCK_BLOCKED", sender);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
@Register("info")
|
||||
public void info(PlayerChatter sender) {
|
||||
sender.getPlayer().spoofChatInput("/bauinfo");
|
||||
}
|
||||
|
||||
@Register("setspectator")
|
||||
public void setSpectator(Chatter sender, @Mapper("addedUsers") @AllowNull @OptionalValue("") SteamwarUser user) {
|
||||
setPerms(sender, user, "setspectator", "BAU_MEMBER_SET_SPECTATOR", member -> {
|
||||
member.setBuild(false);
|
||||
member.setSupervisor(false);
|
||||
});
|
||||
}
|
||||
|
||||
@Register("setbuild")
|
||||
public void setBuild(Chatter sender, @Mapper("addedUsers") @AllowNull @OptionalValue("") SteamwarUser user) {
|
||||
setPerms(sender, user, "setbuild", "BAU_MEMBER_SET_BUILDER", member -> {
|
||||
member.setBuild(true);
|
||||
member.setSupervisor(false);
|
||||
});
|
||||
}
|
||||
|
||||
@Register("setsupervisor")
|
||||
public void setSupervisor(Chatter sender, @Mapper("addedUsers") @AllowNull @OptionalValue("") SteamwarUser user) {
|
||||
setPerms(sender, user, "setsupervisor", "BAU_MEMBER_SET_SUPERVISOR", member -> {
|
||||
member.setBuild(true);
|
||||
member.setSupervisor(true);
|
||||
});
|
||||
}
|
||||
|
||||
private void setPerms(Chatter owner, SteamwarUser user, String name, String permName, Consumer<BauweltMember> setter) {
|
||||
if (user == null) {
|
||||
owner.system("BAU_MEMBER_SET_USAGE", name);
|
||||
return;
|
||||
}
|
||||
|
||||
withMember(owner, user, target -> {
|
||||
setter.accept(target);
|
||||
|
||||
Bauserver bauserver = Bauserver.get(owner.user().getUUID());
|
||||
if(bauserver != null)
|
||||
bauserver.getRegisteredServer().getPlayersConnected().stream().findAny().ifPresent(player -> NetworkSender.send(player, new BaumemberUpdatePacket()));
|
||||
|
||||
Chatter.of(user.getUUID()).system("BAU_MEMBER_SET_TARGET", owner, new Message(permName));
|
||||
owner.system("BAU_MEMBER_SET", new Message(permName));
|
||||
});
|
||||
}
|
||||
|
||||
@Register(value = "delmember", description = "BAU_DELMEMBER_USAGE")
|
||||
public void delmember(Chatter owner, @Mapper("addedUsers") SteamwarUser user) {
|
||||
withMember(owner, user, target -> {
|
||||
target.remove();
|
||||
|
||||
Chatter member = Chatter.of(user.getUUID());
|
||||
member.system("BAU_DELMEMBER_DELETED_TARGET", owner);
|
||||
member.withPlayer(player -> {
|
||||
Bauserver bauserver = Bauserver.get(owner.user().getUUID());
|
||||
if (bauserver != null && bauserver.getRegisteredServer().getPlayersConnected().contains(player))
|
||||
player.createConnectionRequest(VelocityCore.get().getConfig().lobbyserver()).fireAndForget();
|
||||
});
|
||||
|
||||
owner.system("BAU_DELMEMBER_DELETED");
|
||||
});
|
||||
}
|
||||
|
||||
@Mapper(value = "addedUsers", local = true)
|
||||
public TypeMapper<SteamwarUser> addedUsers() {
|
||||
return new TypeMapper<SteamwarUser>() {
|
||||
@Override
|
||||
public SteamwarUser map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return SteamwarUser.get(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return BauweltMember.getMembers(sender.user().getId()).stream()
|
||||
.map(bauweltMember -> SteamwarUser.get(bauweltMember.getMemberID()).getUserName())
|
||||
.toList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Register("resetall")
|
||||
@Register("delete")
|
||||
public void delete(PlayerChatter sender, @OptionalValue(value = "", onlyUINIG = true) ServerVersion version) {
|
||||
SWInventory inventory = new SWInventory(sender, 9, new Message("BAU_DELETE_GUI_NAME"));
|
||||
inventory.addItem(0, new SWItem(new Message("BAU_DELETE_GUI_DELETE"), 10), click -> {
|
||||
String world = version.getWorldFolder(ServerStarter.WORLDS_BASE_PATH) + (version != ServerVersion.SPIGOT_12 ? sender.user().getId() : sender.user().getUUID().toString());
|
||||
|
||||
VelocityCore.schedule(() -> {
|
||||
Bauserver subserver = Bauserver.get(sender.user().getUUID());
|
||||
if(subserver != null)
|
||||
subserver.stop();
|
||||
|
||||
SubserverSystem.deleteFolder(VelocityCore.local, world);
|
||||
sender.system("BAU_DELETE_DELETED");
|
||||
}).schedule();
|
||||
|
||||
inventory.close();
|
||||
});
|
||||
inventory.addItem(8, new SWItem(new Message("BAU_DELETE_GUI_CANCEL"), 1), click -> inventory.close());
|
||||
inventory.open();
|
||||
}
|
||||
|
||||
@Register("test")
|
||||
@Register("testarena")
|
||||
public void testarena(PlayerChatter sender, @Mapper("nonHistoricArenaMode") @OptionalValue("") @AllowNull ArenaMode arenaMode, @Mapper("arenaMap") @OptionalValue("") @AllowNull String map) {
|
||||
FightCommand.createArena(sender, "/bau testarena ", false, arenaMode, map, false, (chatter, mode, m) ->
|
||||
VelocityCore.schedule(() -> new ServerStarter().test(mode, m, sender.getPlayer()).start()).schedule()
|
||||
);
|
||||
}
|
||||
|
||||
@Register(value = "lock", description = "BAU_LOCKED_OPTIONS")
|
||||
public void lock(Chatter sender, BauLockState bauLockState) {
|
||||
BauLock.setLocked(sender, bauLockState);
|
||||
}
|
||||
|
||||
@Register("unlock")
|
||||
public void unlock(Chatter sender) {
|
||||
BauLock.setLocked(sender, BauLockState.OPEN);
|
||||
}
|
||||
|
||||
private static void withMember(Chatter owner, SteamwarUser member, Consumer<BauweltMember> function) {
|
||||
if (member == null) {
|
||||
owner.system("UNKNOWN_PLAYER");
|
||||
return;
|
||||
}
|
||||
|
||||
BauweltMember target = BauweltMember.getBauMember(owner.user().getId(), member.getId());
|
||||
if (target == null) {
|
||||
owner.system("BAU_MEMBER_NOMEMBER");
|
||||
return;
|
||||
}
|
||||
|
||||
function.accept(target);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.sql.SWException;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
|
||||
public class BugCommand extends SWCommand {
|
||||
public BugCommand() {
|
||||
super("bug");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void bugMessage(Chatter sender, String... message) {
|
||||
int id = SWException.logGetId(
|
||||
String.join(" ", message),
|
||||
sender.withPlayerOrOffline(player -> player.getCurrentServer().map(connection -> connection.getServerInfo().getName()).orElse("offline"), () -> "offline") + " " + sender.user().getUserName() + " " + sender.user().getId()
|
||||
);
|
||||
sender.system("BUG_MESSAGE", id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.ArenaMode;
|
||||
import de.steamwar.velocitycore.ServerStarter;
|
||||
import de.steamwar.velocitycore.ServerVersion;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.command.PreviousArguments;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public class BuilderCloudCommand extends SWCommand {
|
||||
|
||||
public BuilderCloudCommand() {
|
||||
super("buildercloud", UserPerm.BUILD, "builder");
|
||||
}
|
||||
|
||||
@Register(value = "create", description = "BUILDERCLOUD_CREATE_USAGE")
|
||||
public void create(Chatter sender, @ErrorMessage("BUILDERCLOUD_VERSION") ServerVersion version, @Mapper("map") String map, @OptionalValue("") @Mapper("generator") @AllowNull File generator) {
|
||||
mapFile(version, map).mkdir();
|
||||
sender.withPlayer(p -> new ServerStarter().builder(version, map, generator).send(p).start());
|
||||
}
|
||||
|
||||
@Register(description = "BUILDERCLOUD_USAGE")
|
||||
public void start(PlayerChatter sender, @ErrorMessage("BUILDERCLOUD_VERSION") ServerVersion version, @Mapper("map") String map) {
|
||||
if(!mapFile(version, map).exists()) {
|
||||
sender.system("BUILDERCLOUD_UNKNOWN_MAP");
|
||||
return;
|
||||
}
|
||||
|
||||
new ServerStarter().builder(version, map, null).send(sender.getPlayer()).start();
|
||||
}
|
||||
|
||||
@Register(value = "rename", description = "BUILDERCLOUD_RENAME_USAGE")
|
||||
public void rename(Chatter sender, @ErrorMessage("BUILDERCLOUD_VERSION") ServerVersion version, @Mapper("map") String oldName, String newName) {
|
||||
File oldMap = mapFile(version, oldName);
|
||||
if(!oldMap.exists()) {
|
||||
sender.system("BUILDERCLOUD_UNKNOWN_MAP");
|
||||
return;
|
||||
}
|
||||
|
||||
File newMap = mapFile(version, newName);
|
||||
if(newMap.exists()) {
|
||||
sender.system("BUILDERCLOUD_EXISTING_MAP");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Files.move(oldMap.toPath(), newMap.toPath());
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException(e);
|
||||
}
|
||||
|
||||
sender.system("BUILDERCLOUD_RENAMED");
|
||||
}
|
||||
|
||||
@Register(value = "deploy", description = "BUILDERCLOUD_DEPLOY_USAGE")
|
||||
public void deploy(Chatter sender, @Mapper("nonHistoricArenaMode") ArenaMode arenaMode, @ErrorMessage("BUILDERCLOUD_VERSION") ServerVersion version, @Mapper("map") String map) {
|
||||
if(!mapFile(version, map).exists()) {
|
||||
sender.system("BUILDERCLOUD_UNKNOWN_MAP");
|
||||
return;
|
||||
}
|
||||
|
||||
VelocityCore.schedule(() -> {
|
||||
VelocityCore.local.execute("/binarys/deployarena.py", arenaMode.getConfig(), Integer.toString(version.getVersionSuffix()), map);
|
||||
ArenaMode.init();
|
||||
sender.system("BUILDERCLOUD_DEPLOY_FINISHED");
|
||||
}).schedule();
|
||||
}
|
||||
|
||||
@Cached(global = true)
|
||||
@Mapper(value = "map", local = true)
|
||||
private TypeMapper<String> mapTypeMapper() {
|
||||
|
||||
return new TypeMapper<String>() {
|
||||
@Override
|
||||
public String map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
File folder = getWorldFolder(previousArguments, 1);
|
||||
|
||||
String[] files;
|
||||
if(folder == null || (files = folder.list()) == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
return Arrays.stream(files).filter(file -> new File(folder, file).isDirectory()).filter(file -> s.startsWith(".") || !file.startsWith(".")).toList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Cached(global = true)
|
||||
@Mapper(value = "generator", local = true)
|
||||
private TypeMapper<File> generatorTypeMapper() {
|
||||
|
||||
return new TypeMapper<File>() {
|
||||
@Override
|
||||
public File map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
if(s.isEmpty())
|
||||
return null;
|
||||
|
||||
File folder = getWorldFolder(previousArguments, 2);
|
||||
|
||||
if(folder == null)
|
||||
throw new SecurityException();
|
||||
|
||||
File generator = new File(folder, s + ".dat");
|
||||
if(!generator.exists() || !generator.isFile())
|
||||
throw new SecurityException();
|
||||
|
||||
return generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
File folder = getWorldFolder(previousArguments, 2);
|
||||
|
||||
String[] files;
|
||||
if(folder == null || (files = folder.list()) == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
return Arrays.stream(files).filter(file -> new File(folder, file).isFile()).filter(file -> file.endsWith(".dat")).map(file -> file.substring(0, file.length() - 4)).toList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private File mapFile(ServerVersion version, String map) {
|
||||
return new File(version.getWorldFolder(ServerStarter.BUILDER_BASE_PATH), map);
|
||||
}
|
||||
|
||||
private File getWorldFolder(PreviousArguments previousArguments, int offset) {
|
||||
ServerVersion v = ServerVersion.get(previousArguments.userArgs[previousArguments.userArgs.length - offset]);
|
||||
if(v == null)
|
||||
return null;
|
||||
return new File(v.getWorldFolder(ServerStarter.BUILDER_BASE_PATH));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.steamwar.velocitycore.ArenaMode;
|
||||
import de.steamwar.velocitycore.ServerStarter;
|
||||
import de.steamwar.persistent.Servertype;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeValidator;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.sql.IgnoreSystem;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import static de.steamwar.persistent.Storage.challenges;
|
||||
|
||||
public class ChallengeCommand extends SWCommand {
|
||||
|
||||
public ChallengeCommand() {
|
||||
super("challenge");
|
||||
}
|
||||
|
||||
@Register(description = "CHALLENGE_USAGE")
|
||||
public void challenge(@Validator("arenaPlayer") PlayerChatter sender, @Validator("target") Player target, @Mapper("nonHistoricArenaMode") @OptionalValue("") @AllowNull ArenaMode arenaMode, @Mapper("arenaMap") @OptionalValue("") @AllowNull String map) {
|
||||
FightCommand.createArena(sender, "/challenge " + target.getUsername() + " ", false, arenaMode, map, false, (chatter, mode, m) -> {
|
||||
Player p = sender.getPlayer();
|
||||
if(challenges.containsKey(target) && challenges.get(target).contains(p)){
|
||||
challenges.remove(target);
|
||||
challenges.remove(p);
|
||||
|
||||
new ServerStarter().arena(mode, map).blueLeader(sender.getPlayer()).redLeader(target).callback(
|
||||
arena -> Chatter.broadcast().system("CHALLENGE_BROADCAST", new Message("CHALLENGE_BROADCAST_HOVER"), ClickEvent.runCommand("/arena " + arena.getServer().getName()), mode.getGameName(), p, target)
|
||||
).start();
|
||||
}else{
|
||||
if(!challenges.containsKey(p)){
|
||||
challenges.put(p, new LinkedList<>());
|
||||
}
|
||||
|
||||
challenges.get(p).add(target);
|
||||
|
||||
sender.system("CHALLENGE_CHALLENGED", target, mode.getGameName());
|
||||
Chatter.of(target).system("CHALLENGE_CHALLENGED_TARGET", p, mode.getGameName(), mode.getMaps().size() != 1 ? new Message("CHALLENGE_CHALLENGED_MAP", m) : "");
|
||||
|
||||
Chatter.of(target).system("CHALLENGE_ACCEPT", new Message("CHALLENGE_ACCEPT_HOVER"), ClickEvent.runCommand("/challenge " + p.getUsername() + " " + mode.getChatName() + " " + m));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Validator(value = "target", local = true)
|
||||
public TypeValidator<Player> targetValidator() {
|
||||
return (sender, value, messageSender) -> {
|
||||
if (value == null) {
|
||||
messageSender.send("CHALLENGE_OFFLINE");
|
||||
return false;
|
||||
}
|
||||
if (sender == value) {
|
||||
messageSender.send("CHALLENGE_SELF");
|
||||
return false;
|
||||
}
|
||||
if (IgnoreSystem.isIgnored(value.getUniqueId(), sender.user().getUUID())) {
|
||||
messageSender.send("CHALLENGE_IGNORED");
|
||||
return false;
|
||||
}
|
||||
|
||||
Subserver subserver = Subserver.getSubserver(value);
|
||||
if (subserver != null && subserver.getType() == Servertype.ARENA) {
|
||||
messageSender.send("CHALLENGE_INARENA");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
public static void remove(Player player){
|
||||
challenges.remove(player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.persistent.Bauserver;
|
||||
import de.steamwar.sql.*;
|
||||
import de.steamwar.velocitycore.ArenaMode;
|
||||
import de.steamwar.velocitycore.ServerStarter;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.discord.DiscordBot;
|
||||
import de.steamwar.velocitycore.discord.util.DiscordAlert;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import java.awt.*;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class CheckCommand extends SWCommand {
|
||||
private static final Map<SchematicType, SchematicType> fightTypes = new HashMap<>();
|
||||
private static final Map<SchematicType, List<String>> checkQuestions = new HashMap<>();
|
||||
|
||||
private static final Map<UUID, CheckSession> currentCheckers = new HashMap<>();
|
||||
private static final Map<Integer, CheckSession> currentSchems = new HashMap<>();
|
||||
|
||||
public static void setCheckQuestions(SchematicType checkType, List<String> checkQuestions) {
|
||||
CheckCommand.checkQuestions.put(checkType, checkQuestions);
|
||||
}
|
||||
|
||||
public static void addFightType(SchematicType checkType, SchematicType fightType) {
|
||||
fightTypes.put(checkType, fightType);
|
||||
}
|
||||
|
||||
public static boolean isChecking(Player player){
|
||||
return currentCheckers.containsKey(player.getUniqueId());
|
||||
}
|
||||
|
||||
public static SchematicNode getCheckingSchem(Player player) {
|
||||
return currentCheckers.get(player.getUniqueId()).schematic;
|
||||
}
|
||||
|
||||
public static Message getWaitTime(SchematicNode schematic) {
|
||||
long waitedMillis = Timestamp.from(Instant.now()).getTime() - schematic.getLastUpdate().getTime();
|
||||
String ce = waitedMillis > 86400000 ? "c" : "e";
|
||||
String color = waitedMillis > 14400000 ? ce : "a";
|
||||
long hours = waitedMillis / 3600000;
|
||||
long minutes = (waitedMillis - hours * 3600000) / 60000;
|
||||
return new Message("CHECK_LIST_WAIT", color, hours, (minutes < 10) ? "0" + minutes : minutes);
|
||||
}
|
||||
|
||||
public CheckCommand() {
|
||||
super("check", UserPerm.CHECK);
|
||||
|
||||
VelocityCore.schedule(() -> sendReminder(Chatter.serverteam())).repeat(10, TimeUnit.MINUTES).schedule();
|
||||
}
|
||||
|
||||
public static void sendReminder(Chatter chatter) {
|
||||
List<SchematicNode> schematics = getSchemsToCheck();
|
||||
if(schematics.size() == currentCheckers.size())
|
||||
return;
|
||||
|
||||
chatter.system("CHECK_REMINDER", new Message("CHECK_REMINDER_HOVER"), ClickEvent.runCommand("/check list"), schematics.size() - currentCheckers.size());
|
||||
}
|
||||
|
||||
@Register(value = "list", description = "CHECK_HELP_LIST")
|
||||
public void list(Chatter sender) {
|
||||
List<SchematicNode> schematicList = getSchemsToCheck();
|
||||
|
||||
sender.system("CHECK_LIST_HEADER", schematicList.size());
|
||||
|
||||
for (SchematicNode schematic : schematicList) {
|
||||
CheckSession current = currentSchems.get(schematic.getId());
|
||||
if (current == null) {
|
||||
sender.prefixless("CHECK_LIST_TO_CHECK",
|
||||
new Message("CHECK_LIST_TO_CHECK_HOVER"),
|
||||
ClickEvent.runCommand("/check schematic " + schematic.getId()),
|
||||
getWaitTime(schematic),
|
||||
schematic.getSchemtype().getKuerzel(), SteamwarUser.get(schematic.getOwner()).getUserName(), schematic.getName());
|
||||
} else {
|
||||
sender.prefixless("CHECK_LIST_CHECKING",
|
||||
new Message("CHECK_LIST_CHECKING_HOVER"),
|
||||
ClickEvent.runCommand("/join " + current.checker.user().getUserName()),
|
||||
getWaitTime(schematic),
|
||||
schematic.getSchemtype().getKuerzel(), SteamwarUser.get(schematic.getOwner()).getUserName(), schematic.getName(), current.checker.user().getUserName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Register(value = "schematic", noTabComplete = true)
|
||||
public void schematic(PlayerChatter sender, String schemID) {
|
||||
if(isChecking(sender.getPlayer())){
|
||||
sender.system("CHECK_SCHEMATIC_ALREADY_CHECKING");
|
||||
return;
|
||||
}
|
||||
|
||||
SchematicNode schem = SchematicNode.getSchematicNode(Integer.parseInt(schemID));
|
||||
if(!schem.getSchemtype().check()){
|
||||
VelocityCore.getLogger().log(Level.SEVERE, () -> sender.user().getUserName() + " tried to check an uncheckable schematic!");
|
||||
return;
|
||||
}else if(schem.getOwner() == sender.user().getId()) {
|
||||
sender.system("CHECK_SCHEMATIC_OWN");
|
||||
return;
|
||||
}
|
||||
|
||||
int playerTeam = sender.user().hasPerm(UserPerm.MODERATION) ? 0 : sender.user().getTeam();
|
||||
if (playerTeam != 0 && SteamwarUser.get(schem.getOwner()).getTeam() == playerTeam) {
|
||||
sender.system("CHECK_SCHEMATIC_OWN_TEAM");
|
||||
return;
|
||||
}
|
||||
new CheckSession(sender, schem);
|
||||
}
|
||||
|
||||
@Register(value = "cancel", description = "CHECK_HELP_CANCEL")
|
||||
@Register("abort")
|
||||
public void abortCommand(PlayerChatter sender) {
|
||||
abort(sender.getPlayer());
|
||||
}
|
||||
|
||||
public static void abort(Player player) {
|
||||
if(notChecking(player))
|
||||
return;
|
||||
|
||||
Chatter.of(player).system("CHECK_ABORT");
|
||||
currentCheckers.get(player.getUniqueId()).abort();
|
||||
}
|
||||
|
||||
@Register(value = "next", description = "CHECK_HELP_NEXT")
|
||||
public void next(PlayerChatter sender) {
|
||||
if(notChecking(sender.getPlayer()))
|
||||
return;
|
||||
|
||||
currentCheckers.get(sender.getPlayer().getUniqueId()).next();
|
||||
}
|
||||
|
||||
@Register(value = "accept")
|
||||
public void accept(PlayerChatter sender) {
|
||||
next(sender);
|
||||
}
|
||||
|
||||
@Register(value = "decline", description = "CHECK_HELP_DECLINE")
|
||||
public void decline(PlayerChatter sender, String... message) {
|
||||
if(notChecking(sender.getPlayer()))
|
||||
return;
|
||||
|
||||
currentCheckers.get(sender.getPlayer().getUniqueId()).decline(String.join(" ", message));
|
||||
}
|
||||
|
||||
public static List<SchematicNode> getSchemsToCheck(){
|
||||
List<SchematicNode> schematicList = new ArrayList<>();
|
||||
|
||||
for (SchematicType type : SchematicType.values()) {
|
||||
if (type.check())
|
||||
schematicList.addAll(SchematicNode.getAllSchematicsOfType(type));
|
||||
}
|
||||
return schematicList;
|
||||
}
|
||||
|
||||
public static String getChecker(SchematicNode schematic) {
|
||||
if (currentSchems.get(schematic.getId()) == null) return null;
|
||||
return currentSchems.get(schematic.getId()).checker.user().getUserName();
|
||||
}
|
||||
|
||||
private static boolean notChecking(Player player){
|
||||
if(!isChecking(player)){
|
||||
Chatter.of(player).system("CHECK_NOT_CHECKING");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class CheckSession{
|
||||
private final PlayerChatter checker;
|
||||
private final SchematicNode schematic;
|
||||
private final Timestamp startTime;
|
||||
private final ListIterator<String> checkList;
|
||||
|
||||
private CheckSession(PlayerChatter checker, SchematicNode schematic){
|
||||
this.checker = checker;
|
||||
this.schematic = schematic;
|
||||
this.startTime = Timestamp.from(Instant.now());
|
||||
this.checkList = checkQuestions.get(schematic.getSchemtype()).listIterator();
|
||||
|
||||
VelocityCore.schedule(() -> {
|
||||
ArenaMode mode = ArenaMode.getBySchemType(fightTypes.get(schematic.getSchemtype()));
|
||||
if(!new ServerStarter().test(mode, mode.getRandomMap(), checker.getPlayer()).check(schematic.getId()).start()) {
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
|
||||
currentCheckers.put(checker.user().getUUID(), this);
|
||||
currentSchems.put(schematic.getId(), this);
|
||||
for(CheckedSchematic previous : CheckedSchematic.previousChecks(schematic))
|
||||
checker.prefixless("CHECK_SCHEMATIC_PREVIOUS", previous.getEndTime(), SteamwarUser.get(previous.getValidator()).getUserName(), previous.getDeclineReason());
|
||||
next();
|
||||
}).schedule();
|
||||
}
|
||||
|
||||
private void next() {
|
||||
if(!checkList.hasNext()){
|
||||
accept();
|
||||
return;
|
||||
}
|
||||
|
||||
checker.prefixless("PLAIN_STRING", checkList.next());
|
||||
|
||||
checker.sendMessage(Component
|
||||
.text(checker.parseToPlain(checkList.hasNext() ? "CHECK_NEXT" : "CHECK_ACCEPT"))
|
||||
.color(NamedTextColor.GREEN)
|
||||
.clickEvent(ClickEvent.runCommand("/check next"))
|
||||
.append(Component
|
||||
.text(" " + checker.parseToPlain("CHECK_DECLINE"))
|
||||
.color(NamedTextColor.RED)
|
||||
.clickEvent(ClickEvent.suggestCommand("/check decline "))));
|
||||
}
|
||||
|
||||
private void accept(){
|
||||
if(concludeCheckSession("freigegeben", fightTypes.get(schematic.getSchemtype()))) {
|
||||
Chatter owner = Chatter.of(SteamwarUser.get(schematic.getOwner()).getUUID());
|
||||
owner.withPlayerOrOffline(
|
||||
player -> owner.system("CHECK_ACCEPTED", schematic.getSchemtype().name(), schematic.getName()),
|
||||
() -> DiscordAlert.send(owner, Color.GREEN, new Message("DC_TITLE_SCHEMINFO"), new Message("DC_SCHEM_ACCEPT", schematic.getName()), true)
|
||||
);
|
||||
notifyTeam(new Message("CHECK_ACCEPTED_TEAM", schematic.getName(), owner.user().getUserName()));
|
||||
}
|
||||
}
|
||||
|
||||
private void decline(String reason){
|
||||
if(concludeCheckSession(reason, SchematicType.Normal)) {
|
||||
Chatter owner = Chatter.of(SteamwarUser.get(schematic.getOwner()).getUUID());
|
||||
owner.withPlayerOrOffline(
|
||||
player -> owner.system("CHECK_DECLINED", schematic.getSchemtype().name(), schematic.getName(), reason),
|
||||
() -> DiscordAlert.send(owner, Color.RED, new Message("DC_TITLE_SCHEMINFO"), new Message("DC_SCHEM_DECLINE", schematic.getName(), reason), false)
|
||||
);
|
||||
notifyTeam(new Message("CHECK_DECLINED_TEAM", schematic.getName(), owner.user().getUserName(), reason));
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyTeam(Message message) {
|
||||
Chatter.serverteam().system(message);
|
||||
DiscordBot.withBot(bot -> bot.getChecklistChannel().system(message));
|
||||
}
|
||||
|
||||
private void abort(){
|
||||
concludeCheckSession("Prüfvorgang abgebrochen", null);
|
||||
}
|
||||
|
||||
private boolean concludeCheckSession(String reason, SchematicType type) {
|
||||
if(SchematicNode.getSchematicNode(schematic.getId()) == null) // Schematic was deleted
|
||||
return false;
|
||||
|
||||
CheckedSchematic.create(schematic, checker.user().getId(), startTime, Timestamp.from(Instant.now()), reason);
|
||||
if(type != null)
|
||||
schematic.setSchemtype(type);
|
||||
|
||||
remove();
|
||||
VelocityCore.schedule(() -> {
|
||||
Bauserver subserver = Bauserver.get(checker.user().getUUID());
|
||||
if(subserver != null)
|
||||
subserver.stop();
|
||||
}).schedule();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void remove() {
|
||||
currentCheckers.remove(checker.user().getUUID());
|
||||
currentSchems.remove(schematic.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.commands;
|
||||
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.SWCommandUtils;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
import de.steamwar.command.TypeValidator;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.sql.Punishment;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class DevCommand extends SWCommand {
|
||||
|
||||
private final File devServerDir = new File("/configs/DevServer");
|
||||
private final Map<String, RegisteredServer> devServers = new HashMap<>();
|
||||
|
||||
public DevCommand() {
|
||||
super("dev");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void simpleCommand(@Validator PlayerChatter sender) {
|
||||
updateDevServers();
|
||||
if (devServers.isEmpty()) {
|
||||
sender.system("DEV_NO_SERVER");
|
||||
return;
|
||||
} else if (devServers.size() == 1) {
|
||||
devServers.values().stream().findAny().ifPresent(server -> sender.getPlayer().createConnectionRequest(server).fireAndForget());
|
||||
return;
|
||||
}
|
||||
|
||||
RegisteredServer server = devServers.get(sender.getPlayer().getUsername().toLowerCase());
|
||||
if (server == null) {
|
||||
sender.system("DEV_UNKNOWN_SERVER");
|
||||
return;
|
||||
}
|
||||
|
||||
sender.getPlayer().createConnectionRequest(server).fireAndForget();
|
||||
}
|
||||
|
||||
@Register
|
||||
public void selectedCommand(@Validator PlayerChatter sender, @Mapper("dev") String name) {
|
||||
updateDevServers();
|
||||
RegisteredServer server = devServers.get(name.toLowerCase());
|
||||
if (server == null) {
|
||||
sender.system("DEV_NO_SERVER");
|
||||
return;
|
||||
}
|
||||
|
||||
sender.getPlayer().createConnectionRequest(server).fireAndForget();
|
||||
}
|
||||
|
||||
@ClassValidator(value = PlayerChatter.class, local = true)
|
||||
public TypeValidator<PlayerChatter> punishmentGuardChecker() {
|
||||
return (sender, value, messageSender) -> {
|
||||
if (sender.user().isPunished(Punishment.PunishmentType.NoDevServer)) {
|
||||
Message message = PunishmentCommand.punishmentMessage(sender.user(), Punishment.PunishmentType.NoDevServer);
|
||||
messageSender.send(message.format(), message.params());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
@Mapper(value = "dev", local = true)
|
||||
public TypeMapper<String> devServers() {
|
||||
return SWCommandUtils.createMapper(s -> s, s -> {
|
||||
updateDevServers();
|
||||
return devServers.keySet();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateDevServers() {
|
||||
String[] serverFiles = devServerDir.list();
|
||||
|
||||
Map<String, Integer> devServerFiles = new HashMap<>();
|
||||
if (serverFiles != null) {
|
||||
for (String serverFile : serverFiles) {
|
||||
String[] server = serverFile.split("\\.");
|
||||
devServerFiles.put(server[0], Integer.parseInt(server[1]));
|
||||
}
|
||||
}
|
||||
|
||||
devServers.entrySet().removeIf(entry -> {
|
||||
if (!devServerFiles.containsKey(entry.getKey())) {
|
||||
VelocityCore.getProxy().unregisterServer(entry.getValue().getServerInfo());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
devServerFiles.forEach((key, value) -> {
|
||||
if (devServers.containsKey(key))
|
||||
return;
|
||||
|
||||
SteamwarUser user = SteamwarUser.get(key);
|
||||
devServers.put(user.getUserName().toLowerCase(), VelocityCore.getProxy().registerServer(new ServerInfo("Dev " + user.getUserName(), new InetSocketAddress("127.0.0.1", value))));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.EventStarter;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.velocitycore.SubserverSystem;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeValidator;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.sql.*;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class EventCommand extends SWCommand {
|
||||
|
||||
public EventCommand() {
|
||||
super("event");
|
||||
}
|
||||
|
||||
@Validator("noEvent")
|
||||
public TypeValidator<Chatter> noEventValidator() {
|
||||
return (sender, value, messageSender) -> Event.get() == null;
|
||||
}
|
||||
|
||||
@Register
|
||||
public void noCurrentEvent(@Validator("noEvent") Chatter sender) {
|
||||
sender.system("EVENT_NO_CURRENT");
|
||||
|
||||
List<Event> coming = Event.getComing();
|
||||
if(coming.isEmpty())
|
||||
return;
|
||||
|
||||
sender.system("EVENT_COMING");
|
||||
|
||||
Instant now = Instant.now();
|
||||
DateTimeFormatter format = DateTimeFormatter.ofPattern(sender.parseToPlain("EVENT_DATE_FORMAT"));
|
||||
for(Event e : coming){
|
||||
sender.prefixless("EVENT_COMING_EVENT", e.getStart().toLocalDateTime().format(format), e.getEnd().toLocalDateTime().format(format), e.getEventName());
|
||||
|
||||
if(now.isBefore(e.getDeadline().toInstant()))
|
||||
sender.prefixless("EVENT_COMING_DEADLINE", e.getDeadline());
|
||||
|
||||
SchematicType schemType = e.getSchematicType();
|
||||
if (schemType != null && schemType.getDeadline() != null && now.isBefore(schemType.getDeadline().toInstant()))
|
||||
sender.prefixless("EVENT_COMING_SCHEM_DEADLINE", schemType.getDeadline());
|
||||
|
||||
Set<Team> teams = TeamTeilnahme.getTeams(e.getEventID());
|
||||
if(!teams.isEmpty())
|
||||
sender.prefixless("EVENT_COMING_TEAMS", teams.stream().map(team -> sender.parseToLegacy("EVENT_COMING_TEAM", team.getTeamColor(), team.getTeamKuerzel())).collect(Collectors.joining(" ")));
|
||||
}
|
||||
}
|
||||
|
||||
@Register
|
||||
public void eventOverview(@Validator(value = "noEvent", invert = true) Chatter sender) {
|
||||
sender.system("EVENT_USAGE");
|
||||
|
||||
Event currentEvent = Event.get();
|
||||
sender.system("EVENT_CURRENT_EVENT", currentEvent.getEventName());
|
||||
|
||||
DateTimeFormatter format = DateTimeFormatter.ofPattern(sender.parseToPlain("EVENT_TIME_FORMAT"));
|
||||
for(EventFight fight : EventFight.getEvent(currentEvent.getEventID())){
|
||||
Team blue = Team.get(fight.getTeamBlue());
|
||||
Team red = Team.get(fight.getTeamRed());
|
||||
StringBuilder fline = new StringBuilder(sender.parseToLegacy("EVENT_CURRENT_FIGHT", fight.getStartTime().toLocalDateTime().format(format), blue.getTeamColor(), blue.getTeamKuerzel(), red.getTeamColor(), red.getTeamKuerzel()));
|
||||
|
||||
if(fight.hasFinished()){
|
||||
switch(fight.getErgebnis()){
|
||||
case 1:
|
||||
fline.append(sender.parseToLegacy("EVENT_CURRENT_FIGHT_WIN", blue.getTeamColor(), blue.getTeamKuerzel()));
|
||||
break;
|
||||
case 2:
|
||||
fline.append(sender.parseToLegacy("EVENT_CURRENT_FIGHT_WIN", red.getTeamColor(), red.getTeamKuerzel()));
|
||||
break;
|
||||
default:
|
||||
fline.append(sender.parseToLegacy("EVENT_CURRENT_FIGHT_DRAW"));
|
||||
}
|
||||
}
|
||||
|
||||
sender.prefixless("PLAIN_STRING", fline.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Register
|
||||
public void eventWithTeam(@Validator(value = "noEvent", invert = true) PlayerChatter sender, @ErrorMessage("EVENT_NO_TEAM") Team team) {
|
||||
Subserver eventArena = EventStarter.getEventServer().get(team.getTeamId());
|
||||
if(eventArena == null || !Subserver.getServerList().contains(eventArena)){
|
||||
sender.system("EVENT_NO_FIGHT_TEAM");
|
||||
return;
|
||||
}
|
||||
if (!PunishmentCommand.isPunishedWithMessage(sender, Punishment.PunishmentType.NoFightServer)) {
|
||||
SubserverSystem.sendPlayer(eventArena, sender.getPlayer());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.Event;
|
||||
import de.steamwar.sql.EventFight;
|
||||
import de.steamwar.sql.Team;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
public class EventRescheduleCommand extends SWCommand {
|
||||
|
||||
public EventRescheduleCommand() {
|
||||
super("eventreschedule", UserPerm.MODERATION);
|
||||
}
|
||||
|
||||
@Register
|
||||
public void reschedule(Chatter sender, Team teamBlue, Team teamRed) {
|
||||
Event event = Event.get();
|
||||
if(event == null){
|
||||
sender.system("EVENTRESCHEDULE_UNKNOWN_TEAM");
|
||||
return;
|
||||
}
|
||||
|
||||
List<EventFight> fights = EventFight.getEvent(event.getEventID());
|
||||
ListIterator<EventFight> it = fights.listIterator(fights.size());
|
||||
Timestamp now = Timestamp.from(new Date().toInstant());
|
||||
while(it.hasPrevious()){
|
||||
EventFight fight = it.previous();
|
||||
if(fight.getStartTime().after(now))
|
||||
continue;
|
||||
|
||||
if(fight.getTeamBlue() == teamBlue.getTeamId() && fight.getTeamRed() == teamRed.getTeamId()){
|
||||
sender.system("EVENTRESCHEDULE_STARTING");
|
||||
fight.reschedule();
|
||||
EventFight.loadAllComingFights();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sender.system("EVENTRESCHEDULE_NO_FIGHT");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.EventFight;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
|
||||
public class EventreloadCommand extends SWCommand {
|
||||
public EventreloadCommand() {
|
||||
super("eventreload", UserPerm.MODERATION);
|
||||
}
|
||||
|
||||
@Register
|
||||
public void execute(Chatter sender) {
|
||||
EventFight.loadAllComingFights();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.steamwar.velocitycore.*;
|
||||
import de.steamwar.velocitycore.inventory.SWInventory;
|
||||
import de.steamwar.velocitycore.inventory.SWItem;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.persistent.Arenaserver;
|
||||
import de.steamwar.persistent.Servertype;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
|
||||
public class FightCommand extends SWCommand {
|
||||
|
||||
public FightCommand() {
|
||||
super("fight", "f");
|
||||
}
|
||||
|
||||
private static void getModes(Chatter sender, String precommand, boolean historic){
|
||||
Component start = Component.empty();
|
||||
for(ArenaMode mode : ArenaMode.getAllModes()){
|
||||
if(mode.withoutChatName() || mode.isHistoric() != historic)
|
||||
continue;
|
||||
|
||||
String command = precommand + mode.getChatName();
|
||||
start = start.append(Component
|
||||
.text(mode.getChatName() + " ")
|
||||
.color(NamedTextColor.GRAY)
|
||||
.decorate(TextDecoration.BOLD)
|
||||
.hoverEvent(HoverEvent.showText(Component.text(("§e" + command))))
|
||||
.clickEvent(ClickEvent.runCommand(command)));
|
||||
}
|
||||
|
||||
sender.sendMessage(start);
|
||||
}
|
||||
|
||||
private static boolean alreadyInArena(PlayerChatter sender){
|
||||
Subserver subserver = Subserver.getSubserver(sender.getPlayer());
|
||||
if(subserver != null && subserver.getType() == Servertype.ARENA){
|
||||
sender.system("FIGHT_IN_ARENA");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void createArena(PlayerChatter sender, String precommand, boolean allowMerging, ArenaMode arenaMode, String map, boolean historic, FightCallback callback) {
|
||||
if(alreadyInArena(sender))
|
||||
return;
|
||||
|
||||
if (arenaMode == null) {
|
||||
getModes(sender, precommand, historic);
|
||||
return;
|
||||
}
|
||||
|
||||
if (map == null)
|
||||
map = arenaMode.getRandomMap();
|
||||
|
||||
if (!allowMerging) {
|
||||
callback.run(sender, arenaMode, map);
|
||||
} else {
|
||||
suggestMerging(sender, arenaMode, map, callback);
|
||||
}
|
||||
}
|
||||
|
||||
private static void suggestMerging(PlayerChatter sender, ArenaMode mode, String map, FightCallback declineMerge) {
|
||||
Arenaserver mergable = null;
|
||||
synchronized (Subserver.getServerList()) {
|
||||
for (Subserver subserver : Subserver.getServerList()) {
|
||||
if(subserver instanceof Arenaserver arenaserver &&
|
||||
(mode.getInternalName().equals(arenaserver.getMode()) && arenaserver.isAllowMerge() && arenaserver.getRegisteredServer().getPlayersConnected().size() == 1)) {
|
||||
mergable = arenaserver;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(mergable == null) {
|
||||
declineMerge.run(sender, mode, map);
|
||||
return;
|
||||
}
|
||||
|
||||
SWInventory inventory = new SWInventory(sender, 9, new Message("FIGHT_MERGE_TITLE"));
|
||||
inventory.addItem(0, new SWItem(new Message("FIGHT_MERGE_DECLINE"), 1), click -> {
|
||||
inventory.close();
|
||||
declineMerge.run(sender, mode, map);
|
||||
});
|
||||
Arenaserver finalMergable = mergable;
|
||||
SWItem item = new SWItem(new Message("FIGHT_MERGE_INFO", mode.getGameName(), finalMergable.getMap()), 11);
|
||||
item.addLore(new Message("FIGHT_MERGE_INFO_LORE_1", finalMergable.getRegisteredServer().getPlayersConnected().toArray(new Player[1])[0].getUsername()));
|
||||
inventory.addItem(4, item, click -> {});
|
||||
inventory.addItem(8, new SWItem(new Message("FIGHT_MERGE_ACCEPT"), 10), click -> {
|
||||
if(Subserver.getServerList().contains(finalMergable)) {
|
||||
finalMergable.sendPlayer(sender.getPlayer());
|
||||
} else {
|
||||
sender.system("FIGHT_MERGE_OFFLINE");
|
||||
declineMerge.run(sender, mode, map);
|
||||
}
|
||||
});
|
||||
inventory.open();
|
||||
}
|
||||
|
||||
@Register
|
||||
public void fight(@Validator("arenaPlayer") PlayerChatter sender, @Mapper("nonHistoricArenaMode") @OptionalValue("") @AllowNull ArenaMode arenaMode, @Mapper("arenaMap") @OptionalValue("") @AllowNull String map) {
|
||||
createArena(sender, "/fight ", true, arenaMode, map, false,
|
||||
(p, mode, m) -> new ServerStarter().arena(mode, m).blueLeader(p.getPlayer()).callback(
|
||||
arena -> Chatter.broadcast().system("FIGHT_BROADCAST", new Message("FIGHT_BROADCAST_HOVER"), ClickEvent.runCommand("/arena " + arena.getServer().getName()), mode.getGameName(), p.getPlayer().getUsername())
|
||||
).start()
|
||||
);
|
||||
}
|
||||
|
||||
public interface FightCallback {
|
||||
void run(PlayerChatter player, ArenaMode mode, String map);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class GDPRQuery extends SWCommand {
|
||||
|
||||
public GDPRQuery() {
|
||||
super("gdprquery", UserPerm.ADMINISTRATION);
|
||||
}
|
||||
|
||||
@Register
|
||||
public void generate(PlayerChatter sender) {
|
||||
generate(sender, sender.user());
|
||||
}
|
||||
|
||||
@Register
|
||||
public void generate(Chatter sender, SteamwarUser user) {
|
||||
VelocityCore.schedule(() -> {
|
||||
try {
|
||||
createZip(sender, user);
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not create zip", e);
|
||||
}
|
||||
}).schedule();
|
||||
}
|
||||
|
||||
private void createZip(Chatter sender, SteamwarUser user) throws IOException {
|
||||
sender.system("GDPR_STATUS_WEBSITE");
|
||||
|
||||
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(user.getUserName() + ".zip"));
|
||||
|
||||
copy(getClass().getClassLoader().getResourceAsStream("GDPRQueryREADME.md"), out, "README.md");
|
||||
copy(getClass().getClassLoader().getResourceAsStream("GDPRQueryREADME.md"), out, "README.txt");
|
||||
|
||||
sender.system("GDPR_STATUS_WORLD");
|
||||
copyBauwelt(user, out, "/home/minecraft/userworlds/" + user.getUUID().toString(), "BuildWorld12");
|
||||
copyBauwelt(user, out, "/home/minecraft/userworlds15/" + user.getId(), "BuildWorld15");
|
||||
|
||||
sender.system("GDPR_STATUS_INVENTORIES");
|
||||
copyPlayerdata(user, out, "/home/minecraft/userworlds", "BuildInventories12");
|
||||
copyPlayerdata(user, out, "/home/minecraft/userworlds15", "BuildInventories15");
|
||||
|
||||
sender.system("GDPR_STATUS_DATABASE");
|
||||
sqlCSV(user, out, bannedIPs, "BannedIPs.csv");
|
||||
sqlCSV(user, out, bauweltMember, "BuildMember.csv");
|
||||
sqlCSV(user, out, bauweltMembers, "BuildMembers.csv");
|
||||
sqlCSV(user, out, checkedSchems, "SchematicChecksessions.csv");
|
||||
sqlCSV(user, out, userElo, "UserElo.csv");
|
||||
sqlCSV(user, out, fights, "Fights.csv");
|
||||
sqlCSV(user, out, ignoredPlayers, "IgnoredPlayers.csv");
|
||||
sqlCSV(user, out, ignoringPlayers, "IgnoringPlayers.csv");
|
||||
sqlCSV(user, out, schematicMember, "SchematicMember.csv");
|
||||
sqlCSV(user, out, schematicMembers, "SchematicMembers.csv");
|
||||
sqlCSV(user, out, pollAnswers, "PollAnswers.csv");
|
||||
sqlCSV(user, out, punishments, "Punishments.csv");
|
||||
sqlCSV(user, out, sessions, "Sessions.csv");
|
||||
sqlCSV(user, out, userData, "UserData.csv");
|
||||
sqlCSV(user, out, personalKits, "PersonalKits.csv");
|
||||
sqlCSV(user, out, schematics, "Schematics.csv");
|
||||
|
||||
personalKits(user, out);
|
||||
schematics(user, out);
|
||||
userConfig(user, out);
|
||||
|
||||
sender.system("GDPR_STATUS_LOGS");
|
||||
copyLogs(user, out, new File("/logs"), "logs");
|
||||
|
||||
out.close();
|
||||
sender.system("GDPR_STATUS_FINISHED");
|
||||
}
|
||||
|
||||
private static final Statement bannedIPs = new Statement("SELECT Timestamp, IP FROM BannedUserIPs WHERE UserID = ?");
|
||||
private static final Statement bauweltMember = new Statement("SELECT BauweltID AS Bauwelt, WorldEdit, World FROM BauweltMember WHERE MemberID = ?");
|
||||
private static final Statement bauweltMembers = new Statement("SELECT u.UserName AS 'User', m.WorldEdit AS WorldEdit, m.World AS World FROM BauweltMember m INNER JOIN UserData u ON m.MemberID = u.id WHERE m.BauweltID = ?");
|
||||
private static final Statement checkedSchems = new Statement("SELECT NodeName AS Schematic, StartTime, EndTime, DeclineReason AS Result FROM CheckedSchematic WHERE NodeOwner = ? ORDER BY StartTime ASC");
|
||||
private static final Statement userElo = new Statement("SELECT GameMode, Elo, Season FROM Elo WHERE UserID = ?");
|
||||
private static final Statement fights = new Statement("SELECT p.Team AS Team, p.Kit AS Kit, p.Kills AS Kills, p.IsOut AS Died, f.GameMode AS GameMode, f.Server AS Server, f.StartTime AS StartTime, f.Duration AS Duration, (f.BlueLeader = p.UserID) AS IsBlueLeader, (f.RedLeader = p.UserID) AS IsRedLeader, f.Win AS Winner, f.WinCondition AS WinCondition FROM Fight f INNER JOIN FightPlayer p ON f.FightID = p.FightID WHERE p.UserID = ? ORDER BY StartTime ASC");
|
||||
private static final Statement ignoredPlayers = new Statement("SELECT u.UserName AS IgnoredPlayer FROM IgnoredPlayers i INNER JOIN UserData u ON i.Ignored = u.id WHERE Ignorer = ?");
|
||||
private static final Statement ignoringPlayers = new Statement("SELECT Ignorer AS IgnoringPlayers FROM IgnoredPlayers WHERE Ignored = ?");
|
||||
private static final Statement schematicMember = new Statement("SELECT s.NodeName AS SchematicName, u.UserName AS SchematicOwner FROM NodeMember m INNER JOIN SchematicNode s ON m.NodeId = s.NodeId INNER JOIN UserData u ON s.NodeOwner = u.id WHERE m.UserId = ?");
|
||||
private static final Statement schematicMembers = new Statement("SELECT s.NodeName AS SchematicName, u.UserName AS Member FROM NodeMember m INNER JOIN SchematicNode s ON m.NodeId = s.NodeId INNER JOIN UserData u ON m.UserId = u.id WHERE s.NodeOwner = ?");
|
||||
private static final Statement pollAnswers = new Statement("SELECT Question, Answer FROM PollAnswer WHERE UserID = ?");
|
||||
private static final Statement punishments = new Statement("SELECT Type, StartTime, EndTime, Perma, Reason FROM Punishments WHERE UserId = ?");
|
||||
private static final Statement sessions = new Statement("SELECT StartTime, EndTime FROM Session WHERE UserID = ?");
|
||||
private static final Statement userData = new Statement("SELECT * FROM UserData WHERE id = ?");
|
||||
private static final Statement personalKits = new Statement("SELECT GameMode, Name, InUse FROM PersonalKit WHERE UserID = ?");
|
||||
private static final Statement personalKitData = new Statement("SELECT GameMode, Name, Inventory, Armor FROM PersonalKit WHERE UserID = ?");
|
||||
private static final Statement schematics = new Statement("SELECT NodeName AS SchematicName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank FROM SchematicNode WHERE NodeOwner = ?");
|
||||
private static final Statement schematicData = new Statement("SELECT NodeName, ParentNode, NodeFormat, NodeData FROM SchematicNode WHERE NodeOwner = ?");
|
||||
private static final Statement userConfig = new Statement("SELECT * FROM UserConfig WHERE User = ?");
|
||||
|
||||
private void sqlCSV(SteamwarUser user, ZipOutputStream out, Statement statement, String path) throws IOException {
|
||||
write(stream -> statement.select(rs -> {
|
||||
try {
|
||||
OutputStreamWriter writer = new OutputStreamWriter(stream);
|
||||
int columns = rs.getMetaData().getColumnCount();
|
||||
|
||||
for(int i = 1; i <= columns; i++) {
|
||||
writer.write(rs.getMetaData().getColumnLabel(i));
|
||||
writer.write(";");
|
||||
}
|
||||
writer.write("\n");
|
||||
|
||||
while(rs.next()) {
|
||||
for(int i = 1; i <= columns; i++) {
|
||||
try {
|
||||
writer.write(rs.getString(i));
|
||||
} catch (NullPointerException e) {
|
||||
// ignored
|
||||
}
|
||||
writer.write(";");
|
||||
}
|
||||
writer.write("\n");
|
||||
}
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not write file", e);
|
||||
}
|
||||
return null;
|
||||
}, user.getId()), out, path);
|
||||
}
|
||||
|
||||
private void personalKits(SteamwarUser user, ZipOutputStream out) {
|
||||
personalKitData.select(rs -> {
|
||||
while(rs.next()) {
|
||||
try {
|
||||
String path = "PersonalKit/" + rs.getString("GameMode") + "/" + rs.getString("Name");
|
||||
try(InputStream data = rs.getBinaryStream("Inventory")) {
|
||||
copy(data, out, path + ".Inventory.yml");
|
||||
}
|
||||
try(InputStream data = rs.getBinaryStream("Armor")) {
|
||||
copy(data, out, path + ".Armor.yml");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not export PersonalKits", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, user.getId());
|
||||
}
|
||||
|
||||
private void schematics(SteamwarUser user, ZipOutputStream out) {
|
||||
schematicData.select(rs -> {
|
||||
while(rs.next()) {
|
||||
String name = (rs.getString("ParentNode") != null ? rs.getString("ParentNode") : "") + ":" + rs.getString("NodeName");
|
||||
boolean format = rs.getBoolean("NodeFormat");
|
||||
try(InputStream data = rs.getBinaryStream("NodeData")) {
|
||||
copy(data, out, "Schematics/" + name + (format ? ".schem" : ".schematic"));
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not export Schematic", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, user.getId());
|
||||
}
|
||||
|
||||
private void userConfig(SteamwarUser user, ZipOutputStream out) {
|
||||
userConfig.select(rs -> {
|
||||
while(rs.next()) {
|
||||
String name = rs.getString("Config");
|
||||
try(InputStream data = rs.getBinaryStream("Value")) {
|
||||
copy(data, out, name + ".yapion");
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not export UserConfig", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, user.getId());
|
||||
}
|
||||
|
||||
private void copyLogs(SteamwarUser user, ZipOutputStream out, File log, String outFile) throws IOException {
|
||||
if (log.isDirectory()) {
|
||||
for(File logfile : log.listFiles()) {
|
||||
copyLogs(user, out, logfile, outFile + "/" + logfile.getName().replace(".gz", ""));
|
||||
}
|
||||
} else {
|
||||
Process reader = new ProcessBuilder("zgrep", "^.*" + user.getUserName() + "\\( issued server command:\\| moved too quickly!\\| executed command:\\| lost connection:\\||\\|»\\|\\[\\|\\]\\).*$", log.getPath()).start();
|
||||
copy(reader.getInputStream(), out, outFile);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyBauwelt(SteamwarUser user, ZipOutputStream out, String inDir, String outDir) throws IOException {
|
||||
File world = new File(inDir);
|
||||
if(!world.exists())
|
||||
return;
|
||||
|
||||
copy(new File(world, "level.dat"), out, outDir + "/level.dat");
|
||||
|
||||
File region = new File(world, "region");
|
||||
for(File regionfile : region.listFiles()) {
|
||||
copy(regionfile, out, outDir + "/region/" + regionfile.getName());
|
||||
}
|
||||
|
||||
File poi = new File(world, "poi");
|
||||
if(poi.exists()) {
|
||||
for(File regionfile : poi.listFiles()) {
|
||||
copy(regionfile, out, outDir + "/poi/" + regionfile.getName());
|
||||
}
|
||||
}
|
||||
|
||||
File playerdata = new File(world, "playerdata/" + user.getUUID().toString() + ".dat");
|
||||
if(playerdata.exists())
|
||||
copy(playerdata, out, outDir + "/playerdata/" + user.getUUID().toString() + ".dat");
|
||||
}
|
||||
|
||||
private void copyPlayerdata(SteamwarUser user, ZipOutputStream out, String inDir, String outDir) throws IOException {
|
||||
File worlds = new File(inDir);
|
||||
String path = "playerdata/" + user.getUUID().toString() + ".dat";
|
||||
|
||||
int i = 0;
|
||||
for(File world : worlds.listFiles()) {
|
||||
File playerdata = new File(world, path);
|
||||
if(!playerdata.exists())
|
||||
continue;
|
||||
|
||||
copy(playerdata, out, outDir + "/" + (i++) + "/" + user.getUUID().toString() + ".dat");
|
||||
}
|
||||
}
|
||||
|
||||
private void copy(File file, ZipOutputStream out, String path) throws IOException {
|
||||
try(FileInputStream in = new FileInputStream(file)) {
|
||||
copy(in, out, path);
|
||||
}
|
||||
}
|
||||
|
||||
private void copy(InputStream in, ZipOutputStream out, String path) throws IOException {
|
||||
boolean initialized = false;
|
||||
|
||||
int bytes;
|
||||
for(byte[] buf = new byte[8192]; (bytes = in.read(buf)) > 0; ) {
|
||||
if(!initialized) {
|
||||
ZipEntry entry = new ZipEntry(path);
|
||||
out.putNextEntry(entry);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
out.write(buf, 0, bytes);
|
||||
}
|
||||
|
||||
if(initialized) {
|
||||
out.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private void write(Writer writer, ZipOutputStream out, String path) throws IOException {
|
||||
ZipEntry entry = new ZipEntry(path);
|
||||
out.putNextEntry(entry);
|
||||
writer.accept(out);
|
||||
out.closeEntry();
|
||||
}
|
||||
|
||||
private interface Writer {
|
||||
void accept(OutputStream stream) throws IOException;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class HelpCommand extends SWCommand {
|
||||
|
||||
public HelpCommand() {
|
||||
super("help", "?");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(Chatter sender) {
|
||||
printPage(sender, ClickEvent::runCommand,
|
||||
"HELP_LOBBY", "/l",
|
||||
"HELP_BAU", "/build",
|
||||
"HELP_BAUSERVER", "/help build",
|
||||
"HELP_FIGHT", "/fight",
|
||||
"HELP_CHALLENGE", "/challenge",
|
||||
"HELP_HISTORIC", "/historic",
|
||||
"HELP_TEAM", "/team",
|
||||
"HELP_JOIN", "/join",
|
||||
"HELP_LOCAL", "/local");
|
||||
}
|
||||
|
||||
@Register({"build","world"})
|
||||
public void buildWorld(Chatter sender) {
|
||||
printPage(sender, "HELP_BAU_GROUP_WORLD_TITLE", "HELP_TNT", "HELP_FIRE", "HELP_FREEZE", "HELP_TPSLIMIT", "HELP_PROTECT", "HELP_RESET");
|
||||
}
|
||||
|
||||
@Register({"build","player"})
|
||||
public void buildPlayer(Chatter sender) {
|
||||
printPage(sender, "HELP_BAU_GROUP_PLAYER_TITLE", "HELP_SPEED", "HELP_NV", "HELP_DEBUGSTICK", "HELP_TRACE", "HELP_LOADER");
|
||||
}
|
||||
|
||||
@Register({"build","worldedit"})
|
||||
@Register({"build","we"})
|
||||
@Register({"build","world-edit"})
|
||||
@Register({"build","edit"})
|
||||
public void buildWorldedit(Chatter sender) {
|
||||
printPage(sender, "HELP_BAU_GROUP_WE_TITLE", "HELP_WE_POS1", "HELP_WE_POS2", "HELP_WE_COPY", "HELP_WE_PASTE", "HELP_WE_FLOPY", "HELP_WE_FLOPYP", "HELP_WE_ROTATE_90", "HELP_WE_ROTATE_180", "HELP_WE_ROTATE_N90");
|
||||
}
|
||||
|
||||
@Register({"build","other"})
|
||||
public void buildOther(Chatter sender) {
|
||||
printPage(sender, "HELP_BAU_GROUP_OTHER_TITLE", "HELP_TESTBLOCK", "HELP_SKULL", "HELP_BAUINFO");
|
||||
sender.prefixless("HELP_SCHEMSUBMIT", new Message("HELP_SCHEMSUBMIT_HOVER"), ClickEvent.openUrl("https://www.youtube.com/watch?v=9QrQ3UBWveE"));
|
||||
}
|
||||
|
||||
@Register("build")
|
||||
public void sendBauHelpGroup(Chatter sender) {
|
||||
printPage(sender, ClickEvent::runCommand,
|
||||
"HELP_BAU_GROUP_ADMIN", "/help build admin",
|
||||
"HELP_BAU_GROUP_WORLD", "/help build world",
|
||||
"HELP_BAU_GROUP_PLAYER", "/help build player",
|
||||
"HELP_BAU_GROUP_WE", "/help build we",
|
||||
"HELP_BAU_GROUP_OTHER", "/help build other");
|
||||
}
|
||||
|
||||
@Register("buildserver")
|
||||
@Register({"build","admin"})
|
||||
@Register({"build","owner"})
|
||||
@Register({"build","bauwelt"})
|
||||
public void sendBauHelp(Chatter sender) {
|
||||
printPage(sender, ClickEvent::suggestCommand,
|
||||
"HELP_BAU_TP", "/build tp ",
|
||||
"HELP_BAU_ADDMEMBER", "/build addmember ",
|
||||
"HELP_BAU_DELMEMBER", "/build delmember ",
|
||||
"HELP_BAU_SET_SPECTATOR", "/build setSpectator ",
|
||||
"HELP_BAU_SET_BUILDER", "/build setBuilder ",
|
||||
"HELP_BAU_SET_SUPERVISOR", "/build setSupervisor ",
|
||||
"HELP_BAU_DELETE", "/build delete ",
|
||||
"HELP_BAU_TESTARENA", "/build testarena ",
|
||||
"HELP_BAU_LOCK", "/build lock ",
|
||||
"HELP_BAU_UNLOCK", "/build unlock");
|
||||
}
|
||||
|
||||
private static void printPage(Chatter sender, Function<String, ClickEvent> action, String... args) {
|
||||
for(int i = 0; i < args.length; i += 2) {
|
||||
String message = args[i];
|
||||
String hoverMessage = message + "_HOVER";
|
||||
String command = args[i+1];
|
||||
|
||||
sender.system(message, new Message(hoverMessage), action.apply(command));
|
||||
}
|
||||
}
|
||||
|
||||
private static void printPage(Chatter sender, String title, String... messages) {
|
||||
sender.system(title);
|
||||
for (String message : messages) {
|
||||
sender.prefixless(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.velocitycore.ArenaMode;
|
||||
import de.steamwar.velocitycore.ServerStarter;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
public class HistoricCommand extends SWCommand {
|
||||
public HistoricCommand() {
|
||||
super("historic");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void historic(@Validator("arenaPlayer") PlayerChatter player, @Mapper("historicArenaMode") @OptionalValue("") @AllowNull ArenaMode arenaMode, @Mapper("arenaMap") @OptionalValue("") @AllowNull String map) {
|
||||
FightCommand.createArena(player, "/historic ", true, arenaMode, map, true, (p, mode, m) -> new ServerStarter().arena(mode, m).blueLeader(p.getPlayer()).callback(
|
||||
arena -> Chatter.broadcast().system("HISTORIC_BROADCAST", new Message("HISTORIC_BROADCAST_HOVER"), ClickEvent.runCommand("/arena " + arena.getServer().getName()), mode.getGameName(), p.getPlayer())
|
||||
).start());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.IgnoreSystem;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
|
||||
public class IgnoreCommand extends SWCommand {
|
||||
|
||||
public IgnoreCommand() {
|
||||
super("ignore");
|
||||
}
|
||||
|
||||
@Register(description = "USAGE_IGNORE")
|
||||
public void genericCommand(Chatter player, @ErrorMessage("UNKNOWN_PLAYER") SteamwarUser target) {
|
||||
SteamwarUser user = player.user();
|
||||
|
||||
if(target.equals(user)){
|
||||
player.system("IGNORE_YOURSELF");
|
||||
return;
|
||||
}
|
||||
if(IgnoreSystem.isIgnored(user, target)){
|
||||
player.system("IGNORE_ALREADY");
|
||||
return;
|
||||
}
|
||||
|
||||
IgnoreSystem.ignore(user, target);
|
||||
player.system("IGNORE_MESSAGE", target);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
public class JoinmeCommand extends SWCommand {
|
||||
|
||||
public JoinmeCommand() {
|
||||
super("joinme", UserPerm.TEAM);
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(PlayerChatter sender) {
|
||||
Chatter.broadcast().system("JOINME_BROADCAST", "JOINME_BROADCAST_HOVER", ClickEvent.runCommand("/join " + sender.getPlayer().getUsername()), sender, sender.getPlayer().getCurrentServer().orElseThrow().getServerInfo().getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
|
||||
public class KickCommand extends SWCommand {
|
||||
|
||||
public KickCommand() {
|
||||
super("kick", UserPerm.MODERATION);
|
||||
}
|
||||
|
||||
@Register(description = "KICK_USAGE")
|
||||
public void genericCommand(Chatter sender, @ErrorMessage("KICK_OFFLINE") Player target, String... message) {
|
||||
if (message.length == 0) {
|
||||
Chatter.disconnect(target).system("KICK_NORMAL");
|
||||
} else {
|
||||
Chatter.disconnect(target).system("KICK_CUSTOM", String.join(" ", message));
|
||||
}
|
||||
sender.system("KICK_CONFIRM", target);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.commands;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
import de.steamwar.persistent.Servertype;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ListCommand extends SWCommand {
|
||||
|
||||
public ListCommand() {
|
||||
super("list");
|
||||
}
|
||||
|
||||
public static synchronized SortedMap<String, List<Player>> getCustomTablist(){
|
||||
SortedMap<String, List<Player>> playerMap = new TreeMap<>();
|
||||
for (Player player : VelocityCore.getProxy().getAllPlayers()) {
|
||||
ServerConnection pserver = player.getCurrentServer().orElse(null);
|
||||
if (pserver == null)
|
||||
continue;
|
||||
|
||||
Subserver subserver = Subserver.getSubserver(pserver.getServerInfo());
|
||||
if (subserver != null && subserver.getType() == Servertype.BAUSERVER) {
|
||||
playerMap.computeIfAbsent("Bau", s -> new ArrayList<>()).add(player);
|
||||
} else {
|
||||
playerMap.computeIfAbsent(pserver.getServerInfo().getName(), s -> new ArrayList<>()).add(player);
|
||||
}
|
||||
}
|
||||
playerMap.forEach((server, players) -> players.sort((player, t1) -> player.getUsername().compareToIgnoreCase(t1.getUsername())));
|
||||
return playerMap;
|
||||
}
|
||||
|
||||
@Register
|
||||
public void list(Chatter sender) {
|
||||
SortedMap<String, List<Player>> playerMap = getCustomTablist();
|
||||
for (String server : playerMap.keySet()) {
|
||||
String serverName = server;
|
||||
if (server.equals("Bau")) {
|
||||
serverName = sender.parseToLegacy("TABLIST_BAU");
|
||||
}
|
||||
sender.prefixless("LIST_COMMAND", serverName, playerMap.get(server).stream().map(Player::getUsername).collect(Collectors.joining(", ")));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.listeners.ChatListener;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
|
||||
public class LocalCommand extends SWCommand {
|
||||
|
||||
public LocalCommand() {
|
||||
super("local", "bc", "bauchat");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(PlayerChatter player, String... message) {
|
||||
ChatListener.localChat(player, String.join(" ", message));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.inventory.SWInventory;
|
||||
import de.steamwar.velocitycore.inventory.SWItem;
|
||||
import de.steamwar.velocitycore.inventory.SWListInv;
|
||||
import de.steamwar.velocitycore.inventory.SWStreamInv;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.sql.Mod;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ModCommand extends SWCommand {
|
||||
|
||||
public ModCommand() {
|
||||
super("mod", UserPerm.MODERATION, "mods");
|
||||
}
|
||||
|
||||
public static final Map<UUID, Mod.ModType> playerFilterType = new HashMap<>();
|
||||
|
||||
@Register
|
||||
public void mods(PlayerChatter sender) {
|
||||
playerFilterType.putIfAbsent(sender.getPlayer().getUniqueId(), Mod.ModType.UNKLASSIFIED);
|
||||
openGui(sender);
|
||||
}
|
||||
|
||||
private void openGui(PlayerChatter player) {
|
||||
SWStreamInv<Mod> swStreamInv = new SWStreamInv<>(player, new Message("MOD_COMMAND_GUI_TITLE"), (click, mod) -> openTypeGUI(player, "MOD_COMMAND_CLASSICIATION_GUI", type -> {
|
||||
mod.setModType(type);
|
||||
SWInventory.close(player);
|
||||
openGui(player);
|
||||
}), page -> {
|
||||
Mod.ModType filtertype = playerFilterType.get(player.user().getUUID());
|
||||
return Mod.getAllModsFiltered(page,45, filtertype).stream().map(mod -> new SWListInv.SWListEntry<>(new SWItem("NAME_TAG", new Message("PLAIN_STRING", mod.getModName())).addLore(new Message("PLAIN_STRING", mod.getPlatform().name())), mod)).toList();
|
||||
});
|
||||
|
||||
swStreamInv.addItem(52, new SWItem("NAME_TAG", new Message("MOD_TITLE_FILTER")), click -> {
|
||||
swStreamInv.close();
|
||||
openTypeGUI(player, "MOD_TITLE_FILTER", type -> playerFilterType.replace(player.user().getUUID(), type));
|
||||
});
|
||||
|
||||
swStreamInv.open();
|
||||
}
|
||||
|
||||
private void openTypeGUI(PlayerChatter player, String title, Consumer<Mod.ModType> function) {
|
||||
SWInventory inv = new SWInventory(player, 9, new Message(title));
|
||||
|
||||
inv.addItem(1, new SWItem(new Message("MOD_UNCLASSIFIED"), 8), click -> function.accept(Mod.ModType.UNKLASSIFIED));
|
||||
inv.addItem(2, new SWItem(new Message("MOD_ALLOWED"), 2), click -> function.accept(Mod.ModType.GREEN));
|
||||
inv.addItem(3, new SWItem(new Message("MOD_FORBIDDEN"), 11), click -> function.accept(Mod.ModType.YELLOW));
|
||||
inv.addItem(4, new SWItem(new Message("MOD_AUTOBAN"), 1), click -> function.accept(Mod.ModType.RED));
|
||||
inv.addItem(5, new SWItem(new Message("MOD_YT"), 13), click -> function.accept(Mod.ModType.YOUTUBER_ONLY));
|
||||
|
||||
inv.addItem(8, new SWItem("ARROW", new Message("MOD_ITEM_BACK")), click -> {
|
||||
inv.close();
|
||||
openGui(player);
|
||||
});
|
||||
|
||||
inv.open();
|
||||
}
|
||||
|
||||
@Register(value = {"set"},description = "MOD_COMMAND_SET_USAGE")
|
||||
public void set(Chatter sender, String modName, Mod.Platform platform, Mod.ModType newModType) {
|
||||
Mod mod = Mod.get(modName, platform);
|
||||
if(mod == null) {
|
||||
sender.system("MOD_COMMAND_NOT_FOUND_IN_DATABASE", modName, platform.name());
|
||||
return;
|
||||
}
|
||||
|
||||
mod.setModType(newModType);
|
||||
sender.system("MOD_CHANGED_TYPE", modName, platform.name(), newModType.name());
|
||||
}
|
||||
|
||||
@Register(value = {"get"},description = "MOD_COMMAND_GET_USAGE")
|
||||
public void get(Chatter sender, String modName, Mod.Platform platform) {
|
||||
Mod mod = Mod.get(modName, platform);
|
||||
if(mod == null) {
|
||||
sender.system("MOD_COMMAND_NOT_FOUND_IN_DATABASE", modName, platform.name());
|
||||
return;
|
||||
}
|
||||
|
||||
sender.system("MOD_COMMAND_INFO", modName, platform.name(), mod.getModType().name());
|
||||
}
|
||||
|
||||
@Register(value = {"next"})
|
||||
public void next(Chatter sender) {
|
||||
Mod mod = Mod.findFirstMod();
|
||||
if(mod == null) {
|
||||
sender.system("MOD_NO_MORE_UNCLASSIFIED_MODS");
|
||||
return;
|
||||
}
|
||||
|
||||
sender.system("MOD_FOUND_NEXT_MOD", mod.getModName(), mod.getPlatform().name());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.steamwar.velocitycore.listeners.ChatListener;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.ChatterGroup;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.sql.IgnoreSystem;
|
||||
|
||||
import static de.steamwar.persistent.Storage.lastChats;
|
||||
|
||||
public class MsgCommand extends SWCommand {
|
||||
|
||||
public MsgCommand() {
|
||||
super("msg", "w", "tell");
|
||||
}
|
||||
|
||||
@Register(description = "MSG_USAGE")
|
||||
public void genericCommand(PlayerChatter sender, @ErrorMessage(value = "MSG_OFFLINE") Player target, @ErrorMessage(value = "MSG_USAGE", allowEAs = false) String... message) {
|
||||
msg(sender, target, message);
|
||||
}
|
||||
|
||||
public static void msg(PlayerChatter sender, Player target, String[] args) {
|
||||
if(target == null) {
|
||||
sender.system("MSG_OFFLINE");
|
||||
return;
|
||||
}
|
||||
|
||||
if (IgnoreSystem.isIgnored(target.getUniqueId(), sender.user().getUUID())) {
|
||||
sender.system("MSG_IGNORED");
|
||||
return;
|
||||
}
|
||||
|
||||
Chatter receiver = Chatter.of(target);
|
||||
ChatListener.sendChat(sender, new ChatterGroup(sender, receiver), "CHAT_MSG", receiver, String.join(" ", args));
|
||||
lastChats.put(sender.getPlayer(), target);
|
||||
lastChats.put(target, sender.getPlayer());
|
||||
}
|
||||
|
||||
public static void remove(Player player){
|
||||
lastChats.remove(player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
|
||||
public class PingCommand extends SWCommand {
|
||||
|
||||
public PingCommand() {
|
||||
super("ping");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(PlayerChatter sender) {
|
||||
sender.system("PING_RESPONSE", sender.getPlayer().getPing());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
|
||||
public class PlaytimeCommand extends SWCommand {
|
||||
|
||||
public PlaytimeCommand() {
|
||||
super("playtime");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(Chatter sender) {
|
||||
SteamwarUser user = sender.user();
|
||||
NumberFormat format = NumberFormat.getNumberInstance(user.getLocale());
|
||||
format.setMaximumFractionDigits(2);
|
||||
String formattedText = format.format((user.getOnlinetime() / 3600d));
|
||||
|
||||
sender.system("HOURS_PLAYED", formattedText);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.listeners.PollSystem;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeValidator;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.PollAnswer;
|
||||
|
||||
public class PollCommand extends SWCommand {
|
||||
|
||||
public PollCommand() {
|
||||
super("poll");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(@Validator Chatter sender) {
|
||||
PollSystem.sendPoll(sender);
|
||||
}
|
||||
|
||||
@Register(noTabComplete = true)
|
||||
public void answerPoll(@Validator Chatter sender, String answerString) {
|
||||
int answer;
|
||||
try {
|
||||
answer = Integer.parseUnsignedInt(answerString);
|
||||
if(answer < 1 || answer > PollSystem.answers())
|
||||
throw new NumberFormatException();
|
||||
}catch(NumberFormatException e){
|
||||
sender.system("POLL_NO_ANSWER");
|
||||
return;
|
||||
}
|
||||
|
||||
PollAnswer pollAnswer = PollAnswer.get(sender.user().getId());
|
||||
if(pollAnswer.hasAnswered())
|
||||
sender.system("POLL_ANSWER_REFRESH");
|
||||
else
|
||||
sender.system("POLL_ANSWER_NEW");
|
||||
|
||||
pollAnswer.setAnswer(answer);
|
||||
}
|
||||
|
||||
@ClassValidator(value = Chatter.class, local = true)
|
||||
public TypeValidator<Chatter> noPoll() {
|
||||
return PollSystem.noPoll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.listeners.PollSystem;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeValidator;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.PollAnswer;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PollresultCommand extends SWCommand {
|
||||
|
||||
public PollresultCommand() {
|
||||
super("pollresult", UserPerm.MODERATION);
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(@Validator Chatter sender) {
|
||||
Map<Integer, Integer> voted = PollAnswer.getCurrentResults();
|
||||
sender.system("POLLRESULT_HEADER", voted.values().stream().reduce(Integer::sum).orElse(0), PollAnswer.getCurrentPoll());
|
||||
for (Map.Entry<Integer, Integer> e: voted.entrySet()) {
|
||||
sender.prefixless("POLLRESULT_LIST", PollSystem.getAnswer(e.getKey()), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@ClassValidator(value = Chatter.class, local = true)
|
||||
public TypeValidator<Chatter> noPoll() {
|
||||
return PollSystem.noPoll();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.commands;
|
||||
|
||||
import com.google.gson.JsonParser;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.listeners.IPSanitizer;
|
||||
import de.steamwar.command.PreviousArguments;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.sql.BannedUserIPs;
|
||||
import de.steamwar.sql.Punishment;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PunishmentCommand {
|
||||
|
||||
private static final String API_URL = "https://api.mojang.com/users/profiles/minecraft/";
|
||||
|
||||
public static SteamwarUser getOrCreateOfflinePlayer(String name) {
|
||||
SteamwarUser user = SteamwarUser.get(name);
|
||||
if (user != null) {
|
||||
return user;
|
||||
}
|
||||
|
||||
UUID uuid = getUUIDofOfflinePlayer(name);
|
||||
if (uuid == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return SteamwarUser.getOrCreate(uuid, name, u -> {}, (o, n) -> {});
|
||||
}
|
||||
|
||||
private static UUID getUUIDofOfflinePlayer(String playerName) {
|
||||
try {
|
||||
final URL url = new URL(API_URL + playerName);
|
||||
String uuid = JsonParser.parseString(new Scanner(url.openConnection().getInputStream()).nextLine()).getAsJsonObject().get("id").getAsString();
|
||||
return UUID.fromString(uuid.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"));
|
||||
} catch (NoSuchElementException e) {
|
||||
// ignore, player does not exist
|
||||
} catch (IOException e) {
|
||||
VelocityCore.getLogger().log(Level.SEVERE, "Could not get offline player UUID %s".formatted(playerName), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isPunishedWithMessage(Chatter player, Punishment.PunishmentType punishment) {
|
||||
SteamwarUser user = player.user();
|
||||
if (!user.isPunished(punishment)) {
|
||||
return false;
|
||||
}
|
||||
player.system(punishmentMessage(user, punishment));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void ban(SteamwarUser user, Timestamp time, String banReason, SteamwarUser punisher, boolean perma) {
|
||||
Player player = VelocityCore.getProxy().getPlayer(user.getUUID()).orElse(null);
|
||||
if (player != null) {
|
||||
String ip = IPSanitizer.getTrueAddress(player).getHostAddress();
|
||||
Chatter.disconnect(player).system(punishmentMessage(user, Punishment.PunishmentType.Ban));
|
||||
for (BannedUserIPs banned : BannedUserIPs.get(ip)) {
|
||||
SteamwarUser bannedUser = SteamwarUser.get(banned.getUserID());
|
||||
if (bannedUser.isPunished(Punishment.PunishmentType.Ban) && bannedUser.getPunishment(Punishment.PunishmentType.Ban).getEndTime().before(time)) {
|
||||
bannedUser.punish(Punishment.PunishmentType.Ban, time, banReason, punisher.getId(), perma);
|
||||
}
|
||||
}
|
||||
BannedUserIPs.banIP(user.getId(), ip);
|
||||
}
|
||||
}
|
||||
|
||||
public static Message punishmentMessage(SteamwarUser user, Punishment.PunishmentType punishment) {
|
||||
Punishment currentPunishment = user.getPunishment(punishment);
|
||||
if (currentPunishment.isPerma()) {
|
||||
return new Message(punishment.getPlayerMessagePerma(), currentPunishment.getReason());
|
||||
} else {
|
||||
return new Message(punishment.getPlayerMessageUntil(), currentPunishment.getEndTime(), currentPunishment.getReason());
|
||||
}
|
||||
}
|
||||
|
||||
public PunishmentCommand(String command, Punishment.PunishmentType punishmentType) {
|
||||
new PunishCommand(command, punishmentType);
|
||||
|
||||
if (punishmentType.getUnpunishmentMessage() == null)
|
||||
return;
|
||||
|
||||
new UnpunishCommand("un" + command, punishmentType);
|
||||
}
|
||||
|
||||
private static final Pattern RELATIVE_PATTERN = Pattern.compile("([1-9]\\d*[hdwmy])+");
|
||||
|
||||
public static Timestamp parseTime(Chatter player, String arg) {
|
||||
if (arg.equalsIgnoreCase("perma")) {
|
||||
return Punishment.PERMA_TIME;
|
||||
} else {
|
||||
if (RELATIVE_PATTERN.matcher(arg).matches()) {
|
||||
Instant instant = Instant.now();
|
||||
StringBuilder st = new StringBuilder();
|
||||
for (int i = 0; i < arg.length(); i++) {
|
||||
char c = arg.charAt(i);
|
||||
if (c >= '0' && c <= '9') {
|
||||
st.append(c);
|
||||
continue;
|
||||
}
|
||||
int amount = Integer.parseInt(st.toString());
|
||||
st = new StringBuilder();
|
||||
switch (c) {
|
||||
case 'h':
|
||||
instant = instant.plus(amount, ChronoUnit.HOURS);
|
||||
break;
|
||||
case 'd':
|
||||
instant = instant.plus(amount, ChronoUnit.DAYS);
|
||||
break;
|
||||
case 'w':
|
||||
instant = instant.plus(Duration.ofSeconds(amount * ChronoUnit.WEEKS.getDuration().getSeconds()));
|
||||
break;
|
||||
case 'm':
|
||||
instant = instant.plus(Duration.ofSeconds(amount * ChronoUnit.MONTHS.getDuration().getSeconds()));
|
||||
break;
|
||||
case 'y':
|
||||
instant = instant.plus(Duration.ofSeconds(amount * ChronoUnit.YEARS.getDuration().getSeconds()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Timestamp.from(instant);
|
||||
}
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy_HH:mm");
|
||||
try {
|
||||
Date parsedDate = dateFormat.parse(arg);
|
||||
return new java.sql.Timestamp(parsedDate.getTime());
|
||||
} catch (ParseException e) {
|
||||
dateFormat = new SimpleDateFormat("dd.MM.yyyy");
|
||||
try {
|
||||
Date parsedDate = dateFormat.parse(arg.split("_")[0]);
|
||||
return new java.sql.Timestamp(parsedDate.getTime());
|
||||
} catch (ParseException exception) {
|
||||
player.system("INVALID_TIME");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class PunishCommand extends SWCommand {
|
||||
|
||||
private final String command;
|
||||
private final Punishment.PunishmentType punishmentType;
|
||||
|
||||
private PunishCommand(String command, Punishment.PunishmentType punishmentType) {
|
||||
super(command, UserPerm.TEAM);
|
||||
this.command = command;
|
||||
this.punishmentType = punishmentType;
|
||||
}
|
||||
|
||||
private SteamwarUser unsafeUser(Chatter sender, String arg) {
|
||||
SteamwarUser target = getOrCreateOfflinePlayer(arg);
|
||||
if(target == null)
|
||||
sender.system("UNKNOWN_PLAYER");
|
||||
return target;
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(Chatter sender, @Mapper("toPunish") String toPunish, String date, @ErrorMessage(allowEAs = false, value = "PUNISHMENT_USAGE_REASON") String... message) {
|
||||
SteamwarUser punisher = sender.user();
|
||||
if (punishmentType.isNeedsAdmin() && !punisher.hasPerm(UserPerm.MODERATION))
|
||||
return;
|
||||
|
||||
SteamwarUser target = unsafeUser(sender, toPunish);
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
Timestamp banTime = parseTime(sender, date);
|
||||
if (banTime == null)
|
||||
return;
|
||||
|
||||
boolean isPerma = date.equalsIgnoreCase("perma");
|
||||
String msg = String.join(" ", message);
|
||||
target.punish(punishmentType, banTime, msg, punisher.getId(), isPerma);
|
||||
if(punishmentType == Punishment.PunishmentType.Ban)
|
||||
ban(target, banTime, msg, punisher, isPerma);
|
||||
Chatter.serverteam().system(punishmentType.getTeamMessage(), new Message("PREFIX"), target, sender, new Message((isPerma ? "PUNISHMENT_PERMA" : "PUNISHMENT_UNTIL"), banTime), msg);
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericError(Chatter sender, String... args) {
|
||||
sender.system("PUNISHMENT_USAGE", command);
|
||||
}
|
||||
|
||||
@Mapper(value = "toPunish", local = true)
|
||||
public TypeMapper<String> allUsers() {
|
||||
return new TypeMapper<String>() {
|
||||
@Override
|
||||
public String map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
List<String> players = VelocityCore.getProxy().getAllPlayers().stream()
|
||||
.map(Player::getUsername)
|
||||
.collect(Collectors.toList());
|
||||
players.add(s);
|
||||
return players;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static class UnpunishCommand extends SWCommand {
|
||||
|
||||
private final String command;
|
||||
private final Punishment.PunishmentType punishmentType;
|
||||
|
||||
private UnpunishCommand(String command, Punishment.PunishmentType punishmentType) {
|
||||
super(command, UserPerm.TEAM);
|
||||
this.command = command;
|
||||
this.punishmentType = punishmentType;
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(Chatter sender, @ErrorMessage("UNKNOWN_PLAYER") SteamwarUser target) {
|
||||
if (punishmentType.isNeedsAdmin() && !sender.user().hasPerm(UserPerm.MODERATION))
|
||||
return;
|
||||
|
||||
if (!target.isPunished(punishmentType)) {
|
||||
sender.system(punishmentType.getUsageNotPunished());
|
||||
return;
|
||||
}
|
||||
|
||||
target.punish(punishmentType, Timestamp.from(new Date().toInstant()), command, sender.user().getId(), false);
|
||||
if(punishmentType == Punishment.PunishmentType.Ban)
|
||||
BannedUserIPs.unbanIPs(target.getId());
|
||||
|
||||
sender.system(punishmentType.getUnpunishmentMessage(), target.getUserName());
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericError(Chatter sender, String... args) {
|
||||
sender.system("UNPUNISHMENT_USAGE", command);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
|
||||
import static de.steamwar.persistent.Storage.lastChats;
|
||||
|
||||
public class RCommand extends SWCommand {
|
||||
|
||||
public RCommand() {
|
||||
super("r", "reply");
|
||||
}
|
||||
|
||||
@Register(description = "R_USAGE")
|
||||
public void genericCommand(PlayerChatter sender, @ErrorMessage(value = "R_USAGE", allowEAs = false) String... message) {
|
||||
MsgCommand.msg(sender, lastChats.get(sender.getPlayer()), message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.ArenaMode;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.UserElo;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class RankCommand extends SWCommand {
|
||||
|
||||
public RankCommand() {
|
||||
super("rank");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void ownRank(Chatter sender) {
|
||||
rank(sender, sender.user());
|
||||
}
|
||||
|
||||
@Register
|
||||
public void rank(Chatter sender, @ErrorMessage("RANK_PLAYER_NOT_FOUND") SteamwarUser user) {
|
||||
if (!sender.user().equals(user))
|
||||
sender.prefixless("RANK_PLAYER_FOUND", user);
|
||||
|
||||
for(ArenaMode mode : ArenaMode.getAllModes()) {
|
||||
if (!mode.isRanked())
|
||||
continue;
|
||||
|
||||
Optional<Integer> elo = UserElo.getElo(user.getId(), mode.getSchemType());
|
||||
Message eloMsg;
|
||||
if (elo.isPresent()) {
|
||||
int placement = UserElo.getPlacement(elo.get(), mode.getSchemType());
|
||||
eloMsg = new Message("RANK_PLACED", placement, elo.get());
|
||||
} else {
|
||||
eloMsg = new Message("RANK_UNPLACED");
|
||||
}
|
||||
|
||||
sender.prefixless("RANK_HEADER", mode.getChatName(), eloMsg);
|
||||
sender.prefixless("RANK_EMBLEM", UserElo.getEmblemProgression(mode.getChatName(), user.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.ArenaMode;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.velocitycore.ServerStarter;
|
||||
import de.steamwar.velocitycore.inventory.SWItem;
|
||||
import de.steamwar.velocitycore.inventory.SWListInv;
|
||||
import de.steamwar.velocitycore.inventory.SWStreamInv;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.sql.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ReplayCommand extends SWCommand {
|
||||
|
||||
public ReplayCommand() {
|
||||
super("replay");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(PlayerChatter sender, @OptionalValue("") String optionalMap) {
|
||||
if (PunishmentCommand.isPunishedWithMessage(sender, Punishment.PunishmentType.NoFightServer))
|
||||
return;
|
||||
|
||||
new SWStreamInv<>(sender, new Message("REPLAY_TITLE"), (click, fight) -> {
|
||||
ArenaMode mode = ArenaMode.getBySchemType(fight.getSchemType());
|
||||
ServerStarter starter = new ServerStarter().replay(fight.getFightID()).blueLeader(sender.getPlayer());
|
||||
|
||||
String map = mode.getRandomMap();
|
||||
if (!optionalMap.equals("")) {
|
||||
String tMap = mode.hasMap(optionalMap);
|
||||
if (tMap != null) map = tMap;
|
||||
}
|
||||
|
||||
if (sender.user().hasPerm(UserPerm.MODERATION) && click.isShiftClick() && fight.replayExists()) {
|
||||
starter.test(mode, map, sender.getPlayer()).start();
|
||||
} else if(!fight.replayAllowed()) {
|
||||
sender.system("REPLAY_UNAVAILABLE");
|
||||
} else {
|
||||
starter.arena(mode, map).start();
|
||||
}
|
||||
}, page -> Fight.getPage(page, 45).stream().map(fight -> new SWListInv.SWListEntry<>(getFightItem(fight), fight)).toList()).open();
|
||||
}
|
||||
|
||||
private SWItem getFightItem(Fight fight) {
|
||||
SchematicType type = fight.getSchemType();
|
||||
SWItem item = new SWItem(type != null ? type.getMaterial() : "BARRIER", parseLeader(fight.getBlueLeader(), fight.getBluePlayers().size(), fight.getWin() == 1));
|
||||
|
||||
List<Message> lore = new ArrayList<>();
|
||||
lore.add(parseLeader(fight.getRedLeader(), fight.getRedPlayers().size(), fight.getWin() == 2));
|
||||
lore.add(new Message("REPLAY_TIME", fight.getStartTime()));
|
||||
lore.add(new Message("SPACER"));
|
||||
lore.add(new Message("REPLAY_SERVER", fight.getServer()));
|
||||
if(!fight.replayAllowed())
|
||||
lore.add(new Message("REPLAY_UNAVAILABLE"));
|
||||
item.setLore(lore);
|
||||
|
||||
if(fight.replayAllowed())
|
||||
item.setEnchanted(true);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private Message parseLeader(SteamwarUser leader, int players, boolean winner) {
|
||||
return new Message("REPLAY_" + (players > 1 ? "" : "SOLO_") + (winner ? "WINNER" : "LOSER"), leader.getUserName(), players - 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class RulesCommand extends SWCommand {
|
||||
public RulesCommand() {
|
||||
super("rules", "regeln");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(Chatter sender) {
|
||||
sender.system("REGELN_RULES");
|
||||
|
||||
for(String ruleset : Arrays.asList("REGELN_AS", "REGELN_MWG", "REGELN_WG", "REGELN_WS", "REGELN_QG", "REGELN_CONDUCT"))
|
||||
sender.prefixless(ruleset, new Message(ruleset + "_HOVER"), ClickEvent.openUrl(sender.parseToPlain(ruleset + "_URL")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
|
||||
public class ServerSwitchCommand extends SWCommand {
|
||||
|
||||
private final RegisteredServer server;
|
||||
|
||||
public ServerSwitchCommand(String cmd, String name, String... aliases) {
|
||||
super(cmd, null, aliases);
|
||||
server = VelocityCore.getProxy().getServer(name).orElseThrow();
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(PlayerChatter sender) {
|
||||
sender.getPlayer().createConnectionRequest(server).fireAndForget();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.listeners.ChatListener;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
|
||||
public class ServerTeamchatCommand extends SWCommand {
|
||||
|
||||
public ServerTeamchatCommand() {
|
||||
super("stc", UserPerm.TEAM, "serverteamchat");
|
||||
}
|
||||
|
||||
@Register(description = "STC_USAGE")
|
||||
public void genericCommand(Chatter sender, @ErrorMessage(value = "STC_USAGE", allowEAs = false) String... message) {
|
||||
ChatListener.sendChat(sender, Chatter.serverteam(), "CHAT_SERVERTEAM", null, String.join(" ", message));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.network.NetworkSender;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.network.packets.server.LocaleInvalidationPacket;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class SetLocaleCommand extends SWCommand {
|
||||
|
||||
public SetLocaleCommand() {
|
||||
super("setlocale", "setlanguage");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(Chatter sender) {
|
||||
sender.user().setLocale(Objects.requireNonNull(sender.getLocale()), true);
|
||||
sender.withPlayer(player -> NetworkSender.send(player, new LocaleInvalidationPacket(sender.user().getId())));
|
||||
sender.system("LOCK_LOCALE_CHANGED");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.Node;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class StatCommand extends SWCommand {
|
||||
|
||||
public StatCommand() {
|
||||
super("stat", UserPerm.ADMINISTRATION, "stats");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(Chatter sender) {
|
||||
Map<String, Integer> serverCount = new HashMap<>();
|
||||
try {
|
||||
Process process = new ProcessBuilder("ps", "x").start();
|
||||
new BufferedReader(new InputStreamReader(process.getInputStream())).lines().forEach(s -> {
|
||||
if (!s.contains("--port"))
|
||||
return;
|
||||
serverCount.compute(
|
||||
s.contains("ssh -L") ? s.substring(s.indexOf("ssh -L") + 6).split(" ")[2] : "sw",
|
||||
(server, count) -> (count != null ? count : 0) + 1
|
||||
);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
throw new SecurityException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
Node.forEach(node -> sender.prefixless("STAT_SERVER", node.getName(), node.belowLoadLimit(), serverCount.getOrDefault(node.getName(), 0)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,601 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import com.velocitypowered.api.proxy.ConnectionRequestBuilder;
|
||||
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
import de.steamwar.persistent.Storage;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.discord.DiscordBot;
|
||||
import de.steamwar.velocitycore.inventory.SWItem;
|
||||
import de.steamwar.velocitycore.inventory.SWListInv;
|
||||
import de.steamwar.command.PreviousArguments;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
import de.steamwar.command.TypeValidator;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.sql.*;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import java.net.*;
|
||||
import java.time.Instant;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static de.steamwar.persistent.Storage.teamInvitations;
|
||||
|
||||
public class TeamCommand extends SWCommand {
|
||||
|
||||
public TeamCommand() {
|
||||
super("team");
|
||||
}
|
||||
|
||||
@Register(noTabComplete = true)
|
||||
public void help(Chatter sender, String... args){
|
||||
helpMessages(sender, "TEAM_HELP_HEADER", "TEAM_HELP_LIST", "TEAM_HELP_INFO", "TEAM_HELP_TP");
|
||||
|
||||
SteamwarUser user = sender.user();
|
||||
if(user.getTeam() == 0) {
|
||||
helpMessages(sender, "TEAM_HELP_CREATE", "TEAM_HELP_JOIN");
|
||||
}else{
|
||||
helpMessages(sender, "TEAM_HELP_CHAT", "TEAM_HELP_EVENT", "TEAM_HELP_LEAVE");
|
||||
|
||||
if(user.isLeader())
|
||||
helpMessages(sender, "TEAM_HELP_INVITE", "TEAM_HELP_REMOVE", "TEAM_HELP_KUERZEL", "TEAM_HELP_NAME", "TEAM_HELP_COLOR", "TEAM_HELP_LEADER", "TEAM_HELP_STEP_BACK", "TEAM_HELP_SERVER");
|
||||
}
|
||||
}
|
||||
|
||||
private void helpMessages(Chatter sender, String... messages) {
|
||||
for(String message : messages)
|
||||
sender.system(message);
|
||||
}
|
||||
|
||||
@Register(value = "create", description = "TEAM_CREATE_USAGE")
|
||||
public void create(@Validator("isNotInTeam") Chatter sender, @Length(min = 2, max = 4) @ErrorMessage("TEAM_KUERZEL_LENGTH") String kuerzel, @Length(min = 4, max = 15) @ErrorMessage("TEAM_NAME_LENGTH") String name){
|
||||
SteamwarUser user = sender.user();
|
||||
Team team = Team.get(user.getTeam());
|
||||
|
||||
if(checkTeamKuerzel(sender, team, kuerzel) || checkTeamName(sender, team, name))
|
||||
return;
|
||||
|
||||
Team.create(kuerzel, name);
|
||||
user.setTeam(Team.get(kuerzel).getTeamId());
|
||||
user.setLeader(true);
|
||||
sender.system("TEAM_CREATE_CREATED", name);
|
||||
}
|
||||
|
||||
@Register("join")
|
||||
public void join(@Validator("isNotInTeam") Chatter sender, String... args){
|
||||
SteamwarUser user = sender.user();
|
||||
|
||||
if(notDuringEvent(sender))
|
||||
return;
|
||||
|
||||
if(!teamInvitations.containsKey(user.getId())){
|
||||
sender.system("TEAM_JOIN_NO_INVITE");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Integer> invs = teamInvitations.get(user.getId());
|
||||
Integer t = null;
|
||||
|
||||
if(invs.size() == 1){
|
||||
t = invs.get(0);
|
||||
}else{
|
||||
if(args.length != 1){
|
||||
sender.system("TEAM_JOIN_USAGE");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(int inv : invs){
|
||||
Team team = Team.get(inv);
|
||||
sb.append(team.getTeamName()).append(" ");
|
||||
}
|
||||
sender.system("TEAM_JOIN_INVITED", sb.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
for(int inv : invs){
|
||||
Team team = Team.get(inv);
|
||||
if(team.getTeamKuerzel().equalsIgnoreCase(args[0]) || team.getTeamName().equalsIgnoreCase(args[0])){
|
||||
t = inv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(t == null){
|
||||
sender.system("TEAM_JOIN_NOT_BY_TEAM");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
user.setTeam(t);
|
||||
teamInvitations.remove(user.getId());
|
||||
sender.system("TEAM_JOIN_JOINED", Team.get(t).getTeamName());
|
||||
}
|
||||
|
||||
@Register("stepback")
|
||||
public void stepBack(@Validator("isLeader") Chatter sender) {
|
||||
SteamwarUser user = sender.user();
|
||||
Team team = Team.get(user.getTeam());
|
||||
|
||||
if(noRemainingLeaders(team, user)){
|
||||
sender.system("TEAM_OTHER_LEADER_REQUIRED");
|
||||
return;
|
||||
}
|
||||
|
||||
user.setLeader(false);
|
||||
sender.system("TEAM_STEP_BACK");
|
||||
}
|
||||
|
||||
@Register("leave")
|
||||
public void leave(@Validator("isInTeam") Chatter sender) {
|
||||
SteamwarUser user = sender.user();
|
||||
Team team = Team.get(user.getTeam());
|
||||
|
||||
int teamSize = team.size();
|
||||
if(teamSize > 1 && user.isLeader() && noRemainingLeaders(team, user)) {
|
||||
sender.system("TEAM_OTHER_LEADER_REQUIRED");
|
||||
return;
|
||||
}
|
||||
|
||||
user.setTeam(0);
|
||||
|
||||
if(teamSize == 1)
|
||||
team.disband(user);
|
||||
|
||||
sender.system("TEAM_LEAVE_LEFT");
|
||||
}
|
||||
|
||||
private boolean noRemainingLeaders(Team team, SteamwarUser except) {
|
||||
return SteamwarUser.getTeam(team.getTeamId()).stream().filter(member -> except.getId() != member.getId()).noneMatch(SteamwarUser::isLeader);
|
||||
}
|
||||
|
||||
|
||||
@Register(value = "invite", description = "TEAM_INVITE_USAGE")
|
||||
public void invite(@Validator("isLeader") Chatter sender, @ErrorMessage("TEAM_INVITE_NO_PLAYER") SteamwarUser target){
|
||||
Team team = Team.get(sender.user().getTeam());
|
||||
|
||||
if(notDuringEvent(sender))
|
||||
return;
|
||||
|
||||
if(target.getTeam() != 0){
|
||||
sender.system("TEAM_INVITE_IN_TEAM");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Integer> invitations = teamInvitations.computeIfAbsent(target.getId(), id -> new ArrayList<>());
|
||||
if(invitations.contains(team.getTeamId())){
|
||||
sender.system("TEAM_INVITE_ALREADY_INVITED");
|
||||
return;
|
||||
}
|
||||
|
||||
invitations.add(team.getTeamId());
|
||||
sender.system("TEAM_INVITE_INVITED", target.getUserName());
|
||||
Chatter.of(target).system("TEAM_INVITE_INVITED_TARGET", team.getTeamColor(), team.getTeamName());
|
||||
}
|
||||
|
||||
@Register(value = "remove", description = "TEAM_REMOVE_USAGE")
|
||||
public void remove(@Validator("isLeader") Chatter sender, @ErrorMessage("TEAM_REMOVE_NOT_PLAYER") @Mapper("memberList") SteamwarUser target){
|
||||
Team team = Team.get(sender.user().getTeam());
|
||||
|
||||
if (target.isLeader()) {
|
||||
sender.system("TEAM_REMOVE_NOT_LEADER");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Integer> invitations = teamInvitations.get(target.getId());
|
||||
if(invitations != null) {
|
||||
sender.system(invitations.remove((Integer) team.getTeamId()) ? "TEAM_REMOVE_INVITE" : "TEAM_REMOVE_NO_INVITE");
|
||||
return;
|
||||
}
|
||||
|
||||
if(target.getTeam() != team.getTeamId()) {
|
||||
sender.system("TEAM_REMOVE_NOT_IN_TEAM");
|
||||
return;
|
||||
}
|
||||
|
||||
target.setTeam(0);
|
||||
|
||||
sender.system("TEAM_REMOVE_REMOVED");
|
||||
Chatter.of(target).system("TEAM_REMOVE_REMOVED_TARGET");
|
||||
}
|
||||
|
||||
@Mapper(value = "memberList", local = true)
|
||||
public TypeMapper<SteamwarUser> memberList() {
|
||||
return new TypeMapper<SteamwarUser>() {
|
||||
@Override
|
||||
public SteamwarUser map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return SteamwarUser.get(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return Team.get(sender.user().getTeam()).getMembers().stream()
|
||||
.map(SteamwarUser::get)
|
||||
.map(SteamwarUser::getUserName)
|
||||
.toList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Register(value = "changekurzel", description = "TEAM_KUERZEL_USAGE")
|
||||
public void changekuerzel(@Validator("isLeader") Chatter sender, @Length(min = 2, max = 4) @ErrorMessage("TEAM_KUERZEL_LENGTH") String kuerzel){
|
||||
Team team = Team.get(sender.user().getTeam());
|
||||
|
||||
if(notDuringEvent(sender))
|
||||
return;
|
||||
|
||||
if(checkTeamKuerzel(sender, team, kuerzel))
|
||||
return;
|
||||
|
||||
team.setTeamKuerzel(kuerzel);
|
||||
sender.system("TEAM_KUERZEL_CHANGED");
|
||||
}
|
||||
|
||||
@Register(value = "changename", description = "TEAM_NAME_USAGE")
|
||||
public void changename(@Validator("isLeader") Chatter sender, @Length(min = 4, max = 15) @ErrorMessage("TEAM_NAME_LENGTH") String name){
|
||||
Team team = Team.get(sender.user().getTeam());
|
||||
|
||||
if(notDuringEvent(sender))
|
||||
return;
|
||||
|
||||
if(checkTeamName(sender, team, name))
|
||||
return;
|
||||
|
||||
team.setTeamName(name);
|
||||
sender.system("TEAM_NAME_CHANGED");
|
||||
}
|
||||
|
||||
@Register(value = "promote", description = "TEAM_LEADER_USAGE")
|
||||
public void promote(@Validator("isLeader") Chatter sender, @ErrorMessage("TEAM_LEADER_NOT_USER") @Mapper("memberList") SteamwarUser target){
|
||||
if(notDuringEvent(sender))
|
||||
return;
|
||||
|
||||
if (target.getTeam() != sender.user().getTeam()) {
|
||||
sender.system("TEAM_LEADER_NOT_MEMBER");
|
||||
return;
|
||||
}
|
||||
|
||||
target.setLeader(true);
|
||||
sender.system("TEAM_LEADER_PROMOTED", target);
|
||||
}
|
||||
|
||||
@Register("info")
|
||||
public void info(@Validator("isInTeam") Chatter sender){
|
||||
info(sender, Team.get(sender.user().getTeam()));
|
||||
}
|
||||
|
||||
@Register(value = "info", description = "TEAM_INFO_USAGE")
|
||||
public void info(Chatter sender, @ErrorMessage("UNKNOWN_TEAM") Team team){
|
||||
List<SteamwarUser> users = team.getMembers().stream().map(SteamwarUser::get).toList();
|
||||
|
||||
sender.system("TEAM_INFO_TEAM", team.getTeamName(), team.getTeamColor(), team.getTeamKuerzel());
|
||||
sender.prefixless("TEAM_INFO_LEADER", users.stream().filter(SteamwarUser::isLeader).count(), getMemberList(users, true));
|
||||
|
||||
String members = getMemberList(users, false);
|
||||
if(!members.isEmpty())
|
||||
sender.prefixless("TEAM_INFO_MEMBER", users.stream().filter(u -> !u.isLeader()).count(), members);
|
||||
|
||||
Set<Event> events = TeamTeilnahme.getEvents(team.getTeamId());
|
||||
if(!events.isEmpty()){
|
||||
sender.prefixless("TEAM_INFO_EVENTS", events.stream().map(Event::getEventName).collect(Collectors.joining(", ")));
|
||||
}
|
||||
}
|
||||
|
||||
private String getMemberList(List<SteamwarUser> users, boolean leaders) {
|
||||
return users.stream()
|
||||
.filter(user -> user.isLeader() == leaders)
|
||||
.map(user -> (VelocityCore.getProxy().getPlayer(user.getUUID()).isPresent() ? "§a" : "§e") + user.getUserName())
|
||||
.collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
@Register("list")
|
||||
public void list(Chatter sender, @Min(intValue = 1) @OptionalValue("1") @ErrorMessage("TEAM_LIST_NOT_PAGE") int page){
|
||||
final int TEAMS_PER_PAGE = 10;
|
||||
|
||||
List<Team> all = Team.getAll();
|
||||
final int lastPage = ((all.size() - 1) / 10) + 1;
|
||||
if(page < 1 || page > lastPage){
|
||||
sender.system("TEAM_LIST_UNKNOWN_PAGE");
|
||||
return;
|
||||
}
|
||||
|
||||
sender.system("TEAM_LIST_HEADER", page, lastPage);
|
||||
|
||||
for(int i = (page-1) * TEAMS_PER_PAGE; i < (page-1) * TEAMS_PER_PAGE + TEAMS_PER_PAGE && i < all.size(); i++){
|
||||
Team tm = all.get(i);
|
||||
|
||||
sender.prefixless("TEAM_LIST_TEAM", new Message("TEAM_LIST_TEAM_HOVER"),
|
||||
ClickEvent.runCommand("/team info " + tm.getTeamKuerzel()), tm.getTeamColor(), tm.getTeamKuerzel(), tm.getTeamName());
|
||||
}
|
||||
|
||||
Component beforePage = Component
|
||||
.text("«« ")
|
||||
.color(page > 1 ? NamedTextColor.YELLOW : NamedTextColor.DARK_GRAY);
|
||||
if(page > 1)
|
||||
beforePage = beforePage
|
||||
.hoverEvent(HoverEvent.showText(sender.parse("TEAM_LIST_PREV")))
|
||||
.clickEvent(ClickEvent.runCommand("/team list " + (page - 1)));
|
||||
|
||||
Component nextPage = sender.parse("TEAM_LIST_PAGE")
|
||||
.color(page > 1 ? NamedTextColor.YELLOW : NamedTextColor.DARK_GRAY);
|
||||
if(page < lastPage)
|
||||
nextPage = nextPage
|
||||
.hoverEvent(HoverEvent.showText(sender.parse("TEAM_LIST_NEXT")))
|
||||
.clickEvent(ClickEvent.runCommand("/team list " + (page + 1)));
|
||||
|
||||
sender.sendMessage(beforePage.append(nextPage));
|
||||
}
|
||||
|
||||
@Register("event")
|
||||
public void event(@Validator("isInTeam") Chatter sender) {
|
||||
Team team = Team.get(sender.user().getTeam());
|
||||
|
||||
sender.system("TEAM_EVENT_USAGE");
|
||||
Set<Event> events = TeamTeilnahme.getEvents(team.getTeamId());
|
||||
if(!events.isEmpty()){
|
||||
sender.system("TEAM_EVENT_HEADER");
|
||||
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern(sender.parseToPlain("EVENT_DATE_FORMAT"));
|
||||
for(Event e : events)
|
||||
sender.prefixless("TEAM_EVENT_EVENT", e.getStart().toLocalDateTime().format(dateFormat), e.getEventName());
|
||||
}
|
||||
}
|
||||
|
||||
@Register("event")
|
||||
public void event(@Validator("isLeader") Chatter sender, Event event){
|
||||
Team team = Team.get(sender.user().getTeam());
|
||||
|
||||
if(notDuringEvent(sender))
|
||||
return;
|
||||
|
||||
if(Instant.now().isAfter(event.getDeadline().toInstant())){
|
||||
sender.system("TEAM_EVENT_OVER");
|
||||
return;
|
||||
}
|
||||
|
||||
if(TeamTeilnahme.nimmtTeil(team.getTeamId(), event.getEventID())){
|
||||
TeamTeilnahme.notTeilnehmen(team.getTeamId(), event.getEventID());
|
||||
sender.system("TEAM_EVENT_LEFT");
|
||||
}else{
|
||||
TeamTeilnahme.teilnehmen(team.getTeamId(), event.getEventID());
|
||||
sender.system("TEAM_EVENT_JOINED", event.getEventName());
|
||||
sender.prefixless("TEAM_EVENT_HOW_TO_LEAVE");
|
||||
}
|
||||
|
||||
DiscordBot.withBot(bot -> bot.getEventChannel().update());
|
||||
}
|
||||
|
||||
@Register("tp")
|
||||
public void tp(@Validator("isInTeam") PlayerChatter sender) {
|
||||
Team team = Team.get(sender.user().getTeam());
|
||||
tp(sender, team);
|
||||
}
|
||||
|
||||
@Register("tp")
|
||||
public void tp(PlayerChatter sender, @ErrorMessage("TEAM_TP_NO_TEAM") Team targetTeam) {
|
||||
if (targetTeam.getAddress() == null || targetTeam.getAddress().isEmpty()) {
|
||||
sender.system("TEAM_NO_ADDRESS");
|
||||
return;
|
||||
}
|
||||
|
||||
InetSocketAddress address = new InetSocketAddress(targetTeam.getAddress(), targetTeam.getPort());
|
||||
ServerInfo serverInfo = Storage.teamServers.computeIfAbsent(targetTeam.getTeamId(), integer -> {
|
||||
ServerInfo info = new ServerInfo("Team " + targetTeam.getTeamKuerzel(), address);
|
||||
VelocityCore.getProxy().registerServer(info);
|
||||
return info;
|
||||
});
|
||||
|
||||
if (!address.equals(serverInfo.getAddress())) {
|
||||
VelocityCore.getProxy().unregisterServer(Storage.teamServers.remove(targetTeam.getTeamId()));
|
||||
tp(sender, targetTeam);
|
||||
return;
|
||||
}
|
||||
|
||||
sender.getPlayer().createConnectionRequest(VelocityCore.getProxy().getServer(serverInfo.getName()).orElseThrow()).connect().whenComplete((result, throwable) -> {
|
||||
if(result.getStatus() != ConnectionRequestBuilder.Status.SUCCESS || throwable != null)
|
||||
sender.system("TEAM_OFFLINE");
|
||||
});
|
||||
}
|
||||
|
||||
@Register(value = "server", description = "TEAM_SERVER_USAGE")
|
||||
public void server(@Validator("isLeader") Chatter sender, String server, @Min(intValue = 1) @Max(intValue = 65535) @ErrorMessage("TEAM_SERVER_PORT_INVALID") int port){
|
||||
Team team = Team.get(sender.user().getTeam());
|
||||
if (PunishmentCommand.isPunishedWithMessage(sender, Punishment.PunishmentType.NoTeamServer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (isLocalhost(InetAddress.getByName(server))) {
|
||||
sender.system("TEAM_SERVER_ADDRESS_INVALID");
|
||||
return;
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
sender.system("TEAM_SERVER_ADDRESS_INVALID");
|
||||
return;
|
||||
}
|
||||
|
||||
team.setAddress(server);
|
||||
team.setPort(port);
|
||||
Storage.teamServers.remove(team.getTeamId());
|
||||
sender.system("TEAM_SERVER_SET");
|
||||
}
|
||||
|
||||
public static boolean isLocalhost(InetAddress addr) {
|
||||
// Check if the address is a valid special local or loop back
|
||||
if (addr.isAnyLocalAddress() || addr.isLoopbackAddress())
|
||||
return true;
|
||||
|
||||
// Check if the address is defined on any interface
|
||||
try {
|
||||
return NetworkInterface.getByInetAddress(addr) != null;
|
||||
} catch (SocketException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<String, Integer> COLOR_CODES = new HashMap<>();
|
||||
|
||||
static {
|
||||
COLOR_CODES.put("4", 1);
|
||||
COLOR_CODES.put("c", 15);
|
||||
COLOR_CODES.put("6", 14);
|
||||
COLOR_CODES.put("e", 11);
|
||||
COLOR_CODES.put("2", 2);
|
||||
COLOR_CODES.put("a", 10);
|
||||
COLOR_CODES.put("b", 12);
|
||||
COLOR_CODES.put("3", 6);
|
||||
COLOR_CODES.put("1", 4);
|
||||
COLOR_CODES.put("9", 6);
|
||||
COLOR_CODES.put("d", 9);
|
||||
COLOR_CODES.put("5", 5);
|
||||
COLOR_CODES.put("f", 15);
|
||||
COLOR_CODES.put("7", 7);
|
||||
COLOR_CODES.put("8", 8);
|
||||
COLOR_CODES.put("0", 16);
|
||||
}
|
||||
|
||||
@Register("color")
|
||||
public void changeColor(@Validator("isLeader") PlayerChatter sender) {
|
||||
Team team = Team.get(sender.user().getTeam());
|
||||
|
||||
if(notDuringEvent(sender))
|
||||
return;
|
||||
|
||||
SWListInv<String> inv = new SWListInv<>(sender, new Message("TEAM_COLOR_TITLE"), COLOR_CODES.entrySet().stream().map(entry -> new SWListInv.SWListEntry<>(new SWItem(new Message("PLAIN_STRING", "§" + entry.getKey() + team.getTeamKuerzel()), entry.getValue()), entry.getKey())).toList(), (click, element) -> {});
|
||||
inv.setCallback((click, element) -> {
|
||||
inv.close();
|
||||
team.setTeamColor(element);
|
||||
});
|
||||
inv.open();
|
||||
}
|
||||
|
||||
@ClassMapper(Event.class)
|
||||
public TypeMapper<Event> eventTypeMapper() {
|
||||
return new TypeMapper<Event>() {
|
||||
@Override
|
||||
public Event map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return Event.get(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(Chatter sender, Event value, MessageSender messageSender) {
|
||||
if (value == null) {
|
||||
sender.system("TEAM_EVENT_NO_EVENT");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return Event.getComing().stream().map(Event::getEventName).toList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Validator(value = "isNotInTeam", local = true)
|
||||
public TypeValidator<Chatter> isNotInTeamValidator() {
|
||||
return (sender, value, messageSender) -> {
|
||||
if (sender.user().getTeam() != 0) {
|
||||
messageSender.send("TEAM_IN_TEAM");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
@Validator(value = "isInTeam", local = true)
|
||||
public TypeValidator<Chatter> isInTeamValidator() {
|
||||
return (sender, value, messageSender) -> {
|
||||
if (sender.user().getTeam() == 0) {
|
||||
messageSender.send("TEAM_NOT_IN_TEAM");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
@Validator(value = "isLeader", local = true)
|
||||
public TypeValidator<Chatter> isLeaderValidator() {
|
||||
return (sender, value, messageSender) -> {
|
||||
SteamwarUser user = sender.user();
|
||||
if (user.getTeam() == 0) {
|
||||
messageSender.send("TEAM_NOT_IN_TEAM");
|
||||
return false;
|
||||
}
|
||||
if (!user.isLeader()) {
|
||||
messageSender.send("TEAM_NOT_LEADER");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
@ClassMapper(Team.class)
|
||||
@Cached(global = true, cacheDuration = 60)
|
||||
public TypeMapper<Team> team() {
|
||||
return new TypeMapper<Team>() {
|
||||
@Override
|
||||
public Team map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return Team.get(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return Team.getAll().stream()
|
||||
.flatMap(team -> Stream.of(team.getTeamName(), team.getTeamKuerzel()))
|
||||
.toList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean checkTeamName(Chatter sender, Team team, String arg){
|
||||
Team t = Team.get(arg);
|
||||
if(t != null && t.getTeamId() != team.getTeamId()){
|
||||
sender.system("TEAM_NAME_TAKEN");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkTeamKuerzel(Chatter sender, Team team, String arg){
|
||||
Team t = Team.get(arg);
|
||||
if(t != null && (team == null || t.getTeamId() != team.getTeamId())){
|
||||
sender.system("TEAM_KUERZEL_TAKEN");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean notDuringEvent(Chatter sender){
|
||||
if(Event.get() != null){
|
||||
sender.system("TEAM_NOT_IN_EVENT");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.listeners.ChatListener;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.ChatterGroup;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
|
||||
public class TeamchatCommand extends SWCommand {
|
||||
|
||||
public TeamchatCommand() {
|
||||
super("tc", "teamchat");
|
||||
}
|
||||
|
||||
@Register(description = "TC_USAGE")
|
||||
public void genericCommand(Chatter sender, @ErrorMessage(value = "TC_USAGE", allowEAs = false) String... args) {
|
||||
SteamwarUser user = sender.user();
|
||||
|
||||
if(user.getTeam() == 0){
|
||||
sender.system("TC_NO_TEAM");
|
||||
return;
|
||||
}
|
||||
|
||||
ChatListener.sendChat(sender, new ChatterGroup(Chatter.allStream().filter(p -> p.user().getTeam() == user.getTeam())), "CHAT_TEAM", null, String.join(" ", args));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import de.steamwar.velocitycore.*;
|
||||
import de.steamwar.velocitycore.util.BauLock;
|
||||
import de.steamwar.command.PreviousArguments;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.persistent.Bauserver;
|
||||
import de.steamwar.persistent.Storage;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.sql.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class TpCommand extends SWCommand {
|
||||
|
||||
public TpCommand(){
|
||||
super("join", "tp", "teleport");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(Chatter sender) {
|
||||
sender.system(Event.get() == null ? "TP_USAGE" : "TP_USAGE_EVENT");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void teleportCommand(PlayerChatter sender, @Mapper("to") String to, String... rest) {
|
||||
RegisteredServer server = getTarget(to);
|
||||
|
||||
//Give control of teleport command to server
|
||||
Player p = sender.getPlayer();
|
||||
if (server == null || server.getPlayersConnected().contains(p)) {
|
||||
if (rest.length == 0) {
|
||||
p.spoofChatInput("/tp " + to);
|
||||
} else {
|
||||
p.spoofChatInput("/tp " + to + " " + String.join(" ", rest));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
teleport(sender, server);
|
||||
}
|
||||
|
||||
@Mapper("to")
|
||||
@Cached(cacheDuration = 10)
|
||||
public TypeMapper<String> tabCompleter() {
|
||||
return new TypeMapper<>() {
|
||||
@Override
|
||||
public String map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (Player player : VelocityCore.getProxy().getAllPlayers()) {
|
||||
list.add(player.getUsername());
|
||||
}
|
||||
if (Event.get() != null) {
|
||||
EventStarter.getEventServer().keySet().forEach(teamId -> {
|
||||
Team team = Team.get(teamId);
|
||||
list.add(team.getTeamName());
|
||||
list.add(team.getTeamKuerzel());
|
||||
});
|
||||
}
|
||||
if (Storage.teamServers.containsValue(sender.getPlayer().getCurrentServer().orElseThrow().getServerInfo())) {
|
||||
Storage.directTabItems.getOrDefault(sender.getPlayer(), Collections.emptyMap()).forEach((uuid, item) -> list.add(item.getProfile().getName()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void teleport(PlayerChatter sender, RegisteredServer server) {
|
||||
if(CheckCommand.isChecking(sender.getPlayer())){
|
||||
sender.system("CHECK_CHECKING");
|
||||
return;
|
||||
}
|
||||
|
||||
Subserver subserver = Subserver.getSubserver(server.getServerInfo());
|
||||
if(subserver == null) {
|
||||
sender.getPlayer().createConnectionRequest(server).fireAndForget();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (subserver.getType()) {
|
||||
case ARENA:
|
||||
if (PunishmentCommand.isPunishedWithMessage(sender, Punishment.PunishmentType.NoFightServer))
|
||||
return;
|
||||
break;
|
||||
|
||||
case BAUSERVER:
|
||||
Bauserver bauserver = (Bauserver) subserver;
|
||||
Player checker = VelocityCore.getProxy().getPlayer(bauserver.getOwner()).orElse(null);
|
||||
if (checker != null && CheckCommand.isChecking(checker)) {
|
||||
if (!sender.user().hasPerm(UserPerm.CHECK) && CheckCommand.getCheckingSchem(checker).getOwner() != sender.user().getId()) {
|
||||
sender.system("JOIN_PLAYER_BLOCK");
|
||||
return;
|
||||
}
|
||||
} else if (BauLock.isLocked(SteamwarUser.get(bauserver.getOwner()), sender.user())) {
|
||||
sender.system("BAU_LOCKED_NOALLOWED");
|
||||
Chatter.of(bauserver.getOwner()).system("BAU_LOCK_BLOCKED", sender);
|
||||
return;
|
||||
} else if (!bauserver.getOwner().equals(sender.user().getUUID()) && BauweltMember.getBauMember(bauserver.getOwner(), sender.user().getUUID()) == null) {
|
||||
SubserverSystem.sendDeniedMessage(sender, bauserver.getOwner());
|
||||
sender.system("JOIN_PLAYER_BLOCK");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case BUILDER:
|
||||
if(!sender.user().hasPerm(UserPerm.BUILD)) {
|
||||
sender.system("JOIN_PLAYER_BLOCK");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
SubserverSystem.sendPlayer(subserver, sender.getPlayer());
|
||||
}
|
||||
|
||||
private static RegisteredServer getTarget(String arg) {
|
||||
RegisteredServer server = null;
|
||||
|
||||
//Get target player server
|
||||
Player target = VelocityCore.getProxy().getPlayer(arg).orElse(null);
|
||||
if(target != null)
|
||||
server = target.getCurrentServer().map(ServerConnection::getServer).orElse(server);
|
||||
|
||||
//Get target team event arena
|
||||
if(server == null){
|
||||
Team team = Team.get(arg);
|
||||
if(team != null){
|
||||
Subserver eventArena = EventStarter.getEventServer().get(team.getTeamId());
|
||||
if(eventArena != null && Subserver.getServerList().contains(eventArena))
|
||||
server = eventArena.getRegisteredServer();
|
||||
}
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.*;
|
||||
import de.steamwar.velocitycore.inventory.SWInventory;
|
||||
import de.steamwar.velocitycore.inventory.SWItem;
|
||||
import de.steamwar.velocitycore.inventory.SWListInv;
|
||||
import de.steamwar.velocitycore.inventory.SWStreamInv;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeValidator;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.persistent.Servertype;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.Tutorial;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class TutorialCommand extends SWCommand {
|
||||
|
||||
public TutorialCommand() {
|
||||
super("tutorial");
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(PlayerChatter sender) {
|
||||
openInventory(sender, true, false);
|
||||
}
|
||||
|
||||
@Register("rate")
|
||||
public void rate(PlayerChatter sender) {
|
||||
sender.getPlayer().spoofChatInput("/tutorial rate");
|
||||
}
|
||||
|
||||
@Register("rate")
|
||||
public void rate(PlayerChatter sender, int id) {
|
||||
Tutorial tutorial = Tutorial.get(id);
|
||||
if(tutorial == null) {
|
||||
sender.getPlayer().spoofChatInput("/tutorial rate"); // Catch players manually entering numbers
|
||||
return;
|
||||
}
|
||||
|
||||
rate(sender, tutorial);
|
||||
}
|
||||
|
||||
@Register(value = "create", description = "TUTORIAL_CREATE_HELP")
|
||||
public void create(PlayerChatter sender, String material, String... name) {
|
||||
create(sender, String.join(" ", name), material.toUpperCase());
|
||||
}
|
||||
|
||||
@Register("own")
|
||||
public void own(PlayerChatter sender) {
|
||||
openInventory(sender, false, true);
|
||||
}
|
||||
|
||||
@Register("unreleased")
|
||||
public void unreleased(@Validator("unreleased") PlayerChatter sender) {
|
||||
openInventory(sender, false, false);
|
||||
}
|
||||
|
||||
@Validator("unreleased")
|
||||
public TypeValidator<Chatter> unreleasedChecker() {
|
||||
return (sender, value, messageSender) -> sender.user().hasPerm(UserPerm.TEAM);
|
||||
}
|
||||
|
||||
private void openInventory(PlayerChatter sender, boolean released, boolean own) {
|
||||
SteamwarUser user = sender.user();
|
||||
|
||||
new SWStreamInv<>(
|
||||
sender,
|
||||
new Message("TUTORIAL_TITLE"),
|
||||
(click, tutorial) -> {
|
||||
if(!released && click.isShiftClick() && user.hasPerm(UserPerm.TEAM) && user.getId() != tutorial.getCreator()) {
|
||||
tutorial.release();
|
||||
openInventory(sender, released, own);
|
||||
return;
|
||||
} else if(own && click.isShiftClick() && click.isRightClick()) {
|
||||
tutorial.delete();
|
||||
SubserverSystem.deleteFolder(VelocityCore.local, world(tutorial).getPath());
|
||||
openInventory(sender, released, own);
|
||||
return;
|
||||
}
|
||||
|
||||
new ServerStarter().tutorial(sender.getPlayer(), tutorial).start();
|
||||
},
|
||||
page -> (own ? Tutorial.getOwn(user.getId(), page, 45) : Tutorial.getPage(page, 45, released)).stream().map(tutorial -> new SWListInv.SWListEntry<>(getTutorialItem(tutorial, own), tutorial)).toList()
|
||||
).open();
|
||||
}
|
||||
|
||||
private SWItem getTutorialItem(Tutorial tutorial, boolean personalHighlights) {
|
||||
SWItem item = new SWItem(tutorial.getItem(), new Message("TUTORIAL_NAME", tutorial.getName()));
|
||||
item.setHideAttributes(true);
|
||||
|
||||
item.addLore(new Message("TUTORIAL_BY", SteamwarUser.get(tutorial.getCreator()).getUserName()));
|
||||
item.addLore(new Message("TUTORIAL_STARS", String.format("%.1f", tutorial.getStars())));
|
||||
|
||||
if (personalHighlights)
|
||||
item.addLore(new Message("TUTORIAL_DELETE"));
|
||||
|
||||
if (personalHighlights && tutorial.isReleased())
|
||||
item.setEnchanted(true);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private void rate(PlayerChatter sender, Tutorial tutorial) {
|
||||
int[] rates = new int[]{1, 2, 3, 4, 5};
|
||||
|
||||
new SWListInv<>(sender, new Message("TUTORIAL_RATE_TITLE"), Arrays.stream(rates).mapToObj(rate -> new SWListInv.SWListEntry<>(new SWItem("NETHER_STAR", new Message("TUTORIAL_RATE", rate)), rate)).toList(), (click, rate) -> {
|
||||
tutorial.rate(sender.user().getId(), rate);
|
||||
SWInventory.close(sender);
|
||||
}).open();
|
||||
}
|
||||
|
||||
private void create(PlayerChatter sender, String name, String item) {
|
||||
Subserver subserver = Subserver.getSubserver(sender.getPlayer());
|
||||
SteamwarUser user = sender.user();
|
||||
File tempWorld = new File(ServerStarter.TEMP_WORLD_PATH, ServerStarter.serverToWorldName(ServerStarter.bauServerName(user)));
|
||||
|
||||
if(subserver == null || !subserver.isStarted() || subserver.getType() != Servertype.BAUSERVER || !tempWorld.exists()) {
|
||||
sender.system("TUTORIAL_CREATE_MISSING");
|
||||
return;
|
||||
}
|
||||
|
||||
subserver.execute("save-all");
|
||||
VelocityCore.schedule(() -> {
|
||||
Tutorial tutorial = Tutorial.create(user.getId(), name, item);
|
||||
File tutorialWorld = world(tutorial);
|
||||
|
||||
if (tutorialWorld.exists())
|
||||
SubserverSystem.deleteFolder(VelocityCore.local, tutorialWorld.getPath());
|
||||
ServerStarter.copyWorld(VelocityCore.local, tempWorld.getPath(), tutorialWorld.getPath());
|
||||
sender.system("TUTORIAL_CREATED");
|
||||
}).delay(1, TimeUnit.SECONDS).schedule();
|
||||
}
|
||||
|
||||
private File world(Tutorial tutorial) {
|
||||
return new File(ServerStarter.TUTORIAL_PATH, String.valueOf(tutorial.getTutorialId()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.ArenaMode;
|
||||
import de.steamwar.command.PreviousArguments;
|
||||
import de.steamwar.command.SWCommandUtils;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
import de.steamwar.command.TypeValidator;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.sql.Punishment;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@UtilityClass
|
||||
public class TypeMappers {
|
||||
|
||||
public static void init() {
|
||||
SWCommandUtils.addValidator("arenaPlayer", arenaPlayer());
|
||||
SWCommandUtils.addMapper("nonHistoricArenaMode", arenaModeTypeMapper(false));
|
||||
SWCommandUtils.addMapper("historicArenaMode", arenaModeTypeMapper(true));
|
||||
SWCommandUtils.addMapper("arenaMap", arenaMapTypeMapper());
|
||||
}
|
||||
|
||||
private static TypeValidator<PlayerChatter> arenaPlayer() {
|
||||
return (sender, player, messageSender) -> !PunishmentCommand.isPunishedWithMessage(player, Punishment.PunishmentType.NoFightServer);
|
||||
}
|
||||
|
||||
private static TypeMapper<ArenaMode> arenaModeTypeMapper(boolean historic) {
|
||||
return new TypeMapper<>() {
|
||||
@Override
|
||||
public ArenaMode map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return ArenaMode.getByChat(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
return ArenaMode.getAllChatNames(historic);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static TypeMapper<String> arenaMapTypeMapper() {
|
||||
return new TypeMapper<>() {
|
||||
@Override
|
||||
public String map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
if (previousArguments.userArgs.length == 0) return null;
|
||||
return ArenaMode.getByChat(previousArguments.userArgs[previousArguments.userArgs.length - 1]).convertToRealMapName(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
if (previousArguments.userArgs.length == 0) return null;
|
||||
ArenaMode arenaMode = ArenaMode.getByChat(previousArguments.userArgs[previousArguments.userArgs.length - 1]);
|
||||
if (arenaMode == null) return null;
|
||||
return arenaMode.getMaps();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.IgnoreSystem;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
|
||||
public class UnIgnoreCommand extends SWCommand {
|
||||
|
||||
public UnIgnoreCommand() {
|
||||
super("unignore");
|
||||
}
|
||||
|
||||
@Register(description = "UNIGNORE_USAGE")
|
||||
public void genericCommand(Chatter sender, @ErrorMessage("UNIGNORE_NOT_PLAYER") SteamwarUser target) {
|
||||
SteamwarUser user = sender.user();
|
||||
|
||||
if(!IgnoreSystem.isIgnored(user, target)){
|
||||
sender.system("UNIGNORE_NOT_IGNORED");
|
||||
return;
|
||||
}
|
||||
|
||||
IgnoreSystem.unIgnore(user, target);
|
||||
sender.system("UNIGNORE_UNIGNORED", target.getUserName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.discord.util.AuthManager;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class VerifyCommand extends SWCommand {
|
||||
|
||||
public VerifyCommand() {
|
||||
super("verify");
|
||||
}
|
||||
|
||||
@Register(description = "VERIFY_USAGE")
|
||||
public void genericCommand(Chatter sender, String code) {
|
||||
byte[] bytes;
|
||||
try {
|
||||
bytes = Base64.getDecoder().decode(code);
|
||||
} catch (IllegalArgumentException e) {
|
||||
sender.system("VERIFY_INVALID");
|
||||
return;
|
||||
}
|
||||
|
||||
if(bytes.length != 16) {
|
||||
sender.system("VERIFY_INVALID");
|
||||
return;
|
||||
}
|
||||
|
||||
User user = AuthManager.connectAuth(sender.user(), code);
|
||||
if(user != null) {
|
||||
VelocityCore.getLogger().log(Level.INFO,"%s Verified with Discorduser: %s".formatted(sender.user().getUserName(), user.getIdLong()));
|
||||
sender.system("VERIFY_SUCCESS", user.getAsTag());
|
||||
} else {
|
||||
sender.system("VERIFY_INVALID");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
public class WebpasswordCommand extends SWCommand {
|
||||
|
||||
public WebpasswordCommand() {
|
||||
super("webpassword", "webpw", "web");
|
||||
}
|
||||
|
||||
|
||||
@Register(description = "WEB_USAGE")
|
||||
public void genericCommand(Chatter sender, String password) {
|
||||
if(password.length() < 8) {
|
||||
sender.system("WEB_PASSWORD_LENGTH");
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder("php", "/var/www/register.php", sender.user().getUserName(), password);
|
||||
pb.redirectErrorStream(true);
|
||||
try {
|
||||
Process regProcess = pb.start();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(regProcess.getInputStream()));
|
||||
String errorLine;
|
||||
if((errorLine = reader.readLine()) != null) {
|
||||
if ("updated".equals(errorLine)) {
|
||||
sender.system("WEB_UPDATED");
|
||||
return;
|
||||
} else {
|
||||
throw new SecurityException("Could not create webaccount " + errorLine);
|
||||
}
|
||||
}
|
||||
|
||||
sender.system("WEB_CREATED");
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not create webaccount", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void changeUsername(String oldUsername, String newUsername){
|
||||
ProcessBuilder pb = new ProcessBuilder("php", "/var/www/changename.php", oldUsername, newUsername);
|
||||
try {
|
||||
pb.start();
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not change username", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.commands;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.steamwar.persistent.Storage;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.mods.ModUtils;
|
||||
import de.steamwar.command.PreviousArguments;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.sql.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DecimalFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
||||
public class WhoisCommand extends SWCommand {
|
||||
public WhoisCommand() {
|
||||
super("whois");
|
||||
}
|
||||
|
||||
@Register(description = "WHOIS_USAGE")
|
||||
public void whois(Chatter sender, long id, WhoisParameterTypes... parameters) {
|
||||
if(!sender.user().hasPerm(UserPerm.ADMINISTRATION)) {
|
||||
sender.system("UNKNOWN_PLAYER");
|
||||
return;
|
||||
}
|
||||
|
||||
// SW ID or Discord ID
|
||||
whois(sender, id < Integer.MAX_VALUE ? SteamwarUser.get((int) id) : SteamwarUser.get(id), parameters);
|
||||
}
|
||||
|
||||
@Register(description = "WHOIS_USAGE")
|
||||
public void whois(Chatter sender, SteamwarUser user, WhoisParameterTypes... parameters) {
|
||||
EnumSet<WhoisParameterTypes> parameterTypes = parameters.length == 0 ? EnumSet.noneOf(WhoisParameterTypes.class) : EnumSet.copyOf(Arrays.asList(parameters));
|
||||
|
||||
Team team = Team.get(user.getTeam());
|
||||
|
||||
sender.system("WHOIS_USERNAME", user.getUserName());
|
||||
sender.system("WHOIS_PREFIX", user.prefix().getColorCode() + user.prefix().getChatPrefix());
|
||||
sender.system("WHOIS_TEAM", new Message("WHOIS_TEAM_HOVER", team.getTeamName()), ClickEvent.runCommand("/team info " + team.getTeamKuerzel()), team.getTeamColor(), team.getTeamKuerzel(), team.getTeamName());
|
||||
|
||||
if (!sender.user().hasPerm(UserPerm.TEAM))
|
||||
return;
|
||||
|
||||
if (sender.user().hasPerm(UserPerm.MODERATION)) {
|
||||
sender.system("WHOIS_ID", user.getId());
|
||||
sender.system("WHOIS_UUID", new Message("WHOIS_UUID_HOVER"), ClickEvent.copyToClipboard(user.getUUID().toString()), user.getUUID().toString());
|
||||
if (user.getDiscordId() != null)
|
||||
sender.system("WHOIS_DISCORD_ID", user.getDiscordId());
|
||||
|
||||
sender.system("WHOIS_PERMS", user.perms().stream().map(Enum::name).collect(Collectors.joining(", ")));
|
||||
}
|
||||
|
||||
Player target = VelocityCore.getProxy().getPlayer(user.getUUID()).orElse(null);
|
||||
Timestamp firstJoin = user.getFirstjoin();
|
||||
double onlineTime = user.getOnlinetime();
|
||||
if(firstJoin == null && target != null) {
|
||||
firstJoin = Storage.sessions.get(target);
|
||||
}
|
||||
|
||||
if(firstJoin != null)
|
||||
sender.system("WHOIS_JOINED_FIRST", firstJoin.toString());
|
||||
sender.system("WHOIS_HOURS_PLAYED", new DecimalFormat("###.##").format(onlineTime / 3600d));
|
||||
|
||||
if(target != null) {
|
||||
sender.system("WHOIS_CURRENT_PLAYED", new DecimalFormat("####.##").format((Instant.now().getEpochSecond() - Storage.sessions.get(target).toInstant().getEpochSecond()) / 60d));
|
||||
sender.system("WHOIS_CURRENT_SERVER", target.getCurrentServer().orElseThrow().getServerInfo().getName());
|
||||
sender.system("WHOIS_CURRENT_PROTOCOL", target.getProtocolVersion().getMostRecentSupportedVersion());
|
||||
|
||||
List<Mod> mods = ModUtils.getPlayerModMap().get(user.getUUID());
|
||||
if(mods == null)
|
||||
mods = Collections.emptyList();
|
||||
|
||||
sender.system("WHOIS_PLATFORM", mods.isEmpty() ? "Vanilla" : mods.get(0).getPlatform().toString());
|
||||
|
||||
if (parameterTypes.contains(WhoisParameterTypes.MOD)) {
|
||||
if (!mods.isEmpty()) {
|
||||
sender.system("WHOIS_ACTIVE_MODS", mods.size(), mods.stream().map(mod -> "§" + mod.getModType().getColorCode() + mod.getModName()).collect(Collectors.joining("§8, ")));
|
||||
} else {
|
||||
sender.system("WHOIS_NO_ACTIVE_MODS");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sender.system("WHOIS_PUNISHMENTS");
|
||||
List<Punishment> punishmentList = Punishment.getAllPunishmentsOfPlayer(user.getId());
|
||||
Set<Punishment.PunishmentType> found = new HashSet<>();
|
||||
boolean isPunished = false;
|
||||
boolean all = parameterTypes.contains(WhoisParameterTypes.ALL);
|
||||
for (Punishment punishment : punishmentList) {
|
||||
if (!all && !punishment.getType().isMulti() && !found.add(punishment.getType())) {
|
||||
continue;
|
||||
}
|
||||
if (!all && !punishment.isCurrent()) {
|
||||
continue;
|
||||
}
|
||||
sender.prefixless("WHOIS_PUNISHMENT", SteamwarUser.get(punishment.getPunisher()), punishment.getType().name(), duration(sender, punishment.getStartTime(), false), duration(sender, punishment.getEndTime(), punishment.isPerma()), punishment.getReason());
|
||||
isPunished = true;
|
||||
}
|
||||
if (!isPunished) {
|
||||
sender.system(all ? "WHOIS_NO_ALL_PUNISHMENT" : "WHOIS_NO_PUNISHMENT");
|
||||
}
|
||||
}
|
||||
|
||||
private Message duration(Chatter sender, Timestamp timestamp, boolean perma) {
|
||||
if(perma)
|
||||
return new Message("PUNISHMENT_PERMA");
|
||||
else
|
||||
return new Message("PLAIN_STRING", timestamp.toLocalDateTime().format(DateTimeFormatter.ofPattern(sender.parseToPlain("TIMEFORMAT"))));
|
||||
}
|
||||
|
||||
@ClassMapper(value = WhoisParameterTypes.class, local = true)
|
||||
public TypeMapper<WhoisParameterTypes> argumentTypeMapper() {
|
||||
WhoisParameterTypes[] values = WhoisParameterTypes.values();
|
||||
|
||||
return new TypeMapper<WhoisParameterTypes>() {
|
||||
@Override
|
||||
public WhoisParameterTypes map(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
SteamwarUser user = sender.user();
|
||||
return Stream.of(values)
|
||||
.filter(p -> user.hasPerm(p.perm))
|
||||
.filter(p -> p.getTabCompletes().contains(s))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> tabCompletes(Chatter sender, PreviousArguments previousArguments, String s) {
|
||||
SteamwarUser user = sender.user();
|
||||
return Stream.of(values)
|
||||
.filter(p -> user.hasPerm(p.perm))
|
||||
.flatMap(p -> p.getTabCompletes().stream())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
public enum WhoisParameterTypes {
|
||||
ALL(Arrays.asList("-a", "-all"), UserPerm.TEAM),
|
||||
MOD(Arrays.asList("-m", "-mod", "-mods"), UserPerm.MODERATION);
|
||||
|
||||
@Getter
|
||||
private final List<String> tabCompletes;
|
||||
private final UserPerm perm;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.discord;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.Event;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.discord.channels.*;
|
||||
import de.steamwar.velocitycore.discord.listeners.ChannelListener;
|
||||
import de.steamwar.velocitycore.discord.listeners.DiscordSchemUpload;
|
||||
import de.steamwar.velocitycore.discord.listeners.DiscordTeamEvent;
|
||||
import de.steamwar.velocitycore.discord.listeners.DiscordTicketHandler;
|
||||
import de.steamwar.velocitycore.discord.util.AuthManager;
|
||||
import lombok.Getter;
|
||||
import net.dv8tion.jda.api.*;
|
||||
import net.dv8tion.jda.api.entities.*;
|
||||
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
|
||||
import net.dv8tion.jda.api.exceptions.ErrorResponseException;
|
||||
import net.dv8tion.jda.api.interactions.commands.Command;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
|
||||
import net.dv8tion.jda.api.interactions.components.ActionRow;
|
||||
import net.dv8tion.jda.api.interactions.components.Button;
|
||||
import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction;
|
||||
import net.dv8tion.jda.api.utils.MemberCachePolicy;
|
||||
|
||||
import javax.security.auth.login.LoginException;
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class DiscordBot {
|
||||
public static final String ARGUMENT_NAME = "arguments";
|
||||
|
||||
@Getter
|
||||
private static DiscordBot instance;
|
||||
|
||||
@Getter
|
||||
private static final Map<String, SWCommand> commands = new HashMap<>();
|
||||
|
||||
public static void withBot(Consumer<DiscordBot> consumer) {
|
||||
if(instance != null)
|
||||
consumer.accept(instance);
|
||||
}
|
||||
|
||||
public static Guild getGuild() {
|
||||
return instance.jda.getGuildById(instance.config.getGuild());
|
||||
}
|
||||
|
||||
@Getter
|
||||
private DiscordChannel announcementChannel;
|
||||
@Getter
|
||||
private DiscordChatRoom ingameChat;
|
||||
@Getter
|
||||
private DiscordChatRoom serverTeamChat;
|
||||
@Getter
|
||||
private StaticMessageChannel eventChannel;
|
||||
@Getter
|
||||
private ChecklistChannel checklistChannel;
|
||||
|
||||
@Getter
|
||||
private final DiscordConfig config;
|
||||
@Getter
|
||||
private final JDA jda;
|
||||
|
||||
public DiscordBot(DiscordConfig config) {
|
||||
this.config = config;
|
||||
|
||||
try {
|
||||
jda = JDABuilder
|
||||
.createDefault(config.getToken())
|
||||
.setStatus(OnlineStatus.ONLINE)
|
||||
.setMemberCachePolicy(MemberCachePolicy.ONLINE)
|
||||
.build();
|
||||
} catch (LoginException e) {
|
||||
throw new SecurityException("Could not login", e);
|
||||
}
|
||||
|
||||
instance = this;
|
||||
VelocityCore.schedule(this::asyncInit).schedule();
|
||||
}
|
||||
|
||||
private void asyncInit() {
|
||||
try {
|
||||
jda.awaitReady();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
activity();
|
||||
new StaticMessageChannel(config.channel("roles"), () -> new MessageBuilder()
|
||||
.setContent("**Rollenvergabe**\nKlicke um eine Rolle zu bekommen:")
|
||||
.setActionRows(ActionRow.of(config.getRoles().values().stream().map(DiscordConfig.DiscordRole::toButton).toArray(Button[]::new))), event -> InteractionReply.reply(event, reply -> {
|
||||
Member member = event.getMember();
|
||||
Guild guild = event.getGuild();
|
||||
Role role = guild.getRoleById(event.getComponentId());
|
||||
|
||||
if (member.getRoles().stream().anyMatch(role::equals)) {
|
||||
guild.removeRoleFromMember(member, role).queue();
|
||||
reply.system("DC_ROLE_REMOVED", role.getAsMention());
|
||||
} else {
|
||||
guild.addRoleToMember(member, role).queue();
|
||||
reply.system("DC_ROLE_ADDED", role.getAsMention());
|
||||
}
|
||||
}));
|
||||
new StaticMessageChannel(config.channel("rules"), () -> new MessageBuilder()
|
||||
.setEmbeds(new EmbedBuilder()
|
||||
.setDescription(String.join("\n", config.getRules()))
|
||||
.setColor(Color.GRAY)
|
||||
.setAuthor("SteamWar", "https://steamwar.de")
|
||||
.setTitle("Regeln und Infos")
|
||||
.build())
|
||||
.setActionRows(
|
||||
ActionRow.of(Button.link("https://steamwar.de", "Website"), Button.link("https://steamwar.de/youtube", "YouTube")),
|
||||
ActionRow.of(Button.primary("auth", Emoji.fromUnicode("U+2705")).withLabel("Minecraft verknüpfen"))
|
||||
), event -> {
|
||||
if(event.getComponentId().equals("auth"))
|
||||
event.reply("Gebe innerhalb der nächsten 10 Minuten ``/verify " + AuthManager.createDiscordAuthToken(event.getUser()) + "`` auf dem Minecraft Server ein").setEphemeral(true).queue();
|
||||
});
|
||||
new StaticMessageChannel(config.channel("ticket"), () -> new MessageBuilder()
|
||||
.setEmbeds(new EmbedBuilder()
|
||||
.setDescription("Hier kannst du Tickets öffnen, welche nur von dir und Teammitgliedern eingesehen werden können.")
|
||||
.setTitle("SteamWar Tickets")
|
||||
.setColor(Color.RED)
|
||||
.build())
|
||||
.setActionRows(ActionRow.of(Arrays.stream(DiscordTicketType.values()).map(DiscordTicketType::toButton).toArray(Button[]::new))), DiscordTicketHandler::openTicket);
|
||||
eventChannel = new StaticMessageChannel(config.channel("events"), EventChannel::get);
|
||||
checklistChannel = new ChecklistChannel(config.channel("checklist"));
|
||||
|
||||
announcementChannel = new DiscordChannel(config.channel("announcement")) {
|
||||
@Override
|
||||
public void received(GuildMessageReceivedEvent event) {
|
||||
Chatter.broadcast().system("ALERT", event.getMessage().getContentDisplay());
|
||||
}
|
||||
};
|
||||
ingameChat = new DiscordChatRoom(config.channel("ingame"), "CHAT_DISCORD_GLOBAL", Chatter::broadcast);
|
||||
serverTeamChat = new DiscordChatRoom(config.channel("serverteam"), "CHAT_SERVERTEAM", Chatter::serverteam);
|
||||
|
||||
VelocityCore.schedule(() -> {
|
||||
try {
|
||||
activity();
|
||||
eventChannel.update();
|
||||
checklistChannel.update();
|
||||
} catch (ErrorResponseException e) {
|
||||
//ignored
|
||||
}
|
||||
}).repeat(30, TimeUnit.SECONDS).schedule();
|
||||
|
||||
jda.addEventListener(
|
||||
new DiscordTicketHandler(),
|
||||
new DiscordTeamEvent(),
|
||||
new ChannelListener(),
|
||||
new DiscordSchemUpload()
|
||||
);
|
||||
|
||||
commandSetup(jda.retrieveCommands().complete(), jda.updateCommands());
|
||||
}
|
||||
|
||||
private final OptionData commandArgument = new OptionData(OptionType.STRING, ARGUMENT_NAME, "Command arguments", false);
|
||||
private void commandSetup(List<Command> existing, CommandListUpdateAction updateCommands) {
|
||||
Set<String> correctCommands = new HashSet<>();
|
||||
for(Command command : existing) {
|
||||
if(!commands.containsKey(command.getName())) {
|
||||
command.delete().complete();
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Command.Option> options = command.getOptions();
|
||||
if(options.size() != 1 || options.get(0).getType() != OptionType.STRING)
|
||||
command.editCommand().clearOptions().addOptions(commandArgument).complete();
|
||||
|
||||
correctCommands.add(command.getName());
|
||||
}
|
||||
|
||||
updateCommands
|
||||
.addCommands(commands
|
||||
.keySet().stream()
|
||||
.filter(command -> !correctCommands.contains(command))
|
||||
.filter(command -> command.matches("^[\\w-]+$"))
|
||||
.map(command -> new CommandData(command, command).addOptions(commandArgument))
|
||||
.toArray(CommandData[]::new))
|
||||
.queue();
|
||||
}
|
||||
|
||||
private boolean activityToggle = false;
|
||||
private void activity() {
|
||||
if(activityToggle) {
|
||||
Event event = Event.get();
|
||||
jda.getPresence().setActivity(event != null ? Activity.competing("dem Event " + event.getEventName()) : Activity.playing("auf SteamWar.de"));
|
||||
} else {
|
||||
int count = VelocityCore.getProxy().getPlayerCount();
|
||||
jda.getPresence().setActivity(Activity.playing(count == 1 ? "mit 1 Spieler" : ("mit " + count + " Spielern")));
|
||||
}
|
||||
|
||||
activityToggle = !activityToggle;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.discord;
|
||||
|
||||
import de.steamwar.velocitycore.Config;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.dv8tion.jda.api.entities.Emoji;
|
||||
import net.dv8tion.jda.api.interactions.components.Button;
|
||||
import net.dv8tion.jda.api.interactions.components.ButtonStyle;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
public class DiscordConfig {
|
||||
|
||||
public static DiscordConfig load() {
|
||||
File file = new File(System.getProperty("user.home"), "discord.yml");
|
||||
if(!file.exists() || VelocityCore.get().getConfig().isEventmode())
|
||||
return null;
|
||||
|
||||
return Config.load(DiscordConfig.class, file, description -> description.addPropertyParameters("roles", String.class, DiscordRole.class));
|
||||
}
|
||||
|
||||
public String channel(String type) {
|
||||
return channels.get(type);
|
||||
}
|
||||
|
||||
private String token;
|
||||
private String guild;
|
||||
|
||||
private Map<String, String> channels;
|
||||
private Map<String, String> ranks;
|
||||
private Map<String, DiscordRole> roles;
|
||||
private List<String> rules;
|
||||
|
||||
private String ticketcategory;
|
||||
|
||||
@NoArgsConstructor
|
||||
public static class DiscordRole {
|
||||
|
||||
private String emoji;
|
||||
private String label;
|
||||
private String roleId;
|
||||
|
||||
public Button toButton() {
|
||||
return Button.of(ButtonStyle.SECONDARY, roleId, label, Emoji.fromUnicode(emoji));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.discord;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.dv8tion.jda.api.entities.Emoji;
|
||||
import net.dv8tion.jda.api.interactions.components.Button;
|
||||
import net.dv8tion.jda.api.interactions.components.ButtonStyle;
|
||||
|
||||
@AllArgsConstructor
|
||||
public enum DiscordTicketType {
|
||||
REPORT("U+1F46E", "Spieler melden", ButtonStyle.DANGER),
|
||||
IDEA("U+1F4A1", "Feature vorschlagen", ButtonStyle.SUCCESS),
|
||||
BUG("U+1F41B", "Bug melden", ButtonStyle.SECONDARY),
|
||||
QUESTION("U+2753", "Fragen", ButtonStyle.PRIMARY),
|
||||
APPEAL("U+1F528", "Entbannungsantrag", ButtonStyle.SECONDARY);
|
||||
|
||||
private final String emoji;
|
||||
private final String label;
|
||||
private final ButtonStyle style;
|
||||
|
||||
public Button toButton() {
|
||||
return Button.of(style, name().toLowerCase(), Emoji.fromUnicode(emoji)).withLabel(label);
|
||||
}
|
||||
|
||||
public String introduction() {
|
||||
return "DC_TICKETINTRO_" + name();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.discord.channels;
|
||||
|
||||
import de.steamwar.sql.SchematicNode;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.velocitycore.commands.CheckCommand;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ChecklistChannel extends DiscordChannel {
|
||||
|
||||
private final List<Integer> lastSchematics = new ArrayList<>();
|
||||
|
||||
public ChecklistChannel(String channel) {
|
||||
super(channel);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
List<SchematicNode> schems = CheckCommand.getSchemsToCheck();
|
||||
|
||||
lastSchematics.removeIf(id -> schems.stream().noneMatch(schem -> schem.getId() == id));
|
||||
schems.removeIf(schem -> lastSchematics.contains(schem.getId()));
|
||||
|
||||
for(SchematicNode schem : schems) {
|
||||
system("CHECK_LIST_TO_CHECK", CheckCommand.getWaitTime(schem), schem.getSchemtype().getKuerzel(), SteamwarUser.get(schem.getOwner()).getUserName(), schem.getName());
|
||||
lastSchematics.add(schem.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.discord.channels;
|
||||
|
||||
import de.steamwar.velocitycore.discord.DiscordBot;
|
||||
import de.steamwar.velocitycore.discord.listeners.ChannelListener;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.events.interaction.GenericComponentInteractionCreateEvent;
|
||||
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
|
||||
|
||||
@AllArgsConstructor
|
||||
public class DiscordChannel extends Chatter.PlayerlessChatter {
|
||||
|
||||
public static SteamwarUser userOrPublic(User dcUser) {
|
||||
SteamwarUser user = SteamwarUser.get(dcUser.getIdLong());
|
||||
return user != null ? user : SteamwarUser.get(0);
|
||||
}
|
||||
|
||||
private final SteamwarUser user;
|
||||
@Getter
|
||||
private final MessageChannel channel;
|
||||
|
||||
public DiscordChannel(User user) {
|
||||
this(userOrPublic(user), user.openPrivateChannel().complete());
|
||||
}
|
||||
|
||||
public DiscordChannel(String channel) {
|
||||
this(SteamwarUser.get(-1), DiscordBot.getGuild().getTextChannelById(channel));
|
||||
ChannelListener.getChannels().put(this.channel, this);
|
||||
}
|
||||
|
||||
public void send(String message) {
|
||||
send(new MessageBuilder()
|
||||
.append(message
|
||||
.replace("&", "")
|
||||
.replace("@everyone", "`@everyone`")
|
||||
.replace("@here", "`@here`")
|
||||
.replaceAll("<[@#]!?\\d+>", "`$0`")));
|
||||
}
|
||||
|
||||
public void send(MessageBuilder builder) {
|
||||
channel.sendMessage(builder.build()).queue();
|
||||
}
|
||||
|
||||
public void received(GuildMessageReceivedEvent event) {
|
||||
event.getMessage().delete().queue();
|
||||
}
|
||||
|
||||
public void received(GenericComponentInteractionCreateEvent event) {
|
||||
//ignored
|
||||
}
|
||||
|
||||
@Override
|
||||
public SteamwarUser user() {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chatShown() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component parse(boolean prefixed, Message message) {
|
||||
return super.parse(false, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Component msg) {
|
||||
send(PlainTextComponentSerializer.plainText().serialize(msg));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.discord.channels;
|
||||
|
||||
import de.steamwar.velocitycore.listeners.ChatListener;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.ChatterGroup;
|
||||
import de.steamwar.sql.Punishment;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class DiscordChatRoom extends DiscordChannel {
|
||||
|
||||
private final String format;
|
||||
private final Supplier<ChatterGroup> target;
|
||||
|
||||
public DiscordChatRoom(String channel, String format, Supplier<ChatterGroup> target) {
|
||||
super(channel);
|
||||
this.format = format;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(GuildMessageReceivedEvent event) {
|
||||
SteamwarUser user = SteamwarUser.get(event.getAuthor().getIdLong());
|
||||
if (user == null || event.getMessage().getContentRaw().length() > 250 || user.isPunished(Punishment.PunishmentType.Ban) || user.isPunished(Punishment.PunishmentType.Mute)) {
|
||||
event.getMessage().delete().queue();
|
||||
return;
|
||||
}
|
||||
|
||||
ChatListener.sendChat(Chatter.of(user), target.get(), format, null, event.getMessage().getContentDisplay().replace('§', '&').replace('\n', ' '));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.discord.channels;
|
||||
|
||||
import de.steamwar.sql.Event;
|
||||
import de.steamwar.sql.EventFight;
|
||||
import de.steamwar.sql.Team;
|
||||
import de.steamwar.sql.TeamTeilnahme;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.entities.Emoji;
|
||||
import net.dv8tion.jda.api.interactions.components.ActionRow;
|
||||
import net.dv8tion.jda.api.interactions.components.selections.SelectionMenu;
|
||||
|
||||
import java.awt.*;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@UtilityClass
|
||||
public class EventChannel {
|
||||
|
||||
public MessageBuilder get() {
|
||||
if (Event.get() == null)
|
||||
return updateComing();
|
||||
|
||||
return updateCurrent();
|
||||
}
|
||||
|
||||
private MessageBuilder updateComing() {
|
||||
EmbedBuilder embedBuilder = new EmbedBuilder()
|
||||
.setColor(Color.GRAY)
|
||||
.setTitle("Zukünftige Events")
|
||||
.setAuthor("SteamWar", "https://www.steamwar.de");
|
||||
|
||||
|
||||
SelectionMenu.Builder menuBuilder = SelectionMenu.create("eventName")
|
||||
.setPlaceholder("Wähle ein Event aus!")
|
||||
.setMinValues(1)
|
||||
.setMaxValues(1);
|
||||
|
||||
Timestamp now = Timestamp.from(Instant.now());
|
||||
List<Event> events = Event.getComing();
|
||||
events.forEach(event -> {
|
||||
StringBuilder st = new StringBuilder();
|
||||
if (event.getDeadline().after(now)) {
|
||||
st.append("Deadline: <t:").append(event.getDeadline().getTime() / 1000).append(":R>\n");
|
||||
}
|
||||
st.append("Start: <t:").append(event.getStart().getTime() / 1000).append(":R>");
|
||||
String teilname = TeamTeilnahme.getTeams(event.getEventID()).stream().map(Team::getTeamKuerzel).collect(Collectors.joining(", "));
|
||||
if (!teilname.isEmpty()) {
|
||||
st.append("\nAngemeldete Teams: ").append(teilname);
|
||||
}
|
||||
embedBuilder.addField(event.getEventName(), st.toString(), false);
|
||||
if(event.getDeadline().after(Timestamp.from(Instant.now()))) {
|
||||
menuBuilder.addOption(event.getEventName(), event.getEventID() + "", "An " + event.getEventName() + " teilnehmen", Emoji.fromUnicode("U+1F4DD"));
|
||||
}
|
||||
});
|
||||
|
||||
MessageBuilder messageBuilder = new MessageBuilder()
|
||||
.setEmbeds(embedBuilder.build());
|
||||
|
||||
if(events.stream().anyMatch(event -> event.getDeadline().after(Timestamp.from(Instant.now())))) {
|
||||
messageBuilder.setActionRows(ActionRow.of(menuBuilder.build()));
|
||||
}
|
||||
return messageBuilder;
|
||||
}
|
||||
|
||||
private MessageBuilder updateCurrent() {
|
||||
Event event = Event.get();
|
||||
EmbedBuilder embedBuilder = new EmbedBuilder()
|
||||
.setColor(Color.GRAY)
|
||||
.setTitle("Event: " + event.getEventName())
|
||||
.setAuthor("SteamWar", "https://www.steamwar.de");
|
||||
|
||||
Instant now = Instant.now();
|
||||
EventFight.getEvent(event.getEventID()).forEach(eventFight -> {
|
||||
Team teamBlue = Team.get(eventFight.getTeamBlue());
|
||||
Team teamRed = Team.get(eventFight.getTeamRed());
|
||||
|
||||
StringBuilder st = new StringBuilder();
|
||||
st.append("Fightbeginn: <t:").append(eventFight.getStartTime().getTime() / 1000).append(":R>");
|
||||
if(now.isAfter(eventFight.getStartTime().toInstant().plus(35, ChronoUnit.MINUTES))) {
|
||||
st.append("\n");
|
||||
if (eventFight.getErgebnis() == 1) {
|
||||
st.append("Sieg ").append(teamBlue.getTeamKuerzel());
|
||||
} else if (eventFight.getErgebnis() == 2) {
|
||||
st.append("Sieg ").append(teamRed.getTeamKuerzel());
|
||||
} else {
|
||||
st.append("Unentschieden");
|
||||
}
|
||||
}
|
||||
embedBuilder.addField(teamBlue.getTeamKuerzel() + " vs. " + teamRed.getTeamKuerzel(), st.toString(), true);
|
||||
});
|
||||
|
||||
return StaticMessageChannel.toMessageBuilder(embedBuilder);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.discord.channels;
|
||||
|
||||
import net.dv8tion.jda.api.interactions.Interaction;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class InteractionReply extends DiscordChannel {
|
||||
|
||||
public static void reply(Interaction interaction, Consumer<InteractionReply> consumer) {
|
||||
InteractionReply reply = new InteractionReply(interaction);
|
||||
consumer.accept(reply);
|
||||
reply.submit();
|
||||
}
|
||||
|
||||
private final Interaction interaction;
|
||||
|
||||
private boolean replied = false;
|
||||
private final List<String> messages = new ArrayList<>();
|
||||
|
||||
private InteractionReply(Interaction interaction) {
|
||||
super(interaction.getUser());
|
||||
this.interaction = interaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Component msg) {
|
||||
if(replied) {
|
||||
super.sendMessage(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
messages.add(PlainTextComponentSerializer.plainText().serialize(msg));
|
||||
}
|
||||
|
||||
public void submit() {
|
||||
(messages.isEmpty() ?
|
||||
interaction.deferReply() :
|
||||
interaction.reply(String.join("\n", messages))
|
||||
).setEphemeral(true).queue();
|
||||
replied = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.discord.channels;
|
||||
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.events.interaction.GenericComponentInteractionCreateEvent;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class StaticMessageChannel extends DiscordChannel {
|
||||
|
||||
public static MessageBuilder toMessageBuilder(EmbedBuilder embedBuilder) {
|
||||
MessageBuilder messageBuilder = new MessageBuilder();
|
||||
messageBuilder.setEmbeds(embedBuilder.build());
|
||||
return messageBuilder;
|
||||
}
|
||||
|
||||
private Message message;
|
||||
private final Supplier<MessageBuilder> supplier;
|
||||
private final Consumer<GenericComponentInteractionCreateEvent> interaction;
|
||||
|
||||
public StaticMessageChannel(String channel, Supplier<MessageBuilder> supplier) {
|
||||
this(channel, supplier, event -> {});
|
||||
}
|
||||
|
||||
public StaticMessageChannel(String channel, Supplier<MessageBuilder> supplier, Consumer<GenericComponentInteractionCreateEvent> interaction) {
|
||||
super(channel);
|
||||
this.supplier = supplier;
|
||||
this.interaction = interaction;
|
||||
|
||||
if(getChannel().hasLatestMessage())
|
||||
message = getChannel().getIterableHistory().complete().stream().filter(m -> m.getAuthor().isBot()).findFirst().orElse(null);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (message == null) {
|
||||
getChannel().sendMessage(supplier.get().build()).queue(m -> message = m);
|
||||
} else {
|
||||
message.editMessage(supplier.get().build()).queue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(GenericComponentInteractionCreateEvent event) {
|
||||
interaction.accept(event);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
* <p>
|
||||
* Copyright (C) 2021 SteamWar.de-Serverteam
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.steamwar.velocitycore.discord.listeners;
|
||||
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.discord.DiscordBot;
|
||||
import de.steamwar.velocitycore.discord.channels.DiscordChannel;
|
||||
import de.steamwar.velocitycore.discord.channels.InteractionReply;
|
||||
import lombok.Getter;
|
||||
import net.dv8tion.jda.api.entities.ChannelType;
|
||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||
import net.dv8tion.jda.api.events.interaction.GenericComponentInteractionCreateEvent;
|
||||
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
|
||||
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
import net.dv8tion.jda.api.interactions.InteractionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class ChannelListener extends ListenerAdapter {
|
||||
@Getter
|
||||
private static final Map<MessageChannel, DiscordChannel> channels = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) {
|
||||
if(event.getAuthor().isBot())
|
||||
return;
|
||||
|
||||
DiscordChannel channel = channels.get(event.getChannel());
|
||||
if(channel != null)
|
||||
channel.received(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGenericComponentInteractionCreate(@NotNull GenericComponentInteractionCreateEvent event) {
|
||||
if(event.getType() != InteractionType.COMPONENT)
|
||||
return;
|
||||
|
||||
DiscordChannel channel = channels.get(event.getChannel());
|
||||
if(channel != null) {
|
||||
channel.received(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if(event.getChannelType() == ChannelType.PRIVATE && event.getComponentId().equals("tada"))
|
||||
event.reply(":tada:").queue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlashCommand(@NotNull SlashCommandEvent event) {
|
||||
InteractionReply.reply(event, sender -> {
|
||||
if(sender.user().getDiscordId() == null)
|
||||
return;
|
||||
|
||||
OptionMapping option = event.getOption(DiscordBot.ARGUMENT_NAME);
|
||||
String args = "";
|
||||
if(option != null)
|
||||
args = option.getAsString();
|
||||
|
||||
VelocityCore.getLogger().log(Level.INFO, "%s -> executed Discord command /%s %s".formatted(sender.user().getUserName(), event.getName(), args));
|
||||
SWCommand command = DiscordBot.getCommands().get(event.getName());
|
||||
UserPerm permission = command.getPermission();
|
||||
if(permission != null && !sender.user().perms().contains(permission))
|
||||
return;
|
||||
|
||||
command.execute(sender, args.split(" "));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.discord.listeners;
|
||||
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.discord.channels.DiscordChannel;
|
||||
import de.steamwar.sql.NodeData;
|
||||
import de.steamwar.sql.Punishment;
|
||||
import de.steamwar.sql.SchematicNode;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class DiscordSchemUpload extends ListenerAdapter {
|
||||
|
||||
private static final List<String> SCHEM_FILE_ENDINGS = Arrays.asList(".schem", ".schematic");
|
||||
|
||||
@Override
|
||||
public void onPrivateMessageReceived(PrivateMessageReceivedEvent event) {
|
||||
Message message = event.getMessage();
|
||||
if(message.getAttachments().isEmpty())
|
||||
return;
|
||||
|
||||
DiscordChannel sender = new DiscordChannel(event.getAuthor());
|
||||
SteamwarUser user = sender.user();
|
||||
if(user.getId() == 0) {
|
||||
sender.system("DC_UNLINKED");
|
||||
return;
|
||||
}
|
||||
|
||||
if(user.isPunished(Punishment.PunishmentType.NoSchemReceiving)) {
|
||||
sender.system("DC_SCHEMUPLOAD_NOPERM");
|
||||
return;
|
||||
}
|
||||
|
||||
for (Message.Attachment attachment : message.getAttachments()) {
|
||||
String fileName = attachment.getFileName();
|
||||
int dot = fileName.lastIndexOf('.');
|
||||
if(dot == -1 || !SCHEM_FILE_ENDINGS.contains(fileName.substring(dot).toLowerCase())) {
|
||||
sender.system("DC_SCHEMUPLOAD_IGNORED", attachment.getFileName());
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = fileName.substring(0, dot);
|
||||
if(SchematicNode.invalidSchemName(new String[] {name})) {
|
||||
sender.system("DC_SCHEMUPLOAD_INVCHAR", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
SchematicNode node = SchematicNode.getSchematicNode(user.getId(), name, (Integer) null);
|
||||
if(node == null)
|
||||
node = SchematicNode.createSchematic(user.getId(), name, null);
|
||||
|
||||
try (InputStream in = attachment.retrieveInputStream().get()) {
|
||||
NodeData.get(node).saveFromStream(in, fileName.substring(dot).equalsIgnoreCase(".schem"));
|
||||
sender.system("DC_SCHEMUPLOAD_SUCCESS", name);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (ExecutionException | IOException e) {
|
||||
VelocityCore.getLogger().log(Level.SEVERE, "Could not upload schem \"%s\" for user \"%s\"".formatted(name, user.getUserName()), e);
|
||||
sender.system("DC_SCHEMUPLOAD_ERROR", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.discord.listeners;
|
||||
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.discord.DiscordBot;
|
||||
import de.steamwar.velocitycore.discord.channels.InteractionReply;
|
||||
import de.steamwar.sql.Event;
|
||||
import net.dv8tion.jda.api.events.interaction.SelectionMenuEvent;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class DiscordTeamEvent extends ListenerAdapter {
|
||||
|
||||
private final String eventsChannel = DiscordBot.getInstance().getConfig().channel("events");
|
||||
|
||||
@Override
|
||||
public void onSelectionMenu(@NotNull SelectionMenuEvent event) {
|
||||
if(!event.getChannel().getId().equals(eventsChannel))
|
||||
return;
|
||||
|
||||
if(event.getSelectedOptions().isEmpty()) {
|
||||
event.deferReply(true).queue();
|
||||
return;
|
||||
}
|
||||
|
||||
InteractionReply.reply(event, reply -> {
|
||||
int eventId;
|
||||
try {
|
||||
eventId = Integer.parseInt(event.getSelectedOptions().get(0).getValue());
|
||||
} catch (NumberFormatException e) {
|
||||
reply.system("UNKNOWN_EVENT");
|
||||
return;
|
||||
}
|
||||
|
||||
if(reply.user().getId() == 0) {
|
||||
reply.system("DC_UNLINKED");
|
||||
return;
|
||||
}
|
||||
|
||||
Event tournament = Event.get(eventId);
|
||||
if(tournament == null){
|
||||
reply.system("UNKNOWN_EVENT");
|
||||
return;
|
||||
}
|
||||
|
||||
VelocityCore.get().getTeamCommand().event(reply, tournament);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.discord.listeners;
|
||||
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.ChatterGroup;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
import de.steamwar.velocitycore.discord.DiscordBot;
|
||||
import de.steamwar.velocitycore.discord.DiscordTicketType;
|
||||
import de.steamwar.velocitycore.discord.channels.DiscordChannel;
|
||||
import de.steamwar.velocitycore.discord.channels.InteractionReply;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Emoji;
|
||||
import net.dv8tion.jda.api.entities.MessageChannel;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.events.interaction.GenericComponentInteractionCreateEvent;
|
||||
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
import net.dv8tion.jda.api.interactions.components.ActionRow;
|
||||
import net.dv8tion.jda.api.interactions.components.Button;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.time.Instant;
|
||||
import java.util.LinkedList;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DiscordTicketHandler extends ListenerAdapter {
|
||||
|
||||
private static final String TICKET_CATEGORY = DiscordBot.getInstance().getConfig().getTicketcategory();
|
||||
private static final String TICKET_LOG = DiscordBot.getInstance().getConfig().channel("ticketlog");
|
||||
private static final String TICKET_CHANNEL = DiscordBot.getInstance().getConfig().channel("ticket");
|
||||
|
||||
public static void openTicket(GenericComponentInteractionCreateEvent event) {
|
||||
DiscordTicketType ticketType = DiscordTicketType.valueOf(event.getComponentId().toUpperCase());
|
||||
SteamwarUser user = SteamwarUser.get(event.getUser().getIdLong());
|
||||
|
||||
TextChannel ticketChannel = event.getGuild().getCategoryById(TICKET_CATEGORY).createTextChannel((user == null ? event.getUser().getName() : user.getUserName()) + "-" + event.getComponentId() + "-" + System.currentTimeMillis() % 1000).complete();
|
||||
ticketChannel.createPermissionOverride(event.getMember()).setAllow(
|
||||
Permission.VIEW_CHANNEL,
|
||||
Permission.MESSAGE_WRITE,
|
||||
Permission.MESSAGE_ATTACH_FILES,
|
||||
Permission.MESSAGE_ADD_REACTION,
|
||||
Permission.MESSAGE_READ,
|
||||
Permission.MESSAGE_EMBED_LINKS,
|
||||
Permission.MESSAGE_HISTORY).complete();
|
||||
ticketChannel.getManager().setTopic(event.getUser().getId()).complete();
|
||||
|
||||
DiscordChannel channel = new DiscordChannel(DiscordChannel.userOrPublic(event.getUser()), ticketChannel);
|
||||
channel.send(new MessageBuilder()
|
||||
.setEmbeds(new EmbedBuilder()
|
||||
.setTitle(channel.parseToPlain("DC_TICKET_TITLE"))
|
||||
.setDescription(channel.parseToPlain(ticketType.introduction()))
|
||||
.setColor(Color.GREEN)
|
||||
.build())
|
||||
.setActionRows(ActionRow.of(Button.danger("close-" + ticketChannel.getName(), channel.parseToPlain("DC_TICKET_CLOSE")).withEmoji(Emoji.fromUnicode("U+26A0")))));
|
||||
|
||||
InteractionReply.reply(event, reply -> reply.system("DC_TICKET_CREATED", ticketChannel.getAsMention()));
|
||||
Chatter.serverteam().prefixless("DISCORD_TICKET_NEW", ticketChannel.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGenericComponentInteractionCreate(@NotNull GenericComponentInteractionCreateEvent event) {
|
||||
MessageChannel messageChannel = event.getChannel();
|
||||
if(messageChannel instanceof TextChannel channel && channel.getParent() != null && channel.getParent().getId().equals(TICKET_CATEGORY) && event.getComponentId().startsWith("close-")) {
|
||||
LinkedList<StringBuilder> messages = channel.getIterableHistory().complete().stream()
|
||||
.filter(message -> !message.getAuthor().isSystem() && !message.getAuthor().isBot())
|
||||
.map(message -> {
|
||||
StringBuilder stringBuilder = new StringBuilder()
|
||||
.append("<t:").append(message.getTimeCreated().toInstant().getEpochSecond()).append("> ")
|
||||
.append("**").append(message.getAuthor().getName()).append("**: ")
|
||||
.append(message.getContentRaw())
|
||||
.append("\n");
|
||||
|
||||
if(!message.getAttachments().isEmpty()) {
|
||||
message.getAttachments().forEach(attachment -> stringBuilder.append(attachment.getUrl()));
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
|
||||
return stringBuilder;
|
||||
})
|
||||
.collect(Collectors.toCollection(LinkedList::new));
|
||||
|
||||
messages.addFirst(new StringBuilder().append("<t:").append(Instant.now().getEpochSecond()).append("> **").append(event.getUser().getName()).append("**: Ticket closed"));
|
||||
|
||||
LinkedList<StringBuilder> messageBuilders = new LinkedList<>();
|
||||
messageBuilders.add(new StringBuilder());
|
||||
messages.descendingIterator()
|
||||
.forEachRemaining(stringBuilder -> {
|
||||
if(stringBuilder.length() >= 4096) {
|
||||
messageBuilders.getLast().append(stringBuilder.substring(0, 4090));
|
||||
messageBuilders.add(new StringBuilder(stringBuilder.substring(4090, stringBuilder.length() - 1)));
|
||||
} else if (stringBuilder.length() + messageBuilders.getLast().length() >= 4096) {
|
||||
messageBuilders.add(new StringBuilder(stringBuilder.toString()));
|
||||
} else {
|
||||
messageBuilders.getLast().append(stringBuilder);
|
||||
}
|
||||
});
|
||||
|
||||
EmbedBuilder embedBuilder = new EmbedBuilder()
|
||||
.setColor(Color.GREEN)
|
||||
.setTimestamp(Instant.now())
|
||||
.setTitle(event.getTextChannel().getName());
|
||||
|
||||
if(channel.getTopic() != null && !channel.getTopic().isEmpty()) {
|
||||
User user = event.getJDA().retrieveUserById(channel.getTopic()).complete();
|
||||
embedBuilder.setAuthor(user.getName(), null, user.getAvatarUrl());
|
||||
}
|
||||
|
||||
TextChannel logChannel = event.getGuild().getTextChannelById(TICKET_LOG);
|
||||
messageBuilders.forEach(stringBuilder -> logChannel.sendMessage(new MessageBuilder().setEmbeds(embedBuilder.setDescription(stringBuilder.toString()).build()).build()).queue());
|
||||
|
||||
Chatter.serverteam().prefixless("DISCORD_TICKET_CLOSED", channel.getName());
|
||||
channel.delete().reason("Closed").queue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) {
|
||||
TextChannel channel = event.getChannel();
|
||||
if(
|
||||
channel.getParent() != null &&
|
||||
channel.getParent().getId().equals(TICKET_CATEGORY) &&
|
||||
!channel.getId().equals(TICKET_CHANNEL) &&
|
||||
!channel.getId().equals(TICKET_LOG)
|
||||
) {
|
||||
if(event.getAuthor().isBot())
|
||||
return;
|
||||
|
||||
ChatterGroup receivers = new ChatterGroup(Chatter.allStream().filter(player -> player.user().hasPerm(UserPerm.TICKET_LOG)));
|
||||
try {
|
||||
SteamwarUser user = SteamwarUser.get(Long.parseLong(channel.getTopic()));
|
||||
if(user != null && !user.perms().contains(UserPerm.TEAM))
|
||||
receivers = new ChatterGroup(receivers, Chatter.of(user));
|
||||
} catch(NumberFormatException e) {
|
||||
//ignored
|
||||
}
|
||||
|
||||
receivers.prefixless("DISCORD_TICKET_MESSAGE", new Message("DISCORD_TICKET_HOVER"), ClickEvent.openUrl(event.getMessage().getJumpUrl()), event.getChannel().getName(), event.getAuthor().getName(), event.getMessage().getContentRaw());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.discord.util;
|
||||
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.discord.channels.DiscordChannel;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.entities.Emoji;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.interactions.components.ActionRow;
|
||||
import net.dv8tion.jda.api.interactions.components.Button;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@UtilityClass
|
||||
public class AuthManager {
|
||||
|
||||
private final Map<String, User> TOKENS = new HashMap<>();
|
||||
private final Random rand = new Random();
|
||||
|
||||
public String createDiscordAuthToken(User user) {
|
||||
TOKENS.values().removeIf(user::equals);
|
||||
|
||||
byte[] randBytes = new byte[16];
|
||||
rand.nextBytes(randBytes);
|
||||
String code = Base64.getEncoder().encodeToString(randBytes);
|
||||
|
||||
TOKENS.put(code, user);
|
||||
VelocityCore.getLogger().log(Level.INFO, "Created Discord Auth-Token: %s for: %s".formatted(code, user.getAsTag()));
|
||||
VelocityCore.schedule(() -> TOKENS.remove(code)).delay(10, TimeUnit.MINUTES).schedule();
|
||||
return code;
|
||||
}
|
||||
|
||||
public User connectAuth(SteamwarUser user, String code) {
|
||||
User dcUser = TOKENS.remove(code);
|
||||
if(dcUser == null)
|
||||
return null;
|
||||
|
||||
user.setDiscordId(dcUser.getIdLong());
|
||||
|
||||
DiscordChannel channel = new DiscordChannel(dcUser);
|
||||
channel.send(new MessageBuilder()
|
||||
.setContent(channel.parseToPlain("DC_AUTH_SUCCESS", user))
|
||||
.setActionRows(ActionRow.of(Button.success("tada", Emoji.fromUnicode("U+1F389")))));
|
||||
|
||||
return dcUser;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.discord.util;
|
||||
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.velocitycore.discord.DiscordBot;
|
||||
import de.steamwar.velocitycore.discord.channels.DiscordChannel;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.MessageBuilder;
|
||||
import net.dv8tion.jda.api.entities.Emoji;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.interactions.components.ActionRow;
|
||||
import net.dv8tion.jda.api.interactions.components.Button;
|
||||
|
||||
import java.awt.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@UtilityClass
|
||||
public class DiscordAlert {
|
||||
|
||||
public static void send(Chatter player, Color color, Message title, Message description, boolean success) {
|
||||
DiscordBot.withBot(bot -> {
|
||||
Long discordId = player.user().getDiscordId();
|
||||
if(discordId == null)
|
||||
return;
|
||||
|
||||
User user = DiscordBot.getInstance().getJda().getUserById(discordId);
|
||||
if(user == null)
|
||||
return;
|
||||
|
||||
MessageBuilder builder = new MessageBuilder()
|
||||
.setEmbeds(new EmbedBuilder()
|
||||
.setAuthor("SteamWar", "https://steamwar.de", "https://cdn.discordapp.com/app-icons/869606970099904562/60c884000407c02671d91d8e7182b8a1.png")
|
||||
.setColor(color)
|
||||
.setTitle(player.parseToPlain(title))
|
||||
.setDescription(player.parseToPlain(description))
|
||||
.setTimestamp(Instant.now())
|
||||
.build());
|
||||
if(success)
|
||||
builder.setActionRows(ActionRow.of(Button.success("tada", Emoji.fromUnicode("U+1F389"))));
|
||||
|
||||
new DiscordChannel(user).send(builder);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* 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.steamwar.velocitycore.discord.util;
|
||||
|
||||
import de.steamwar.velocitycore.discord.DiscordBot;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.exceptions.ErrorResponseException;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@UtilityClass
|
||||
public class DiscordRanks {
|
||||
|
||||
private final Map<UserPerm.Prefix, String> prefixToPermName = UserPerm.prefixes.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, entry -> entry.getKey().name().toLowerCase()));
|
||||
|
||||
public void update(SteamwarUser user) {
|
||||
if (user.getDiscordId() == null)
|
||||
return;
|
||||
|
||||
Set<String> swRoles = new HashSet<>(DiscordBot.getInstance().getConfig().getRanks().values());
|
||||
|
||||
Guild guild = DiscordBot.getGuild();
|
||||
guild.retrieveMemberById(user.getDiscordId()).queue(member -> {
|
||||
String prefixRole = DiscordBot.getInstance().getConfig().getRanks().get(prefixToPermName.get(user.prefix()));
|
||||
member.getRoles().stream()
|
||||
.filter(role -> swRoles.contains(role.getId()))
|
||||
.filter(role -> !role.getId().equals(prefixRole))
|
||||
.forEach(role -> guild.removeRoleFromMember(member, role).queue());
|
||||
|
||||
if (prefixRole != null && member.getRoles().stream().noneMatch(role -> role.getId().equals(prefixRole)))
|
||||
guild.addRoleToMember(member, guild.getRoleById(prefixRole)).queue();
|
||||
}, e -> {
|
||||
if(e instanceof ErrorResponseException err && err.getErrorCode() == 10007)
|
||||
user.setDiscordId(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.inventory;
|
||||
|
||||
public interface InvCallback {
|
||||
|
||||
void clicked(ClickType click);
|
||||
|
||||
enum ClickType {
|
||||
LEFT,
|
||||
SHIFT_LEFT,
|
||||
RIGHT,
|
||||
SHIFT_RIGHT,
|
||||
WINDOW_BORDER_LEFT,
|
||||
WINDOW_BORDER_RIGHT,
|
||||
MIDDLE,
|
||||
NUMBER_KEY,
|
||||
DOUBLE_CLICK,
|
||||
DROP,
|
||||
CONTROL_DROP,
|
||||
CREATIVE,
|
||||
UNKNOWN;
|
||||
|
||||
public boolean isKeyboardClick() {
|
||||
return this == NUMBER_KEY || this == DROP || this == CONTROL_DROP;
|
||||
}
|
||||
|
||||
public boolean isCreativeAction() {
|
||||
return this == MIDDLE || this == CREATIVE;
|
||||
}
|
||||
|
||||
public boolean isRightClick() {
|
||||
return this == RIGHT || this == SHIFT_RIGHT;
|
||||
}
|
||||
|
||||
public boolean isLeftClick() {
|
||||
return this == LEFT || this == SHIFT_LEFT || this == DOUBLE_CLICK || this == CREATIVE;
|
||||
}
|
||||
|
||||
public boolean isShiftClick() {
|
||||
return this == SHIFT_LEFT || this == SHIFT_RIGHT || this == CONTROL_DROP;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.inventory;
|
||||
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.velocitycore.network.NetworkSender;
|
||||
import de.steamwar.velocitycore.network.handlers.InventoryCallbackHandler;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.network.packets.server.CloseInventoryPacket;
|
||||
import de.steamwar.network.packets.server.InventoryPacket;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class SWInventory {
|
||||
|
||||
private final Map<Integer, SWItem> itemMap = new HashMap<>();
|
||||
private final Chatter player;
|
||||
private final int size;
|
||||
private final Message title;
|
||||
@Setter
|
||||
private InvCallback close;
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean next = false;
|
||||
|
||||
private final AtomicBoolean processingClick = new AtomicBoolean();
|
||||
|
||||
public SWInventory(PlayerChatter player, int size, Message title) {
|
||||
InventoryCallbackHandler.inventoryHashMap.put(player.user().getId(), this);
|
||||
this.player = player;
|
||||
this.size = size;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public void addItem(int pos, SWItem item, InvCallback callback) {
|
||||
item.setCallback(callback);
|
||||
addItem(pos, item);
|
||||
}
|
||||
|
||||
public void addItem(int pos, SWItem item) {
|
||||
itemMap.put(pos, item);
|
||||
}
|
||||
|
||||
public void setCallback(int pos, InvCallback callback) {
|
||||
itemMap.get(pos).setCallback(callback);
|
||||
}
|
||||
|
||||
public void handleCallback(InvCallback.ClickType type, int pos) {
|
||||
if(processingClick.compareAndSet(false, true)) {
|
||||
itemMap.get(pos).getCallback().clicked(type);
|
||||
processingClick.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleClose() {
|
||||
if(processingClick.compareAndSet(false, true)) {
|
||||
InventoryCallbackHandler.inventoryHashMap.remove(player.user().getId(), this);
|
||||
if(close != null)
|
||||
close.clicked(null);
|
||||
processingClick.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void open() {
|
||||
InventoryPacket inv = new InventoryPacket(player.parseToLegacy(title), player.user().getId(), size, map(itemMap, (integer, swItem) -> swItem.writeToString(player, integer).toString()));
|
||||
player.withPlayer(p -> NetworkSender.send(p, inv));
|
||||
}
|
||||
|
||||
private static <T, K, J> Map<T, J> map(Map<T, K> map, BiFunction<T, K, J> function) {
|
||||
Map<T, J> result = new HashMap<>();
|
||||
map.forEach((key, value) -> result.put(key, function.apply(key, value)));
|
||||
return result;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
close(player);
|
||||
}
|
||||
|
||||
public static void close(Chatter player) {
|
||||
player.withPlayer(p -> NetworkSender.send(p, new CloseInventoryPacket(player.user().getId())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.inventory;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Setter
|
||||
public class SWItem {
|
||||
|
||||
@Getter
|
||||
private String material = "DYE";
|
||||
private Message title;
|
||||
private String skullOwner;
|
||||
private boolean enchanted;
|
||||
private boolean hideAttributes;
|
||||
private List<Message> lore = new ArrayList<>();
|
||||
@Getter
|
||||
private InvCallback callback;
|
||||
private int color = 0;
|
||||
|
||||
public SWItem(String material, Message title) {
|
||||
this.material = material.toUpperCase();
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public SWItem(Message title, int color) {
|
||||
this.title = title;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public static SWItem getSkull(String skullOwner) {
|
||||
SWItem item = new SWItem("SKULL", new Message("PLAIN_STRING", skullOwner));
|
||||
item.setSkullOwner(skullOwner);
|
||||
return item;
|
||||
}
|
||||
|
||||
public SWItem addLore(Message lore) {
|
||||
this.lore.add(lore);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JsonObject writeToString(Chatter player, int position) {
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty("material", material);
|
||||
object.addProperty("position", position);
|
||||
object.addProperty("title", player.parseToLegacy(title));
|
||||
if(skullOwner != null)
|
||||
object.addProperty("skullOwner", skullOwner);
|
||||
if(enchanted)
|
||||
object.addProperty("enchanted", true);
|
||||
if(hideAttributes)
|
||||
object.addProperty("hideAttributes", true);
|
||||
if(color != 0)
|
||||
object.addProperty("color", color);
|
||||
if(lore != null) {
|
||||
JsonArray array = new JsonArray();
|
||||
for (Message lores : lore) {
|
||||
array.add(player.parseToLegacy(lores));
|
||||
}
|
||||
object.add("lore", array);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
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.steamwar.velocitycore.inventory;
|
||||
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SWListInv<T> extends SWInventory {
|
||||
@Setter
|
||||
private ListCallback<T> callback;
|
||||
private final List<SWListEntry<T>> elements;
|
||||
private int page;
|
||||
|
||||
public SWListInv(PlayerChatter p, Message t, List<SWListEntry<T>> l, ListCallback<T> c){
|
||||
super(p, (l.size()>45) ? 54 : (l.size() + 9-l.size()%9), t);
|
||||
callback = c;
|
||||
elements = l;
|
||||
page = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(){
|
||||
if(elements.size() > 54){
|
||||
if(page != 0)
|
||||
addItem(45, new SWItem(new Message("INV_PAGE_BACK", "e"), 10), (InvCallback.ClickType click) -> {
|
||||
page--;
|
||||
open();
|
||||
});
|
||||
else
|
||||
addItem(45, new SWItem(new Message("INV_PAGE_BACK", "7"), 8), (InvCallback.ClickType click) -> {});
|
||||
if(page < elements.size()/45)
|
||||
addItem(53, new SWItem(new Message("INV_PAGE_NEXT", "e"), 10), (InvCallback.ClickType click) -> {
|
||||
page++;
|
||||
open();
|
||||
});
|
||||
else
|
||||
addItem(53, new SWItem(new Message("INV_PAGE_NEXT", "7"), 8), (InvCallback.ClickType click) -> {});
|
||||
}
|
||||
|
||||
int ipageLimit = elements.size() - page*45;
|
||||
if(ipageLimit > 45 && elements.size() > 54){
|
||||
ipageLimit = 45;
|
||||
}
|
||||
int i = page*45;
|
||||
for(int ipage=0; ipage < ipageLimit; ipage++ ){
|
||||
SWItem e = elements.get(i).getItem();
|
||||
|
||||
final int pos = i;
|
||||
addItem(ipage, e);
|
||||
setCallback(ipage, (InvCallback.ClickType click) -> callback.clicked(click, elements.get(pos).getObject()));
|
||||
i++;
|
||||
}
|
||||
super.open();
|
||||
}
|
||||
|
||||
public interface ListCallback<T>{
|
||||
void clicked(InvCallback.ClickType click, T element);
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public static class SWListEntry<T> {
|
||||
final SWItem item;
|
||||
final T object;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user