forked from SteamWar/SteamWar
Merge branch 'main' into schematic-investigations
# Conflicts: # CommonCore/SQL/src/de/steamwar/sql/CheckedSchematic.java # VelocityCore/src/de/steamwar/velocitycore/commands/CheckCommand.java
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
steamwar.java
|
||||
alias(libs.plugins.shadow)
|
||||
}
|
||||
|
||||
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/
|
||||
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
finalizedBy(tasks.shadowJar)
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.velocity)
|
||||
annotationProcessor(libs.velocityapi)
|
||||
|
||||
implementation(libs.jda) {
|
||||
exclude(module = "opus-java")
|
||||
}
|
||||
|
||||
implementation(libs.sqlite)
|
||||
implementation(libs.mysql)
|
||||
|
||||
implementation(libs.msgpack)
|
||||
implementation(libs.apolloprotos)
|
||||
|
||||
implementation(libs.nbt)
|
||||
}
|
||||
@@ -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.discord;
|
||||
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
|
||||
@Plugin(
|
||||
id = "depencendiesvelocitycore",
|
||||
name = "DepencendiesVelocityCore"
|
||||
)
|
||||
public class Dependencies {
|
||||
}
|
||||
@@ -24,9 +24,11 @@ import com.google.inject.Inject;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.name.Names;
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.velocitypowered.api.command.BrigadierCommand;
|
||||
import com.velocitypowered.api.command.CommandManager;
|
||||
import com.velocitypowered.api.command.CommandMeta;
|
||||
import com.velocitypowered.api.command.CommandSource;
|
||||
import com.velocitypowered.api.event.EventManager;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
@@ -71,6 +73,8 @@ public class Persistent {
|
||||
private final Logger logger;
|
||||
private final Path directory;
|
||||
|
||||
private boolean restartQueued = false;
|
||||
|
||||
@Inject
|
||||
public Persistent(ProxyServer proxy, Logger logger, @DataDirectory Path dataDirectory) {
|
||||
instance = this;
|
||||
@@ -81,6 +85,12 @@ public class Persistent {
|
||||
|
||||
@Subscribe
|
||||
public void onEnable(ProxyInitializeEvent event) {
|
||||
proxy.getScheduler().buildTask(instance, () -> {
|
||||
if (!restartQueued) return;
|
||||
if (!proxy.getAllPlayers().isEmpty()) return;
|
||||
proxy.shutdown();
|
||||
}).repeat(10, TimeUnit.SECONDS).schedule();
|
||||
|
||||
proxy.getCommandManager().register(
|
||||
new BrigadierCommand(
|
||||
BrigadierCommand.literalArgumentBuilder("softreload")
|
||||
@@ -89,6 +99,14 @@ public class Persistent {
|
||||
.build()
|
||||
)
|
||||
);
|
||||
proxy.getCommandManager().register(
|
||||
new BrigadierCommand(
|
||||
BrigadierCommand.literalArgumentBuilder("queuerestart")
|
||||
.requires(commandSource -> commandSource.hasPermission("bungeecore.softreload"))
|
||||
.executes(this::queueRestart)
|
||||
.build()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@@ -97,6 +115,7 @@ public class Persistent {
|
||||
}
|
||||
|
||||
public int softreload() {
|
||||
restartQueued = false;
|
||||
PluginContainer container = null;
|
||||
ReloadablePlugin plugin = null;
|
||||
try {
|
||||
@@ -200,4 +219,15 @@ public class Persistent {
|
||||
ResourceBundle.clearCache(classLoader);
|
||||
classLoader.close();
|
||||
}
|
||||
|
||||
public int queueRestart(CommandContext<CommandSource> context) {
|
||||
if (restartQueued) {
|
||||
restartQueued = false;
|
||||
context.getSource().sendPlainMessage("§eRestart dequeued§8.");
|
||||
} else {
|
||||
restartQueued = true;
|
||||
context.getSource().sendPlainMessage("§eRestart queued§8.");
|
||||
}
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ public class Subserver {
|
||||
try {
|
||||
if (checkpoint) {
|
||||
start(process.getErrorStream(), line -> line.contains("Restore finished successfully."));
|
||||
Thread.sleep(300); //Wait for port to be reopened
|
||||
Thread.sleep(300);
|
||||
} else {
|
||||
start(process.getInputStream(), line -> {
|
||||
if (line.contains("Loading libraries, please wait"))
|
||||
|
||||
@@ -22,19 +22,6 @@ plugins {
|
||||
alias(libs.plugins.shadow)
|
||||
}
|
||||
|
||||
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.build {
|
||||
finalizedBy(tasks.shadowJar)
|
||||
}
|
||||
@@ -51,21 +38,10 @@ dependencies {
|
||||
compileOnly(libs.viavelocity)
|
||||
|
||||
compileOnly(project(":VelocityCore:Persistent", "default"))
|
||||
compileOnly(project(":VelocityCore:Dependencies", "default"))
|
||||
|
||||
implementation(project(":CommonCore"))
|
||||
implementation(project(":CommandFramework"))
|
||||
|
||||
implementation(libs.sqlite)
|
||||
implementation(libs.mysql)
|
||||
|
||||
implementation(libs.jda) {
|
||||
exclude(module = "opus-java")
|
||||
}
|
||||
|
||||
implementation(libs.msgpack)
|
||||
implementation(libs.apolloprotos)
|
||||
|
||||
implementation(libs.nbt)
|
||||
}
|
||||
|
||||
tasks.register<DevServer>("DevVelocity") {
|
||||
@@ -73,5 +49,6 @@ tasks.register<DevServer>("DevVelocity") {
|
||||
description = "Run a Dev Velocity"
|
||||
dependsOn(":VelocityCore:shadowJar")
|
||||
dependsOn(":VelocityCore:Persistent:jar")
|
||||
dependsOn(":VelocityCore:Dependencies:shadowJar")
|
||||
template = "DevVelocity"
|
||||
}
|
||||
|
||||
@@ -326,12 +326,15 @@ CHECK_ABORT=§aThe test operation was canceled!
|
||||
CHECK_NEXT=Next question
|
||||
CHECK_ACCEPT=Accept
|
||||
CHECK_DECLINE=Decline
|
||||
CHECK_MARK_DECLINE=Mark 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!
|
||||
CHECK_DECLINED_QUESTIONS=§fQuestions answered declined:
|
||||
CHECK_DECLINED_QUESTION_FORMAT=§c{0}: {1}
|
||||
|
||||
#HistoricCommand
|
||||
HISTORIC_BROADCAST=§7Historic §e{0} §7fight by §e{1}§8!
|
||||
@@ -603,7 +606,7 @@ 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}
|
||||
LIST_COMMAND=§e{0}§8 [{1}]: §7{2}
|
||||
|
||||
#EventStarter
|
||||
EVENT_FIGHT_BROADCAST=§eClick here §7for the fight §{0}{1} §8vs §{2}{3}
|
||||
|
||||
@@ -308,12 +308,14 @@ CHECK_ABORT=§aDer Prüfvorgang wurde abgebrochen!
|
||||
CHECK_NEXT=Nächste Frage
|
||||
CHECK_ACCEPT=Annehmen
|
||||
CHECK_DECLINE=Ablehnen
|
||||
CHECK_MARK_DECLINE=Ablehnen Markieren
|
||||
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!
|
||||
CHECK_DECLINED_QUESTIONS=§fAls abgelehnt markierte Fragen:
|
||||
|
||||
#HistoricCommand
|
||||
HISTORIC_BROADCAST=§7Historischer §e{0}§8-§7Kampf von §e{1}§8!
|
||||
@@ -574,11 +576,8 @@ 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}
|
||||
|
||||
@@ -87,10 +87,11 @@ public interface Chatter {
|
||||
}
|
||||
default void withPlayerOrOffline(Consumer<Player> withPlayer, Runnable withOffline) {
|
||||
Player player = getPlayer();
|
||||
if(player == null)
|
||||
if(player == null) {
|
||||
withOffline.run();
|
||||
else
|
||||
} else {
|
||||
withPlayer.accept(player);
|
||||
}
|
||||
}
|
||||
default void withPlayer(Consumer<Player> function) {
|
||||
withPlayerOrOffline(function, () -> {});
|
||||
|
||||
@@ -23,7 +23,9 @@ import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.sql.EventFight;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.Team;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
@@ -36,6 +38,7 @@ import static de.steamwar.persistent.Storage.eventServer;
|
||||
|
||||
public class EventStarter {
|
||||
|
||||
@Getter
|
||||
private static final Map<Integer, String> spectatePorts = new HashMap<>();
|
||||
|
||||
public static void addSpectateServer(int port, String command) {
|
||||
@@ -68,6 +71,15 @@ public class EventStarter {
|
||||
starter.callback(subserver -> {
|
||||
eventServer.put(blue.getTeamId(), subserver);
|
||||
eventServer.put(red.getTeamId(), subserver);
|
||||
|
||||
if (VelocityCore.get().getConfig().isEventmode()) {
|
||||
VelocityCore.getProxy().getAllPlayers().forEach(player -> {
|
||||
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
|
||||
if (user.getTeam() == blue.getTeamId() || user.getTeam() == red.getTeamId()) {
|
||||
subserver.sendPlayer(player);
|
||||
}
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
|
||||
command = "/event " + blue.getTeamKuerzel();
|
||||
@@ -76,6 +88,7 @@ public class EventStarter {
|
||||
}
|
||||
Chatter.broadcast().system("EVENT_FIGHT_BROADCAST", new Message("EVENT_FIGHT_BROADCAST_HOVER"), ClickEvent.runCommand(command), blue.getTeamColor(), blue.getTeamName(), red.getTeamColor(), red.getTeamName());
|
||||
}
|
||||
EventFight.clearActiveFightsCache();
|
||||
}
|
||||
|
||||
private EventFight nextFight(Queue<EventFight> fights){
|
||||
|
||||
@@ -52,7 +52,6 @@ public class ServerStarter {
|
||||
public static final String TEMP_WORLD_PATH = TMP_DATA + "arenaserver/";
|
||||
|
||||
private static final String WORLDS_FOLDER = "/worlds";
|
||||
public static final String TUTORIAL_PATH = WORLDS_FOLDER + "/tutorials/";
|
||||
public static final String WORLDS_BASE_PATH = WORLDS_FOLDER + "/userworlds";
|
||||
public static final String BUILDER_BASE_PATH = WORLDS_FOLDER + "/builder";
|
||||
|
||||
@@ -194,15 +193,6 @@ public class ServerStarter {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerStarter tutorial(Player owner, Tutorial tutorial) {
|
||||
version = ServerVersion.SPIGOT_15;
|
||||
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);
|
||||
@@ -286,6 +276,7 @@ public class ServerStarter {
|
||||
|
||||
int port = portrange.freePort();
|
||||
String serverName = serverNameProvider.apply(port);
|
||||
arguments.put("serverName", serverName);
|
||||
|
||||
if(node == null) {
|
||||
node = Node.getNode();
|
||||
|
||||
@@ -44,15 +44,14 @@ public enum ServerVersion {
|
||||
PAPER_18("paper-1.18.2.jar", 15, ProtocolVersion.MINECRAFT_1_18_2),
|
||||
PAPER_19("paper-1.19.3.jar", 19, ProtocolVersion.MINECRAFT_1_19_3),
|
||||
PAPER_20("paper-1.20.1.jar", 20, ProtocolVersion.MINECRAFT_1_20),
|
||||
DEVEL_21("paper-1.21.5.jar", 21, ProtocolVersion.MINECRAFT_1_21_5),
|
||||
PAPER_21("paper-1.21.3.jar", 21, ProtocolVersion.MINECRAFT_1_21_2);
|
||||
PAPER_21("paper-1.21.6.jar", 21, ProtocolVersion.MINECRAFT_1_21_6);
|
||||
|
||||
private static final Map<String, ServerVersion> chatMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
chatMap.put("21", ServerVersion.PAPER_21);
|
||||
chatMap.put("1.21", ServerVersion.PAPER_21);
|
||||
chatMap.put("1.21.3", ServerVersion.PAPER_21);
|
||||
chatMap.put("1.21.6", ServerVersion.PAPER_21);
|
||||
|
||||
chatMap.put("20", ServerVersion.PAPER_20);
|
||||
chatMap.put("1.20", ServerVersion.PAPER_20);
|
||||
@@ -95,10 +94,6 @@ public enum ServerVersion {
|
||||
}
|
||||
|
||||
public static ServerVersion get(int version) {
|
||||
if (version == 21) {
|
||||
return DEVEL_21;
|
||||
}
|
||||
|
||||
return versionMap.get(version);
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ import java.util.logging.Logger;
|
||||
@Plugin(
|
||||
id = "velocitycore",
|
||||
name = "VelocityCore",
|
||||
dependencies = { @Dependency(id = "persistentvelocitycore") }
|
||||
dependencies = { @Dependency(id = "persistentvelocitycore"), @Dependency(id = "depencendiesvelocitycore") }
|
||||
)
|
||||
public class VelocityCore implements ReloadablePlugin {
|
||||
|
||||
@@ -153,6 +153,7 @@ public class VelocityCore implements ReloadablePlugin {
|
||||
new CheckListener();
|
||||
new IPSanitizer();
|
||||
new VersionAnnouncer();
|
||||
new TexturePackSystem();
|
||||
|
||||
local = new Node.LocalNode();
|
||||
if(MAIN_SERVER) {
|
||||
@@ -214,16 +215,16 @@ public class VelocityCore implements ReloadablePlugin {
|
||||
new ChallengeCommand();
|
||||
new HistoricCommand();
|
||||
new ReplayCommand();
|
||||
new TutorialCommand();
|
||||
|
||||
new Broadcaster();
|
||||
new CookieEvents();
|
||||
}else{
|
||||
new EventModeListener();
|
||||
}
|
||||
|
||||
for(PacketHandler handler : new PacketHandler[] {
|
||||
new EloPlayerHandler(), new EloSchemHandler(), new ExecuteCommandHandler(), new FightInfoHandler(),
|
||||
new ImALobbyHandler(), new InventoryCallbackHandler(), new PrepareSchemHandler()
|
||||
new ImALobbyHandler(), new InventoryCallbackHandler(), new PrepareSchemHandler(), new PlayerSkinHandler()
|
||||
})
|
||||
handler.register();
|
||||
|
||||
@@ -288,7 +289,7 @@ public class VelocityCore implements ReloadablePlugin {
|
||||
if(server.getSpectatePort() != 0)
|
||||
EventStarter.addSpectateServer(server.getSpectatePort(), cmd);
|
||||
|
||||
new ServerSwitchCommand(cmd, entry.getKey(), cmds.toArray(new String[0]));
|
||||
new ServerSwitchCommand(cmd, entry.getKey(), server.getSpectatePort() != 0, cmds.toArray(new String[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class CheckCommand extends SWCommand {
|
||||
@@ -98,12 +99,11 @@ public class CheckCommand extends SWCommand {
|
||||
for (SchematicNode schematic : schematicList) {
|
||||
CheckSession current = currentSchems.get(schematic.getId());
|
||||
if (current == null) {
|
||||
Optional<CheckedSchematic> lastCheck = CheckedSchematic.getLastCheck(schematic.getId());
|
||||
sender.prefixless("CHECK_LIST_TO_CHECK",
|
||||
lastCheck.map(CheckedSchematic::isInvestigationPending).orElse(false) ? new Message("PLAIN_STRING", lastCheck.map(CheckedSchematic::getInvestigationPendingReason).orElseThrow()) : new Message("CHECK_LIST_TO_CHECK_HOVER"),
|
||||
!lastCheck.map(CheckedSchematic::isInvestigationPending).orElse(false) || sender.user().hasPerm(UserPerm.MODERATION) ? ClickEvent.runCommand("/check schematic " + schematic.getId()) : ClickEvent.suggestCommand(""),
|
||||
new Message("CHECK_LIST_TO_CHECK_HOVER"),
|
||||
ClickEvent.runCommand("/check schematic " + schematic.getId()),
|
||||
getWaitTime(schematic),
|
||||
schematic.getSchemtype().getKuerzel(), SteamwarUser.get(schematic.getOwner()).getUserName(), (lastCheck.map(CheckedSchematic::isInvestigationPending).orElse(false) ? "§c" : "") + schematic.getName());
|
||||
schematic.getSchemtype().getKuerzel(), SteamwarUser.get(schematic.getOwner()).getUserName(), schematic.getName());
|
||||
} else {
|
||||
sender.prefixless("CHECK_LIST_CHECKING",
|
||||
new Message("CHECK_LIST_CHECKING_HOVER"),
|
||||
@@ -129,10 +129,6 @@ public class CheckCommand extends SWCommand {
|
||||
sender.system("CHECK_SCHEMATIC_OWN");
|
||||
return;
|
||||
}
|
||||
Optional<CheckedSchematic> lastCheck = CheckedSchematic.getLastCheck(schem.getId());
|
||||
if(!lastCheck.map(CheckedSchematic::isInvestigationPending).orElse(false) || sender.user().hasPerm(UserPerm.MODERATION)) {
|
||||
sender.system("CHECK_SCHEMATIC_INVESTIGATION_PENDING");
|
||||
}
|
||||
|
||||
int playerTeam = sender.user().hasPerm(UserPerm.MODERATION) ? 0 : sender.user().getTeam();
|
||||
if (playerTeam != 0 && SteamwarUser.get(schem.getOwner()).getTeam() == playerTeam) {
|
||||
@@ -169,6 +165,14 @@ public class CheckCommand extends SWCommand {
|
||||
next(sender);
|
||||
}
|
||||
|
||||
@Register(value = "decline", description = "CHECK_HELP_DECLINE")
|
||||
public void decline(PlayerChatter sender) {
|
||||
if(notChecking(sender.getPlayer()))
|
||||
return;
|
||||
|
||||
currentCheckers.get(sender.getPlayer().getUniqueId()).markDeclined();
|
||||
}
|
||||
|
||||
@Register(value = "decline", description = "CHECK_HELP_DECLINE")
|
||||
public void decline(PlayerChatter sender, String... message) {
|
||||
if(notChecking(sender.getPlayer()))
|
||||
@@ -177,14 +181,6 @@ public class CheckCommand extends SWCommand {
|
||||
currentCheckers.get(sender.getPlayer().getUniqueId()).decline(String.join(" ", message));
|
||||
}
|
||||
|
||||
@Register(value = "block")
|
||||
public void block(PlayerChatter sender, String... message) {
|
||||
if(notChecking(sender.getPlayer()))
|
||||
return;
|
||||
|
||||
currentCheckers.get(sender.getPlayer().getUniqueId()).block(String.join(" ", message));
|
||||
}
|
||||
|
||||
public static List<SchematicNode> getSchemsToCheck(){
|
||||
List<SchematicNode> schematicList = new ArrayList<>();
|
||||
|
||||
@@ -213,6 +209,8 @@ public class CheckCommand extends SWCommand {
|
||||
private final SchematicNode schematic;
|
||||
private final Timestamp startTime;
|
||||
private final ListIterator<String> checkList;
|
||||
private String currentQuestion;
|
||||
private final List<String> declinedQuestions = new ArrayList<>();
|
||||
|
||||
private CheckSession(PlayerChatter checker, SchematicNode schematic){
|
||||
this.checker = checker;
|
||||
@@ -225,7 +223,7 @@ public class CheckCommand extends SWCommand {
|
||||
currentCheckers.put(checker.user().getUUID(), this);
|
||||
currentSchems.put(schematic.getId(), this);
|
||||
|
||||
for(CheckedSchematic previous : CheckedSchematic.getLastDeclinedOfNode(schematic.getId()))
|
||||
for(CheckedSchematic previous : CheckedSchematic.previousChecks(schematic))
|
||||
checker.prefixless("CHECK_SCHEMATIC_PREVIOUS", previous.getEndTime(), SteamwarUser.get(previous.getValidator()).getUserName(), previous.getDeclineReason());
|
||||
next();
|
||||
}).start();
|
||||
@@ -233,42 +231,70 @@ public class CheckCommand extends SWCommand {
|
||||
|
||||
private void next() {
|
||||
if(!checkList.hasNext()){
|
||||
accept();
|
||||
if (declinedQuestions.isEmpty()) {
|
||||
accept();
|
||||
} else {
|
||||
checker.system("CHECK_DECLINED_QUESTIONS");
|
||||
int i = 1;
|
||||
for (String s : declinedQuestions) {
|
||||
checker.prefixless("CHECK_DECLINED_QUESTION_FORMAT", i++, s);
|
||||
}
|
||||
declinedQuestions.clear();
|
||||
checker.sendMessage(Component
|
||||
.text(checker.parseToPlain("CHECK_ACCEPT"))
|
||||
.color(NamedTextColor.GREEN)
|
||||
.clickEvent(ClickEvent.suggestCommand("/check accept"))
|
||||
.append(Component
|
||||
.text(" " + checker.parseToPlain("CHECK_DECLINE"))
|
||||
.color(NamedTextColor.RED)
|
||||
.clickEvent(ClickEvent.suggestCommand("/check decline "))));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
checker.prefixless("PLAIN_STRING", checkList.next());
|
||||
currentQuestion = checkList.next();
|
||||
|
||||
checker.prefixless("PLAIN_STRING", currentQuestion);
|
||||
|
||||
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"))
|
||||
.text(" " + checker.parseToPlain("CHECK_MARK_DECLINE"))
|
||||
.color(NamedTextColor.RED)
|
||||
.clickEvent(ClickEvent.suggestCommand("/check decline "))));
|
||||
.clickEvent(ClickEvent.runCommand("/check decline"))));
|
||||
}
|
||||
|
||||
private void markDeclined() {
|
||||
declinedQuestions.add(currentQuestion);
|
||||
next();
|
||||
}
|
||||
|
||||
private void accept(){
|
||||
if(concludeCheckSession("freigegeben", fightTypes.get(schematic.getSchemtype()), false)) {
|
||||
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()));
|
||||
}
|
||||
|
||||
return owner.getPlayer() != null;
|
||||
});
|
||||
}
|
||||
|
||||
private void decline(String reason){
|
||||
if(concludeCheckSession(reason, SchematicType.Normal, false)) {
|
||||
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));
|
||||
}
|
||||
|
||||
return owner.getPlayer() != null;
|
||||
});
|
||||
}
|
||||
|
||||
private void notifyTeam(Message message) {
|
||||
@@ -277,20 +303,18 @@ public class CheckCommand extends SWCommand {
|
||||
}
|
||||
|
||||
private void abort(){
|
||||
concludeCheckSession("Prüfvorgang abgebrochen", null, false);
|
||||
concludeCheckSession("Prüfvorgang abgebrochen", null, () -> true);
|
||||
}
|
||||
|
||||
private boolean concludeCheckSession(String reason, SchematicType type, boolean investigation) {
|
||||
boolean exists = SchematicNode.getSchematicNode(schematic.getId()) != null;
|
||||
|
||||
if(exists) {
|
||||
if (investigation) {
|
||||
CheckedSchematic.createInvestigationPending(schematic, startTime, Timestamp.from(Instant.now()), checker.user().getId(), reason);
|
||||
} else {
|
||||
CheckedSchematic.create(schematic, checker.user().getId(), startTime, Timestamp.from(Instant.now()), reason);
|
||||
}
|
||||
if(type != null)
|
||||
private void concludeCheckSession(String reason, SchematicType type, BooleanSupplier sendMessageIsOnline) {
|
||||
if(SchematicNode.getSchematicNode(schematic.getId()) != null) {
|
||||
CheckedSchematic.create(schematic, checker.user().getId(), startTime, Timestamp.from(Instant.now()), reason, sendMessageIsOnline.getAsBoolean());
|
||||
if(type != null) {
|
||||
schematic.setSchemtype(type);
|
||||
if (type == SchematicType.Normal) {
|
||||
schematic.setPrepared(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remove();
|
||||
@@ -299,16 +323,11 @@ public class CheckCommand extends SWCommand {
|
||||
if(subserver != null)
|
||||
subserver.stop();
|
||||
}).schedule();
|
||||
return exists;
|
||||
}
|
||||
|
||||
private void remove() {
|
||||
currentCheckers.remove(checker.user().getUUID());
|
||||
currentSchems.remove(schematic.getId());
|
||||
}
|
||||
|
||||
public void block(String reason) {
|
||||
concludeCheckSession(reason, null, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class ListCommand extends SWCommand {
|
||||
if (server.equals("Bau")) {
|
||||
serverName = sender.parseToLegacy("TABLIST_BAU");
|
||||
}
|
||||
sender.prefixless("LIST_COMMAND", serverName, playerMap.get(server).stream().map(Player::getUsername).collect(Collectors.joining(", ")));
|
||||
sender.prefixless("LIST_COMMAND", serverName, playerMap.get(server).size(), playerMap.get(server).stream().map(Player::getUsername).collect(Collectors.joining(", ")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,22 +19,41 @@
|
||||
|
||||
package de.steamwar.velocitycore.commands;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.messages.PlayerChatter;
|
||||
import de.steamwar.sql.EventFight;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
|
||||
public class ServerSwitchCommand extends SWCommand {
|
||||
|
||||
private final RegisteredServer server;
|
||||
private final boolean isSpectateServer;
|
||||
|
||||
public ServerSwitchCommand(String cmd, String name, String... aliases) {
|
||||
public ServerSwitchCommand(String cmd, String name, boolean isSpectateServer, String... aliases) {
|
||||
super(cmd, null, aliases);
|
||||
server = VelocityCore.getProxy().getServer(name).orElseThrow();
|
||||
this.isSpectateServer = isSpectateServer;
|
||||
}
|
||||
|
||||
@Register
|
||||
public void genericCommand(PlayerChatter sender) {
|
||||
if (isSpectateServer && sender.getPlayer().getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
SteamwarUser user = SteamwarUser.get(sender.getPlayer().getUniqueId());
|
||||
List<EventFight> activeFights = EventFight.getActiveFights();
|
||||
|
||||
if (activeFights.stream()
|
||||
.anyMatch(fight -> fight.getTeamRed() == user.getTeam() || fight.getTeamBlue() == user.getTeam())) {
|
||||
sender.getPlayer().transferToHost(new InetSocketAddress("steamwar.de", 25566));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sender.getPlayer().createConnectionRequest(server).fireAndForget();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* 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.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.Subserver;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.Tutorial;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
import de.steamwar.velocitycore.ServerStarter;
|
||||
import de.steamwar.velocitycore.SubserverSystem;
|
||||
import de.steamwar.velocitycore.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 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.isBuild(subserver) || !subserver.isStarted() || !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()));
|
||||
}
|
||||
}
|
||||
@@ -85,9 +85,9 @@ public class DiscordChannel extends Chatter.PlayerlessChatter {
|
||||
public void send(String message) {
|
||||
message = message
|
||||
.replace("&", "")
|
||||
.replace("@everyone", "`@everyone`")
|
||||
.replace("@here", "`@here`")
|
||||
.replaceAll("<[@#]!?\\d+>", "`$0`");
|
||||
.replace("@everyone", "@\u200Beveryone")
|
||||
.replace("@here", "@\u200Bhere")
|
||||
.replaceAll("<([@#])(!?\\d+)>", "<$1\u200B$2>");
|
||||
|
||||
if (maxNumberOfWebhooks > 0 && getChannel() instanceof TextChannel && message.contains("»")) {
|
||||
String[] strings = message.split("»", 2);
|
||||
|
||||
@@ -94,7 +94,7 @@ public class DiscordSchemUpload extends ListenerAdapter {
|
||||
version = NodeData.SchematicFormat.MCEDIT;
|
||||
}
|
||||
|
||||
NodeData.get(node).saveFromStream(new ByteArrayInputStream(bytes), version);
|
||||
NodeData.saveFromStream(node, new ByteArrayInputStream(bytes), version);
|
||||
sender.system("DC_SCHEMUPLOAD_SUCCESS", name);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
|
||||
@@ -42,6 +42,7 @@ public class SWItem {
|
||||
@Getter
|
||||
private InvCallback callback;
|
||||
private int color = 0;
|
||||
private int customModelData = 0;
|
||||
|
||||
public SWItem(String material, Message title) {
|
||||
this.material = material.toUpperCase();
|
||||
@@ -64,6 +65,11 @@ public class SWItem {
|
||||
return this;
|
||||
}
|
||||
|
||||
public SWItem setCustomModelData(int customModelData) {
|
||||
this.customModelData = customModelData;
|
||||
return this;
|
||||
}
|
||||
|
||||
public JsonObject writeToString(Chatter player, int position) {
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty("material", material);
|
||||
@@ -84,6 +90,9 @@ public class SWItem {
|
||||
}
|
||||
object.add("lore", array);
|
||||
}
|
||||
if (customModelData > 0) {
|
||||
object.addProperty("customModelData", customModelData);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ import com.velocitypowered.api.event.player.PlayerChatEvent;
|
||||
import com.velocitypowered.api.event.player.TabCompleteEvent;
|
||||
import com.velocitypowered.api.proxy.ConsoleCommandSource;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.ChatterGroup;
|
||||
import de.steamwar.messages.Message;
|
||||
@@ -80,17 +82,32 @@ public class ChatListener extends BasicListener {
|
||||
if(VelocityCore.getProxy().getCommandManager().hasCommand(cmd)) {
|
||||
CommandSource source = e.getCommandSource();
|
||||
String name;
|
||||
if(source instanceof Player player)
|
||||
SteamwarUser user = null;
|
||||
if (source instanceof Player player) {
|
||||
user = SteamwarUser.get(player.getUniqueId());
|
||||
name = player.getUsername();
|
||||
else if(source instanceof ConsoleCommandSource)
|
||||
} else if (source instanceof ConsoleCommandSource) {
|
||||
user = SteamwarUser.get(-1);
|
||||
name = "«CONSOLE»";
|
||||
else
|
||||
} else {
|
||||
name = source.toString();
|
||||
}
|
||||
|
||||
if (noLogCommands.contains(cmd)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case "msg":
|
||||
case "r":
|
||||
case "tc":
|
||||
AuditLog.createSensitiveCommand(AuditLog.SERVER_NAME_VELOCITY, null, user, "/" + command);
|
||||
break;
|
||||
default:
|
||||
AuditLog.createCommand(AuditLog.SERVER_NAME_VELOCITY, null, user, "/" + command);
|
||||
break;
|
||||
}
|
||||
|
||||
cmdLogger.log(Level.INFO, "%s -> executed command /%s".formatted(name, command));
|
||||
} else if (e.getCommandSource() instanceof Player player) {
|
||||
// System.out.println("spoofChatInput " + e);
|
||||
@@ -106,8 +123,8 @@ public class ChatListener extends BasicListener {
|
||||
|
||||
e.setResult(PlayerChatEvent.ChatResult.denied());
|
||||
|
||||
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
|
||||
if (message.contains("jndi:ldap")) {
|
||||
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
|
||||
PunishmentCommand.ban(user, Punishment.PERMA_TIME, "Versuchte Exploit-Ausnutzung", SteamwarUser.get(-1), true);
|
||||
VelocityCore.getLogger().log(Level.SEVERE, "%s %s wurde automatisch wegen jndi:ldap gebannt.".formatted(user.getUserName(), user.getId()));
|
||||
return;
|
||||
@@ -117,13 +134,20 @@ public class ChatListener extends BasicListener {
|
||||
return;
|
||||
|
||||
Subserver subserver = Subserver.getSubserver(player);
|
||||
String serverName = AuditLog.SERVER_NAME_VELOCITY;
|
||||
if(Subserver.isArena(subserver) && subserver.getServer() == player.getCurrentServer().orElseThrow().getServerInfo()) {
|
||||
serverName = subserver.getServer().getName();
|
||||
localChat(Chatter.of(player), message);
|
||||
} else if (message.startsWith("+")) {
|
||||
serverName = player.getCurrentServer()
|
||||
.map(ServerConnection::getServerInfo)
|
||||
.map(ServerInfo::getName)
|
||||
.orElse(serverName);
|
||||
localChat(Chatter.of(player), message.substring(1));
|
||||
} else {
|
||||
sendChat(Chatter.of(player), Chatter.globalChat(), "CHAT_GLOBAL", null, message);
|
||||
}
|
||||
AuditLog.createChat(serverName, null, user, message);
|
||||
}
|
||||
|
||||
private static boolean isMistypedCommand(Player player, String message) {
|
||||
|
||||
@@ -23,17 +23,23 @@ import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.connection.DisconnectEvent;
|
||||
import com.velocitypowered.api.event.connection.PostLoginEvent;
|
||||
import com.velocitypowered.api.event.permission.PermissionsSetupEvent;
|
||||
import com.velocitypowered.api.event.player.KickedFromServerEvent;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.permission.Tristate;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.messages.Message;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.sql.CheckedSchematic;
|
||||
import de.steamwar.sql.SchematicType;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
import de.steamwar.velocitycore.EventStarter;
|
||||
import de.steamwar.velocitycore.commands.*;
|
||||
import de.steamwar.velocitycore.discord.DiscordBot;
|
||||
import de.steamwar.velocitycore.discord.util.DiscordRanks;
|
||||
import de.steamwar.velocitycore.mods.ModUtils;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
import java.util.HashSet;
|
||||
@@ -82,12 +88,35 @@ public class ConnectionListener extends BasicListener {
|
||||
}
|
||||
}
|
||||
|
||||
for (CheckedSchematic checkedSchematic : CheckedSchematic.getUnseen(user)) {
|
||||
SchematicType type = SchematicType.fromDB(checkedSchematic.getNodeType());
|
||||
if(type == null) continue;
|
||||
if (checkedSchematic.getDeclineReason().equals("freigegeben")) {
|
||||
chatter.system("CHECK_ACCEPTED", type.name(), checkedSchematic.getSchemName());
|
||||
} else {
|
||||
chatter.system("CHECK_DECLINED", type.name(), checkedSchematic.getSchemName(), checkedSchematic.getDeclineReason());
|
||||
}
|
||||
|
||||
checkedSchematic.setSeen(true);
|
||||
}
|
||||
|
||||
if(newPlayers.contains(player.getUniqueId())){
|
||||
Chatter.broadcast().system("JOIN_FIRST", player);
|
||||
newPlayers.remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
DiscordBot.withBot(bot -> DiscordRanks.update(user));
|
||||
|
||||
if (player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
player.requestCookie(EventModeListener.EVENT_TO_SPECTATE_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void kickEvent(KickedFromServerEvent event) {
|
||||
if (event.getResult() instanceof KickedFromServerEvent.RedirectPlayer red) {
|
||||
event.setResult(KickedFromServerEvent.RedirectPlayer.create(red.getServer(), Component.empty()));
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2025 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.listeners;
|
||||
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.player.CookieReceiveEvent;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import de.steamwar.sql.EventFight;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.velocitycore.EventStarter;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
|
||||
public class CookieEvents extends BasicListener {
|
||||
|
||||
@Subscribe
|
||||
public void handleCookies(CookieReceiveEvent e) {
|
||||
if (e.getOriginalKey().equals(EventModeListener.EVENT_TO_SPECTATE_KEY)) {
|
||||
Player player = e.getPlayer();
|
||||
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
|
||||
|
||||
EventFight.getActiveFights().stream()
|
||||
.filter(fight -> fight.getTeamRed() == user.getTeam() || fight.getTeamBlue() == user.getTeam())
|
||||
.filter(fight -> fight.getSpectatePort() != null)
|
||||
.filter(fight -> fight.getSpectatePort() != 0)
|
||||
.findFirst()
|
||||
.flatMap(fight -> VelocityCore.getProxy().getServer(EventStarter.getSpectatePorts().get(fight.getSpectatePort())))
|
||||
.ifPresent(registeredServer -> player.createConnectionRequest(registeredServer).fireAndForget());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,31 +19,88 @@
|
||||
|
||||
package de.steamwar.velocitycore.listeners;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.connection.PostLoginEvent;
|
||||
import com.velocitypowered.api.event.player.ServerConnectedEvent;
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.sql.Event;
|
||||
import de.steamwar.sql.EventFight;
|
||||
import de.steamwar.sql.Referee;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.TeamTeilnahme;
|
||||
import de.steamwar.velocitycore.EventStarter;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import net.kyori.adventure.key.Key;
|
||||
|
||||
public class EventModeListener extends BasicListener {
|
||||
|
||||
public static final Key EVENT_TO_SPECTATE_KEY = Key.key("sw", "event_to_spectate");
|
||||
|
||||
@Subscribe
|
||||
public void onPostLogin(PostLoginEvent e) {
|
||||
Chatter sender = Chatter.disconnect(e.getPlayer());
|
||||
Player player = e.getPlayer();
|
||||
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
|
||||
Chatter sender = Chatter.disconnect(player);
|
||||
|
||||
Event event = Event.get();
|
||||
if(event == null) {
|
||||
sender.system("EVENTMODE_KICK");
|
||||
if (event == null) {
|
||||
if (player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
sender.system("EVENTMODE_KICK");
|
||||
} else {
|
||||
player.transferToHost(new InetSocketAddress("steamwar.de", 25565));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(TeamTeilnahme.nimmtTeil(sender.user().getTeam(), event.getEventID()))
|
||||
if (TeamTeilnahme.nimmtTeil(user.getTeam(), event.getEventID())) {
|
||||
if (player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_5) && VelocityCore.getProxy().getAllPlayers().stream().map(p -> SteamwarUser.get(p.getUniqueId())).filter(u -> u.getTeam() == user.getTeam()).count() > event.getMaximumTeamMembers()) {
|
||||
player.storeCookie(EVENT_TO_SPECTATE_KEY, "TRUE".getBytes());
|
||||
player.transferToHost(new InetSocketAddress("steamwar.de", 25565));
|
||||
return;
|
||||
}
|
||||
|
||||
Subserver server = EventStarter.getEventServer().get(user.getTeam());
|
||||
|
||||
if (server != null) {
|
||||
server.sendPlayer(player);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Referee.get(event.getEventID()).contains(user.getId()))
|
||||
return;
|
||||
|
||||
if(Referee.get(event.getEventID()).contains(sender.user().getId()))
|
||||
return;
|
||||
if (player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
sender.system("EVENTMODE_KICK");
|
||||
} else {
|
||||
player.transferToHost(new InetSocketAddress("steamwar.de", 25565));
|
||||
}
|
||||
}
|
||||
|
||||
sender.system("EVENTMODE_KICK");
|
||||
@Subscribe
|
||||
public void onLobby(ServerConnectedEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
|
||||
if (player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
|
||||
|
||||
List<EventFight> activeFights = EventFight.getActiveFights();
|
||||
|
||||
if (activeFights.stream()
|
||||
.noneMatch(fight -> fight.getTeamRed() == user.getTeam() || fight.getTeamBlue() == user.getTeam())) {
|
||||
player.transferToHost(new InetSocketAddress("steamwar.de", 25565));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ package de.steamwar.velocitycore.listeners;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.connection.DisconnectEvent;
|
||||
import com.velocitypowered.api.event.connection.PostLoginEvent;
|
||||
import de.steamwar.sql.AuditLog;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.sql.Session;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
@@ -36,10 +37,12 @@ public class SessionManager extends BasicListener {
|
||||
@Subscribe
|
||||
public void onPostLogin(PostLoginEvent event){
|
||||
sessions.put(event.getPlayer(), Timestamp.from(Instant.now()));
|
||||
AuditLog.createJoin(AuditLog.SERVER_NAME_VELOCITY, null, SteamwarUser.get(event.getPlayer().getUniqueId()));
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onDisconnect(DisconnectEvent e){
|
||||
AuditLog.createLeave(AuditLog.SERVER_NAME_VELOCITY, null, SteamwarUser.get(e.getPlayer().getUniqueId()));
|
||||
Timestamp timestamp = sessions.remove(e.getPlayer());
|
||||
if(timestamp != null) {
|
||||
VelocityCore.schedule(() -> Session.insertSession(SteamwarUser.get(e.getPlayer().getUniqueId()).getId(), timestamp)).schedule();
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.listeners;
|
||||
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.player.ServerPostConnectEvent;
|
||||
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
// https://jd.papermc.io/velocity/3.4.0/com/velocitypowered/api/proxy/player/ResourcePackInfo.Builder.html#setHash(byte%5B%5D)
|
||||
public class TexturePackSystem extends BasicListener {
|
||||
|
||||
private static final File PACKS_DIR = new File("/var/www/packs");
|
||||
private static final String BASE_ULR = "https://packs.steamwar.de/";
|
||||
private TreeMap<Integer, Integer> protocolVersionToPackVersion = new TreeMap<>();
|
||||
|
||||
public TexturePackSystem() {
|
||||
// https://minecraft.wiki/w/Pack_format#List_of_resource_pack_formats
|
||||
// https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol_version_numbers
|
||||
protocolVersionToPackVersion.put(759, 9);
|
||||
protocolVersionToPackVersion.put(761, 12);
|
||||
protocolVersionToPackVersion.put(762, 13);
|
||||
protocolVersionToPackVersion.put(763, 15);
|
||||
protocolVersionToPackVersion.put(764, 18);
|
||||
protocolVersionToPackVersion.put(765, 22);
|
||||
protocolVersionToPackVersion.put(766, 32);
|
||||
protocolVersionToPackVersion.put(767, 34);
|
||||
protocolVersionToPackVersion.put(768, 42);
|
||||
protocolVersionToPackVersion.put(769, 46);
|
||||
protocolVersionToPackVersion.put(770, 55);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onLogin(ServerPostConnectEvent event) {
|
||||
if (event.getPreviousServer() != null) {
|
||||
return;
|
||||
}
|
||||
VelocityCore.schedule(() -> {
|
||||
TreeMap<Integer, File> fileTreeMap = new TreeMap<>();
|
||||
for (File fileEntry : PACKS_DIR.listFiles()) {
|
||||
try {
|
||||
int packVersion = Integer.parseInt(fileEntry.getName().split("_")[0]);
|
||||
fileTreeMap.put(packVersion, fileEntry);
|
||||
} catch (NumberFormatException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
int playerVersion = event.getPlayer().getProtocolVersion().getProtocol();
|
||||
Map.Entry<Integer, Integer> packVersionEntry = protocolVersionToPackVersion.floorEntry(playerVersion);
|
||||
if (packVersionEntry == null) return;
|
||||
Map.Entry<Integer, File> selectedPackEntry = fileTreeMap.floorEntry(packVersionEntry.getValue());
|
||||
if (selectedPackEntry == null) return;
|
||||
File selectedPack = selectedPackEntry.getValue();
|
||||
|
||||
String fileName = selectedPack.getName();
|
||||
fileName = fileName.substring(fileName.indexOf('_') + 1, fileName.lastIndexOf('.'));
|
||||
byte[] hash = hexStringToByteArray(fileName);
|
||||
|
||||
ResourcePackInfo resourcePackInfo = VelocityCore.getProxy().createResourcePackBuilder(BASE_ULR + selectedPack.getName())
|
||||
.setId(UUID.nameUUIDFromBytes(fileName.getBytes(StandardCharsets.UTF_8)))
|
||||
.setHash(hash)
|
||||
.setShouldForce(false)
|
||||
.setPrompt(Component.text("The SteamWar TexturePack improves GUIs!"))
|
||||
.build();
|
||||
event.getPlayer().sendResourcePacks(resourcePackInfo);
|
||||
}).delay(500, TimeUnit.MILLISECONDS).schedule();
|
||||
}
|
||||
|
||||
public static byte[] hexStringToByteArray(String s) {
|
||||
int len = s.length();
|
||||
byte[] data = new byte[len / 2];
|
||||
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
|
||||
+ Character.digit(s.charAt(i+1), 16));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -27,19 +27,36 @@ import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.velocity.platform.VelocityViaConfig;
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.network.packets.server.ClientVersionPacket;
|
||||
import de.steamwar.persistent.Subserver;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.network.NetworkSender;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
public class VersionAnnouncer extends BasicListener {
|
||||
|
||||
@Subscribe
|
||||
public void postConnect(ServerConnectedEvent e) {
|
||||
ServerInfo server = e.getServer().getServerInfo();
|
||||
if(!Subserver.isBuild(Subserver.getSubserver(server)))
|
||||
return;
|
||||
|
||||
Player player = e.getPlayer();
|
||||
int serverVersion = ((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols().get(server.getName());
|
||||
if(Via.getAPI().getPlayerVersion(player) == serverVersion)
|
||||
|
||||
int playerVersion = Via.getAPI().getPlayerVersion(player);
|
||||
ProtocolVersion protocolVersion = ProtocolVersion.getProtocolVersion(serverVersion);
|
||||
if (protocolVersion.isSupported()) {
|
||||
// PluginChannel 'vv:proxy_details' from ViaVersion apparently does not work any longer!
|
||||
VelocityCore.schedule(() -> {
|
||||
String[] strings = protocolVersion.getVersionIntroducedIn().split("\\.");
|
||||
NetworkSender.send(player, new ClientVersionPacket(player.getUniqueId(), Integer.parseInt(strings[1])));
|
||||
}).delay(Duration.of(100, ChronoUnit.MILLIS)).schedule();
|
||||
}
|
||||
|
||||
if(playerVersion == serverVersion)
|
||||
return;
|
||||
|
||||
if(!Subserver.isBuild(Subserver.getSubserver(server)))
|
||||
return;
|
||||
|
||||
player.sendActionBar(Chatter.of(player).parse("SERVER_VERSION", ProtocolVersion.getProtocolVersion(serverVersion).getMostRecentSupportedVersion()));
|
||||
|
||||
@@ -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.network.handlers;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.connection.PostLoginEvent;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import de.steamwar.network.packets.PacketHandler;
|
||||
import de.steamwar.network.packets.common.PlayerSkinRequestPacket;
|
||||
import de.steamwar.network.packets.common.PlayerSkinResponsePacket;
|
||||
import de.steamwar.velocitycore.VelocityCore;
|
||||
import de.steamwar.velocitycore.network.NetworkSender;
|
||||
import de.steamwar.velocitycore.network.ServerMetaInfo;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PlayerSkinHandler extends PacketHandler {
|
||||
|
||||
private final int maxCacheSize = 1000;
|
||||
|
||||
public PlayerSkinHandler() {
|
||||
VelocityCore.getProxy().getEventManager().register(VelocityCore.get(), this);
|
||||
}
|
||||
|
||||
private Map<UUID, SkinData> skins = new LinkedHashMap<>() {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<UUID, SkinData> eldest) {
|
||||
return size() > maxCacheSize;
|
||||
}
|
||||
};
|
||||
|
||||
@Handler
|
||||
@SneakyThrows
|
||||
public void handle(PlayerSkinRequestPacket packet) {
|
||||
if (skins.containsKey(packet.getUuid())) {
|
||||
SkinData skinData = skins.get(packet.getUuid());
|
||||
NetworkSender.send(((ServerMetaInfo) packet.getMetaInfos()).sender().getServer(), new PlayerSkinResponsePacket(packet.getUuid(), skinData.skin, skinData.signature));
|
||||
return;
|
||||
}
|
||||
|
||||
String url = "https://sessionserver.mojang.com/session/minecraft/profile/" + packet.getUuid().toString().replace("-", "") + "?unsigned=false";
|
||||
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
|
||||
connection.setReadTimeout(5000);
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setRequestProperty("User-Agent", "SkinFetcher");
|
||||
|
||||
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
InputStream is = connection.getInputStream();
|
||||
String json = new BufferedReader(new InputStreamReader(is))
|
||||
.lines().collect(Collectors.joining("\n"));
|
||||
|
||||
JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
|
||||
JsonArray properties = obj.getAsJsonArray("properties");
|
||||
for (JsonElement propElement : properties) {
|
||||
JsonObject prop = propElement.getAsJsonObject();
|
||||
if (prop.get("name").getAsString().equals("textures")) {
|
||||
String skin = prop.get("value").getAsString();
|
||||
String signature = prop.get("signature").getAsString();
|
||||
skins.put(packet.getUuid(), new SkinData(skin, signature));
|
||||
NetworkSender.send(((ServerMetaInfo) packet.getMetaInfos()).sender().getServer(), new PlayerSkinResponsePacket(packet.getUuid(), skin, signature));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPostLogin(PostLoginEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
GameProfile gameProfile = player.getGameProfile();
|
||||
GameProfile.Property property = gameProfile.getProperties().stream().filter(p -> p.getName().equals("textures")).findFirst().orElse(null);
|
||||
if (property == null) return;
|
||||
skins.put(player.getUniqueId(), new SkinData(property.getValue(), property.getSignature()));
|
||||
|
||||
Set<UUID> uuidSet = skins.keySet();
|
||||
VelocityCore.getProxy().getAllServers().forEach(server -> {
|
||||
for (UUID uuid : uuidSet) {
|
||||
NetworkSender.send(server, new PlayerSkinResponsePacket(uuid, property.getValue(), property.getSignature()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public record SkinData(String skin, String signature) {}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public class Tablist extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private static final UUID[] swUuids = IntStream.range(0, 80).mapToObj(i -> UUID.randomUUID()).toArray(UUID[]::new);
|
||||
private static final String[] swNames = IntStream.range(0, 80).mapToObj(i -> " »SW« " + String.format("%02d", i)).toArray(String[]::new);
|
||||
public static final UpdateTeamsPacket createTeamPacket = new UpdateTeamsPacket("zzzzzsw-tab", UpdateTeamsPacket.Mode.CREATE, Component.empty(), Component.empty(), Component.empty(), UpdateTeamsPacket.NameTagVisibility.NEVER, UpdateTeamsPacket.CollisionRule.ALWAYS, 21, (byte)0x00, Arrays.stream(Tablist.swNames).toList());
|
||||
public static final UpdateTeamsPacket createTeamPacket = new UpdateTeamsPacket21("zzzzzsw-tab", UpdateTeamsPacket.Mode.CREATE, Component.empty(), Component.empty(), Component.empty(), UpdateTeamsPacket.NameTagVisibility.NEVER, UpdateTeamsPacket.CollisionRule.ALWAYS, 21, (byte)0x00, Arrays.stream(Tablist.swNames).toList());
|
||||
|
||||
private final Map<UUID, UpsertPlayerInfoPacket.Entry> directTabItems;
|
||||
private final List<UpsertPlayerInfoPacket.Entry> current = new ArrayList<>();
|
||||
@@ -75,26 +75,12 @@ public class Tablist extends ChannelInboundHandlerAdapter {
|
||||
List<TablistPart.Item> tablist = new ArrayList<>();
|
||||
List<TablistPart.Item> direct = new ArrayList<>();
|
||||
global.print(viewer, player, tablist, direct);
|
||||
|
||||
// NPC handling
|
||||
List<UpsertPlayerInfoPacket.Entry> update = new ArrayList<>();
|
||||
synchronized (directTabItems) {
|
||||
for (TablistPart.Item item : direct) {
|
||||
UpsertPlayerInfoPacket.Entry tabItem = directTabItems.get(item.getUuid());
|
||||
|
||||
if(tabItem == null) {
|
||||
tablist.add(0, item);
|
||||
} else if(!item.getDisplayName().equals(getDisplayName(tabItem))) {
|
||||
tabItem.setDisplayName(new ComponentHolder(player.getProtocolVersion(), item.getDisplayName()));
|
||||
tabItem.setListed(true);
|
||||
update.add(tabItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
tablist.addAll(0, direct);
|
||||
|
||||
// Main list handling
|
||||
int i = 0;
|
||||
List<UpsertPlayerInfoPacket.Entry> add = new ArrayList<>();
|
||||
List<UpsertPlayerInfoPacket.Entry> update = new ArrayList<>();
|
||||
List<UpsertPlayerInfoPacket.Entry> remove = new ArrayList<>();
|
||||
for (; i < tablist.size() && i < 80; i++) {
|
||||
TablistPart.Item item = tablist.get(i);
|
||||
@@ -171,6 +157,8 @@ public class Tablist extends ChannelInboundHandlerAdapter {
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
sendTabPacket(new ArrayList<>(directTabItems.values()), null);
|
||||
directTabItems.clear();
|
||||
sendTabPacket(current, null);
|
||||
current.clear();
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.tablist;
|
||||
|
||||
import com.velocitypowered.api.network.ProtocolVersion;
|
||||
import com.velocitypowered.proxy.protocol.ProtocolUtils;
|
||||
import com.velocitypowered.proxy.protocol.packet.UpdateTeamsPacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class UpdateTeamsPacket21 extends UpdateTeamsPacket {
|
||||
|
||||
private String name;
|
||||
private Mode mode;
|
||||
private Component displayName;
|
||||
private Component prefix;
|
||||
private Component suffix;
|
||||
private NameTagVisibility nameTagVisibility;
|
||||
private CollisionRule collisionRule;
|
||||
private int color;
|
||||
private byte friendlyFlags;
|
||||
private List<String> players;
|
||||
|
||||
public UpdateTeamsPacket21(String name, Mode mode, Component displayName, Component prefix, Component suffix, NameTagVisibility nameTagVisibility, CollisionRule collisionRule, int color, byte friendlyFlags, List<String> players) {
|
||||
super(name, mode, displayName, prefix, suffix, nameTagVisibility, collisionRule, color, friendlyFlags, players);
|
||||
this.name = name;
|
||||
this.mode = mode;
|
||||
this.displayName = displayName;
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
this.nameTagVisibility = nameTagVisibility;
|
||||
this.collisionRule = collisionRule;
|
||||
this.color = color;
|
||||
this.friendlyFlags = friendlyFlags;
|
||||
this.players = players;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
|
||||
ProtocolUtils.writeString(byteBuf, this.name);
|
||||
byteBuf.writeByte(this.mode.ordinal());
|
||||
switch (this.mode) {
|
||||
case CREATE:
|
||||
case UPDATE:
|
||||
(new ComponentHolder(protocolVersion, this.displayName)).write(byteBuf);
|
||||
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_13)) {
|
||||
(new ComponentHolder(protocolVersion, this.prefix)).write(byteBuf);
|
||||
(new ComponentHolder(protocolVersion, this.suffix)).write(byteBuf);
|
||||
}
|
||||
|
||||
byteBuf.writeByte(this.friendlyFlags);
|
||||
if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_21_5)) {
|
||||
ProtocolUtils.writeVarInt(byteBuf, this.nameTagVisibility.ordinal());
|
||||
ProtocolUtils.writeVarInt(byteBuf, this.collisionRule.ordinal());
|
||||
} else {
|
||||
ProtocolUtils.writeString(byteBuf, this.nameTagVisibility.getValue());
|
||||
ProtocolUtils.writeString(byteBuf, this.collisionRule.getValue());
|
||||
}
|
||||
if (protocolVersion.greaterThan(ProtocolVersion.MINECRAFT_1_12_2)) {
|
||||
ProtocolUtils.writeVarInt(byteBuf, this.color);
|
||||
(new ComponentHolder(protocolVersion, this.prefix)).write(byteBuf);
|
||||
(new ComponentHolder(protocolVersion, this.suffix)).write(byteBuf);
|
||||
} else {
|
||||
byteBuf.writeByte((byte)this.color);
|
||||
}
|
||||
|
||||
ProtocolUtils.writeVarInt(byteBuf, this.players.size());
|
||||
|
||||
for(String player : this.players) {
|
||||
ProtocolUtils.writeString(byteBuf, player);
|
||||
}
|
||||
break;
|
||||
case ADD_PLAYER:
|
||||
case REMOVE_PLAYER:
|
||||
ProtocolUtils.writeVarInt(byteBuf, this.players.size());
|
||||
|
||||
for(String player : this.players) {
|
||||
ProtocolUtils.writeString(byteBuf, player);
|
||||
}
|
||||
case REMOVE:
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
package de.steamwar.velocitycore.util;
|
||||
|
||||
import de.steamwar.messages.Chatter;
|
||||
import de.steamwar.sql.BauweltMember;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.UserConfig;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
@@ -44,6 +45,10 @@ public class BauLock {
|
||||
case NOBODY:
|
||||
locked = true;
|
||||
break;
|
||||
case SUPERVISOR:
|
||||
BauweltMember member = BauweltMember.getBauMember(owner.getId(), target.getId());
|
||||
locked = !member.isSupervisor();
|
||||
break;
|
||||
case SERVERTEAM:
|
||||
locked = !target.hasPerm(UserPerm.TEAM);
|
||||
break;
|
||||
|
||||
@@ -22,6 +22,7 @@ package de.steamwar.velocitycore.util;
|
||||
public enum BauLockState {
|
||||
|
||||
NOBODY, // Locks the build server for all users
|
||||
SUPERVISOR, // Locks the build server for supervisors
|
||||
SERVERTEAM, // opens the build server only for every added user which is a server team member
|
||||
TEAM_AND_SERVERTEAM, //opens the build server only for every added user which is in the same team as the buildOwner and every server team member
|
||||
TEAM, //opens the build server only for every added user which is in the same team as the buildOwner
|
||||
|
||||
Reference in New Issue
Block a user