64 Commits

Author SHA1 Message Date
eb218c33ca Fix missing key.reset() in BackendSync directory watch logic
All checks were successful
SteamWarCI Build successful
2025-07-20 00:08:51 +02:00
7b01f11b5b Introduce backend synchronization system for Velocity and WebsiteBackend
All checks were successful
SteamWarCI Build successful
2025-07-20 00:06:19 +02:00
fd57ba43e9 Mark createdAt as primary key in NodeData class
All checks were successful
SteamWarCI Build successful
2025-07-19 22:48:03 +02:00
03005adcd8 Merge pull request 'Add enhance ReplayCommand' (#115) from add-fight-id into main
All checks were successful
SteamWarCI Build successful
Reviewed-on: #115
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
2025-07-19 22:06:36 +02:00
679d373a1e Fix colors final time, for 1.15 and earlier support
All checks were successful
SteamWarCI Build successful
2025-07-19 18:11:10 +02:00
828084a3d6 Update Guide color
All checks were successful
SteamWarCI Build successful
2025-07-19 17:58:53 +02:00
2b782585b1 Hotfix TeamCommand and WhoisCommand
All checks were successful
SteamWarCI Build successful
2025-07-19 17:54:39 +02:00
b43965be91 Revert "Update PREFIX_GUIDE color to §a in UserPerm"
All checks were successful
SteamWarCI Build successful
This reverts commit 30cdbe072e.
2025-07-19 17:45:39 +02:00
d82f306094 Add getById method in Fight class and enhance ReplayCommand handling with admin replay checks
All checks were successful
SteamWarCI Build successful
2025-07-19 17:12:44 +02:00
30cdbe072e Update PREFIX_GUIDE color to §a in UserPerm
All checks were successful
SteamWarCI Build successful
2025-07-19 17:07:18 +02:00
db7e1a5fc9 Add immersive portals channel to PluginMessage listener
All checks were successful
SteamWarCI Build successful
2025-07-19 17:01:30 +02:00
3e5055c246 Refine checkpoint handling in Subserver and remove unnecessary debug logs in CheckpointUtilsJ9
All checks were successful
SteamWarCI Build successful
2025-07-16 09:43:24 +02:00
44c06314c6 Update checkpoint restoration message handling in Subserver
All checks were successful
SteamWarCI Build successful
2025-07-16 09:39:38 +02:00
e06742d6d2 SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java aktualisiert
All checks were successful
SteamWarCI Build successful
2025-07-16 09:34:38 +02:00
62e674ed42 SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java aktualisiert
All checks were successful
SteamWarCI Build successful
2025-07-14 19:40:33 +02:00
0464442b83 VelocityCore/Persistent/src/de/steamwar/persistent/Subserver.java aktualisiert
All checks were successful
SteamWarCI Build successful
2025-07-14 19:38:46 +02:00
c682333771 Add Criu Debug
All checks were successful
SteamWarCI Build successful
2025-07-14 19:13:25 +02:00
58ab619144 Add Criu Debug
All checks were successful
SteamWarCI Build successful
2025-07-14 19:08:35 +02:00
00de852575 Add Criu Debug
All checks were successful
SteamWarCI Build successful
2025-07-14 19:07:48 +02:00
948cf5e8db Add Criu Debug
All checks were successful
SteamWarCI Build successful
2025-07-14 18:52:08 +02:00
7aba8da5a0 Add revision handling to setSchematic method in FightTeam
All checks were successful
SteamWarCI Build successful
2025-07-14 13:40:43 +02:00
5a77854752 Fix replaceColor usage and correct config flag handling
All checks were successful
SteamWarCI Build successful
2025-07-14 11:20:26 +02:00
cf1422f532 Fix NodeData query to correctly order by CreatedAt descending
All checks were successful
SteamWarCI Build successful
2025-07-14 09:46:06 +02:00
6260e65b33 Merge pull request 'Add Schematic Revisions' (#93) from schematic-revisions into main
All checks were successful
SteamWarCI Build successful
Reviewed-on: #93
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
2025-07-14 09:13:16 +02:00
6db404c1e6 Merge pull request 'Add AuditLog' (#89) from AuditLog into main
All checks were successful
SteamWarCI Build successful
Reviewed-on: #89
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2025-07-14 09:13:02 +02:00
b086fcaa32 Refactor validator method in download command
All checks were successful
SteamWarCI Build successful
2025-07-13 21:11:18 +02:00
f33b3521b8 Hotfix TNTPoint for 1.15 or earlier
All checks were successful
SteamWarCI Build successful
2025-07-13 21:00:42 +02:00
dc72ec1b93 Hotfix REntityServer for 1.15 or earlier
All checks were successful
SteamWarCI Build successful
2025-07-13 20:57:22 +02:00
0e9c9bd4dc Hotfix DiscordChannel
All checks were successful
SteamWarCI Build successful
2025-07-13 20:48:43 +02:00
291b6b1804 Merge pull request 'Add Winconditions.TIMED_DAMAGE_TECH_KO and Winconditions.RANDOM_ROTATE' (#111) from FightSystem/RandomRotationAndTimedDamageTechKO into main
All checks were successful
SteamWarCI Build successful
Reviewed-on: #111
Reviewed-by: D4rkr34lm <dark@steamwar.de>
2025-07-13 18:40:52 +02:00
104f0cf02d Fix final stuff
All checks were successful
SteamWarCI Build successful
2025-07-13 18:39:53 +02:00
f7662cdcba Fix build
All checks were successful
SteamWarCI Build successful
2025-07-13 18:15:24 +02:00
167b36b10c Update RandomRotate
Some checks failed
SteamWarCI Build failed
2025-07-13 18:10:53 +02:00
b9b541957b Fix older replays
All checks were successful
SteamWarCI Build successful
2025-07-13 17:54:28 +02:00
e9d107f0ed Fix older replays
All checks were successful
SteamWarCI Build successful
2025-07-13 17:54:06 +02:00
1e264a63a2 Add Winconditions.TIMED_DAMAGE_TECH_KO and Winconditions.RANDOM_ROTATE
All checks were successful
SteamWarCI Build successful
2025-07-13 16:48:35 +02:00
868ba4073b Add Winconditions.TIMED_DAMAGE_TECH_KO and Winconditions.RANDOM_ROTATE
All checks were successful
SteamWarCI Build successful
2025-07-13 16:46:11 +02:00
3410dd5a4b Merge pull request 'Improve perceived server start time' (#108) from VelocityCore/ImprovePerceivedServerStartTimeWithCRIU into main
All checks were successful
SteamWarCI Build successful
Reviewed-on: #108
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2025-07-10 13:46:03 +02:00
b86a26a709 Fix Simulator.autoTrace
All checks were successful
SteamWarCI Build successful
2025-07-10 13:44:06 +02:00
71238a0167 Add Simulator.autoTestblock
All checks were successful
SteamWarCI Build successful
2025-07-10 13:40:21 +02:00
30ac947ebb Add Simulator.autoTestblock
All checks were successful
SteamWarCI Build successful
2025-07-10 13:39:03 +02:00
a7d64b5887 Improve TickManager21
All checks were successful
SteamWarCI Build successful
2025-07-10 13:21:17 +02:00
d7908c8255 Improve perceived server start time
All checks were successful
SteamWarCI Build successful
2025-07-10 13:02:24 +02:00
12f26b982e Rever CheckpointUtilsJ9
All checks were successful
SteamWarCI Build successful
2025-07-10 10:52:14 +02:00
2be4118399 Close server socket before world saving
All checks were successful
SteamWarCI Build successful
2025-07-10 10:23:28 +02:00
9d6981ee0c Trigger rebuild
All checks were successful
SteamWarCI Build successful
2025-07-10 10:09:39 +02:00
97a4d47aa7 Merge pull request 'Add support for TPS and tick rate management in 1.21+' (#105) from 1.21.1/tpslimit into main
All checks were successful
SteamWarCI Build successful
Reviewed-on: #105
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
2025-07-08 22:17:22 +02:00
d657f9871d Update and integrate legacy system
All checks were successful
SteamWarCI Build successful
2025-07-08 22:16:52 +02:00
a572b84016 Add Items
All checks were successful
SteamWarCI Build successful
2025-07-08 21:11:27 +02:00
f1c6b4b453 Update UserPerm colors "final?"
All checks were successful
SteamWarCI Build successful
2025-07-08 19:58:49 +02:00
d0414c71f3 Fix v3Mode handling in WorldEditWrapper14
All checks were successful
SteamWarCI Build successful
2025-07-08 12:07:03 +02:00
3530aec5e2 Add more Flowers and add Leather horse Armour
All checks were successful
SteamWarCI Build successful
2025-07-08 10:45:40 +02:00
cccd090357 Add support for TPS and tick rate management in 1.21+
All checks were successful
SteamWarCI Build successful
2025-07-07 22:43:16 +02:00
3ae9a41b31 Hotfix: Entities on 1.21+
All checks were successful
SteamWarCI Build successful
2025-07-06 21:58:05 +02:00
b8b38cf777 Merge pull request 'Handle KickedFromServerEvent with redirect and empty component' (#103) from remove-kicked-message into main
All checks were successful
SteamWarCI Build successful
Reviewed-on: #103
2025-07-06 17:58:46 +02:00
c1eca74dd0 Handle KickedFromServerEvent with redirect and empty component
All checks were successful
SteamWarCI Build successful
2025-07-06 14:06:07 +02:00
8c23bf5bd4 Fix 1.21 DisplayEntities
All checks were successful
SteamWarCI Build successful
2025-07-06 11:58:54 +02:00
556c8f7db1 Fix MissileWars team colors and TNTLeague team colors
All checks were successful
SteamWarCI Build successful
2025-07-04 17:49:58 +02:00
5c7c982175 Merge branch 'main' into schematic-revisions
All checks were successful
SteamWarCI Build successful
2025-07-03 00:45:03 +02:00
d5ca1e14e1 Add prepared flag to schematics and refactor related logic
All checks were successful
SteamWarCI Build successful
2025-07-02 12:25:58 +02:00
4bd5d9eb0b Remove unused get and query
All checks were successful
SteamWarCI Build successful
2025-07-02 10:00:43 +02:00
60a70dfc40 Remove unused get
All checks were successful
SteamWarCI Build successful
2025-07-02 09:59:09 +02:00
4c98ce4aff Add Schematic Revisions
All checks were successful
SteamWarCI Build successful
2025-07-01 21:39:08 +02:00
617bae5a5c Add AuditLog
All checks were successful
SteamWarCI Build successful
2025-07-01 18:48:59 +02:00
98 changed files with 1476 additions and 918 deletions

View File

@@ -0,0 +1,140 @@
/*
* 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.bausystem.utils;
import de.steamwar.bausystem.region.GlobalRegion;
import de.steamwar.bausystem.utils.bossbar.BossBarService;
import de.steamwar.bausystem.utils.tps.TPSFreezeUtils;
import de.steamwar.bausystem.utils.tps.TPSLimitUtils;
import de.steamwar.core.TPSWarpUtils;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class TickManager15 implements TickManager, Listener {
private static float currentTPSLimit = 20;
private boolean currentlyStepping = false;
private float currentLimit;
private int stepsTotal;
private int stepsLeft;
@Override
public boolean canFreeze() {
return TPSFreezeUtils.isCanFreeze();
}
@Override
public void setTickRate(float tickRate) {
if (currentlyStepping) {
currentlyStepping = false;
Bukkit.getOnlinePlayers().forEach(player -> {
BossBarService.instance.remove(player, GlobalRegion.getInstance(), "TickStep");
});
}
TPSWarpUtils.warp(tickRate);
if (currentTPSLimit == 0 && tickRate != 0) {
TPSFreezeUtils.unfreeze();
}
currentTPSLimit = tickRate;
if (tickRate == 0) {
TPSLimitUtils.unlimit();
TPSFreezeUtils.freeze();
} else if (tickRate < 20.0) {
TPSLimitUtils.limit(tickRate);
} else if (tickRate >= 20) {
TPSLimitUtils.unlimit();
}
}
@Override
public boolean isFrozen() {
return TPSFreezeUtils.frozen();
}
@Override
public void setFreeze(boolean freeze) {
if (freeze) {
setTickRate(0);
}
}
@Override
public void stepTicks(int ticks) {
currentLimit = 0;
setTickRate(20);
stepsLeft = ticks;
stepsTotal = ticks;
currentlyStepping = true;
}
@Override
public void sprintTicks(int ticks) {
currentLimit = currentTPSLimit;
setTickRate(4000);
stepsLeft = ticks;
stepsTotal = ticks;
currentlyStepping = true;
}
@Override
public boolean isSprinting() {
return currentlyStepping && currentTPSLimit > 20;
}
@Override
public boolean isStepping() {
return currentlyStepping && currentTPSLimit <= 20;
}
@Override
public float getTickRate() {
return currentTPSLimit;
}
@Override
public void setBlockTpsPacket(boolean block) {
}
@Override
public long getTotalTicks() {
return stepsTotal;
}
@Override
public long getDoneTicks() {
return stepsTotal - stepsLeft;
}
@Override
public long getRemainingTicks() {
return stepsLeft;
}
@EventHandler
public void onTickEnd(TickEndEvent event) {
if (!currentlyStepping) return;
stepsLeft--;
if (stepsLeft <= 0) {
setTickRate(currentLimit);
}
}
}

View File

@@ -1,23 +1,23 @@
/*
* This file is a part of the SteamWar software.
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
* 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 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.
* 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/>.
* 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.bausystem.features.tpslimit;
package de.steamwar.bausystem.utils.tps;
import de.steamwar.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol;

View File

@@ -1,23 +1,23 @@
/*
* This file is a part of the SteamWar software.
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
* 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 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.
* 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/>.
* 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.bausystem.features.tpslimit;
package de.steamwar.bausystem.utils.tps;
import de.steamwar.Reflection;
import lombok.Getter;

View File

@@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bausystem.features.tpslimit;
package de.steamwar.bausystem.utils.tps;
import de.steamwar.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol;

View File

@@ -22,7 +22,6 @@ package de.steamwar.bausystem.utils;
import com.destroystokyo.paper.event.server.ServerTickEndEvent;
import com.destroystokyo.paper.event.server.ServerTickStartEvent;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.tpslimit.TPSFreezeUtils;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -37,7 +36,7 @@ public class TickListener19 implements TickListener, Listener {
@EventHandler
public void onServerTickStart(ServerTickStartEvent event) {
if (TPSFreezeUtils.isFrozen()) return;
if (TickManager.impl.isFrozen()) return;
Bukkit.getPluginManager().callEvent(new TickStartEvent());
tickStartRan = true;
}

View File

@@ -94,7 +94,7 @@ public class NMSWrapper21 implements NMSWrapper {
return false;
}
return drillDown(data.contents(), 0, 0) <= threshold;
return drillDown(data.contents(), 0, 0) > threshold;
}
private int drillDown(List<ItemStack> items, int layer, int start) {

View File

@@ -0,0 +1,150 @@
/*
* 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.bausystem.utils;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.Reflection;
import de.steamwar.bausystem.BauSystem;
import net.minecraft.network.protocol.game.ClientboundTickingStatePacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.ServerTickRateManager;
import net.minecraft.world.TickRateManager;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class TickManager21 implements TickManager {
private static final ServerTickRateManager manager = MinecraftServer.getServer().tickRateManager();
private static final Reflection.Field<Integer> frozenTicksToRun = Reflection.getField(TickRateManager.class, int.class, 0);
private static final Reflection.Field<Long> remainingSprintTicks = Reflection.getField(ServerTickRateManager.class, long.class, 0);
private boolean blockTpsPacket = true;
private int totalSteps;
public TickManager21() {
TinyProtocol.instance.addFilter(ClientboundTickingStatePacket.class, this::blockPacket);
}
private Object blockPacket(Player player, Object packet) {
if (blockTpsPacket) {
return new ClientboundTickingStatePacket(20, manager.isFrozen());
} else {
return packet;
}
}
@Override
public boolean canFreeze() {
return true;
}
@Override
public void setBlockTpsPacket(boolean block) {
blockTpsPacket = block;
if (blockTpsPacket) {
ClientboundTickingStatePacket packet = new ClientboundTickingStatePacket(20, manager.isFrozen());
Bukkit.getOnlinePlayers().forEach(player -> TinyProtocol.instance.sendPacket(player, packet));
} else {
ClientboundTickingStatePacket packet = new ClientboundTickingStatePacket(manager.tickrate(), manager.isFrozen());
Bukkit.getOnlinePlayers().forEach(player -> TinyProtocol.instance.sendPacket(player, packet));
}
}
@Override
public void setTickRate(float tickRate) {
if (isFrozen()) {
setFreeze(false);
}
manager.setTickRate(tickRate);
}
@Override
public boolean isFrozen() {
return manager.isFrozen();
}
@Override
public void setFreeze(boolean freeze) {
manager.setFrozen(freeze);
}
@Override
public void stepTicks(int ticks) {
if (manager.isSprinting()) {
manager.stopSprinting();
} else if (manager.isSteppingForward()) {
manager.stopStepping();
}
this.totalSteps = ticks;
manager.setFrozen(true);
manager.stepGameIfPaused(ticks);
manager.setFrozen(false);
Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), (bukkitTask) -> {
if (manager.isSteppingForward()) return;
manager.setFrozen(true);
bukkitTask.cancel();
}, 1, 1);
manager.tick();
}
@Override
public void sprintTicks(int ticks) {
if (manager.isSteppingForward()) {
manager.stopStepping();
} else if (manager.isSprinting()) {
manager.stopSprinting();
}
this.totalSteps = ticks;
manager.requestGameToSprint(ticks, true);
}
@Override
public boolean isSprinting() {
return manager.isSprinting();
}
@Override
public boolean isStepping() {
return manager.isSteppingForward();
}
@Override
public float getTickRate() {
return manager.tickrate();
}
@Override
public long getRemainingTicks() {
if (isSprinting()) {
return remainingSprintTicks.get(manager);
} else {
return frozenTicksToRun.get(manager);
}
}
@Override
public long getDoneTicks() {
return totalSteps - getRemainingTicks();
}
@Override
public long getTotalTicks() {
return totalSteps;
}
}

View File

@@ -19,7 +19,6 @@
package de.steamwar.bausystem;
import de.steamwar.core.WorldEditRendererCUIEditor;
import de.steamwar.bausystem.config.BauServer;
import de.steamwar.bausystem.configplayer.Config;
import de.steamwar.bausystem.configplayer.ConfigConverter;
@@ -29,7 +28,6 @@ import de.steamwar.bausystem.features.script.lua.libs.LuaLib;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.panzern.Panzern;
import de.steamwar.bausystem.features.slaves.panzern.PanzernAlgorithm;
import de.steamwar.bausystem.features.tpslimit.TPSFreezeUtils;
import de.steamwar.bausystem.features.tracer.TraceManager;
import de.steamwar.bausystem.features.tracer.TraceRecorder;
import de.steamwar.bausystem.features.world.BauScoreboard;
@@ -39,11 +37,13 @@ import de.steamwar.bausystem.region.loader.RegionLoader;
import de.steamwar.bausystem.region.loader.Updater;
import de.steamwar.bausystem.utils.ScoreboardElement;
import de.steamwar.bausystem.utils.TickListener;
import de.steamwar.bausystem.utils.TickManager;
import de.steamwar.bausystem.worlddata.WorldData;
import de.steamwar.command.AbstractValidator;
import de.steamwar.command.SWCommand;
import de.steamwar.command.SWCommandUtils;
import de.steamwar.core.Core;
import de.steamwar.core.WorldEditRendererCUIEditor;
import de.steamwar.linkage.LinkedInstance;
import de.steamwar.linkage.MaxVersion;
import de.steamwar.linkage.MinVersion;
@@ -266,7 +266,7 @@ public class BauSystem extends JavaPlugin {
@Override
public void run() {
if (TPSFreezeUtils.isFrozen()) return;
if (TickManager.impl.isFrozen()) return;
if (counter >= delay) {
runnable.run();
cancel();
@@ -284,7 +284,7 @@ public class BauSystem extends JavaPlugin {
@Override
public void run() {
if (TPSFreezeUtils.isFrozen()) return;
if (TickManager.impl.isFrozen()) return;
if (counter >= (first ? delay : period)) {
first = false;
runnable.run();

View File

@@ -20,6 +20,7 @@
package de.steamwar.bausystem.features.script.lua.libs;
import de.steamwar.bausystem.features.tpslimit.TPSSystem;
import de.steamwar.bausystem.utils.TickManager;
import de.steamwar.core.TPSWatcher;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.LinkedInstance;
@@ -51,7 +52,7 @@ public class TpsLib implements LuaLib {
tpsLib.set("fiveMinute", getter(() -> TPSWatcher.getTPS(TPSWatcher.TPSType.FIVE_MINUTES)));
tpsLib.set("tenMinute", getter(() -> TPSWatcher.getTPS(TPSWatcher.TPSType.TEN_MINUTES)));
tpsLib.set("current", getter(TPSWatcher::getTPS));
tpsLib.set("limit", getter(TPSSystem::getCurrentTPSLimit));
tpsLib.set("limit", getter(() -> (double) TickManager.impl.getTickRate()));
return tpsLib;
}
}

View File

@@ -23,7 +23,6 @@ import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.SWUtils;
import de.steamwar.bausystem.features.simulator.data.Simulator;
import de.steamwar.bausystem.features.simulator.execute.SimulatorExecutor;
import de.steamwar.bausystem.features.simulator.preview.SimulatorPreviewCalculator;
import de.steamwar.command.PreviousArguments;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
@@ -31,7 +30,6 @@ import de.steamwar.command.TypeValidator;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.LinkedInstance;
import de.steamwar.linkage.MinVersion;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -78,7 +76,7 @@ public class SimulatorCommand extends SWCommand {
@Register(value = "start", description = "SIMULATOR_START_HELP")
public void start(@Validator Player p, @ErrorMessage("SIMULATOR_NOT_EXISTS") Simulator simulator) {
SimulatorExecutor.run(simulator, () -> {});
SimulatorExecutor.run(p, simulator, null);
}
@Register(value = "rename", description = "SIMULATOR_RENAME_HELP")
@@ -92,20 +90,6 @@ public class SimulatorCommand extends SWCommand {
}
}
@Register(value = "test")
public void test(Player player) {
for (int i = 0; i < 1; i++) {
SimulatorPreviewCalculator data = new SimulatorPreviewCalculator(null);
data.spawnTNT(0, 166, 0);
data.calculate(simulatorPreviewResult -> {
simulatorPreviewResult.show(player);
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
simulatorPreviewResult.hide(player);
}, 100);
});
}
}
@ClassMapper(value = Simulator.class, local = true)
public TypeMapper<Simulator> allSimulators() {
return new TypeMapper<>() {

View File

@@ -367,7 +367,7 @@ public class SimulatorCursor implements Listener {
if (simulator == null) {
return;
}
SimulatorExecutor.run(simulator, () -> {});
SimulatorExecutor.run(event.getPlayer(), simulator, null);
return;
}

View File

@@ -40,9 +40,11 @@ public final class Simulator {
private SimulatorStabGenerator stabGenerator = null;
private Material material = Material.BARREL;
private final String name;
private boolean autoTrace = false;
private final List<SimulatorGroup> groups = new ArrayList<>();
private boolean autoTrace = false;
private boolean autoTestblock = false;
public void move(int x, int y, int z) {
groups.forEach(simulatorGroup -> {
simulatorGroup.move(x, y, z);

View File

@@ -31,6 +31,7 @@ import de.steamwar.linkage.Linked;
import de.steamwar.linkage.MinVersion;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -46,7 +47,7 @@ public class SimulatorExecutor implements Listener {
private static Map<Long, Map<Integer, List<SimulatorAction>>> tickStartActions = new HashMap<>();
private static Map<Long, List<SimulatorAction>> tickEndActions = new HashMap<>();
public static boolean run(Simulator simulator, Runnable onEnd) {
public static boolean run(Player player, Simulator simulator, Runnable onEnd) {
if (currentlyRunning.contains(simulator)) return false;
currentlyRunning.add(simulator);
@@ -83,10 +84,15 @@ public class SimulatorExecutor implements Listener {
});
}
onEnd.run();
if (onEnd != null) {
onEnd.run();
}
}
});
if (player != null && simulator.isAutoTestblock()) {
player.performCommand("tb");
}
if (simulator.isAutoTrace() && onEnd == null) {
simulator.getGroups()
.stream()

View File

@@ -58,7 +58,7 @@ public abstract class StabStep {
protected abstract void start();
protected final void runSimulator(Runnable onFinish) {
SimulatorExecutor.run(data.simulator, () -> {
SimulatorExecutor.run(null, data.simulator, () -> {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
if (this instanceof Listener) {
HandlerList.unregisterAll((Listener) this);

View File

@@ -56,10 +56,14 @@ public class SimulatorSettingsGui extends SimulatorBaseGui {
}));
//AutoTrace
inventory.setItem(20, new SWItem(simulator.isAutoTrace() ? Material.CHAIN_COMMAND_BLOCK : Material.COMMAND_BLOCK, "§eAutoTrace§8: " + (simulator.isAutoTrace() ? "§aOn" : "§cOff"), clickType -> {
inventory.setItem(19, new SWItem(simulator.isAutoTrace() ? Material.CHAIN_COMMAND_BLOCK : Material.COMMAND_BLOCK, "§eAutoTrace§8: " + (simulator.isAutoTrace() ? "§aOn" : "§cOff"), clickType -> {
simulator.setAutoTrace(!simulator.isAutoTrace());
SimulatorWatcher.update(simulator);
}));
inventory.setItem(20, new SWItem(simulator.isAutoTestblock() ? Material.END_STONE : Material.BARRIER, "§eTestblock§8: " + (simulator.isAutoTestblock() ? "§aOn" : "§cOff"), clickType -> {
simulator.setAutoTestblock(!simulator.isAutoTestblock());
SimulatorWatcher.update(simulator);
}));
//Pos X
inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {

View File

@@ -1,23 +0,0 @@
/*
* 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.bausystem.features.simulator.preview;
public class SimulatorPreview {
}

View File

@@ -1,76 +0,0 @@
/*
* 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.bausystem.features.simulator.preview;
import lombok.AllArgsConstructor;
import lombok.ToString;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.VoxelShape;
import java.util.List;
import java.util.stream.Collectors;
@AllArgsConstructor
@ToString
public class SimulatorPreviewAABB {
public double minX;
public double minY;
public double minZ;
public double maxX;
public double maxY;
public double maxZ;
public SimulatorPreviewAABB copy() {
return new SimulatorPreviewAABB(minX, minY, minZ, maxX, maxY, maxZ);
}
public void expandTowards(double vx, double vy, double vz) {
if (vx < 0) {
minX += vx;
} else {
maxX += vx;
}
if (vy < 0) {
minY += vy;
} else {
maxY += vy;
}
if (vz < 0) {
minZ += vz;
} else {
maxZ += vz;
}
}
public void add(double vx, double vy, double vz) {
minX += vx;
minY += vy;
minZ += vz;
}
public boolean intersects(double x, double y, double z, BoundingBox boundingBox) {
return minX - (x + boundingBox.getMaxX()) < -1.0E-7 &&
maxX - (x + boundingBox.getMinX()) > 1.0E-7 &&
minY - (y + boundingBox.getMaxY()) < -1.0E-7 &&
maxY - (y + boundingBox.getMinY()) > 1.0E-7 &&
minZ - (z + boundingBox.getMaxZ()) < -1.0E-7 &&
maxZ - (z + boundingBox.getMinZ()) > 1.0E-7;
}
}

View File

@@ -1,114 +0,0 @@
/*
* 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.bausystem.features.simulator.preview;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.simulator.data.Simulator;
import de.steamwar.bausystem.features.tracer.TNTPoint;
import de.steamwar.bausystem.features.tracer.Trace;
import lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.util.Consumer;
import org.bukkit.util.Vector;
import org.bukkit.util.VoxelShape;
import java.util.*;
@RequiredArgsConstructor
public class SimulatorPreviewCalculator {
private static final World WORLD = Bukkit.getWorlds().get(0);
public final Simulator simulator;
public final List<SimulatorPreviewTNT> tnts = new ArrayList<>();
private int ticks = 0;
private final Set<SimulatorPreviewPos> air = new HashSet<>();
private final Map<SimulatorPreviewPos, BlockData> datas = new HashMap<>();
private final Map<SimulatorPreviewPos, VoxelShape> shapes = new HashMap<>();
public BlockData getBlockData(int x, int y, int z) {
SimulatorPreviewPos pos = new SimulatorPreviewPos(x, y, z);
if (air.contains(pos)) return null;
return datas.computeIfAbsent(pos, __ -> {
BlockData blockData = WORLD.getBlockData(x, y, z);
if (blockData.getMaterial().isAir()) {
air.add(pos);
return null;
}
return blockData;
});
}
public VoxelShape getBlockShape(int x, int y, int z) {
SimulatorPreviewPos pos = new SimulatorPreviewPos(x, y, z);
if (air.contains(pos)) return null;
return shapes.computeIfAbsent(pos, __ -> {
Block block = WORLD.getBlockAt(x, y, z);
if (block.getType().isAir()) {
air.add(pos);
return null;
}
return block.getCollisionShape();
});
}
public void setAir(int x, int y, int z) {
SimulatorPreviewPos pos = new SimulatorPreviewPos(x, y, z);
air.add(pos);
datas.remove(pos);
shapes.remove(pos);
}
public void spawnTNT(double x, double y, double z) {
tnts.add(new SimulatorPreviewTNT(this, x, y, z));
}
public void calculate(Consumer<SimulatorPreviewResult> result) {
List<TNTPoint> tntPoints = new ArrayList<>();
Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), bukkitTask -> {
long time = System.currentTimeMillis();
while (!tnts.isEmpty()) {
if (System.currentTimeMillis() - time > 40) {
return;
}
tick(tntPoints);
}
bukkitTask.cancel();
System.out.println(tntPoints);
result.accept(new SimulatorPreviewResult(new Trace(null, tntPoints), air));
}, 1, 1);
}
private void tick(List<TNTPoint> tntPoints) {
System.out.println("TICK");
tnts.removeIf(simulatorPreviewTNT -> {
tntPoints.add(new TNTPoint(0, false, false, true, false, false, ticks, simulatorPreviewTNT.fuse, new Location(WORLD, simulatorPreviewTNT.x + 0.49, simulatorPreviewTNT.y, simulatorPreviewTNT.z + 0.49), new Vector(simulatorPreviewTNT.vx, simulatorPreviewTNT.vy, simulatorPreviewTNT.vz), tntPoints));
simulatorPreviewTNT.tick();
if (!simulatorPreviewTNT.removed) return false;
tntPoints.add(new TNTPoint(0, true, false, true, false, false, ticks, simulatorPreviewTNT.fuse, new Location(WORLD, simulatorPreviewTNT.x + 0.49, simulatorPreviewTNT.y, simulatorPreviewTNT.z + 0.49), new Vector(simulatorPreviewTNT.vx, simulatorPreviewTNT.vy, simulatorPreviewTNT.vz), tntPoints));
return true;
});
ticks++;
}
}

View File

@@ -1,31 +0,0 @@
/*
* 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.bausystem.features.simulator.preview;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@EqualsAndHashCode
final class SimulatorPreviewPos {
public final int x;
public final int y;
public final int z;
}

View File

@@ -1,61 +0,0 @@
/*
* 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.bausystem.features.simulator.preview;
import de.steamwar.bausystem.features.tracer.Trace;
import de.steamwar.bausystem.features.tracer.rendering.BundleFilter;
import de.steamwar.bausystem.features.tracer.rendering.PlayerTraceShowData;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import java.util.Set;
@Getter
public class SimulatorPreviewResult {
private static final World WORLD = Bukkit.getWorlds().get(0);
private static final BlockData AIR = Material.AIR.createBlockData();
private final Trace trace;
private final Set<SimulatorPreviewPos> air;
public SimulatorPreviewResult(Trace trace, Set<SimulatorPreviewPos> air) {
this.trace = trace;
this.air = air;
}
public void show(Player player) {
trace.render(player, new PlayerTraceShowData(BundleFilter.DEFAULT));
air.forEach(simulatorPreviewPos -> {
player.sendBlockChange(new Location(WORLD, simulatorPreviewPos.x, simulatorPreviewPos.y, simulatorPreviewPos.z, 0, 0), AIR);
});
}
public void hide(Player player) {
trace.hide(player);
air.forEach(simulatorPreviewPos -> {
player.sendBlockChange(new Location(WORLD, simulatorPreviewPos.x, simulatorPreviewPos.y, simulatorPreviewPos.z, 0, 0), WORLD.getBlockData(simulatorPreviewPos.x, simulatorPreviewPos.y, simulatorPreviewPos.z));
});
}
}

View File

@@ -1,228 +0,0 @@
/*
* 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.bausystem.features.simulator.preview;
import org.bukkit.Axis;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import org.bukkit.util.VoxelShape;
import java.util.Random;
public class SimulatorPreviewTNT {
private static final double size = 0.98;
private static final Random random = new Random();
private final SimulatorPreviewCalculator data;
private boolean gravity = true;
int fuse = 80;
double x;
double y;
double z;
double vx;
double vy;
double vz;
private SimulatorPreviewVec collide = new SimulatorPreviewVec();
private boolean onGround;
boolean removed = false;
public SimulatorPreviewTNT(SimulatorPreviewCalculator data, double x, double y, double z) {
this.data = data;
this.x = x;
this.y = y;
this.z = z;
double d = random.nextDouble() * Math.PI * 2;
this.vx = -Math.sin(d) * 0.02;
this.vy = 0.2;
this.vz = -Math.cos(d) * 0.02;
}
public void tick() {
System.out.println(x + " " + y + " " + z);
// TODO: Issue in movement still!
// System.out.println(x + " " + y + " " + z);
// Gravity
if (gravity) {
vy -= 0.04;
}
// Movement
move();
// TODO: EffectsFromOtherBlocks
// Velocity * 0.98
vx *= 0.98;
vy *= 0.98;
vz *= 0.98;
// OnGround Velocity * 0.7 -0.5 0.7
if (onGround) {
vx *= 0.7;
vy *= -0.5;
vz *= 0.7;
}
// Decrease Fuse
fuse--;
if (fuse <= 0) {
// Explode on zero Fuse
explode();
} else {
// TODO: or do water Movement!
}
}
public void move() {
collide();
double collisionLengthSquared = collide.lengthSquared();
if (collisionLengthSquared > 1.0E-7 || new Vector(vx, vy, vz).lengthSquared() - collisionLengthSquared < 1.0E-7) {
x += collide.x;
y += collide.y;
z += collide.z;
}
boolean xCollision = !equal(vx, collide.x);
boolean zCollision = !equal(vz, collide.z);
boolean horizontalCollision = xCollision || zCollision;
if (Math.abs(vy) > 0.0F) {
boolean verticalCollision = vy != collide.y;
onGround = verticalCollision && vy < (double) 0.0F;
}
if (horizontalCollision) {
if (xCollision) vx = 0;
if (zCollision) vz = 0;
}
vx = collide.x;
vy = collide.y;
vz = collide.z;
// TODO: Get Block -> updateEntityMovementAfterFallOn!
// TODO: Get BlockSpeedFactor multiply
}
public static boolean equal(double first, double second) {
return Math.abs(second - first) < (double) 1.0E-5F;
}
public void collide() {
boolean xZero = vx == 0;
boolean zZero = vz == 0;
if (xZero && vy == 0 && zZero) {
collide.x = 0;
collide.y = 0;
collide.z = 0;
return;
}
SimulatorPreviewAABB box = new SimulatorPreviewAABB(x, y, z, x + size, y + size, z + size);
double vx = this.vx;
double vy = this.vy;
double vz = this.vz;
if (vy != 0) {
vy = iterateBlocks(box.copy(), Axis.Y, vy);
if (vy != 0) box.add(0, vy, 0);
}
boolean xSmaller = Math.abs(vx) < Math.abs(vz);
if (xSmaller && vz != 0) {
vz = iterateBlocks(box.copy(), Axis.Z, vz);
if (vz != 0) box.add(0, 0, vz);
}
if (vx != 0) {
vx = iterateBlocks(box.copy(), Axis.X, vx);
if (vx != 0) box.add(vx, 0, 0);
}
if (!xSmaller && vz != 0) {
vz = iterateBlocks(box.copy(), Axis.Z, vz);
if (vz != 0) box.add(0, 0, vz);
}
collide.x = vx;
collide.y = vy;
collide.z = vz;
}
private double iterateBlocks(SimulatorPreviewAABB box, Axis axis, double v) {
switch (axis) {
case X -> box.expandTowards(v, 0, 0);
case Y -> box.expandTowards(0, v, 0);
case Z -> box.expandTowards(0, 0, v);
}
boolean negative = v < 0;
for (int x = floor(box.minX - 1.0E-7) - 1; x < floor(box.maxX + 1.0E-7) + 1; x++) {
for (int y = floor(box.minY - 1.0E-7) - 1; y < floor(box.maxY + 1.0E-7) + 1; y++) {
for (int z = floor(box.minZ - 1.0E-7) - 1; z < floor(box.maxZ + 1.0E-7) + 1; z++) {
VoxelShape shape = data.getBlockShape(x, y, z);
if (shape == null) continue;
for (BoundingBox other : shape.getBoundingBoxes()) {
switch (axis) {
case X -> {
if (box.intersects(x, y, z, other)) {
if (negative) {
v = Math.max(v, x + other.getMaxX() - this.x);
} else {
v = Math.min(v, x + other.getMinX() - this.x - size);
}
}
}
case Y -> {
if (box.intersects(x, y, z, other)) {
if (negative) {
v = Math.max(v, y + other.getMaxY() - this.y);
} else {
v = Math.min(v, y + other.getMinY() - this.y - size);
}
}
}
case Z -> {
if (box.intersects(x, y, z, other)) {
if (negative) {
v = Math.max(v, z + other.getMaxZ() - this.z);
} else {
v = Math.min(v, z + other.getMinZ() - this.z - size);
}
}
}
}
}
}
}
}
return v;
}
public static int floor(double value) {
int i = (int) value;
return value < (double) i ? i - 1 : i;
}
public void explode() {
removed = true;
// TODO: Implement
}
}

View File

@@ -1,30 +0,0 @@
/*
* 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.bausystem.features.simulator.preview;
public class SimulatorPreviewVec {
public double x;
public double y;
public double z;
public double lengthSquared() {
return x * x + y * y + z * z;
}
}

View File

@@ -68,6 +68,7 @@ public class SimFormatSimulatorLoader implements SimulatorLoader {
private void loadSimulator(YAPIONObject simulatorObject, Simulator simulator) {
simulator.setMaterial(Material.valueOf(simulatorObject.getPlainValue("material")));
simulator.setAutoTrace(simulatorObject.getPlainValue("autoTrace"));
simulator.setAutoTestblock(simulatorObject.getPlainValueOrDefault("autoTestblock", false));
YAPIONArray groups = simulatorObject.getArray("groups");
groups.streamObject().forEach(groupObject -> {

View File

@@ -39,6 +39,7 @@ public class SimulatorSaver {
YAPIONObject simulatorObject = new YAPIONObject();
simulatorObject.add("material", simulator.getMaterial().name());
simulatorObject.add("autoTrace", simulator.isAutoTrace());
simulatorObject.add("autoTestblock", simulator.isAutoTestblock());
YAPIONArray groups = new YAPIONArray();
simulator.getGroups().forEach(group -> {

View File

@@ -1,20 +1,20 @@
/*
* This file is a part of the SteamWar software.
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
* 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 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.
* 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/>.
* 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.bausystem.features.tpslimit;

View File

@@ -27,19 +27,17 @@ import de.steamwar.bausystem.region.GlobalRegion;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.utils.ScoreboardElement;
import de.steamwar.bausystem.utils.TickEndEvent;
import de.steamwar.bausystem.utils.TickManager;
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
import de.steamwar.bausystem.utils.bossbar.BossBarService;
import de.steamwar.command.AbstractSWCommand;
import de.steamwar.command.SWCommand;
import de.steamwar.core.Core;
import de.steamwar.core.TPSWarpUtils;
import de.steamwar.core.TPSWatcher;
import de.steamwar.inventory.SWAnvilInv;
import de.steamwar.inventory.SWItem;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.LinkedInstance;
import de.steamwar.linkage.MaxVersion;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.boss.BarColor;
@@ -52,91 +50,61 @@ import org.bukkit.inventory.ItemStack;
import java.util.Arrays;
@Linked
@MaxVersion(20) // Hotfix for 1.21 tps limit! -> Backport coming later
public class TPSSystem implements Listener {
@Getter
private static double currentTPSLimit = 20;
public TPSSystem() {
if (TPSFreezeUtils.isCanFreeze()) {
if (TickManager.impl.canFreeze()) {
new TPSFreezeCommand();
new TickFreezeCommand();
new TickStepCommand();
}
new TPSLimitCommand();
new TickLimitCommand();
if (Core.getVersion() >= 15 && Core.getVersion() <= 20) { // If 1.21 support is not directly present
if (Core.getVersion() >= 15) {
new TPSWarpCommand();
new TickWarpCommand();
if (TPSFreezeUtils.isCanFreeze()) {
if (TickManager.impl.canFreeze()) {
new TickWarpingCommand();
}
}
if (Core.getVersion() >= 21) {
new Tick21Command();
}
new TPSDefaultCommand();
new TickDefaultCommand();
new TPSBaseCommand();
new TickBaseCommand();
}
private void setTPS(double tps) {
if (currentlyStepping) {
currentlyStepping = false;
Bukkit.getOnlinePlayers().forEach(player -> {
BossBarService.instance.remove(player, GlobalRegion.getInstance(), "TickStep");
});
}
TPSWarpUtils.warp(tps);
if (currentTPSLimit == 0 && tps != 0) {
TPSFreezeUtils.unfreeze();
}
currentTPSLimit = tps;
if (tps == 0) {
TPSLimitUtils.unlimit();
TPSFreezeUtils.freeze();
} else if (tps < 20.0) {
TPSLimitUtils.limit(tps);
} else if (tps >= 20) {
TPSLimitUtils.unlimit();
}
Bukkit.getOnlinePlayers().forEach(player -> {
if (currentTPSLimit == 0) {
SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("TPSLIMIT_FROZEN", player));
} else {
SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("TPSLIMIT_SET", player, currentTPSLimit));
}
});
}
private boolean currentlyStepping = false;
private double currentLimit;
private int stepsTotal;
private int stepsLeft;
private void setSkip(int steps, double tpsLimitToUse) {
currentLimit = tpsLimitToUse == 20 ? 0 : currentTPSLimit;
setTPS(tpsLimitToUse);
stepsLeft = steps;
stepsTotal = steps;
currentlyStepping = true;
Bukkit.getPluginManager().registerEvents(TickManager.impl, BauSystem.getInstance());
}
@EventHandler
public void onTickEnd(TickEndEvent event) {
if (!currentlyStepping) return;
if (stepsTotal > 1) {
bossbar();
}
private void bossbar() {
if ((TickManager.impl.isStepping() || TickManager.impl.isSprinting()) && TickManager.impl.getRemainingTicks() > 0) {
Bukkit.getOnlinePlayers().forEach(player -> {
BauSystemBossbar bossbar = BossBarService.instance.get(player, GlobalRegion.getInstance(), "TickStep");
bossbar.setColor(BarColor.YELLOW);
bossbar.setTitle(BauSystem.MESSAGE.parse("TICK_BOSSBAR", player, (stepsTotal - stepsLeft), stepsTotal));
bossbar.setProgress((stepsTotal - stepsLeft) / (double) stepsTotal);
bossbar.setTitle(BauSystem.MESSAGE.parse("TICK_BOSSBAR", player, TickManager.impl.getDoneTicks(), TickManager.impl.getTotalTicks()));
bossbar.setProgress(TickManager.impl.getDoneTicks() / (double) TickManager.impl.getTotalTicks());
});
} else {
Bukkit.getOnlinePlayers().forEach(player -> {
BossBarService.instance.remove(player, GlobalRegion.getInstance(), "TickStep");
});
}
stepsLeft--;
if (stepsLeft <= 0) {
setTPS(currentLimit);
}
}
public static void sendTickRateChange() {
Bukkit.getOnlinePlayers().forEach(player -> {
if (TickManager.impl.isFrozen()) {
SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("TPSLIMIT_FROZEN", player));
} else {
SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("TPSLIMIT_SET", player, TickManager.impl.getTickRate()));
}
});
}
private class TPSBaseCommand extends SWCommand {
@@ -157,7 +125,8 @@ public class TPSSystem implements Listener {
@Register(value = "0", description = "TPSLIMIT_FREEZE_HELP")
public void freeze(@Validator Player player) {
setTPS(0);
TickManager.impl.setFreeze(true);
sendTickRateChange();
}
}
@@ -169,8 +138,9 @@ public class TPSSystem implements Listener {
}
@Register(description = "TPSLIMIT_LIMIT_HELP")
public void limit(@Validator Player player, @Min(doubleValue = 0.5) @Max(doubleValue = 20.0) double tpsLimit) {
setTPS(tpsLimit);
public void limit(@Validator Player player, @Min(doubleValue = 0.5) @Max(doubleValue = 20.0) float tpsLimit) {
TickManager.impl.setTickRate(tpsLimit);
sendTickRateChange();
}
}
@@ -182,8 +152,9 @@ public class TPSSystem implements Listener {
}
@Register(description = "TPSLIMIT_WARP_HELP")
public void warp(@Validator Player player, @Min(doubleValue = 20.0, inclusive = false) double tpsLimit) {
setTPS(tpsLimit);
public void warp(@Validator Player player, @Min(doubleValue = 20.0, inclusive = false) float tpsLimit) {
TickManager.impl.setTickRate(tpsLimit);
sendTickRateChange();
}
}
@@ -196,12 +167,13 @@ public class TPSSystem implements Listener {
@Register(description = "TPSLIMIT_HELP")
public void currentLimit(Player player) {
BauSystem.MESSAGE.send("TPSLIMIT_CURRENT", player, currentTPSLimit);
BauSystem.MESSAGE.send("TPSLIMIT_CURRENT", player, TickManager.impl.getTickRate());
}
@Register(value = "default", description = "TPSLIMIT_DEFAULT_HELP")
public void reset(@Validator Player player) {
setTPS(20);
TickManager.impl.setTickRate(20.0F);
sendTickRateChange();
}
}
@@ -223,12 +195,14 @@ public class TPSSystem implements Listener {
@Register(value = {"rate", "0"}, description = "TICK_FREEZE_HELP")
@Register(value = "freeze", description = "TICK_FREEZE_HELP_2")
public void freeze(@Validator Player player) {
setTPS(0);
TickManager.impl.setFreeze(true);
sendTickRateChange();
}
@Register(value = "unfreeze", description = "TICK_UNFREEZE_HELP")
public void unfreeze(@Validator Player player) {
setTPS(20);
TickManager.impl.setTickRate(20.0F);
sendTickRateChange();
}
}
@@ -241,7 +215,9 @@ public class TPSSystem implements Listener {
@Register(value = "step", description = "TICK_STEPPING_HELP")
public void step(@Validator Player player, @Min(intValue = 1) @OptionalValue("1") int steps) {
setSkip(steps, 20);
TickManager.impl.stepTicks(steps);
sendTickRateChange();
bossbar();
}
}
@@ -253,8 +229,9 @@ public class TPSSystem implements Listener {
}
@Register(value = "warp", description = "TICK_WARPING_HELP")
public void warp(@Validator Player player, @Min(intValue = 1) @OptionalValue("1") int steps, @Min(doubleValue = 20) @OptionalValue("4000") double tps) {
setSkip(steps, tps);
public void warp(@Validator Player player, @Min(intValue = 1) @OptionalValue("1") int steps) {
TickManager.impl.sprintTicks(steps);
sendTickRateChange();
}
}
@@ -266,8 +243,9 @@ public class TPSSystem implements Listener {
}
@Register(value = "rate", description = "TICK_LIMIT_HELP")
public void limit(@Validator Player player, @Min(doubleValue = 0.5, inclusive = false) @Max(doubleValue = 20.0) double tpsLimit) {
setTPS(tpsLimit);
public void limit(@Validator Player player, @Min(doubleValue = 0.5, inclusive = false) @Max(doubleValue = 20.0) float tpsLimit) {
TickManager.impl.setTickRate(tpsLimit);
sendTickRateChange();
}
}
@@ -279,8 +257,9 @@ public class TPSSystem implements Listener {
}
@Register(value = "rate", description = "TICK_WARP_HELP")
public void warp(@Validator Player player, @Min(doubleValue = 20.0, inclusive = false) double tpsLimit) {
setTPS(tpsLimit);
public void warp(@Validator Player player, @Min(doubleValue = 20.0, inclusive = false) float tpsLimit) {
TickManager.impl.setTickRate(tpsLimit);
sendTickRateChange();
}
}
@@ -293,12 +272,31 @@ public class TPSSystem implements Listener {
@Register(value = "rate", description = "TICK_HELP")
public void currentLimit(Player player) {
BauSystem.MESSAGE.send("TPSLIMIT_CURRENT", player, currentTPSLimit);
BauSystem.MESSAGE.send("TPSLIMIT_CURRENT", player, TickManager.impl.getTickRate());
}
@Register(value = {"rate", "default"}, description = "TICK_DEFAULT_HELP")
public void reset(@Validator Player player) {
setTPS(20);
TickManager.impl.setTickRate(20.0F);
sendTickRateChange();
}
}
@AbstractSWCommand.PartOf(TickBaseCommand.class)
private class Tick21Command extends SWCommand {
private Tick21Command() {
super("");
}
@Register(value = "normalclient")
public void smooth(@Validator Player player) {
TickManager.impl.setBlockTpsPacket(true);
}
@Register(value = "slowclient")
public void unsmooth(@Validator Player player) {
TickManager.impl.setBlockTpsPacket(false);
}
}
@@ -320,7 +318,10 @@ public class TPSSystem implements Listener {
@Override
public String get(Region region, Player p) {
if (tpsSystem != null && tpsSystem.currentlyStepping) {
boolean isWarping = TickManager.impl.isSprinting();
boolean isFrozen = TickManager.impl.isFrozen();
if (tpsSystem != null && isWarping) {
long time = System.currentTimeMillis() % 1000;
if (time < 250) {
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: §7•••";
@@ -331,7 +332,7 @@ public class TPSSystem implements Listener {
} else {
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: §7••§e•";
}
} else if (TPSFreezeUtils.frozen()) {
} else if (isFrozen) {
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: " + BauSystem.MESSAGE.parse("SCOREBOARD_TPS_FROZEN", p);
} else {
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: " + tpsColor() + TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.ONE_SECOND) + tpsLimit();
@@ -340,20 +341,20 @@ public class TPSSystem implements Listener {
private String tpsColor() {
double tps = TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.ONE_SECOND);
if (tps > TPSSystem.getCurrentTPSLimit() * 0.9) {
if (tps > TickManager.impl.getTickRate() * 0.9) {
return "§a";
}
if (tps > TPSSystem.getCurrentTPSLimit() * 0.5) {
if (tps > TickManager.impl.getTickRate() * 0.5) {
return "§e";
}
return "§c";
}
private String tpsLimit() {
if (TPSSystem.getCurrentTPSLimit() == 20) {
if (TickManager.impl.getTickRate() == 20) {
return "";
}
return "§8/§7" + TPSSystem.getCurrentTPSLimit();
return "§8/§7" + TickManager.impl.getTickRate();
}
}
@@ -369,7 +370,7 @@ public class TPSSystem implements Listener {
@Override
public ItemStack getItem(Player player) {
return new SWItem(Material.CLOCK, BauSystem.MESSAGE.parse("TPSLIMIT_GUI_ITEM_NAME", player), Arrays.asList(BauSystem.MESSAGE.parse("TPSLIMIT_GUI_ITEM_LORE", player, tpsSystem.currentTPSLimit)), false, clickType -> {
return new SWItem(Material.CLOCK, BauSystem.MESSAGE.parse("TPSLIMIT_GUI_ITEM_NAME", player), Arrays.asList(BauSystem.MESSAGE.parse("TPSLIMIT_GUI_ITEM_LORE", player, TickManager.impl.getTickRate())), false, clickType -> {
}).getItemStack();
}

View File

@@ -22,6 +22,7 @@ package de.steamwar.bausystem.features.tracer;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.region.utils.RegionExtensionType;
import de.steamwar.bausystem.region.utils.RegionType;
import de.steamwar.core.Core;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -36,7 +37,7 @@ import java.util.Optional;
/**
* Recording of a tnt at a specific tick
*/
@AllArgsConstructor
@AllArgsConstructor(access = AccessLevel.PACKAGE)
@Getter
public class TNTPoint{
/**
@@ -101,7 +102,11 @@ public class TNTPoint{
List<TNTPoint> history, List<Block> destroyedBlocks) {
this.tntId = tntId;
this.explosion = explosion;
this.inWater = tnt.isInWater();
if (Core.getVersion() > 15) {
this.inWater = tnt.isInWater();
} else {
this.inWater = false;
}
this.afterFirstExplosion = afterFirstExplosion;
this.ticksSinceStart = ticksSinceStart;
fuse = tnt.getFuseTicks();

View File

@@ -21,6 +21,7 @@ package de.steamwar.bausystem.features.world;
import de.steamwar.bausystem.Permission;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.NodeData;
import de.steamwar.sql.SchematicData;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
@@ -65,7 +66,8 @@ public class ClipboardListener implements Listener {
}
try {
new SchematicData(schematic).saveFromPlayer(e.getPlayer());
NodeData.get(schematic).forEach(NodeData::delete);
SchematicData.saveFromPlayer(e.getPlayer(), schematic);
} catch (Exception ex) {
if (newSchem) {
schematic.delete();

View File

@@ -0,0 +1,46 @@
/*
* 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.bausystem.utils;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.core.VersionDependent;
import org.bukkit.event.Listener;
public interface TickManager extends Listener {
TickManager impl = VersionDependent.getVersionImpl(BauSystem.getInstance());
void setTickRate(float tickRate);
float getTickRate();
boolean canFreeze();
void setFreeze(boolean freeze);
boolean isFrozen();
void stepTicks(int ticks);
boolean isStepping();
void sprintTicks(int ticks);
boolean isSprinting();
void setBlockTpsPacket(boolean block);
long getRemainingTicks();
long getDoneTicks();
long getTotalTicks();
}

View File

@@ -0,0 +1,25 @@
/*
* 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.data;
public class SyncCommands {
public static final String RELOAD_PLAYER = "reload_player";
public static final String RELOAD_EVENT = "reload_event";
}

View File

@@ -0,0 +1,125 @@
/*
* 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.sql;
import de.steamwar.sql.internal.Field;
import de.steamwar.sql.internal.SqlTypeMapper;
import de.steamwar.sql.internal.Statement;
import de.steamwar.sql.internal.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import java.sql.Timestamp;
import java.time.Instant;
@AllArgsConstructor
public class AuditLog {
static {
SqlTypeMapper.nameEnumMapper(AuditLog.Type.class);
}
public static final String SERVER_NAME_VELOCITY = "Velocity";
private static final Table<AuditLog> table = new Table<>(AuditLog.class);
private static final Statement create = table.insertFields(true, "time", "serverName", "serverOwner", "actor", "actionType", "actionText");
@Getter
@Field
private final Timestamp time;
@Getter
@Field
private final String serverName;
@Field(nullable = true)
private final int serverOwner;
@Field
private final int actor;
@Getter
@Field
private final Type actionType;
@Getter
@Field
private final String actionText;
public enum Type {
JOIN,
LEAVE,
COMMAND,
SENSITIVE_COMMAND,
CHAT,
GUI_OPEN,
GUI_CLOSE,
GUI_CLICK,
}
private static void create(String serverName, SteamwarUser serverOwner, SteamwarUser actor, Type actionType, String text) {
create.insertGetKey(Timestamp.from(Instant.now()), serverName, serverOwner, actor, actionType, text);
}
public static void createJoin(@NonNull String jointServerName, SteamwarUser serverOwner, @NonNull SteamwarUser joinedPlayer) {
create(jointServerName, serverOwner, joinedPlayer, Type.JOIN, "");
}
public static void createLeave(@NonNull String leftServerName, SteamwarUser serverOwner, @NonNull SteamwarUser joinedPlayer) {
create(leftServerName, serverOwner, joinedPlayer, Type.LEAVE, "");
}
public static void createCommand(@NonNull String serverName, SteamwarUser serverOwner, SteamwarUser player, @NonNull String command) {
if (player == null) return;
create(serverName, serverOwner, player, Type.COMMAND, command);
}
public static void createSensitiveCommand(@NonNull String serverName, SteamwarUser serverOwner, SteamwarUser player, @NonNull String command) {
if (player == null) return;
create(serverName, serverOwner, player, Type.SENSITIVE_COMMAND, command);
}
public static void createChat(@NonNull String serverName, SteamwarUser serverOwner, @NonNull SteamwarUser chatter, @NonNull String chat) {
create(serverName, serverOwner, chatter, Type.CHAT, chat);
}
public static void createGuiOpen(@NonNull String serverName, SteamwarUser serverOwner, @NonNull SteamwarUser player, @NonNull String guiName) {
create(serverName, serverOwner, player, Type.GUI_OPEN, guiName);
}
public static void createGuiClick(@NonNull String serverName, SteamwarUser serverOwner, @NonNull SteamwarUser player, @NonNull String guiName, @NonNull String clickType, int slot, @NonNull String itemName) {
create(serverName, serverOwner, player, Type.GUI_CLICK, "Gui: " + guiName + "\nSlot: " + slot + "\nClickType: " + clickType + "\nItemName: " + itemName);
}
public static void createGuiClose(@NonNull String serverName, SteamwarUser serverOwner, @NonNull SteamwarUser player, @NonNull String guiName) {
create(serverName, serverOwner, player, Type.GUI_CLOSE, guiName);
}
public SteamwarUser getServerOwner() {
return SteamwarUser.get(serverOwner);
}
public SteamwarUser getActor() {
return SteamwarUser.get(actor);
}
}

View File

@@ -35,7 +35,8 @@ import java.util.stream.Collectors;
public class Fight {
private static final Table<Fight> table = new Table<>(Fight.class);
private static final SelectStatement<Fight> getPage = new SelectStatement<>(table, "SELECT f.*, (b.NodeId IS NULL OR b.AllowReplay) AND (r.NodeId IS NULL OR r.AllowReplay) AS ReplayAllowed FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId ORDER BY FightID DESC LIMIT ?, ?");
private static final SelectStatement<Fight> getPage = new SelectStatement<>(table, "SELECT f.*, (b.NodeId IS NULL OR b.Config & 2) AND (r.NodeId IS NULL OR r.Config & 2) AS ReplayAllowed FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId ORDER BY FightID DESC LIMIT ?, ?");
private static final SelectStatement<Fight> getById = new SelectStatement<>(table, "SELECT f.*, (b.NodeId IS NULL OR b.Config & 2) AND (r.NodeId IS NULL OR r.Config & 2) AS ReplayAllowed FROM Fight f LEFT OUTER JOIN SchematicNode b ON f.BlueSchem = b.NodeId LEFT OUTER JOIN SchematicNode r ON f.RedSchem = r.NodeId WHERE FightId = ?");
private static final Statement insert = table.insertFields(true, "GameMode", "Server", "StartTime", "Duration", "BlueLeader", "RedLeader", "BlueSchem", "RedSchem", "Win", "WinCondition");
private static final Statement updateReplayAvailable = table.update(Table.PRIMARY, "ReplayAvailable");
@@ -51,6 +52,10 @@ public class Fight {
return fights;
}
public static Fight getById(int fightID) {
return getById.select(fightID);
}
public static int create(String gamemode, String server, Timestamp starttime, int duration, int blueleader, int redleader, Integer blueschem, Integer redschem, int win, String wincondition){
return insert.insertGetKey(gamemode, server, starttime, duration, blueleader, redleader, blueschem, redschem, win, wincondition);
}

View File

@@ -23,8 +23,13 @@ import de.steamwar.sql.internal.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import javax.swing.plaf.nimbus.State;
import java.io.*;
import java.sql.PreparedStatement;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.zip.GZIPInputStream;
@AllArgsConstructor
@@ -40,26 +45,47 @@ public class NodeData {
private static final Table<NodeData> table = new Table<>(NodeData.class);
private static final Statement updateDatabase = new Statement("INSERT INTO NodeData(NodeId, NodeFormat, SchemData) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE NodeFormat = VALUES(NodeFormat), SchemData = VALUES(SchemData)");
private static final Statement selSchemData = new Statement("SELECT SchemData FROM NodeData WHERE NodeId = ?");
private static final Statement updateDatabase = new Statement("INSERT INTO NodeData(NodeId, NodeFormat, SchemData) VALUES (?, ?, ?)", true);
private static final Statement selSchemData = new Statement("SELECT SchemData FROM NodeData WHERE NodeId = ? AND CreatedAt = ?");
private static final Statement delete = table.delete(Table.PRIMARY);
private static final SelectStatement<NodeData> get = table.select(Table.PRIMARY);
private static final SelectStatement<NodeData> get = new SelectStatement<>(table, "SELECT NodeId, CreatedAt, NodeFormat FROM NodeData WHERE NodeId = ? ORDER BY CreatedAt ");
private static final Statement getRevisions = new Statement("SELECT COUNT(DISTINCT CreatedAt) as CNT FROM NodeData WHERE NodeId = ?");
private static final SelectStatement<NodeData> getLatest = new SelectStatement<>(table, "SELECT NodeId, CreatedAt, NodeFormat FROM NodeData WHERE NodeId = ? ORDER BY CreatedAt DESC LIMIT 1");
public static NodeData get(SchematicNode node) {
if(node.isDir())
throw new IllegalArgumentException("Node is a directory");
return get.select(rs -> {
if(rs.next()) {
return new NodeData(node.getId(), SchematicFormat.values()[rs.getInt("NodeFormat")]);
public static NodeData getLatest(SchematicNode node) {
if (node.isDir()) throw new IllegalArgumentException("Node is dir");
return Optional.ofNullable(getLatest.select(node)).orElseGet(() -> new NodeData(node.getId(), Timestamp.from(Instant.now()), SchematicFormat.MCEDIT));
}
public static List<NodeData> get(SchematicNode node) {
return get.listSelect(node);
}
public static NodeData get(SchematicNode node, int revision) {
return get.listSelect(node).get(revision - 1);
}
public static int getRevisions(SchematicNode node) {
return getRevisions.select(rs -> {
if (rs.next()) {
return rs.getInt("CNT");
} else {
return new NodeData(node.getId(), SchematicFormat.MCEDIT);
return 0;
}
}, node);
}
public static void saveFromStream(SchematicNode node, InputStream blob, SchematicFormat format) {
updateDatabase.update(node.getId(), format, blob);
}
@Field(keys = {Table.PRIMARY})
private final int nodeId;
@Field(keys = {Table.PRIMARY})
private Timestamp createdAt;
@Field
private SchematicFormat nodeFormat;
@@ -84,15 +110,19 @@ public class NodeData {
} catch (IOException e) {
throw new SecurityException("SchemData is wrong", e);
}
}, nodeId);
}, nodeId, createdAt);
} catch (Exception e) {
throw new IOException(e);
}
}
@Deprecated
public void saveFromStream(InputStream blob, SchematicFormat newFormat) {
updateDatabase.update(nodeId, newFormat, blob);
nodeFormat = newFormat;
saveFromStream(SchematicNode.getSchematicNode(nodeId), blob, newFormat);
}
public void delete() {
delete.update(nodeId, createdAt);
}
@AllArgsConstructor

View File

@@ -42,13 +42,13 @@ public class SchematicNode {
TAB_CACHE.clear();
}
private static final String nodeSelector = "SELECT NodeId, NodeOwner, NodeOwner AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode ";
private static final String nodeSelector = "SELECT NodeId, NodeOwner, NodeOwner AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode ";
private static final Table<SchematicNode> table = new Table<>(SchematicNode.class);
private static final Statement create = table.insertFields(true, "NodeOwner", "NodeName", "ParentNode", "NodeItem",
"NodeType");
private static final Statement update = table.update(Table.PRIMARY, "NodeName", "ParentNode", "NodeItem",
"NodeType", "NodeRank", "ReplaceColor", "AllowReplay");
"NodeType", "NodeRank", "Config");
private static final Statement delete = table.delete(Table.PRIMARY);
private static final SelectStatement<SchematicNode> byId = new SelectStatement<>(table,
@@ -66,13 +66,13 @@ public class SchematicNode {
private static final SelectStatement<SchematicNode> all = new SelectStatement<>(table,
"WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId");
private static final SelectStatement<SchematicNode> list = new SelectStatement<>(table,
"SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId "
"SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId "
+ Statement.NULL_SAFE_EQUALS
+ "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName");
+ "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byParentName = new SelectStatement<>(table,
"SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId "
"SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId "
+ Statement.NULL_SAFE_EQUALS
+ "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?");
+ "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?");
private static final SelectStatement<SchematicNode> schematicAccessibleForUser = new SelectStatement<>(table,
"WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeId = ?");
private static final SelectStatement<SchematicNode> accessibleByUserTypeInParent = new SelectStatement<>(table,
@@ -81,7 +81,7 @@ public class SchematicNode {
private static final SelectStatement<SchematicNode> accessibleByUserType = new SelectStatement<>(table,
"WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeType = ?");
private static final SelectStatement<SchematicNode> byIdAndUser = new SelectStatement<>(table,
"SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE NodeId = ?");
"SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode WHERE NodeId = ?");
private static final SelectStatement<SchematicNode> allParentsOfNode = new SelectStatement<>(table,
"WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? AND EffectiveOwner = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.ReplaceColor, SN.AllowReplay FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId");
@@ -108,10 +108,8 @@ public class SchematicNode {
private SchematicType nodeType;
@Field(def = "0")
private int nodeRank;
@Field(def = "1")
private boolean replaceColor;
@Field(def = "1")
private boolean allowReplay;
@Field
private int config;
private String brCache;
@@ -125,8 +123,7 @@ public class SchematicNode {
String nodeItem,
SchematicType nodeType,
int nodeRank,
boolean replaceColor,
boolean allowReplay) {
int config) {
this.nodeId = nodeId;
this.nodeOwner = nodeOwner;
this.effectiveOwner = effectiveOwner;
@@ -136,8 +133,7 @@ public class SchematicNode {
this.nodeType = nodeType;
this.lastUpdate = lastUpdate;
this.nodeRank = nodeRank;
this.replaceColor = replaceColor;
this.allowReplay = allowReplay;
this.config = config;
}
public static List<SchematicNode> getAll(SteamwarUser user) {
@@ -407,7 +403,7 @@ public class SchematicNode {
public String getFileEnding() {
if (isDir())
throw new SecurityException("Node is Directory");
return NodeData.get(this).getNodeFormat().getFileEnding();
return NodeData.getLatest(this).getNodeFormat().getFileEnding();
}
public int getRank() {
@@ -441,24 +437,45 @@ public class SchematicNode {
}
public boolean replaceColor() {
return replaceColor;
return getConfig(ConfigFlags.REPLACE_COLOR);
}
public void setReplaceColor(boolean replaceColor) {
if (isDir())
throw new SecurityException("Is Directory");
this.replaceColor = replaceColor;
updateDB();
setConfig(ConfigFlags.REPLACE_COLOR, replaceColor);
}
public boolean allowReplay() {
return allowReplay;
return getConfig(ConfigFlags.ALLOW_REPLAY);
}
public void setAllowReplay(boolean allowReplay) {
if (isDir())
throw new SecurityException("Is Directory");
this.allowReplay = allowReplay;
setConfig(ConfigFlags.ALLOW_REPLAY, allowReplay);
}
public boolean isPrepared() {
return getConfig(ConfigFlags.IS_PREPARED);
}
public void setPrepared(boolean prepared) {
if (isDir())
throw new SecurityException("Is Directory");
setConfig(ConfigFlags.IS_PREPARED, prepared);
}
public boolean getConfig(ConfigFlags flag) {
return (config & (1 << flag.ordinal())) != 0;
}
public void setConfig(ConfigFlags flag, boolean value) {
if (value) {
config |= (1 << flag.ordinal());
} else {
config &= ~(1 << flag.ordinal());
}
updateDB();
}
@@ -486,7 +503,7 @@ public class SchematicNode {
private void updateDB() {
this.lastUpdate = Timestamp.from(Instant.now());
update.update(nodeName, parentNode, nodeItem, nodeType, nodeRank, replaceColor, allowReplay, nodeId);
update.update(nodeName, parentNode, nodeItem, nodeType, nodeRank, config, nodeId);
TAB_CACHE.clear();
}
@@ -608,4 +625,10 @@ public class SchematicNode {
TAB_CACHE.computeIfAbsent(user.getId(), integer -> new HashMap<>()).putIfAbsent(cacheKey, list);
return list;
}
public static enum ConfigFlags {
REPLACE_COLOR,
ALLOW_REPLAY,
IS_PREPARED
}
}

View File

@@ -54,13 +54,13 @@ public enum UserPerm {
emptyPrefix = new Prefix("§7", "");
p.put(PREFIX_NONE, emptyPrefix);
p.put(PREFIX_YOUTUBER, new Prefix("§7", "YT"));
p.put(PREFIX_GUIDE, new Prefix("§a", "Guide")); // 55FF55
p.put(PREFIX_GUIDE, new Prefix("§x§e§7§6§2§e§d", "Guide")); // E762ED
p.put(PREFIX_SUPPORTER, new Prefix("§x§3§4§0§0§f§f", "Sup")); // 3400ff
p.put(PREFIX_MODERATOR, new Prefix("§x§c§7§5§e§2§2", "Mod")); // C75E22
p.put(PREFIX_BUILDER, new Prefix("§2", "Arch")); // 00AA00
p.put(PREFIX_DEVELOPER, new Prefix("§3", "Dev")); // 00AAAA
p.put(PREFIX_ADMIN, new Prefix("§x§F§2§2§8§2§4", "Admin")); // F22824
p.put(PREFIX_SUPPORTER, new Prefix("§x§6§0§9§5§F§B", "Sup")); // 6095FB
p.put(PREFIX_MODERATOR, new Prefix("§x§F§F§A§2§5§C", "Mod")); // FFA25C
p.put(PREFIX_BUILDER, new Prefix("§x§6§0§F§F§6§A", "Arch")); // 60FF6A
p.put(PREFIX_DEVELOPER, new Prefix("§x§0§B§B§C§B§3", "Dev")); // 0BBCB3
p.put(PREFIX_ADMIN, new Prefix("§x§F§F§2§B§2§4", "Admin")); // FF2B24
prefixes = Collections.unmodifiableMap(p);
}

View File

@@ -145,6 +145,6 @@ public class WorldeditWrapper14 implements WorldeditWrapper {
throw new SecurityException(e);
}
new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), NodeData.SchematicFormat.SPONGE_V2);
SchematicData.saveFromBytes(schem, outputStream.toByteArray(), NodeData.SchematicFormat.SPONGE_V2);
}
}

View File

@@ -140,6 +140,6 @@ public class WorldeditWrapper8 implements WorldeditWrapper {
throw new SecurityException(e);
}
new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), NodeData.SchematicFormat.MCEDIT);
SchematicData.saveFromBytes(schem, outputStream.toByteArray(), NodeData.SchematicFormat.MCEDIT);
}
}

View File

@@ -108,6 +108,7 @@ public class Config {
public static final boolean PercentEntern;
public static final boolean PercentBlocksWhitelist;
public static final Set<Material> PercentBlocks;
public static final int TechKoTime;
//default kits
public static final String MemberDefault;
@@ -209,6 +210,7 @@ public class Config {
PercentEntern = config.getBoolean("WinConditionParams.PercentEntern", true);
PercentBlocksWhitelist = config.getBoolean("WinConditionParams.BlocksWhitelist", false);
PercentBlocks = Collections.unmodifiableSet(config.getStringList("WinConditionParams.Blocks").stream().map(Material::valueOf).collect(Collectors.toSet()));
TechKoTime = config.getInt("WinConditionParams.TechKoTime", 90);
EnterStages = Collections.unmodifiableList(config.getIntegerList("EnterStages"));
AllowMissiles = config.getBoolean("Arena.AllowMissiles", !EnterStages.isEmpty());

View File

@@ -41,6 +41,7 @@ import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.utils.*;
import de.steamwar.fightsystem.winconditions.*;
import de.steamwar.message.Message;
import de.steamwar.sql.NodeData;
import de.steamwar.sql.SchematicNode;
import lombok.Getter;
import org.bukkit.Bukkit;
@@ -68,6 +69,11 @@ public class FightSystem extends JavaPlugin {
Core.setInstance(this);
TinyProtocol.init();
}
if (Config.SpectatePort != 0) {
Core.setServerName("Spectate");
} else if (Config.ReplayID != 0) {
Core.setServerName("Replay");
}
message = new Message("de.steamwar.fightsystem.FightSystem", FightSystem.class.getClassLoader());
@@ -126,6 +132,7 @@ public class FightSystem extends JavaPlugin {
new WinconditionPointsAirShip();
new WinconditionTimeout();
new WinconditionTimeTechKO();
new WinconditionTimedDamageTechKO();
new EventTeamOffWincondition();
new WinconditionComparisonTimeout(Winconditions.HEART_RATIO_TIMEOUT, "HeartTimeout", "WIN_MORE_HEALTH", FightTeam::getHeartRatio);
new WinconditionComparisonTimeout(Winconditions.PERCENT_TIMEOUT, "PercentTimeout", "WIN_LESS_DAMAGE", team -> -Wincondition.getPercentWincondition().getPercent(team));
@@ -173,11 +180,8 @@ public class FightSystem extends JavaPlugin {
SchematicNode checkSchematicNode = SchematicNode.getSchematicNode(Config.CheckSchemID);
Fight.getBlueTeam().setSchem(checkSchematicNode);
if (checkSchematicNode.getName().endsWith("-prepared")) {
SchematicNode unpreparedSchematicNode = SchematicNode.getSchematicNode(checkSchematicNode.getOwner(), checkSchematicNode.getName().substring(0, checkSchematicNode.getName().length() - 9), checkSchematicNode.getParent());
if (unpreparedSchematicNode != null) {
Fight.getRedTeam().setSchem(unpreparedSchematicNode);
}
if (checkSchematicNode.isPrepared()) {
Fight.getRedTeam().setSchem(checkSchematicNode, NodeData.getRevisions(checkSchematicNode) - 1);
}
new TechareaCommand();

View File

@@ -191,6 +191,7 @@ BAR_POINTS_OF={0}§8/§7{1} §8Points
BAR_PERCENT={0}§8%
BAR_CANNONS={0} §8Cannons
BAR_WATER={0} §8Water
BAR_SECONDS={0}§8s
# Winconditions

View File

@@ -19,20 +19,14 @@
package de.steamwar.fightsystem.fight;
import com.comphenix.tinyprotocol.TinyProtocol;
import com.mojang.authlib.GameProfile;
import de.steamwar.core.Core;
import de.steamwar.core.ProtocolWrapper;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.record.GlobalRecorder;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Sound;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import java.util.Collection;
import java.util.HashSet;

View File

@@ -31,6 +31,7 @@ import de.steamwar.fightsystem.states.StateDependent;
import de.steamwar.fightsystem.utils.ColorConverter;
import de.steamwar.fightsystem.utils.Region;
import de.steamwar.fightsystem.utils.WorldeditWrapper;
import de.steamwar.fightsystem.winconditions.Winconditions;
import de.steamwar.sql.SchematicData;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SchematicType;
@@ -51,20 +52,28 @@ public class FightSchematic extends StateDependent {
private final FightTeam team;
private final Region region;
private final boolean rotate;
@Getter
private boolean usedRotate;
@Getter
private Clipboard clipboard = null;
private int schematic = 0;
public FightSchematic(FightTeam team, boolean rotate) {
public FightSchematic(FightTeam team, boolean usedRotate) {
super(ArenaMode.All, FightState.PostSchemSetup);
this.team = team;
this.region = team.getSchemRegion();
this.rotate = rotate;
this.rotate = usedRotate;
this.usedRotate = usedRotate;
register();
}
public void setChangeRotate(boolean rotate) {
this.usedRotate = this.rotate ^ rotate;
}
public boolean hasSchematic() {
return clipboard != null;
}
@@ -74,9 +83,13 @@ public class FightSchematic extends StateDependent {
}
public void setSchematic(SchematicNode schem) {
setSchematic(schem, -1);
}
public void setSchematic(SchematicNode schem, int revision) {
schematic = schem.getId();
try {
clipboard = new SchematicData(schem).load();
clipboard = new SchematicData(schem, revision).load();
if(schem.replaceColor())
replaceTeamColor(clipboard);
@@ -119,10 +132,15 @@ public class FightSchematic extends StateDependent {
}
if(ArenaMode.AntiReplay.contains(Config.mode)) {
boolean changeRotation = false;
if (Config.ActiveWinconditions.contains(Winconditions.RANDOM_ROTATE)) {
changeRotation = new Random().nextBoolean();
usedRotate = rotate ^ changeRotation;
}
if(team.isBlue())
GlobalRecorder.getInstance().blueSchem(schematic);
GlobalRecorder.getInstance().blueSchem(schematic, changeRotation);
else
GlobalRecorder.getInstance().redSchem(schematic);
GlobalRecorder.getInstance().redSchem(schematic, changeRotation);
}
Bukkit.getScheduler().runTask(FightSystem.getPlugin(), this::paste);
@@ -140,7 +158,6 @@ public class FightSchematic extends StateDependent {
FreezeWorld freezer = new FreezeWorld();
team.teleportToSpawn();
Vector dims = WorldeditWrapper.impl.getDimensions(clipboard);
WorldeditWrapper.impl.pasteClipboard(
clipboard,
@@ -149,8 +166,8 @@ public class FightSchematic extends StateDependent {
Config.PasteAligned && Config.BlueToRedX != 0 ? region.getSizeX()/2.0 - dims.getBlockX() : -dims.getBlockX()/2.0,
Config.WaterDepth != 0 ? Config.WaterDepth - WorldeditWrapper.impl.getWaterDepth(clipboard) : 0,
Config.PasteAligned && Config.BlueToRedZ != 0 ? region.getSizeZ()/2.0 - dims.getBlockZ() : -dims.getBlockZ()/2.0
).add(new Vector(rotate ? 1 : 0, 0, rotate ? 1 : 0)),
new AffineTransform().rotateY(rotate ? 180 : 0)
).add(new Vector(usedRotate ? 1 : 0, 0, usedRotate ? 1 : 0)),
new AffineTransform().rotateY(usedRotate ? 180 : 0)
);
FightSystem.getHullHider().initialize(team);
team.getPlayers().forEach(fightPlayer -> fightPlayer.ifAI(ai -> ai.schematic(clipboard)));

View File

@@ -412,7 +412,11 @@ public class FightTeam {
}
public void setSchem(SchematicNode schematic){
this.schematic.setSchematic(schematic);
setSchem(schematic, -1);
}
public void setSchem(SchematicNode schematic, int revision){
this.schematic.setSchematic(schematic, revision);
broadcast("SCHEMATIC_CHOSEN", Config.GameName, schematic.getName());
}
@@ -458,6 +462,10 @@ public class FightTeam {
return schematic.getId();
}
public void setSchematicChangeRotate(boolean rotate) {
schematic.setChangeRotate(rotate);
}
public Clipboard getClipboard() {
return schematic.getClipboard();
}

View File

@@ -83,13 +83,8 @@ public class PrepareSchem implements Listener {
return;
}
if(schemExists(schem))
return;
SchematicNode old = schem;
schem = SchematicNode.createSchematicNode(schem.getOwner(), preparedName(schem), schem.getParent(), Config.SchematicType.checkType().toDB(), schem.getItem());
schem.setReplaceColor(old.replaceColor());
schem.setAllowReplay(old.allowReplay());
schem.setSchemtype(Config.SchematicType.checkType());
schem.setPrepared(true);
try{
WorldeditWrapper.impl.saveSchem(schem, region, minY);
@@ -119,20 +114,5 @@ public class PrepareSchem implements Listener {
FightState.setFightState(FightState.PRE_SCHEM_SETUP);
FightState.setFightState(FightState.POST_SCHEM_SETUP);
}
schemExists(SchematicNode.getSchematicNode(Config.PrepareSchemID));
}
private boolean schemExists(SchematicNode schem) {
if(SchematicNode.getSchematicNode(schem.getOwner(), preparedName(schem), schem.getParent()) != null) {
FightSystem.getMessage().broadcast("PREPARE_SCHEM_EXISTS");
Bukkit.shutdown();
return true;
}
return false;
}
private String preparedName(SchematicNode schem) {
return schem.getName() + "-prepared";
}
}

View File

@@ -20,7 +20,6 @@
package de.steamwar.fightsystem.record;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import de.steamwar.core.Core;
import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.core.WorldEditWrapper;
import de.steamwar.entity.REntity;
@@ -144,6 +143,8 @@ public class PacketProcessor implements Listener {
packetDecoder[0xb2] = this::teams;
packetDecoder[0xb3] = () -> pasteEmbeddedSchem(Fight.getBlueTeam());
packetDecoder[0xb4] = () -> pasteEmbeddedSchem(Fight.getRedTeam());
packetDecoder[0xb5] = () -> rotateSchem(Fight.getBlueTeam());
packetDecoder[0xb6] = () -> rotateSchem(Fight.getRedTeam());
packetDecoder[0xc0] = this::scoreboardTitle;
packetDecoder[0xc1] = this::scoreboardData;
packetDecoder[0xc2] = this::bossBar;
@@ -529,6 +530,14 @@ public class PacketProcessor implements Listener {
execSync(() -> team.pasteSchem(schemId, clipboard));
}
private void rotateSchem(FightTeam team) throws IOException {
boolean changeRotate = source.readBoolean();
execSync(() -> {
team.setSchematicChangeRotate(changeRotate);
});
}
private void teams() throws IOException {
int blueId = source.readInt();
int redId = source.readInt();

View File

@@ -61,9 +61,9 @@ public interface Recorder {
default void enableTeam(FightTeam team){
if(FightState.Schem.contains(FightState.getFightState())){
if(team.isBlue())
blueSchem(team.getSchematic());
blueSchem(team.getSchematic(), false);
else
redSchem(team.getSchematic());
redSchem(team.getSchematic(), false);
}
if(FightState.AntiSpectate.contains(FightState.getFightState())){
@@ -123,6 +123,8 @@ public interface Recorder {
* TeamIDPacket (0xb2) + int blueTeamId, redTeamId
* BlueEmbeddedSchemPacket (0xb3) + int blueSchemId + gzipt NBT blob
* RedEmbeddedSchemPacket (0xb4) + int redSchemId + gzipt NBT blob
* BlueSchemRotatePacket (0xb5) + boolean changeRotate
* RedSchemRotatePacket (0xb6) + boolean changeRotate
*
* DEPRECATED ScoreboardTitlePacket (0xc0) + String scoreboardTitle
* DEPRECATED ScoreboardDataPacket (0xc1) + String key + int value
@@ -259,14 +261,20 @@ public interface Recorder {
write(0xb2, blueTeamId, redTeamId);
}
default void blueSchem(int schemId) {
default void blueSchem(int schemId, boolean changeRotate) {
rotate(0xb5, changeRotate);
schem(0xb3, 0xb0, schemId);
}
default void redSchem(int schemId) {
default void redSchem(int schemId, boolean changeRotate) {
rotate(0xb6, changeRotate);
schem(0xb4, 0xb1, schemId);
}
default void rotate(int packetId, boolean changeRotate) {
write(packetId, changeRotate);
}
default void schem(int embedId, int noEmbedId, int schemId){
if(schemId == 0) {
write(noEmbedId, schemId);
@@ -275,7 +283,7 @@ public interface Recorder {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try{
copy(NodeData.get(SchematicNode.getSchematicNode(schemId)).schemData(), buffer);
copy(NodeData.getLatest(SchematicNode.getSchematicNode(schemId)).schemData(), buffer);
}catch (EOFException e) {
Bukkit.getLogger().log(Level.INFO, "EOFException ignored");
} catch (IOException e) {
@@ -339,6 +347,8 @@ public interface Recorder {
stream.writeShort((Short)o);
else if(o instanceof Integer)
stream.writeInt((Integer)o);
else if(o instanceof Long)
stream.writeLong((Long)o);
else if(o instanceof Float)
stream.writeFloat((Float)o);
else if(o instanceof Double)

View File

@@ -20,6 +20,7 @@
package de.steamwar.fightsystem.winconditions;
import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.countdown.Countdown;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam;
@@ -30,7 +31,6 @@ import de.steamwar.fightsystem.states.StateDependentTask;
import de.steamwar.fightsystem.utils.Message;
import de.steamwar.fightsystem.utils.SWSound;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent;
@@ -41,8 +41,7 @@ import java.util.Map;
public class WinconditionTimeTechKO extends Wincondition implements Listener {
private static final int TECH_KO_TIME_IN_S = 90;
private static final int TECH_KO_HALF_TIME = TECH_KO_TIME_IN_S/2;
private static final int TECH_KO_HALF_TIME = Config.TechKoTime/2;
private final Map<Integer, FightTeam> spawnLocations = new HashMap<>();
private final Map<FightTeam, TechKOCountdown> countdowns = new HashMap<>();

View File

@@ -0,0 +1,115 @@
/*
* 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.fightsystem.winconditions;
import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.countdown.Countdown;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependent;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.utils.Message;
import de.steamwar.fightsystem.utils.SWSound;
import org.bukkit.Location;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent;
import java.util.HashMap;
import java.util.Map;
public class WinconditionTimedDamageTechKO extends Wincondition implements PrintableWincondition, Listener {
private final Map<FightTeam, TechKOCountdown> countdowns = new HashMap<>();
public WinconditionTimedDamageTechKO() {
super("TechKO");
new StateDependentListener(Winconditions.TIMED_DAMAGE_TECH_KO, FightState.Running, this);
new StateDependent(Winconditions.TIMED_DAMAGE_TECH_KO, FightState.Running) {
@Override
public void enable() {
Fight.teams().forEach(team -> {
TechKOCountdown countdown = new TechKOCountdown(team, Config.TechKoTime);
countdowns.put(team, countdown);
countdown.enable();
});
}
@Override
public void disable() {
countdowns.values().forEach(Countdown::disable);
countdowns.clear();
}
}.register();
}
@Override
public Message getDisplay(FightTeam team) {
return new Message("BAR_SECONDS", team.getPrefix() + countdowns.get(team).getTimeLeft());
}
@EventHandler
public void onExplode(EntityExplodeEvent e) {
if (e.getEntityType() != TrickyTrialsWrapper.impl.getTntEntityType())
return;
Location location = e.getLocation();
TechKOCountdown countdown = null;
FightTeam fightTeam = null;
for (FightTeam team : Fight.teams()) {
FightTeam current = Fight.getOpposite(team);
if (current.getExtendRegion().inRegion(location)) {
fightTeam = current;
countdown = countdowns.get(team);
break;
}
}
if (fightTeam == null) {
return;
}
FightTeam finalFightTeam = fightTeam;
TechKOCountdown finalCountdown = countdown;
e.blockList().forEach(block -> {
if (block.isEmpty()) return;
if (finalFightTeam.getExtendRegion().inRegion(block)) {
finalCountdown.disable();
finalCountdown.enable();
}
});
}
private class TechKOCountdown extends Countdown {
private final FightTeam team;
public TechKOCountdown(FightTeam team, int countdownTime) {
super(countdownTime, new Message("TECHKO_COUNTDOWN", team.getColoredName()), SWSound.BLOCK_NOTE_PLING, false);
this.team = team;
}
@Override
public void countdownFinished() {
win(Fight.getOpposite(team), "WIN_TECHKO", team.getColoredName());
}
}
}

View File

@@ -31,6 +31,7 @@ public enum Winconditions {
POINTS,
POINTS_AIRSHIP,
TIMED_DAMAGE_TECH_KO,
TIME_TECH_KO,
WATER_TECH_KO,
PUMPKIN_TECH_KO,
@@ -41,4 +42,5 @@ public enum Winconditions {
PERSISTENT_DAMAGE,
TNT_DISTRIBUTION,
NO_GRAVITY,
RANDOM_ROTATE,
}

View File

@@ -53,6 +53,7 @@ public class BauSystem extends JavaPlugin implements Listener {
@Override
public void onEnable() {
Core.setServerName("Dev");
plugin = this;
Mapper.init();

View File

@@ -53,7 +53,7 @@ public class ClipboardListener implements Listener {
}
try {
new SchematicData(schematic).saveFromPlayer(e.getPlayer());
SchematicData.saveFromPlayer(e.getPlayer(), schematic);
} catch (Exception ex) {
if (newSchem) {
schematic.delete();

View File

@@ -19,6 +19,7 @@
package de.steamwar.lobby;
import de.steamwar.core.Core;
import de.steamwar.entity.REntityServer;
import de.steamwar.lobby.command.FlyCommand;
import de.steamwar.lobby.command.HologramCommand;
@@ -52,6 +53,7 @@ public class LobbySystem extends JavaPlugin {
message = new Message("de.steamwar.lobby.LobbySystem", getClassLoader());
entityServer = new REntityServer();
debugEntityServer = new REntityServer();
Core.setServerName("Lobby");
CustomMap.init();

View File

@@ -158,7 +158,7 @@ public class Config {
EventKampf = null;
TeamBlueName = "Blau";
TeamRedName = "Rot";
TeamBlueColor = "§3";
TeamBlueColor = "§9";
TeamRedColor = "§c";
EventTeamBlueID = 0;
EventTeamRedID = 0;

View File

@@ -76,7 +76,13 @@ public class AutoCheckerItems15 implements AutoCheckerItems {
Material.DIAMOND_HORSE_ARMOR,
Material.IRON_HORSE_ARMOR,
Material.GOLDEN_HORSE_ARMOR,
Material.HONEY_BOTTLE);
Material.LEATHER_HORSE_ARMOR,
Material.HONEY_BOTTLE,
Material.LILAC,
Material.ROSE_BUSH,
Material.PEONY,
Material.TALL_GRASS,
Material.LARGE_FERN);
@Override
public Set<Material> getInventoryMaterials() {

View File

@@ -43,12 +43,19 @@ public class AutoCheckerItems19 extends AutoCheckerItems15 {
Material.LILY_OF_THE_VALLEY,
Material.WITHER_ROSE,
Material.SUNFLOWER,
Material.LILAC,
Material.ROSE_BUSH,
Material.PEONY,
Material.TALL_GRASS,
Material.LARGE_FERN,
Material.TORCHFLOWER,
// 16-stackable Items
Material.HONEY_BOTTLE,
// Non-stackable items
Material.DIAMOND_HORSE_ARMOR,
Material.IRON_HORSE_ARMOR,
Material.GOLDEN_HORSE_ARMOR,
Material.LEATHER_HORSE_ARMOR,
// Disks
Material.MUSIC_DISC_11,
Material.MUSIC_DISC_13,

View File

@@ -26,6 +26,7 @@ CLICK_DRAG_ITEM=§7Click or drag item here
CURRENT=§7Current: {0}
CONFIRM=§aConfirm
CANCEL=§cCancel
BLANK={0}
UTIL_NAME_REQUIRED=§cFolder name required
UTIL_NAME_TOO_LONG=§cSchematic name too long
@@ -49,6 +50,7 @@ UTIL_LIST_NEXT=Page ({0}/{1}) »»
UTIL_LIST_NEXT_HOVER=§eNext page
UTIL_INFO_SCHEM=§7Schematic: §e{0}
UTIL_INFO_NAME=§7Name: §e{0}
UTIL_INFO_REVISIONS=§7Revisions: §e{0}
UTIL_INFO_OWNER=§7Owner: §e{0}
UTIL_INFO_PARENT=§7Directory: §e{0}
UTIL_INFO_UPDATED=§7Last update: §e{0}
@@ -70,6 +72,7 @@ UTIL_INFO_ACTION_TYPE_HOVER=§eChange schematic type
UTIL_INFO_ACTION_ADD_HOVER=§eAdd member
UTIL_INFO_ACTION_REMOVE_HOVER=§eRemove {0}
UTIL_INFO_ACTION_MOVE_HOVER=§eMove schematic
UTIL_INFO_ACTION_REVISIONS_HOVER=§eList revisions
UTIL_INFO_ACTION_RENAME_HOVER=§eRename schematic
UTIL_INFO_ACTION_DELETE=(Delete)
UTIL_INFO_ACTION_DELETE_HOVER=§eDelete schematic
@@ -79,6 +82,7 @@ UTIL_LOAD_DIR=§cYou cannot load folders
UTIL_LOAD_DONE=§7Schematic §e{0} loaded
UTIL_LOAD_NO_DATA=§cNo data could be found in the Schematic
UTIL_LOAD_ERROR=§cThe schematic could not be loaded
UTIL_LOAD_ILLEGAL_REVISION=§cThe schematic doesn't have {0} revisions
UTIL_DOWNLOAD_PUNISHED=§cYou are not allowed to download schematics: §f§l{0}
UTIL_DOWNLOAD_NOT_OWN=§cYou may download only your own schematics
UTIL_DOWNLOAD_LINK=Your download link:
@@ -224,6 +228,9 @@ GUI_DELETE_MEMBER_TITLE=Remove {0}
GUI_DELETE_MEMBER_DONE=Access to Schematic §e{0} §7removed
GUI_DELETE_MEMBERS_TITLE=Remove members
GUI_CHANGE_ITEM=Change item
GUI_LOAD_LATEST=§eLeft §7Click → §eLoad latest
GUI_LOAD_REVISION=§eRight §7Click → §eList Revisions
GUI_LOAD_REVISION_TITLE=Select Revision
AUTO_CHECK_RESULT_NOT_LOAD=The schematic could not be loaded
AUTO_CHECK_RESULT_TOO_WIDE=The schematic is too wide ({0} > {1})
@@ -263,4 +270,8 @@ AUTO_CHECKER_RESULT_RECORD=§7Record: §c[{0}, {1}, {2}]
AUTO_CHECKER_RESULT_TOO_MANY_DISPENSER_ITEMS=§7Dispenser: §c[{0}, {1}, {2}]§7, §c{3} §7items, Max: §e{4}
AUTO_CHECKER_RESULT_FORBIDDEN_ITEM_NBT=§7Forbidden Item NBT: [{0}, {1}, {2}] -> §c{3}
AUTO_CHECKER_RESULT_TELEPORT_HERE=§7Teleport to block
AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cThe deadline has expired: {0}
AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cThe deadline has expired: {0}
REVISIONS_TITLE=§7Revisions:
REVISIONS_REVISION_NUMBER=§7#{0}: §e{1}
REVISIONS_EMPTY=§cNo Revisions

View File

@@ -90,6 +90,9 @@ UTIL_SUBMIT_DIRECT=§eDirekt einsenden
UTIL_SUBMIT_DIRECT_DONE=§aDie Schematic wird zeitnah überprüft
UTIL_SUBMIT_EXTEND=§eSchematic ausfahren
UTIL_SUBMIT_EXTEND_DONE=§aDer Vorbereitungsserver wird gestartet
UTIL_INFO_ACTION_REVISIONS_HOVER=§eVersionen anzeigen
UTIL_LOAD_ILLEGAL_REVISION=§cDie schematic hat nicht {0} Versionen
UTIL_INFO_REVISIONS=§7Versionen: §e{0}
COMMAND_INVALID_NODE=§cDie Schematic konnte nicht gefunden werden
COMMAND_NOT_OWN=§cDas darfst du nur bei deinen eigenen Schematics machen
@@ -204,6 +207,9 @@ GUI_DELETE_MEMBER_TITLE={0} entfernen
GUI_DELETE_MEMBER_DONE=Zugriff zu Schematic §e{0} §7entfernt
GUI_DELETE_MEMBERS_TITLE=Mitglieder entfernen
GUI_CHANGE_ITEM=Item ändern
GUI_LOAD_LATEST=§eLinks §7Klick → §eLetzte Laden
GUI_LOAD_REVISION=§eRechts §7Klick → §eVersionen anzeigen
GUI_LOAD_REVISION_TITLE=Version Laden
AUTO_CHECK_RESULT_NOT_LOAD=Die Schematic konnte nicht geladen werden
AUTO_CHECK_RESULT_TOO_WIDE=Die Schematic ist zu breit ({0} > {1})
@@ -242,4 +248,7 @@ AUTO_CHECKER_RESULT_RECORD=§7Schallplatte: §c[{0}, {1}, {2}]
AUTO_CHECKER_RESULT_TOO_MANY_DISPENSER_ITEMS=§7Dispenser: §c[{0}, {1}, {2}]§7, §c{3} §7gegenstände, Max: §e{4}
AUTO_CHECKER_RESULT_FORBIDDEN_ITEM_NBT=§7Verbotene NBT-Daten: [{0}, {1}, {2}] -> §c{3}
AUTO_CHECKER_RESULT_TELEPORT_HERE=§7Zum block teleportieren
AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cDer einsendeschluss ist bereits vorbei: {0}
AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cDer einsendeschluss ist bereits vorbei: {0}
REVISIONS_TITLE=§7Versionen:
REVISIONS_EMPTY=§cKeine Versionen

View File

@@ -43,7 +43,7 @@ public class DownloadCommand extends SWCommand {
}
try {
new SchematicData(copyNode).saveFromPlayer(player);
SchematicData.saveFromPlayer(player, copyNode);
} catch (IOException e) {
SchematicSystem.MESSAGE.send("DOWNLOAD_ERROR", player);
if (newSchem) {

View File

@@ -95,9 +95,28 @@ public class GUI {
SteamwarUser user = getUser(player);
SWInventory inv = new SWInventory(player, 9 * 2, node.generateBreadcrumbs());
if(!node.isDir()) {
inv.setItem(0, SWItem.getMaterial("WOOD_AXE"), SchematicSystem.MESSAGE.parse("GUI_INFO_LOAD", player), click -> {
player.closeInventory();
SchematicCommandUtils.loadSchem(player, node);
inv.setItem(0, SWItem.getMaterial("WOOD_AXE"), SchematicSystem.MESSAGE.parse("GUI_INFO_LOAD", player), Arrays.asList(
SchematicSystem.MESSAGE.parse("GUI_LOAD_LATEST", player),
SchematicSystem.MESSAGE.parse("GUI_LOAD_REVISION", player)
), false, click -> {
if (click.isLeftClick()) {
player.closeInventory();
SchematicCommandUtils.loadSchem(player, node, -1);
} else if (click.isRightClick()) {
List<SWListInv.SWListEntry<Integer>> entries = new ArrayList<>();
List<NodeData> datas = NodeData.get(node);
for (int i = 0; i < datas.size(); i++) {
entries.add(new SWListInv.SWListEntry<>(new SWItem(SWItem.getMaterial(node.getItem()), "§e" + SchematicSystem.MESSAGE.parse("BLANK", player, datas.get(i).getCreatedAt())), i));
}
SWListInv<Integer> listInv = new SWListInv<>(player, SchematicSystem.MESSAGE.parse("GUI_LOAD_REVISION_TITLE", player, node.generateBreadcrumbs()), entries, (clickType, revision) -> {
if(revision == null) return;
player.closeInventory();
SchematicCommandUtils.loadSchem(player, node, revision);
});
listInv.setCallback(-999, click2 -> player.closeInventory());
listInv.open();
}
});
}

View File

@@ -223,6 +223,11 @@ public class SchematicCommandUtils {
} else {
SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_PARENT", player, node.getParent() == null ? "/" : node.getParentNode().generateBreadcrumbs());
}
player.spigot().sendMessage(
new ComponentBuilder(SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_REVISIONS", false, player, NodeData.getRevisions(node)))
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[] {SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_REVISIONS_HOVER", false, player)}))
.event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem revisions " + node.generateBreadcrumbs()))
.create());
SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_UPDATED", player, node.getLastUpdate());
if (!node.isDir()) {
if(node.getOwner() == user.getId()) {
@@ -357,7 +362,7 @@ public class SchematicCommandUtils {
PUBLIC_TOGGLED.remove(player);
}
public static void loadSchem(Player player, SchematicNode node) {
public static void loadSchem(Player player, SchematicNode node, int revision) {
SteamwarUser user = getUser(player);
if(BauServerInfo.isBauServer() && BauServerInfo.getOwnerId() != user.getId() &&
(Punishment.isPunished(user, Punishment.PunishmentType.NoSchemSharing, punishment ->
@@ -372,11 +377,13 @@ public class SchematicCommandUtils {
}
try {
new SchematicData(node).loadToPlayer(player);
new SchematicData(node, revision).loadToPlayer(player);
SchematicSystem.MESSAGE.send("UTIL_LOAD_DONE", player, node.getName());
Bukkit.getLogger().log(Level.INFO, "{0} has loaded Schematic {1} {2}", new Object[]{player.getName(), node.getId(), node.getName()});
} catch (NoClipboardException e) {
SchematicSystem.MESSAGE.send("UTIL_LOAD_NO_DATA", player);
} catch (IllegalArgumentException e) {
SchematicSystem.MESSAGE.send("UTIL_LOAD_ILLEGAL_REVISION", player, revision);
} catch (Exception e) {
SchematicSystem.MESSAGE.send("UTIL_LOAD_ERROR", player);
Bukkit.getLogger().log(Level.INFO, e.getMessage(), e);
@@ -421,6 +428,8 @@ public class SchematicCommandUtils {
return;
}
node.setPrepared(false);
if (type.writeable()) {
node.setSchemtype(type);
SchematicSystem.MESSAGE.send("UTIL_TYPE_DONE", player);
@@ -483,7 +492,7 @@ public class SchematicCommandUtils {
node.setAllowReplay(!node.allowReplay());
submitSchemGUI(player, node, type);
});
inv.setItem(1, SWItem.getMaterial(node.replaceColor() ? "PINK_WOOL" : "LIGHT_GRAY_WOOL"), SchematicSystem.MESSAGE.parse(node.allowReplay()?"UTIL_SUBMIT_COLOR_ON":"UTIL_SUBMIT_COLOR_OFF", player), click -> {
inv.setItem(1, SWItem.getMaterial(node.replaceColor() ? "PINK_WOOL" : "LIGHT_GRAY_WOOL"), SchematicSystem.MESSAGE.parse(node.replaceColor()?"UTIL_SUBMIT_COLOR_ON":"UTIL_SUBMIT_COLOR_OFF", player), click -> {
node.setReplaceColor(!node.replaceColor());
submitSchemGUI(player, node, type);
});

View File

@@ -49,11 +49,11 @@ public class SavePart extends SWCommand {
SchematicSelector selector = new SchematicSelector(player, SchematicSelector.selectSchematicNode(), schematicNode -> {
if(schematicNode == null || schematicNode.isDir()) {
SWAnvilInv anvilInv = new SWAnvilInv(player, SchematicSystem.MESSAGE.parse("COMMAND_ENTER_NAME", player));
anvilInv.setCallback(s -> saveSchem(player, schematicNode==null?s:(schematicNode.generateBreadcrumbs() + s), true));
anvilInv.setCallback(s -> saveSchem(player, schematicNode==null?s:(schematicNode.generateBreadcrumbs() + s)));
anvilInv.setItem(Material.CAULDRON);
anvilInv.open();
} else {
saveSchem(player, schematicNode.generateBreadcrumbs(), true);
saveSchem(player, schematicNode.generateBreadcrumbs());
}
});
selector.setSingleDirOpen(false);
@@ -62,7 +62,7 @@ public class SavePart extends SWCommand {
@Register("save")
@Register("s")
public void saveSchem(Player player, @AbstractSWCommand.Mapper("stringMapper") String name, @AbstractSWCommand.StaticValue(value = {"", "-f"}, allowISE=true) @AbstractSWCommand.OptionalValue("") boolean overwrite) {
public void saveSchem(Player player, @AbstractSWCommand.Mapper("stringMapper") String name) {
SteamwarUser user = getUser(player);
if(BauServerInfo.isBauServer() && BauServerInfo.getOwnerId() != user.getId() &&
(Punishment.isPunished(user, Punishment.PunishmentType.NoSchemReceiving, punishment ->
@@ -88,9 +88,6 @@ public class SavePart extends SWCommand {
} else if (!node.getSchemtype().writeable() || node.getOwner() != user.getId()) {
SchematicSystem.MESSAGE.send("COMMAND_SAVE_NO_OVERWRITE", player);
return;
} else if(!overwrite) {
SchematicSystem.MESSAGE.send("COMMAND_SAVE_OVERWRITE_CONFIRM", player, SchematicSystem.MESSAGE.parse("COMMAND_SAVE_OVERWRITE_CONFIRM_HOVER", player), new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem s " + name + " -f"), node.generateBreadcrumbs());
return;
}
}
@@ -101,7 +98,7 @@ public class SavePart extends SWCommand {
}
try {
new SchematicData(node).saveFromPlayer(player);
SchematicData.saveFromPlayer(player, node);
} catch (NoClipboardException e) {
SchematicSystem.MESSAGE.send("COMMAND_SAVE_CLIPBOARD_EMPTY", player);
if (newSchem)

View File

@@ -21,13 +21,23 @@ package de.steamwar.schematicsystem.commands.schematiccommand.parts;
import de.steamwar.command.AbstractSWCommand;
import de.steamwar.command.SWCommand;
import de.steamwar.schematicsystem.SchematicSystem;
import de.steamwar.schematicsystem.commands.schematiccommand.GUI;
import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils;
import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand;
import de.steamwar.sql.NodeData;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.entity.Player;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.List;
import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.*;
@AbstractSWCommand.PartOf(SchematicCommand.class)
@@ -69,6 +79,25 @@ public class ViewPart extends SWCommand {
printSchemInfo(player, node);
}
@Register("revisions")
public void revisions(Player player, @Validator("isSchemValidator") SchematicNode node) {
List<NodeData> revisions = NodeData.get(node);
if(revisions.isEmpty()) {
SchematicSystem.MESSAGE.send("REVISIONS_EMPTY", player);
return;
}
SchematicSystem.MESSAGE.send("REVISIONS_TITLE", player);
for (int j = Math.max(0, revisions.size() - 10); j < revisions.size(); j++) {
player.spigot().sendMessage(
new ComponentBuilder(SchematicSystem.MESSAGE.parseToComponent("REVISIONS_REVISION_NUMBER", false, player, j + 1, revisions.get(j).getCreatedAt()))
.event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem load " + (node.getOwner() == 0 ? "public " : "") + node.generateBreadcrumbs() + " " + (j + 1)))
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[]{SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_LOAD_HOVER", false, player)}))
.create()
);
}
}
@Register(value = "page", noTabComplete = true)
public void pageCommand(Player player, int page) {
cachedSchemList(player, page);
@@ -76,14 +105,14 @@ public class ViewPart extends SWCommand {
@Register({"l", "public"})
@Register({"load", "public"})
public void loadSchemPublic(Player player, @Validator("isSchemValidator") @Mapper("publicMapper") SchematicNode node) {
loadSchem(player, node);
public void loadSchemPublic(Player player, @Validator("isSchemValidator") @Mapper("publicMapper") SchematicNode node, @OptionalValue("-1") int revision) {
loadSchem(player, node, revision);
}
@Register("l")
@Register("load")
public void loadSchem(Player player, @Validator("isSchemValidator") SchematicNode node) {
SchematicCommandUtils.loadSchem(player, node);
public void loadSchem(Player player, @Validator("isSchemValidator") SchematicNode node, @OptionalValue("-1") int revision) {
SchematicCommandUtils.loadSchem(player, node, revision);
}
@Register("gui")
@@ -92,7 +121,7 @@ public class ViewPart extends SWCommand {
}
@Register("download")
public void download(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node) {
public void download(Player player, @Validator("isSchemValidator") SchematicNode node) {
SchematicCommandUtils.download(player, node);
}
}

View File

@@ -565,17 +565,17 @@ public class WorldEditWrapper14 implements WorldEditWrapper {
for (Map<String, Tag> tileEntity : tileEntityTags) {
int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue();
final BlockVector3 pt = BlockVector3.at(pos[0], pos[1], pos[2]);
Map<String, Tag> values = Maps.newHashMap(tileEntity);
Map<String, Tag> values = Maps.newHashMap(v3Mode ? requireTag(tileEntity, "Data", CompoundTag.class).getValue() : tileEntity);
if(faweSchem){
values.put("x", new IntTag(pt.getBlockX() - offsetX));
values.put("y", new IntTag(pt.getBlockY() - offsetY));
values.put("z", new IntTag(pt.getBlockZ() - offsetZ));
}else{
values.put("x", new IntTag(pt.getBlockX()));
values.put("y", new IntTag(pt.getBlockY()));
values.put("z", new IntTag(pt.getBlockZ()));
values.putIfAbsent("x", new IntTag(pt.getBlockX()));
values.putIfAbsent("y", new IntTag(pt.getBlockY()));
values.putIfAbsent("z", new IntTag(pt.getBlockZ()));
}
values.put("id", values.get("Id"));
values.putIfAbsent("id", values.get("Id"));
values.remove("Id");
values.remove("Pos");
if (fixer != null) {

View File

@@ -0,0 +1,34 @@
/*
* 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.entity;
import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket;
import net.minecraft.world.entity.PositionMoveRotation;
import net.minecraft.world.phys.Vec3;
import java.util.Collections;
public class PacketConstructor21 implements PacketConstructor{
@Override
public Object teleportPacket(int entityId, double x, double y, double z, float yaw, float pitch) {
PositionMoveRotation rot = new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, pitch, yaw);
return new ClientboundTeleportEntityPacket(entityId, rot, Collections.emptySet(), false);
}
}

View File

@@ -19,6 +19,10 @@
package de.steamwar.command;
import de.steamwar.core.Core;
import de.steamwar.providers.BauServerInfo;
import de.steamwar.sql.AuditLog;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@@ -31,5 +35,6 @@ public class CaseInsensitiveCommandsListener implements Listener {
String[] strings = event.getMessage().split(" ");
strings[0] = strings[0].toLowerCase();
event.setMessage(String.join(" ", strings));
AuditLog.createCommand(Core.getServerName(), BauServerInfo.getOwnerUser(), SteamwarUser.get(event.getPlayer().getUniqueId()), event.getMessage());
}
}

View File

@@ -94,6 +94,7 @@ class CheckpointUtilsJ9 {
private static final Reflection.Method bind = Reflection.getMethod(TinyProtocol.serverConnection, null, InetAddress.class, int.class);
private static void freezeInternal(Path path) throws Exception {
Bukkit.getPluginManager().callEvent(new CRIUSleepEvent());
Bukkit.getWorlds().forEach(FlatteningWrapper.impl::syncSave);
Statement.closeAll();
@@ -119,8 +120,9 @@ class CheckpointUtilsJ9 {
criu.checkpointJVM();
} catch (JVMCRIUException e) {
Path logfile = path.resolve("criu.log");
if(logfile.toFile().exists())
if(logfile.toFile().exists()) {
throw new IllegalStateException("Could not create checkpoint, criu log:\n" + new String(Files.readAllBytes(logfile)), e);
}
throw e;
}

View File

@@ -33,6 +33,8 @@ import de.steamwar.network.handlers.ServerDataHandler;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.internal.Statement;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Listener;
@@ -52,12 +54,17 @@ public class Core extends JavaPlugin {
return Reflection.MAJOR_VERSION;
}
@Getter
@Setter
private static JavaPlugin instance;
public static JavaPlugin getInstance() {
return instance;
}
public static void setInstance(JavaPlugin instance) {
Core.instance = instance;
@Getter
private static String serverName = "";
public static void setServerName(String serverName) {
if (serverName.isEmpty()) {
Core.serverName = serverName;
}
}
private ErrorHandler errorHandler;
@@ -66,6 +73,7 @@ public class Core extends JavaPlugin {
@Override
public void onLoad() {
setInstance(this);
serverName = System.getProperty("serverName", "");
}
@Override

View File

@@ -19,6 +19,9 @@
package de.steamwar.core.events;
import de.steamwar.core.Core;
import de.steamwar.providers.BauServerInfo;
import de.steamwar.sql.AuditLog;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserPerm;
import de.steamwar.sql.internal.Statement;
@@ -44,12 +47,14 @@ public class PlayerJoinedEvent implements Listener{
player.setDisplayName(prefix.getColorCode() + player.getName() + "§r");
event.setJoinMessage("§a§l» §r" + player.getDisplayName());
AuditLog.createJoin(Core.getServerName(), BauServerInfo.getOwnerUser(), user);
}
@EventHandler
@EventHandler(priority = EventPriority.LOWEST)
private void onQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
event.setQuitMessage("§c§l« §r" + player.getDisplayName());
AuditLog.createLeave(Core.getServerName(), BauServerInfo.getOwnerUser(), SteamwarUser.get(player.getUniqueId()));
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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.entity;
import de.steamwar.core.Core;
import de.steamwar.core.VersionDependent;
public interface PacketConstructor {
public static final PacketConstructor impl = VersionDependent.getVersionImpl(Core.getInstance());
Object teleportPacket(int entityId, double x, double y, double z, float yaw, float pitch);
}

View File

@@ -21,6 +21,7 @@ package de.steamwar.entity;
import de.steamwar.Reflection;
import de.steamwar.core.BountifulWrapper;
import de.steamwar.core.Core;
import lombok.Getter;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -59,7 +60,7 @@ public class RBlockDisplay extends RDisplay {
private static final Class<?> iBlockDataClass = Reflection.getClass("net.minecraft.world.level.block.state.BlockState");
private static final Reflection.Method getState = Reflection.getTypedMethod(Reflection.getClass("org.bukkit.craftbukkit.block.data.CraftBlockData"), "getState", iBlockDataClass);
private static final Object blockWatcher = BountifulWrapper.impl.getDataWatcherObject(22, iBlockDataClass);
private static final Object blockWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 23 : 22, iBlockDataClass);
private void getBlock(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || !block.getAsString(true).equals(DEFAULT_BLOCK.getAsString(true))) {
packetSink.accept(blockWatcher, getState.invoke(block));

View File

@@ -20,6 +20,7 @@
package de.steamwar.entity;
import de.steamwar.core.BountifulWrapper;
import de.steamwar.core.Core;
import lombok.Getter;
import lombok.NonNull;
import org.bukkit.Color;
@@ -110,10 +111,10 @@ public abstract class RDisplay extends REntity {
sendPacket(updatePacketSink, this::getTransformData);
}
private static final Object translationWatcher = BountifulWrapper.impl.getDataWatcherObject(10, Vector3f.class);
private static final Object leftRotationWatcher = BountifulWrapper.impl.getDataWatcherObject(12, Quaternionf.class);
private static final Object scaleWatcher = BountifulWrapper.impl.getDataWatcherObject(11, Vector3f.class);
private static final Object rightRotationWatcher = BountifulWrapper.impl.getDataWatcherObject(13, Quaternionf.class);
private static final Object translationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 11 : 10, Vector3f.class);
private static final Object leftRotationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 13 : 12, Quaternionf.class);
private static final Object scaleWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 12 : 11, Vector3f.class);
private static final Object rightRotationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 14 : 13, Quaternionf.class);
private void getTransformData(boolean ignoreDefault, BiConsumer<Object, Object> dataSink) {
if (ignoreDefault || !transform.equals(DEFAULT_TRANSFORM)) {
@@ -129,8 +130,8 @@ public abstract class RDisplay extends REntity {
sendPacket(updatePacketSink, this::getInterpolationDuration);
}
private static final Object transformationInterpolationDurationWatcher = BountifulWrapper.impl.getDataWatcherObject(8, Integer.class);
private static final Object positionOrRotationInterpolationDurationWatcher = BountifulWrapper.impl.getDataWatcherObject(9, Integer.class);
private static final Object transformationInterpolationDurationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 9 : 8, Integer.class);
private static final Object positionOrRotationInterpolationDurationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 10 : 9, Integer.class);
private void getInterpolationDuration(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || interpolationDelay != 0) {
@@ -144,7 +145,7 @@ public abstract class RDisplay extends REntity {
sendPacket(updatePacketSink, this::getViewRange);
}
private static final Object viewRangeWatcher = BountifulWrapper.impl.getDataWatcherObject(16, Float.class);
private static final Object viewRangeWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 17 : 16, Float.class);
private void getViewRange(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || viewRange != 1.0F) {
@@ -157,7 +158,7 @@ public abstract class RDisplay extends REntity {
sendPacket(updatePacketSink, this::getShadowRadius);
}
private static final Object shadowRadiusWatcher = BountifulWrapper.impl.getDataWatcherObject(17, Float.class);
private static final Object shadowRadiusWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 18 : 17, Float.class);
private void getShadowRadius(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || shadowRadius != 0.0F) {
@@ -170,7 +171,7 @@ public abstract class RDisplay extends REntity {
sendPacket(updatePacketSink, this::getShadowStrength);
}
private static final Object shadowStrengthWatcher = BountifulWrapper.impl.getDataWatcherObject(18, Float.class);
private static final Object shadowStrengthWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 19 : 18, Float.class);
private void getShadowStrength(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || shadowStrength != 1.0F) {
@@ -183,7 +184,7 @@ public abstract class RDisplay extends REntity {
sendPacket(updatePacketSink, this::getDisplayWidth);
}
private static final Object displayWidthWatcher = BountifulWrapper.impl.getDataWatcherObject(19, Float.class);
private static final Object displayWidthWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 20 : 19, Float.class);
private void getDisplayWidth(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || displayWidth != 0.0F) {
@@ -196,7 +197,7 @@ public abstract class RDisplay extends REntity {
sendPacket(updatePacketSink, this::getDisplayHeight);
}
private static final Object displayHeightWatcher = BountifulWrapper.impl.getDataWatcherObject(20, Float.class);
private static final Object displayHeightWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 21 : 20, Float.class);
private void getDisplayHeight(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || displayHeight != 0.0F) {
@@ -209,7 +210,7 @@ public abstract class RDisplay extends REntity {
sendPacket(updatePacketSink, this::getInterpolationDelay);
}
private static final Object interpolationDelayWatcher = BountifulWrapper.impl.getDataWatcherObject(7, Integer.class);
private static final Object interpolationDelayWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 8 : 7, Integer.class);
private void getInterpolationDelay(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || interpolationDelay != 0) {
@@ -222,7 +223,7 @@ public abstract class RDisplay extends REntity {
sendPacket(updatePacketSink, this::getBillboard);
}
private static final Object billboardWatcher = BountifulWrapper.impl.getDataWatcherObject(14, Byte.class);
private static final Object billboardWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 15 : 14, Byte.class);
private void getBillboard(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || billboard != Display.Billboard.FIXED) {
@@ -235,7 +236,7 @@ public abstract class RDisplay extends REntity {
sendPacket(updatePacketSink, this::getGlowColorOverride);
}
private static final Object glowColorOverrideWatcher = BountifulWrapper.impl.getDataWatcherObject(21, Integer.class);
private static final Object glowColorOverrideWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 22 : 21, Integer.class);
private void getGlowColorOverride(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || glowColorOverride != null) {
@@ -248,7 +249,7 @@ public abstract class RDisplay extends REntity {
sendPacket(updatePacketSink, this::getBrightness);
}
private static final Object brightnessWatcher = BountifulWrapper.impl.getDataWatcherObject(15, Integer.class);
private static final Object brightnessWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 16 : 15, Integer.class);
private void getBrightness(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || brightness != null) {

View File

@@ -397,6 +397,10 @@ public class REntity {
public static final Reflection.Field<Integer> teleportEntity = Reflection.getField(teleportPacket, int.class, 0);
public static final BountifulWrapper.PositionSetter teleportPosition = BountifulWrapper.impl.getPositionSetter(teleportPacket, Core.getVersion() == 8 ? 1 : 0);
private Object getTeleportPacket(){
if (Core.getVersion() >= 21) {
return PacketConstructor.impl.teleportPacket(entityId, x, y, z, pitch, yaw);
}
Object packet = Reflection.newInstance(teleportPacket);
teleportEntity.set(packet, entityId);
teleportPosition.set(packet, x, y, z, pitch, yaw);

View File

@@ -50,11 +50,11 @@ public class REntityServer implements Listener {
private static final Class<?> useEntity = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundInteractPacket");
private static final Reflection.Field<Integer> useEntityTarget = Reflection.getField(useEntity, int.class, 0);
private static final Class<?> useEntityEnumAction = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundInteractPacket$Action");
private static final Class<?> useEntityEnumActionType = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundInteractPacket$ActionType");
private static final Reflection.Field<?> useEntityAction = Reflection.getField(useEntity, useEntityEnumAction, 0);
private static final Function<Object, Integer> getEntityAction;
static {
if(Core.getVersion() > 15) {
Class<?> useEntityEnumActionType = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundInteractPacket$ActionType");
Reflection.Method useEntityGetAction = Reflection.getTypedMethod(useEntityEnumAction, null, useEntityEnumActionType);
getEntityAction = value -> ((Enum<?>) useEntityGetAction.invoke(value)).ordinal();
} else {

View File

@@ -20,6 +20,7 @@
package de.steamwar.entity;
import de.steamwar.core.BountifulWrapper;
import de.steamwar.core.Core;
import de.steamwar.core.ProtocolWrapper;
import lombok.Getter;
import org.bukkit.Location;
@@ -60,14 +61,14 @@ public class RItemDisplay extends RDisplay {
sendPacket(updatePacketSink, this::getItemStack);
}
private static final Object itemStackWatcher = BountifulWrapper.impl.getDataWatcherObject(22, ProtocolWrapper.itemStack);
private static final Object itemStackWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 23 : 22, ProtocolWrapper.itemStack);
private void getItemStack(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || !itemStack.equals(DEFAULT_ITEM_STACK)) {
packetSink.accept(itemStackWatcher, asNMSCopy.invoke(null, itemStack));
}
}
private static final Object itemDisplayTransformWatcher = BountifulWrapper.impl.getDataWatcherObject(23, Byte.class);
private static final Object itemDisplayTransformWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 24 : 23, Byte.class);
public void setItemDisplayTransform(ItemDisplay.ItemDisplayTransform itemDisplayTransform) {
this.itemDisplayTransform = itemDisplayTransform;
sendPacket(updatePacketSink, this::getItemDisplayTransform);

View File

@@ -22,6 +22,7 @@ package de.steamwar.entity;
import de.steamwar.Reflection;
import de.steamwar.core.BountifulWrapper;
import de.steamwar.core.ChatWrapper;
import de.steamwar.core.Core;
import lombok.Getter;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
@@ -74,7 +75,7 @@ public class RTextDisplay extends RDisplay {
}
private static final Class<?> iChatBaseComponent = Reflection.getClass("net.minecraft.network.chat.Component");
private static final Object textWatcher = BountifulWrapper.impl.getDataWatcherObject(22, iChatBaseComponent);
private static final Object textWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 23 : 22, iChatBaseComponent);
private void getText(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || !text.isEmpty()) {
packetSink.accept(textWatcher, ChatWrapper.impl.stringToChatComponent(text));
@@ -86,7 +87,7 @@ public class RTextDisplay extends RDisplay {
sendPacket(updatePacketSink, this::getLineWidth);
}
private static final Object lineWidthWatcher = BountifulWrapper.impl.getDataWatcherObject(23, Integer.class);
private static final Object lineWidthWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 24 : 23, Integer.class);
private void getLineWidth(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || lineWidth != 200) {
packetSink.accept(lineWidthWatcher, lineWidth);
@@ -98,7 +99,7 @@ public class RTextDisplay extends RDisplay {
sendPacket(updatePacketSink, this::getTextOpacity);
}
private static final Object textOpacityWatcher = BountifulWrapper.impl.getDataWatcherObject(25, Byte.class);
private static final Object textOpacityWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 26 : 25, Byte.class);
private void getTextOpacity(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
if (ignoreDefault || textOpacity != (byte) -1) {
packetSink.accept(textOpacityWatcher, textOpacity);
@@ -125,7 +126,7 @@ public class RTextDisplay extends RDisplay {
sendPacket(updatePacketSink, this::getTextStatus);
}
private static final Object textStatusWatcher = BountifulWrapper.impl.getDataWatcherObject(26, Byte.class);
private static final Object textStatusWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 27 : 26, Byte.class);
private void getTextStatus(boolean ignoreDefault, BiConsumer<Object, Object> packetSink) {
byte status = 0;

View File

@@ -20,7 +20,9 @@
package de.steamwar.inventory;
import de.steamwar.core.Core;
import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.providers.BauServerInfo;
import de.steamwar.sql.AuditLog;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@@ -145,6 +147,7 @@ public class SWInventory implements Listener {
Bukkit.getPluginManager().registerEvents(this, Core.getInstance());
open = true;
}
AuditLog.createGuiOpen(Core.getServerName(), BauServerInfo.getOwnerUser(), SteamwarUser.get(player.getUniqueId()), title);
}
@EventHandler
@@ -156,6 +159,7 @@ public class SWInventory implements Listener {
e.setCancelled(true);
Core.getInstance().getLogger().info("[SWINV] " + e.getWhoClicked().getName() + " " + e.getClick().name() + " clicked " + e.getRawSlot() + " on " + (e.getCurrentItem() != null ? e.getCurrentItem().getItemMeta().getDisplayName() : "[EMPTY]") + " in " + e.getView().getTitle());
callbacks.get(e.getRawSlot()).accept(e);
AuditLog.createGuiClick(Core.getServerName(), BauServerInfo.getOwnerUser(), SteamwarUser.get(player.getUniqueId()), e.getView().getTitle(), e.getClick().name(), e.getRawSlot(), (e.getCurrentItem() != null ? e.getCurrentItem().getItemMeta().getDisplayName() : "[EMPTY]"));
}
}
@@ -167,8 +171,10 @@ public class SWInventory implements Listener {
InventoryClickEvent.getHandlerList().unregister(this);
InventoryCloseEvent.getHandlerList().unregister(this);
Core.getInstance().getLogger().info("[SWINV] " + player.getName() + " closed " + title);
if(callbacks.containsKey(-1))
if(callbacks.containsKey(-1)) {
callbacks.get(-1).accept(null);
}
open = false;
AuditLog.createGuiClose(Core.getServerName(), BauServerInfo.getOwnerUser(), SteamwarUser.get(player.getUniqueId()), title);
}
}

View File

@@ -19,6 +19,7 @@
package de.steamwar.providers;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.Bukkit;
public class BauServerInfo {
@@ -37,4 +38,9 @@ public class BauServerInfo {
public static boolean isBauServer() {
return bauOwner != null;
}
public static SteamwarUser getOwnerUser() {
if (bauOwner == null) return null;
return SteamwarUser.get(bauOwner);
}
}

View File

@@ -47,11 +47,25 @@ public class SchematicData {
private final NodeData data;
public SchematicData(SchematicNode node) {
this.data = NodeData.get(node);
this.data = NodeData.getLatest(node);
if(node.isDir())
throw new SecurityException("Node is Directory");
}
public SchematicData(SchematicNode node, int revision) {
if(node.isDir())
throw new SecurityException("Node is Directory");
if (revision < 1) {
this.data = NodeData.getLatest(node);
} else {
if (NodeData.getRevisions(node) < revision) {
throw new IllegalArgumentException("Revision " + revision + " does not exist");
}
this.data = NodeData.get(node, revision);
}
}
public Clipboard load() throws IOException, NoClipboardException {
return WorldEditWrapper.impl.getClipboard(data.schemData(), data.getNodeFormat());
}
@@ -60,12 +74,12 @@ public class SchematicData {
WorldEditWrapper.impl.setPlayerClipboard(player, data.schemData(), data.getNodeFormat());
}
public void saveFromPlayer(Player player) throws IOException, NoClipboardException {
data.saveFromStream(WorldEditWrapper.impl.getPlayerClipboard(player), WorldEditWrapper.impl.getNativeFormat());
public static void saveFromPlayer(Player player, SchematicNode node) throws IOException, NoClipboardException {
NodeData.saveFromStream(node, WorldEditWrapper.impl.getPlayerClipboard(player), WorldEditWrapper.impl.getNativeFormat());
}
@Deprecated
public void saveFromBytes(byte[] bytes, NodeData.SchematicFormat newFormat) {
data.saveFromStream(new ByteArrayInputStream(bytes), newFormat);
public static void saveFromBytes(SchematicNode node, byte[] bytes, NodeData.SchematicFormat newFormat) {
NodeData.saveFromStream(node, new ByteArrayInputStream(bytes), newFormat);
}
}

View File

@@ -63,7 +63,7 @@ data class TNTLeagueConfig(
blueTeam = TeamConfig(TNTLeagueWorldConfig.blueTeam, SubMessage("PLAIN_STRING", "§${eventTeamBlue.teamColor}${eventTeamBlue.teamName}"), eventTeamBlue.teamColor[0])
redTeam = TeamConfig(TNTLeagueWorldConfig.redTeam, SubMessage("PLAIN_STRING", "§${eventTeamRed.teamColor}${eventTeamRed.teamName}"), eventTeamRed.teamColor[0])
} else {
blueTeam = TeamConfig(TNTLeagueWorldConfig.blueTeam, SubMessage("BLUE"), '3')
blueTeam = TeamConfig(TNTLeagueWorldConfig.blueTeam, SubMessage("BLUE"), '9')
redTeam = TeamConfig(TNTLeagueWorldConfig.redTeam, SubMessage("RED"), 'c')
}
}

View File

@@ -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"))

View File

@@ -397,7 +397,7 @@ 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}
REPLAY_SERVER=§7{0} #{1}
#TutorialCommand
TUTORIAL_TITLE=Tutorials

View File

@@ -0,0 +1,97 @@
/*
* 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;
import de.steamwar.data.SyncCommands;
import de.steamwar.sql.Event;
import de.steamwar.sql.EventFight;
import de.steamwar.sql.SteamwarUser;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
public class BackendSync implements Runnable {
private static final Path syncPath = new File("/run/sync").toPath();
private final Thread thread;
private final WatchService watchService;
public BackendSync() {
try {
watchService
= FileSystems.getDefault().newWatchService();
} catch (IOException e) {
throw new SecurityException("Could not create watch service", e);
}
thread = new Thread(this, "BackendSync");
thread.start();
}
public void stop() {
try {
watchService.close();
thread.join();
} catch (IOException | InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private void handleCommand(String name) {
try {
String[] parts = name.split("\\.");
switch (parts[0]) {
case SyncCommands.RELOAD_EVENT -> EventFight.loadAllComingFights();
case SyncCommands.RELOAD_PLAYER -> SteamwarUser.invalidate(Integer.parseInt(parts[1]));
default -> VelocityCore.getLogger().warning("Unknown command: " + name);
}
} catch (Exception e) {
VelocityCore.getLogger().throwing(this.getClass().getName(), "handleCommand", e);
}
}
@Override
public void run() {
try {
syncPath.register(watchService,
java.nio.file.StandardWatchEventKinds.ENTRY_CREATE);
WatchKey key;
while ((key = watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
String command = event.context().toString();
handleCommand(command);
if (!VelocityCore.get().getConfig().isEventmode()) {
Path path = syncPath.resolve((Path) event.context());
Files.delete(path);
}
}
key.reset();
}
} catch (InterruptedException | ClosedWatchServiceException ignored) {
Thread.currentThread().interrupt();
} catch (Exception e) {
VelocityCore.getLogger().throwing(this.getClass().getName(), "run", e);
}
}
}

View File

@@ -276,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();

View File

@@ -95,6 +95,7 @@ public class VelocityCore implements ReloadablePlugin {
private Config config;
private ErrorLogger errorLogger;
private TablistManager tablistManager;
private BackendSync backendSync;
@Getter
private TeamCommand teamCommand;
@@ -147,6 +148,8 @@ public class VelocityCore implements ReloadablePlugin {
new ReplayMod();
new FML2();
backendSync = new BackendSync();
new ConnectionListener();
new ChatListener();
new BanListener();
@@ -268,6 +271,8 @@ public class VelocityCore implements ReloadablePlugin {
logger.log(Level.SEVERE, "Could not shutdown discord bot", e);
}
backendSync.stop();
if(tablistManager != null)
tablistManager.disable();
errorLogger.unregister();

View File

@@ -309,8 +309,12 @@ public class CheckCommand extends SWCommand {
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)
if(type != null) {
schematic.setSchemtype(type);
if (type == SchematicType.Normal) {
schematic.setPrepared(false);
}
}
}
remove();

View File

@@ -38,31 +38,51 @@ public class ReplayCommand extends SWCommand {
super("replay");
}
@Register
public void genericCommand(PlayerChatter sender, int replayId, @StaticValue(value = {"", "-a"}, allowISE=true) @OptionalValue("") boolean isAdmin, @OptionalValue("") String optionalMap) {
Fight fight = Fight.getById(replayId);
if (fight == null) {
sender.system("REPLAY_UNAVAILABLE");
return;
}
startReplay(sender, isAdmin, optionalMap, fight);
}
@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();
}
startReplay(sender, click.isShiftClick(), optionalMap, fight);
}, page -> Fight.getPage(page, 45).stream().map(fight -> new SWListInv.SWListEntry<>(getFightItem(fight), fight)).toList()).open();
}
private void startReplay(PlayerChatter sender, boolean isAdmin, String optionalMap, Fight fight) {
if (PunishmentCommand.isPunishedWithMessage(sender, Punishment.PunishmentType.NoFightServer))
return;
ArenaMode mode = ArenaMode.getBySchemType(fight.getSchemType());
ServerStarter starter = new ServerStarter().replay(fight.getFightID()).blueLeader(sender.getPlayer());
String map = mode.getRandomMap();
if (!optionalMap.isEmpty()) {
String tMap = mode.hasMap(optionalMap);
if (tMap != null) map = tMap;
}
if (sender.user().hasPerm(UserPerm.MODERATION) && isAdmin && fight.replayExists()) {
System.out.println("Starting admin replay");
starter.test(mode, map, sender.getPlayer()).start();
} else if(!fight.replayAllowed()) {
sender.system("REPLAY_UNAVAILABLE");
} else {
starter.arena(mode, map).start();
}
}
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));
@@ -71,7 +91,7 @@ public class ReplayCommand extends SWCommand {
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()));
lore.add(new Message("REPLAY_SERVER", fight.getServer(), Integer.toString(fight.getFightID())));
if(!fight.replayAllowed())
lore.add(new Message("REPLAY_UNAVAILABLE"));
item.setLore(lore);

View File

@@ -333,7 +333,7 @@ public class TeamCommand extends SWCommand {
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());
ClickEvent.runCommand("/team info " + tm.getTeamName()), tm.getTeamColor(), tm.getTeamKuerzel(), tm.getTeamName());
}
Component beforePage = Component

View File

@@ -66,7 +66,7 @@ public class WhoisCommand extends SWCommand {
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());
sender.system("WHOIS_TEAM", new Message("WHOIS_TEAM_HOVER", team.getTeamName()), ClickEvent.runCommand("/team info " + team.getTeamName()), team.getTeamColor(), team.getTeamKuerzel(), team.getTeamName());
if (!sender.user().hasPerm(UserPerm.TEAM))
return;

View File

@@ -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);

View File

@@ -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();

View File

@@ -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) {

View File

@@ -23,6 +23,7 @@ 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;
@@ -38,6 +39,7 @@ 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;
@@ -110,6 +112,13 @@ public class ConnectionListener extends BasicListener {
}
}
@Subscribe
public void kickEvent(KickedFromServerEvent event) {
if (event.getResult() instanceof KickedFromServerEvent.RedirectPlayer red) {
event.setResult(KickedFromServerEvent.RedirectPlayer.create(red.getServer(), Component.empty()));
}
}
@Subscribe
public void onDisconnect(DisconnectEvent e){
ChallengeCommand.remove(e.getPlayer());

View File

@@ -338,7 +338,8 @@ public class PluginMessage extends BasicListener {
"frozenlib:moving_restriction_sound_packet", "frozenlib:remove_entity_screen_shakes_packet",
"frozenlib:remove_screen_shakes_packet", "frozenlib:screen_shake_entity_packet",
"frozenlib:screen_shake_packet", "frozenlib:spotting_icon_packet", "frozenlib:wind_disturbance_packet",
"frozenlib:spotting_icon_remove_packet", "frozenlib:starting_moving_restriction_looping_sound_packet"
"frozenlib:spotting_icon_remove_packet", "frozenlib:starting_moving_restriction_looping_sound_packet",
"imm_ptl:remote_cts" //https://www.curseforge.com/minecraft/mc-mods/immersive-portals-mod
))
channelRegisterHandlers.put(channel, player -> {});

View File

@@ -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();

View File

@@ -0,0 +1,49 @@
/*
* 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.data
import de.steamwar.sql.SteamwarUser
import java.io.File
import java.nio.file.Files
object VelocitySync {
private const val SYNC_PATH = "/run/sync"
private val SYNC_FILE = File(SYNC_PATH)
private val isWindows = System.getProperty("os.name").lowercase().contains("win")
private val lastSendMap = mutableMapOf<String, Long>()
private fun sendCommand(command: String, vararg args: String) {
if (isWindows) { return }
val name = command + if (args.isNotEmpty()) "." + args.joinToString(".") else ""
if (lastSendMap[name] != null || lastSendMap[name]!! > System.currentTimeMillis() - 1000) {
return
}
lastSendMap[name] = System.currentTimeMillis()
Files.createFile(File(SYNC_FILE, name).toPath())
}
fun reloadEvent() = sendCommand(SyncCommands.RELOAD_EVENT)
fun reloadPlayer(user: SteamwarUser) = sendCommand(SyncCommands.RELOAD_PLAYER, user.id.toString())
}

View File

@@ -20,6 +20,7 @@
package de.steamwar.routes
import de.steamwar.ResponseError
import de.steamwar.data.VelocitySync
import de.steamwar.sql.*
import io.ktor.http.*
import io.ktor.server.application.*
@@ -112,6 +113,7 @@ fun Route.configureEventFightRoutes() {
if (fight.group != null) {
eventFight.setGroup(fight.group)
}
VelocitySync.reloadEvent()
call.respond(HttpStatusCode.Created, ResponseEventFight(eventFight))
}
route("/{fight}") {
@@ -143,11 +145,13 @@ fun Route.configureEventFightRoutes() {
}
fight.update(start, spielmodus, map, teamBlue, teamRed, spectatePort)
VelocitySync.reloadEvent()
call.respond(HttpStatusCode.OK, ResponseEventFight(fight))
}
delete {
val fight = call.receiveFight() ?: return@delete
fight.delete()
VelocitySync.reloadEvent()
call.respond(HttpStatusCode.OK)
}

View File

@@ -89,7 +89,7 @@ fun Route.configureSchematic() {
return@get
}
val data = NodeData.get(node) ?: run {
val data = NodeData.getLatest(node) ?: run {
call.respond(HttpStatusCode.InternalServerError)
return@get
}
@@ -166,8 +166,7 @@ fun Route.configureSchematic() {
} catch (_: Exception) {}
}
val data = NodeData(node.id, version)
data.saveFromStream(content.inputStream(), version)
NodeData.saveFromStream(node, content.inputStream(), version)
call.respond(ResponseSchematic(node))
} catch (e: Exception) {

View File

@@ -19,6 +19,7 @@
package de.steamwar.routes
import de.steamwar.data.VelocitySync
import de.steamwar.plugins.SWPermissionCheck
import de.steamwar.plugins.getUser
import de.steamwar.sql.SteamwarUser
@@ -86,6 +87,8 @@ fun Route.configureUserPerms() {
}
UserPerm.addPerm(user, UserPerm.entries.find { it == prefix }!!)
VelocitySync.reloadPlayer(user)
call.respond(HttpStatusCode.Accepted)
}
put("/{perm}") {
@@ -96,6 +99,8 @@ fun Route.configureUserPerms() {
call.respond(HttpStatusCode.Accepted)
return@put
}
VelocitySync.reloadPlayer(user)
call.respond(HttpStatusCode.NoContent)
}
delete("/{perm}") {
@@ -106,6 +111,8 @@ fun Route.configureUserPerms() {
call.respond(HttpStatusCode.Accepted)
return@delete
}
VelocitySync.reloadPlayer(user)
call.respond(HttpStatusCode.NoContent)
}
}