Compare commits

..
Author SHA1 Message Date
Chaoscaot 829d8a6cdf Initial ChaosSchematicReader
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-01-21 23:33:45 +01:00
110 changed files with 1270 additions and 1460 deletions
@@ -100,6 +100,7 @@ public class TickManager21 implements TickManager {
manager.setFrozen(true);
bukkitTask.cancel();
}, 1, 1);
manager.tick();
}
@Override
@@ -31,7 +31,10 @@ import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class DesignEndStone {
@@ -53,10 +56,11 @@ public class DesignEndStone {
this.maxY = region.getBuildArea().getMaxPoint(false).getY();
this.maxZ = region.getBuildArea().getMaxPoint(false).getZ();
limited = Arrays.stream(Material.values())
.filter(Material::isBlock)
.filter(material -> !material.isLegacy())
.filter(material -> material.getBlastResistance() > region.getGameModeConfig().Schematic.MaxDesignBlastResistance)
limited = region.getGameModeConfig().Schematic.Limited
.entrySet()
.stream()
.filter(entry -> entry.getValue() == 0)
.flatMap(entry -> entry.getKey().stream())
.collect(Collectors.toSet());
calculateFromBottom = region.getGameModeConfig().Arena.NoFloor;
@@ -1,63 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.dev;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import java.io.File;
import java.io.IOException;
@Linked
public class CreateKitCommand extends SWCommand {
public CreateKitCommand() {
super("createkit");
if (!BauSystem.DEV_SERVER) unregister();
}
@Register
public void onCommand(Player player, String name) {
YamlConfiguration yaml = new YamlConfiguration();
yaml.set("Items", player.getInventory().getContents());
yaml.set("Armor", player.getInventory().getArmorContents());
yaml.set("Effects", player.getActivePotionEffects());
yaml.set("LeaderAllowed", true);
yaml.set("MemberAllowed", true);
yaml.set("EnterStage", 0);
yaml.set("TNT", true);
YamlConfiguration kits = new YamlConfiguration();
kits.set("Kits." + name, yaml);
try {
kits.save(new File("new.kits.yaml"));
player.sendMessage("Kit created!");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@@ -46,16 +46,6 @@ import org.bukkit.event.player.PlayerInteractEvent;
@Linked
public class FreezeListener implements Listener, ScoreboardElement {
@EventHandler
public void onBlockExplode(BlockExplodeEvent e) {
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) return;
e.setCancelled(true);
BlockState state = e.getBlock().getState();
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
state.update(true, false);
}, 1L);
}
@EventHandler
public void onEntitySpawn(EntitySpawnEvent e) {
if (Region.getRegion(e.getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) return;
@@ -67,7 +67,11 @@ public class TNTListener implements Listener, ScoreboardElement {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onExplode(EntityExplodeEvent event) {
explode(event.blockList(), event.getEntity() instanceof TNTPrimed);
if (!(event.getEntity() instanceof TNTPrimed)) {
event.blockList().clear();
return;
}
explode(event.blockList(), true);
}
@Override
@@ -150,13 +150,11 @@ public class SimulatorObserverGui extends SimulatorScrollGui<ObserverPhase> {
Consumer<Integer> setter = observerPhase::setTickOffset;
return new SWItem[] {
new SWItem(SWItem.getDye(getter.get() < max ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
setter.accept(Math.min(max, getter.get() + (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED),
observer,
new SWItem(SWItem.getDye(getter.get() > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8:§e -5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
setter.accept(Math.max(min, getter.get() - (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),
@@ -32,7 +32,6 @@ import de.steamwar.inventory.SWItem;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import java.util.Arrays;
@@ -98,7 +97,6 @@ public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui {
//Tick Offset
int offset = observer.getTickOffset();
inventory.setItem(10, new SWItem(SWItem.getDye(offset < max ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
observer.setTickOffset(Math.min(max, offset + (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -115,7 +113,6 @@ public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui {
inventory.setItem(19, offsetItem);
inventory.setItem(28, new SWItem(SWItem.getDye(offset > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
observer.setTickOffset(Math.max(min, offset - (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
@@ -123,7 +120,6 @@ public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui {
//Order
int order = observer.getOrder();
inventory.setItem(13, new SWItem(SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
observer.setOrder(Math.min(SimulatorPhase.ORDER_LIMIT, order + (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -142,7 +138,6 @@ public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui {
inventory.setItem(22, orderItem);
inventory.setItem(31, new SWItem(SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
observer.setOrder(Math.max(-SimulatorPhase.ORDER_LIMIT, order - (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
@@ -28,7 +28,6 @@ import de.steamwar.data.CMDs;
import de.steamwar.inventory.SWItem;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import java.util.Arrays;
@@ -68,7 +67,6 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui {
// Base Tick
int baseTicks = observer.getBaseTick();
inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
observer.changeBaseTicks(clickType.isShiftClick() ? 5 : 1);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -83,7 +81,6 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui {
baseTick.getItemStack().setAmount(Math.max(1, Math.min(baseTicks, 64)));
inventory.setItem(18, baseTick);
inventory.setItem(27, new SWItem(SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
if (baseTicks - (clickType.isShiftClick() ? 5 : 1) < 0) {
observer.changeBaseTicks(-baseTicks);
} else {
@@ -94,7 +91,6 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui {
//Pos X
inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
observer.move(clickType.isShiftClick() ? 5 : 1, 0, 0);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -106,14 +102,12 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui {
}, this).open();
}));
inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
observer.move(clickType.isShiftClick() ? -5 : -1, 0, 0);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
//Pos Y
inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
observer.move(0, clickType.isShiftClick() ? 5 : 1, 0);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
@@ -125,14 +119,12 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui {
}, this).open();
}));
inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
observer.move(0, clickType.isShiftClick() ? -5 : -1, 0);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
//Pos Z
inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
observer.move(0, 0, clickType.isShiftClick() ? 5 : 1);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED));
@@ -144,7 +136,6 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui {
}, this).open();
}));
inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
observer.move(0, 0, clickType.isShiftClick() ? -5 : -1);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
@@ -165,13 +165,11 @@ public class SimulatorRedstoneGui extends SimulatorScrollGui<SimulatorRedstoneGu
Consumer<Integer> setter = redstoneSubPhase.place ? redstoneSubPhase.phase::setTickOffset : redstoneSubPhase.phase::setLifetime;
return new SWItem[] {
new SWItem(SWItem.getDye(getter.get() < max ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
setter.accept(Math.min(max, getter.get() + (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED),
redstone,
new SWItem(SWItem.getDye(getter.get() > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8:§e -5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
setter.accept(Math.max(min, getter.get() - (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),
@@ -31,7 +31,6 @@ import de.steamwar.data.CMDs;
import de.steamwar.inventory.SWItem;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import java.util.Arrays;
@@ -99,7 +98,6 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui {
//Tick Offset
int offset = redstone.getTickOffset();
inventory.setItem(10, new SWItem(SWItem.getDye(offset < maxOffset ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
redstone.setTickOffset(Math.min(maxOffset, offset + (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -116,7 +114,6 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui {
inventory.setItem(19, offsetItem);
inventory.setItem(28, new SWItem(SWItem.getDye(offset > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
redstone.setTickOffset(Math.max(min, offset - (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
@@ -124,7 +121,6 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui {
//Lifetime
int lifetime = redstone.getLifetime();
inventory.setItem(11, new SWItem(SWItem.getDye(lifetime < maxLifetime ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
redstone.setLifetime(Math.min(maxLifetime, lifetime + (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -141,7 +137,6 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui {
inventory.setItem(20, lifetimeItem);
inventory.setItem(29, new SWItem(SWItem.getDye(lifetime > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
redstone.setLifetime(Math.max(0, lifetime - (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
@@ -149,7 +144,6 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui {
//Order
int order = redstone.getOrder();
inventory.setItem(13, new SWItem(SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
redstone.setOrder(Math.min(SimulatorPhase.ORDER_LIMIT, order + (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -168,7 +162,6 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui {
inventory.setItem(22, orderItem);
inventory.setItem(31, new SWItem(SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
redstone.setOrder(Math.max(-SimulatorPhase.ORDER_LIMIT, order - (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
@@ -28,7 +28,6 @@ import de.steamwar.data.CMDs;
import de.steamwar.inventory.SWItem;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import java.util.Arrays;
@@ -67,7 +66,6 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui {
// Base Tick
int baseTicks = redstone.getBaseTick();
inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
redstone.changeBaseTicks(clickType.isShiftClick() ? 5 : 1);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -82,7 +80,6 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui {
baseTick.getItemStack().setAmount(Math.max(1, Math.min(baseTicks, 64)));
inventory.setItem(18, baseTick);
inventory.setItem(27, new SWItem(SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
if (baseTicks - (clickType.isShiftClick() ? 5 : 1) < 0) {
redstone.changeBaseTicks(-baseTicks);
} else {
@@ -93,7 +90,6 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui {
//Pos X
inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
redstone.move(clickType.isShiftClick() ? 5 : 1, 0, 0);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -105,14 +101,12 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui {
}, this).open();
}));
inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
redstone.move(clickType.isShiftClick() ? -5 : -1, 0, 0);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
//Pos Y
inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
redstone.move(0, clickType.isShiftClick() ? 5 : 1, 0);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -124,14 +118,12 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui {
}, this).open();
}));
inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
redstone.move(0, clickType.isShiftClick() ? -5 : -1, 0);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
//Pos Z
inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
redstone.move(0, 0, clickType.isShiftClick() ? 5 : 1);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -143,7 +135,6 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui {
}, this).open();
}));
inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
redstone.move(0, 0, clickType.isShiftClick() ? -5 : -1);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
@@ -138,13 +138,11 @@ public class SimulatorTNTGui extends SimulatorScrollGui<TNTPhase> {
return new SWItem[]{
new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tntSetting.setCount(tntSetting.getCount() + (clickType.isShiftClick() ? 5 : 1));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED),
tnt,
new SWItem(SWItem.getDye(tntSetting.getCount() > 1 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8:§e -5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tntSetting.setCount(Math.max(1, tntSetting.getCount() - (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED),
@@ -31,7 +31,6 @@ import de.steamwar.data.CMDs;
import de.steamwar.inventory.SWItem;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import java.util.Arrays;
@@ -79,7 +78,6 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui {
//Count
int count = tnt.getCount();
inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.setCount(count + (clickType.isShiftClick() ? 5 : 1));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -96,7 +94,6 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui {
inventory.setItem(18, countItem);
inventory.setItem(27, new SWItem(SWItem.getDye(count > 1 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.setCount(Math.max(1, count - (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
@@ -104,7 +101,6 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui {
//Tick Offset
int offset = tnt.getTickOffset();
inventory.setItem(10, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.setTickOffset(offset + (clickType.isShiftClick() ? 5 : 1));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -121,7 +117,6 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui {
inventory.setItem(19, offsetItem);
inventory.setItem(28, new SWItem(SWItem.getDye(offset > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.setTickOffset(Math.max(0, offset - (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
@@ -129,7 +124,6 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui {
//Lifetime
int lifetime = tnt.getLifetime();
inventory.setItem(11, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.setLifetime(lifetime + (clickType.isShiftClick() ? 5 : 1));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -146,7 +140,6 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui {
inventory.setItem(20, lifetimeItem);
inventory.setItem(29, new SWItem(SWItem.getDye(lifetime > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.setLifetime(Math.max(1, lifetime - (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
@@ -154,7 +147,6 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui {
//Order
int order = tnt.getOrder();
inventory.setItem(13, new SWItem(SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.setOrder(Math.min(SimulatorPhase.ORDER_LIMIT, order + (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -173,35 +165,30 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui {
inventory.setItem(22, orderItem);
inventory.setItem(31, new SWItem(SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.setOrder(Math.max(-SimulatorPhase.ORDER_LIMIT, order - (clickType.isShiftClick() ? 5 : 1)));
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
//Jump
SWItem jumpX = new SWItem(tnt.isXJump() ? Material.LIME_WOOL : Material.RED_WOOL, "§7TNT §eJump X§8: " + (tnt.isZJump() ? "§aon" : "§coff"), clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.setXJump(!tnt.isXJump());
SimulatorWatcher.update(simulator);
});
inventory.setItem(33, jumpX);
SWItem jumpY = new SWItem(tnt.isYJump() ? Material.LIME_WOOL : Material.RED_WOOL, "§7TNT §eJump Y§8: " + (tnt.isYJump() ? "§aon" : "§coff"), clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.setYJump(!tnt.isYJump());
SimulatorWatcher.update(simulator);
});
inventory.setItem(16, jumpY);
SWItem jumpZ = new SWItem(tnt.isZJump() ? Material.LIME_WOOL : Material.RED_WOOL, "§7TNT §eJump Z§8: " + (tnt.isZJump() ? "§aon" : "§coff"), clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.setZJump(!tnt.isZJump());
SimulatorWatcher.update(simulator);
});
inventory.setItem(35, jumpZ);
SWItem jumpAll = new SWItem(Material.TNT, "§7TNT §eJump §8: " + (tnt.hasJump() ? "§aon" : "§coff"), clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.setJump(!tnt.hasJump());
SimulatorWatcher.update(simulator);
});
@@ -28,7 +28,6 @@ import de.steamwar.data.CMDs;
import de.steamwar.inventory.SWItem;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import java.util.ArrayList;
import java.util.Arrays;
@@ -76,7 +75,6 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui {
// Base Tick
int baseTicks = tnt.getBaseTick();
inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.changeBaseTicks(clickType.isShiftClick() ? 5 : 1);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -91,7 +89,6 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui {
baseTick.getItemStack().setAmount(Math.max(1, Math.min(baseTicks, 64)));
inventory.setItem(18, baseTick);
inventory.setItem(27, new SWItem(SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
if (baseTicks - (clickType.isShiftClick() ? 5 : 1) < 0) {
tnt.changeBaseTicks(-baseTicks);
} else {
@@ -139,7 +136,6 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui {
// Pos X
inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+0.0625"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.move(clickType.isShiftClick() ? 0.0625 : 1, 0, 0);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -151,14 +147,12 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui {
}, this).open();
}));
inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-0.0625"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.move(clickType.isShiftClick() ? -0.0625 : -1, 0, 0);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
// Pos Y
inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+0.0625"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.move(0, clickType.isShiftClick() ? 0.0625 : 1, 0);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -170,14 +164,12 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui {
}, this).open();
}));
inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-0.0625"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.move(0, clickType.isShiftClick() ? -0.0625 : -1, 0);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
// Pos Z
inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+0.0625"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.move(0, 0, clickType.isShiftClick() ? 0.0625 : 1);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED));
@@ -189,7 +181,6 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui {
}, this).open();
}));
inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-0.0625"), false, clickType -> {
if (clickType == ClickType.DOUBLE_CLICK) return;
tnt.move(0, 0, clickType.isShiftClick() ? -0.0625 : -1);
SimulatorWatcher.update(simulator);
}).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED));
@@ -101,7 +101,7 @@ public class BlockBoundingBox {
addPixel(Material.END_STONE.createBlockData(), 0, 0, 0, 16, 16, 16, null);
addPixel(NMSWrapper.impl.pathMaterial().createBlockData(), 0, 0, 0, 16, 15, 16, createItem("LAUFBAU_BLOCK_GRASS_PATH", NMSWrapper.impl.pathMaterial()));
addPixel(Material.MUD.createBlockData(), 0, 0, 0, 16, 14, 16, createItem("LAUFBAU_BLOCK_SOUL_SAND", Material.SOUL_SAND));
addPixel(Material.SOUL_SAND.createBlockData(), 0, 0, 0, 16, 14, 16, createItem("LAUFBAU_BLOCK_SOUL_SAND", Material.SOUL_SAND));
Cocoa cocoaNorth = (Cocoa) Material.COCOA.createBlockData();
cocoaNorth.setAge(2);
@@ -25,14 +25,12 @@ import de.steamwar.bausystem.shared.Pair;
import de.steamwar.bausystem.utils.WorldEditUtils;
import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.MinVersion;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
@Linked
@MinVersion(19)
public class LaufbauCommand extends SWCommand {
public LaufbauCommand() {
@@ -135,7 +135,7 @@ public abstract class ViewFlag {
}
Location secoundLocation;
if (Math.abs(previousVelocity.getX()) >= Math.abs(previousVelocity.getZ())) {
if (previousVelocity.getX() >= previousVelocity.getZ()) {
secoundLocation = previous.getLocation().clone().add(delta.getX(), delta.getY(), 0);
} else {
secoundLocation = previous.getLocation().clone().add(0, delta.getY(), delta.getZ());
@@ -198,16 +198,6 @@ public abstract class ViewFlag {
}
};
public static ViewFlag HIGHLIGHT = new ViewFlag(true, false, "highlight", "h") {
@Override
public void modify(REntityServer server, List<TraceEntity> entities) {
for (TraceEntity entity : entities) {
entity.setGlowing(true);
}
}
};
/**
* Name of the flag
*/
@@ -0,0 +1,189 @@
/*
* 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.features.worldedit;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.region.Point;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.utils.FlatteningWrapper;
import de.steamwar.core.SWPlayer;
import de.steamwar.core.WorldEditRenderer;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.MinVersion;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.Vector;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
@Linked
@MinVersion(20)
public class SelectAdjacent implements Listener {
private Vector[] FACES = {
new Vector(1, 0, 0),
new Vector(-1, 0, 0),
new Vector(0, 1, 0),
new Vector(0, -1, 0),
new Vector(0, 0, 1),
new Vector(0, 0, -1),
new Vector(1, 1, 0),
new Vector(1, -1, 0),
new Vector(1, 0, 1),
new Vector(1, 0, -1),
new Vector(-1, 1, 0),
new Vector(-1, -1, 0),
new Vector(-1, 0, 1),
new Vector(-1, 0, -1),
new Vector(0, 1, 1),
new Vector(0, 1, -1),
new Vector(0, -1, 1),
new Vector(0, -1, -1),
};
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if (!event.hasItem()) return;
if (event.getItem().getType() != Material.WOODEN_AXE) return;
if (!event.getPlayer().isSneaking()) return;
if (event.getAction() != Action.LEFT_CLICK_BLOCK) return;
Material material = event.getPlayer().getInventory().getItemInOffHand().getType();
Selector selector;
if (material.isAir()) {
selector = new Selector(event.getClickedBlock(), event.getPlayer(), __ -> true);
} else {
selector = new Selector(event.getClickedBlock(), event.getPlayer(), type -> type == material);
}
SWPlayer.of(event.getPlayer()).setComponent(selector);
}
private class Selector implements SWPlayer.Component {
private static final int MAX_BLOCKS = 500_000;
private int minX;
private int minY;
private int minZ;
private int maxX;
private int maxY;
private int maxZ;
private BukkitTask bukkitTask;
private Predicate<Material> predicate;
private Set<Location> seen = new HashSet<>();
private Set<Location> toCalc = new HashSet<>();
private Region.Area area;
public Selector(Block block, Player player, Predicate<Material> predicate) {
this.predicate = predicate;
toCalc.add(block.getLocation());
minX = block.getX();
minY = block.getY();
minZ = block.getZ();
maxX = block.getX();
maxY = block.getY();
maxZ = block.getZ();
Region region = Region.getRegion(block.getLocation());
area = Region.Area.EMPTY;
if (region.getBuildArea().inRegion(block.getLocation(), true)) {
area = region.getBuildArea();
} else if (region.getTestblockArea().inRegion(block.getLocation(), true)) {
area = region.getTestblockArea();
} else if (region.getArea().inRegion(block.getLocation(), true)) {
area = region.getArea();
}
bukkitTask = Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), () -> {
run();
long volume = (long)(maxX - minX + 1) * (long)(maxY - minY + 1) * (long)(maxZ - minZ + 1);
player.sendTitle("", "§e" + volume + " §7Blocks", 0, 5, 0);
Point minPoint = new Point(minX, minY, minZ);
Point maxPoint = new Point(maxX, maxY, maxZ);
FlatteningWrapper.impl.setSelection(player, minPoint, maxPoint);
WorldEditRenderer.renderPlayer(player);
// boolean finished = toCalc.stream().allMatch(location -> {
// return location.getBlockX() >= minX && location.getBlockY() >= minY && location.getBlockZ() >= minZ &&
// location.getBlockX() <= maxX && location.getBlockY() <= maxY && location.getBlockZ() <= maxZ;
// });
if (toCalc.isEmpty() || seen.size() > MAX_BLOCKS) {
bukkitTask.cancel();
player.sendTitle("§aDone", "§e" + volume + " §7Blocks", 0, 20, 5);
SWPlayer.of(player).removeComponent(Selector.class);
}
}, 1, 1);
}
private void cancel() {
bukkitTask.cancel();
}
private void run() {
Set<Location> current = toCalc;
toCalc = new HashSet<>();
for (Location location : current) {
Block block = location.getBlock();
if (block.isEmpty() || block.isLiquid()) continue;
if (!predicate.test(block.getType())) continue;
seen.add(location);
if (!area.inRegion(block.getLocation(), true)) continue;
minX = Math.min(minX, location.getBlockX());
maxX = Math.max(maxX, location.getBlockX());
minY = Math.min(minY, location.getBlockY());
maxY = Math.max(maxY, location.getBlockY());
minZ = Math.min(minZ, location.getBlockZ());
maxZ = Math.max(maxZ, location.getBlockZ());
for (Vector face : FACES) {
Block next = block.getRelative(face.getBlockX(), face.getBlockY(), face.getBlockZ());
if (next.isEmpty() || next.isLiquid()) continue;
if (!predicate.test(next.getType())) continue;
Location loc = next.getLocation();
if (seen.contains(loc)) continue;
toCalc.add(loc);
}
}
}
@Override
public void onUnmount(SWPlayer player) {
cancel();
}
}
}
@@ -28,11 +28,11 @@ import org.jetbrains.exposed.v1.javatime.timestamp
import java.time.Instant
object AuditLogTable: IntIdTable("AuditLog", "AuditLogId") {
val time = timestamp("Time").index()
val server = varchar("ServerName", 255).index()
val serverOwner = reference("ServerOwner", SteamwarUserTable).nullable().index()
val actor = reference("Actor", SteamwarUserTable).index()
val action = enumerationByName("ActionType", 255, AuditLog.Type::class).index()
val time = timestamp("Time")
val server = varchar("ServerName", 255)
val serverOwner = reference("ServerOwner", SteamwarUserTable).nullable()
val actor = reference("Actor", SteamwarUserTable)
val action = enumerationByName("ActionType", 255, AuditLog.Type::class)
val actionText = text("ActionText")
}
@@ -33,13 +33,9 @@ import java.sql.Timestamp
import java.time.Instant
object BannedUserIPsTable: CompositeIdTable("BannedUserIPs") {
val userId = reference("UserID", SteamwarUserTable).index()
val timestamp = timestamp("Timestamp").index()
val ip = varchar("IP", 45).entityId()
init {
addIdColumn(userId)
}
val userId = reference("UserID", SteamwarUserTable)
val timestamp = timestamp("Timestamp")
val ip = varchar("IP", 45)
override val primaryKey = PrimaryKey(userId, ip)
}
@@ -32,8 +32,8 @@ import org.jetbrains.exposed.v1.jdbc.insertIgnore
import java.util.*
object BauweltMemberTable: CompositeIdTable("BauweltMember") {
val bauweltId = reference("BauweltID", SteamwarUserTable).index()
val memberId = reference("MemberID", SteamwarUserTable).index()
val bauweltId = reference("BauweltID", SteamwarUserTable)
val memberId = reference("MemberID", SteamwarUserTable)
val build = bool("Build")
val worldEdit = bool("WorldEdit")
val world = bool("World")
@@ -20,7 +20,6 @@
package de.steamwar.sql
import de.steamwar.sql.internal.useDb
import org.jetbrains.exposed.v1.core.ReferenceOption
import org.jetbrains.exposed.v1.core.SortOrder
import org.jetbrains.exposed.v1.core.and
import org.jetbrains.exposed.v1.core.dao.id.CompositeID
@@ -35,23 +34,19 @@ import org.jetbrains.exposed.v1.jdbc.insertIgnore
import java.sql.Timestamp
object CheckedSchematicTable: CompositeIdTable("CheckedSchematic") {
val nodeId = optReference("NodeId", SchematicNodeTable, onDelete = ReferenceOption.SET_NULL, onUpdate = ReferenceOption.SET_NULL).index()
val nodeOwner = reference("NodeOwner", SteamwarUserTable).index()
val nodeName = varchar("NodeName", 64).entityId().index()
val validator = reference("Validator", SteamwarUserTable).index()
val startTime = timestamp("StartTime").entityId().index()
val nodeId = optReference("NodeId", SchematicNodeTable)
val nodeOwner = reference("NodeOwner", SteamwarUserTable)
val nodeName = varchar("NodeName", 64).entityId()
val validator = reference("Validator", SteamwarUserTable)
val startTime = timestamp("StartTime").entityId()
val endTime = timestamp("EndTime")
val declineReason = text("DeclineReason")
val seen = bool("Seen").index()
val seen = bool("Seen")
val nodeType = varchar("NodeType", 16)
init {
addIdColumn(nodeOwner)
addIdColumn(nodeName)
index(false, nodeOwner, endTime)
index(false, startTime, endTime, nodeName)
index(false, seen, nodeOwner, startTime)
}
}
+2 -2
View File
@@ -36,8 +36,8 @@ import java.time.Instant
object EventTable : IntIdTable("Event", "EventId") {
val name = varchar("EventName", 100).uniqueIndex()
val deadline = timestamp("Deadline")
val start = timestamp("Start").index()
val end = timestamp("End").index()
val start = timestamp("Start")
val end = timestamp("End")
val maxPlayers = integer("MaximumTeamMembers")
val schemType = varchar("SchemType", 16).nullable()
val publicsOnly = bool("PublicSchemsOnly")
@@ -33,17 +33,17 @@ import java.time.Instant
import java.util.*
object EventFightTable : IntIdTable("EventFight", "FightID") {
val eventId = reference("EventID", EventTable).index()
val startTime = timestamp("StartTime").index()
val eventId = reference("EventID", EventTable)
val startTime = timestamp("StartTime")
val gamemode = text("Spielmodus")
val map = text("Map")
val groupId = optReference("GroupId", EventGroupTable).index()
val teamBlue = reference("TeamBlue", TeamTable).index()
val teamRed = reference("TeamRed", TeamTable).index()
val groupId = optReference("GroupId", EventGroupTable)
val teamBlue = reference("TeamBlue", TeamTable)
val teamRed = reference("TeamRed", TeamTable)
val spectatePort = integer("SpectatePort").nullable()
val bestOf = integer("BestOf")
val ergebnis = integer("Ergebnis")
val fight = optReference("Fight", FightTable).index()
val fight = optReference("Fight", FightTable)
}
class EventFight(id: EntityID<Int>) : IntEntity(id), Comparable<EventFight> {
@@ -34,10 +34,6 @@ object EventGroupTable : IntIdTable("EventGroup", "Id") {
val pointsPerWin = integer("PointsPerWin").default(3)
val pointsPerLoss = integer("PointsPerLoss").default(0)
val pointsPerDraw = integer("PointsPerDraw").default(1)
init {
uniqueIndex(event, name)
}
}
class EventGroup(id: EntityID<Int>) : IntEntity(id) {
@@ -94,7 +90,7 @@ class EventGroup(id: EntityID<Int>) : IntEntity(id) {
set(value) {
groupPointsPerDraw = value
}
val dependents by lazy { EventRelation.getGroupRelations(this) }
val dependents by lazy { EventRelation.getGroupRelations(this).toList() }
val lastFight by lazy { Optional.ofNullable(fights.maxByOrNull { it.startTime }) }
fun getId() = id.value
@@ -29,7 +29,7 @@ import org.jetbrains.exposed.v1.dao.IntEntityClass
import org.jetbrains.exposed.v1.jdbc.select
object EventRelationTable : IntIdTable("EventRelation") {
val fightId = reference("FightId", EventFightTable).index()
val fightId = reference("FightId", EventFightTable)
val fightTeam = enumeration("FightTeam", EventRelation.FightTeam::class)
val fromType = enumeration("FromType", EventRelation.FromType::class)
val fromId = integer("FromId")
@@ -51,11 +51,11 @@ class EventRelation(id: EntityID<Int>) : IntEntity(id) {
@JvmStatic
fun getFightRelations(fight: EventFight) =
useDb { find { (EventRelationTable.fromId eq fight.id.value) and (EventRelationTable.fromType eq FromType.FIGHT) }.toList() }
useDb { find { (EventRelationTable.fromId eq fight.id.value) and (EventRelationTable.fromType eq FromType.FIGHT) } }
@JvmStatic
fun getGroupRelations(group: EventGroup) =
useDb { find { (EventRelationTable.fromId eq group.id.value) and (EventRelationTable.fromType eq FromType.GROUP) }.toList() }
useDb { find { (EventRelationTable.fromId eq group.id.value) and (EventRelationTable.fromType eq FromType.GROUP) } }
@JvmStatic
fun create(fight: EventFight, fightTeam: FightTeam, fromType: FromType, fromId: Int, fromPlace: Int) = useDb {
+5 -5
View File
@@ -34,14 +34,14 @@ import org.jetbrains.exposed.v1.jdbc.update
import java.sql.Timestamp
object FightTable : IntIdTable("Fight", "FightId") {
val gamemode = varchar("Gamemode", 30).index()
val gamemode = varchar("Gamemode", 30)
val server = text("Server")
val startTime = timestamp("StartTime")
val duration = integer("Duration")
val blueLeader = reference("BlueLeader", SteamwarUserTable).index()
val redLeader = reference("RedLeader", SteamwarUserTable).index()
val blueSchem = optReference("BlueSchem", SchematicNodeTable, onDelete = ReferenceOption.SET_NULL).index()
val redSchem = optReference("RedSchem", SchematicNodeTable, onDelete = ReferenceOption.SET_NULL).index()
val blueLeader = reference("BlueLeader", SteamwarUserTable)
val redLeader = reference("RedLeader", SteamwarUserTable)
val blueSchem = optReference("BlueSchem", SchematicNodeTable, onDelete = ReferenceOption.SET_NULL)
val redSchem = optReference("RedSchem", SchematicNodeTable, onDelete = ReferenceOption.SET_NULL)
val win = enumeration("Win", Fight.WinningTeam::class)
val winCondition = varchar("WinCondition", 100)
val replayAvailable = bool("ReplayAvailable")
@@ -30,7 +30,7 @@ import org.jetbrains.exposed.v1.jdbc.insertIgnore
object FightPlayerTable : CompositeIdTable("FightPlayer") {
val fightId = reference("FightId", FightTable)
val userId = reference("UserId", SteamwarUserTable).index()
val userId = reference("UserId", SteamwarUserTable)
val team = integer("Team")
val kit = varchar("Kit", 64)
val kills = integer("Kills")
@@ -52,10 +52,6 @@ public final class GameModeConfig<M, W> {
private static final Map<String, GameModeConfig<?, String>> byGameName;
private static final Map<SchematicType, GameModeConfig<?, String>> bySchematicType;
public static <M> Collection<GameModeConfig<M, String>> getAll() {
return (Collection) byFileName.values();
}
public static <M> GameModeConfig<M, String> getByFileName(File file) {
return (GameModeConfig<M, String>) byFileName.get(file.getName());
}
@@ -91,24 +87,8 @@ public final class GameModeConfig<M, W> {
byFileName = new HashMap<>();
byGameName = new HashMap<>();
bySchematicType = new HashMap<>();
SchematicType.values();
DEFAULTS = SQLWrapper.impl.loadGameModeConfig(null);
init();
}
public static void init() {
byFileName.clear();
byGameName.clear();
bySchematicType.clear();
File folder = SQLWrapper.impl.getSchemTypesFolder();
if (!folder.exists()) return;
if (!folder.isDirectory()) return;
for (File file : Objects.requireNonNull(folder.listFiles())) {
if (!file.getName().endsWith(".yml")) continue;
if (file.getName().endsWith(".kits.yml")) continue;
SQLWrapper.impl.loadGameModeConfig(file);
}
byFileName.values().forEach(gameModeConfig -> {
List<SchematicType> subTypes = Collections.unmodifiableList(gameModeConfig.Schematic.SubTypesStrings.stream()
@@ -422,13 +402,6 @@ public final class GameModeConfig<M, W> {
*/
public final int WaterDepth;
/**
* If TNT should break blocks even underwater
*
* @implSpec {@code true} by default
*/
public final boolean WaterDamage;
/**
* The outer border of the arena, measured in blocks around the schematic areas
*/
@@ -460,13 +433,6 @@ public final class GameModeConfig<M, W> {
*/
public final boolean DisableSnowMelt;
/**
* Disable ice forming
*
* @implSpec {@code false} by default
*/
public final boolean DisableIceForm;
/**
* Allow leaving the arena area as spectator
*
@@ -491,13 +457,11 @@ public final class GameModeConfig<M, W> {
private ArenaConfig(YMLWrapper loader, SchematicConfig.SizeConfig Size, List<Integer> EnterStages) {
loaded = loader.canLoad();
WaterDepth = loader.getInt("WaterDepth", 0);
WaterDamage = loader.getBoolean("WaterDamage", true);
Schem2Border = new Schem2BorderConfig(loader.with("Schem2Border"));
SpawnOffset = new SpawnOffsetConfig(loader.with("SpawnOffset"), Size);
BorderFromSchematic = loader.getInt("BorderFromSchematic", 21);
GroundWalkable = loader.getBoolean("GroundWalkable", true);
DisableSnowMelt = loader.getBoolean("DisableSnowMelt", false);
DisableIceForm = loader.getBoolean("DisableIceForm", false);
Leaveable = loader.getBoolean("Leaveable", false);
AllowMissiles = loader.getBoolean("AllowMissiles", !EnterStages.isEmpty());
NoFloor = loader.getBoolean("NoFloor", false);
@@ -633,18 +597,18 @@ public final class GameModeConfig<M, W> {
public final boolean IgnorePublicOnly;
/**
* Replacements that should be done during PRE_RUNNING with no block updates
* If obsidian and bedrock should be replaced during PRE_RUNNING
*
* @implSpec {@code {}} by default
* @implSpec {@code false} by default
*/
public final Map<M, M> ReplacementsWithoutBlockUpdates;
public final boolean ReplaceObsidianBedrock;
/**
* Replacements that should be done during PRE_RUNNING with block updates
* If the replacement should happen with block updates
*
* @implSpec {@code {}} by default
* @implSpec {@code false} by default
*/
public final Map<M, M> ReplacementsWithBlockUpdates;
public final boolean ReplaceWithBlockupdates;
/**
* If the schematic perparation arena mode is time limited
@@ -677,7 +641,7 @@ public final class GameModeConfig<M, W> {
/**
* Maximal blast resistance for the design blocks
*
* @implSpec {@link SchematicConfig#MaxBlastResistance} by default
* @implSpec {@code Double.MAX_VALUE} by default
*/
public final double MaxDesignBlastResistance;
@@ -691,9 +655,9 @@ public final class GameModeConfig<M, W> {
loaded = loader.canLoad();
Size = new SizeConfig(loader.with("Size"));
Inset = new InsetConfig(loader.with("Inset"));
Type = null;
Type = loader.getSchematicType("Type", "Normal");
SubTypesStrings = loader.getStringList("SubTypes");
SubTypes = new ArrayList<>();
SubTypes = loader.getSchematicTypeList("SubTypes");
Shortcut = loader.getString("Shortcut", "");
Material = loader.getMaterial("Material", "STONE_BUTTON");
ManualCheck = loader.getBoolean("ManualCheck", true);
@@ -701,11 +665,13 @@ public final class GameModeConfig<M, W> {
PasteAligned = loader.getBoolean("PasteAligned", false);
OnlyPublicSchematics = loader.getBoolean("OnlyPublicSchematics", false);
IgnorePublicOnly = loader.getBoolean("IgnorePublicOnly", false);
ReplaceObsidianBedrock = loader.getBoolean("ReplaceObsidianBedrock", false);
ReplaceWithBlockupdates = loader.getBoolean("ReplaceWithBlockupdates", false);
UnlimitedPrepare = loader.getBoolean("UnlimitedPrepare", false);
MaxBlocks = loader.getInt("MaxBlocks", 0);
MaxDispenserItems = loader.getInt("MaxDispenserItems", 128);
MaxBlastResistance = loader.getDouble("MaxBlastResistance", Double.MAX_VALUE);
MaxDesignBlastResistance = loader.getDouble("MaxDesignBlastResistance", MaxBlastResistance);
MaxDesignBlastResistance = loader.getDouble("MaxDesignBlastResistance", Double.MAX_VALUE);
Map<Set<M>, Integer> Limited = new HashMap<>();
for (Map<?, ?> entry : loader.getMapList("Limited")) {
@@ -724,9 +690,6 @@ public final class GameModeConfig<M, W> {
Limited.put(Collections.singleton((M) material), 0);
});
this.Limited = Collections.unmodifiableMap(Limited);
this.ReplacementsWithoutBlockUpdates = loader.getMap("ReplacementsWithoutBlockUpdates", loader.materialMapper, loader.materialMapper);
this.ReplacementsWithBlockUpdates = loader.getMap("ReplacementsWithBlockUpdates", loader.materialMapper, loader.materialMapper);
}
@ToString
@@ -30,8 +30,8 @@ import org.jetbrains.exposed.v1.dao.CompositeEntityClass
import java.util.*
object IgnoreSystemTable: CompositeIdTable("IgnoredPlayers") {
val ignorer = reference("Ignorer", SteamwarUserTable).index()
val ignored = reference("Ignored", SteamwarUserTable).index()
val ignorer = reference("Ignorer", SteamwarUserTable)
val ignored = reference("Ignored", SteamwarUserTable)
override val primaryKey = PrimaryKey(ignorer, ignored)
@@ -35,7 +35,7 @@ import java.io.InputStream
import java.util.zip.GZIPInputStream
object NodeDataTable: CompositeIdTable("NodeData") {
val nodeId = reference("NodeId", SchematicNodeTable).index()
val nodeId = reference("NodeId", SchematicNodeTable)
val createdAt = timestamp("CreatedAt").defaultExpression(CurrentTimestamp).entityId()
val nodeFormat = enumeration("NodeFormat", NodeData.SchematicFormat::class)
val schemData = blob("SchemData")
@@ -88,6 +88,8 @@ class NodeData(id: EntityID<CompositeID>): CompositeEntity(id) {
schemData.inputStream.let { if(decompress) GZIPInputStream(it) else it }
}
fun schemData() = schemData(true)
override fun delete() = useDb { super.delete() }
enum class SchematicFormat(val fileEnding: String) {
@@ -20,7 +20,6 @@
package de.steamwar.sql
import de.steamwar.sql.internal.useDb
import org.jetbrains.exposed.v1.core.ReferenceOption
import org.jetbrains.exposed.v1.core.dao.id.EntityID
import org.jetbrains.exposed.v1.core.dao.id.IdTable
import org.jetbrains.exposed.v1.core.eq
@@ -33,8 +32,8 @@ import java.sql.Timestamp
import java.time.Instant
object NodeDownloadTable: IdTable<Int>("NodeDownload") {
override val id = reference("NodeId", SchematicNodeTable, onDelete = ReferenceOption.CASCADE).uniqueIndex()
val link = varchar("Link", 255).uniqueIndex()
override val id = reference("NodeId", SchematicNodeTable).uniqueIndex()
val link = varchar("Link", 255)
val timestamp = timestamp("Timestamp").defaultExpression(CurrentTimestamp)
}
@@ -20,7 +20,6 @@
package de.steamwar.sql
import de.steamwar.sql.internal.useDb
import org.jetbrains.exposed.v1.core.ReferenceOption
import org.jetbrains.exposed.v1.core.and
import org.jetbrains.exposed.v1.core.dao.id.CompositeID
import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
@@ -33,9 +32,9 @@ import java.util.*
import kotlin.jvm.optionals.getOrNull
object NodeMemberTable : CompositeIdTable("NodeMember") {
val node = reference("NodeId", SchematicNodeTable, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE).index()
val userId = reference("UserId", SteamwarUserTable).index()
val parentNode = optReference("ParentId", SchematicNodeTable).index()
val node = reference("NodeId", SchematicNodeTable)
val userId = reference("UserId", SteamwarUserTable)
val parentNode = optReference("ParentId", SchematicNodeTable)
override val primaryKey = PrimaryKey(node, userId)
@@ -95,7 +94,7 @@ class NodeMember(id: EntityID<CompositeID>) : CompositeEntity(id) {
{ Optional.ofNullable(it?.value) })
private set
fun setParentId(id: Int?) = useDb {
fun setParentId(id: Int?) {
parent = Optional.ofNullable(id)
}
@@ -41,7 +41,6 @@ object PersonalKitTable: CompositeIdTable("PersonalKit") {
init {
addIdColumn(userId)
index(false, userId, gamemode)
}
}
@@ -34,16 +34,12 @@ import java.util.function.Consumer
object PunishmentTable : IntIdTable("Punishments", "PunishmentId") {
val userId = reference("UserId", SteamwarUserTable)
val punisher = reference("Punisher", SteamwarUserTable).index()
val punisher = reference("Punisher", SteamwarUserTable)
val type = enumerationByName("Type", 32, Punishment.PunishmentType::class)
val startTime = timestamp("StartTime")
val endTime = timestamp("EndTime")
val perma = bool("Perma")
val reason = text("Reason")
init {
index(false, userId, type)
}
}
class Punishment(id: EntityID<Int>) : IntEntity(id) {
@@ -30,7 +30,7 @@ import org.jetbrains.exposed.v1.dao.CompositeEntityClass
object RefereeTable: CompositeIdTable("Referee") {
val eventId = reference("EventId", EventTable)
val userId = reference("UserId", SteamwarUserTable).index()
val userId = reference("UserId", SteamwarUserTable)
override val primaryKey = PrimaryKey(eventId, userId)
@@ -36,5 +36,8 @@ public interface SQLWrapper<M> {
return Collections.emptyList();
}
default void processSchematicType(GameModeConfig<?, String> gameModeConfig) {
}
void additionalExceptionMetadata(StringBuilder builder);
}
@@ -34,17 +34,13 @@ import java.util.*
import java.util.function.Consumer
object SchematicNodeTable : IntIdTable("SchematicNode", "NodeId") {
val owner = reference("NodeOwner", SteamwarUserTable).index()
val owner = reference("NodeOwner", SteamwarUserTable)
val name = varchar("NodeName", 64)
val parent = optReference("ParentNode", SchematicNodeTable).index()
val parent = optReference("ParentNode", SchematicNodeTable)
val lastUpdate = timestamp("LastUpdate").defaultExpression(CurrentTimestamp)
val item = text("NodeItem")
val type = varchar("NodeType", 16).nullable().index()
val type = varchar("NodeType", 16).nullable()
val config = integer("Config")
init {
uniqueIndex(parent, owner, name)
}
}
class SchematicNode(id: EntityID<Int>) : IntEntity(id) {
@@ -150,91 +146,7 @@ class SchematicNode(id: EntityID<Int>) : IntEntity(id) {
@JvmStatic
fun parentsOfNode(user: SteamwarUser, id: Int) = fromSql(
"""
WITH RECURSIVE
ESN_R AS (
SELECT SchematicNode.NodeId AS NodeId,
NM.UserId AS EffectiveOwner,
NM.ParentId AS ParentNode
FROM SchematicNode
INNER JOIN NodeMember NM ON NM.NodeId = SchematicNode.NodeId
UNION ALL
SELECT S.NodeId AS NodeId,
ESN_R.EffectiveOwner AS EffectiveOwner,
S.ParentNode AS ParentNode
FROM SchematicNode S
INNER JOIN ESN_R ON S.ParentNode = ESN_R.NodeId
),
ESN_R2 AS (
SELECT SchematicNode.NodeId AS NodeId,
NM.UserId AS UserId,
SchematicNode.NodeOwner AS EffectiveOwner,
SchematicNode.ParentNode AS ParentNode
FROM SchematicNode
INNER JOIN NodeMember NM ON NM.NodeId = SchematicNode.NodeId
UNION ALL
SELECT S.NodeId AS NodeId,
ESN_R2.EffectiveOwner AS EffectiveOwner,
ESN_R2.UserId AS UserId,
S.ParentNode AS ParentNode
FROM SchematicNode S
INNER JOIN ESN_R2 ON S.ParentNode = ESN_R2.NodeId
WHERE S.NodeOwner <> ESN_R2.EffectiveOwner
),
ESN_R3 AS (
SELECT SchematicNode.NodeId AS NodeId,
SchematicNode.NodeOwner AS NodeOwner,
SchematicNode.NodeOwner AS EffectiveOwner,
SchematicNode.ParentNode AS ParentNode
FROM SchematicNode
UNION ALL
SELECT S.NodeId AS NodeId,
S.NodeOwner AS NodeOwner,
ESN_R3.EffectiveOwner AS EffectiveOwner,
S.ParentNode AS ParentNode
FROM SchematicNode S
INNER JOIN ESN_R3 ON S.ParentNode = ESN_R3.NodeId
WHERE ESN_R3.NodeOwner <> S.NodeOwner
),
ResolvedNodes AS (
SELECT ESN_R.NodeId AS NodeId,
ESN_R.EffectiveOwner AS EffectiveOwner,
ESN_R.ParentNode AS ParentNode
FROM ESN_R
UNION
SELECT ESN_R2.NodeId AS NodeId,
ESN_R2.UserId AS EffectiveOwner,
ESN_R2.ParentNode AS ParentNode
FROM ESN_R2
INNER JOIN SchematicNode SN2 ON ESN_R2.NodeId = SN2.NodeId
WHERE ESN_R2.ParentNode IS NOT NULL
AND SN2.NodeOwner <> ESN_R2.EffectiveOwner
UNION
SELECT ESN_R3.NodeId AS NodeId,
ESN_R3.EffectiveOwner AS EffectiveOwner,
ESN_R3.ParentNode AS ParentNode
FROM ESN_R3
WHERE ESN_R3.NodeOwner <> ESN_R3.EffectiveOwner
UNION
SELECT SchematicNode.NodeId AS NodeId,
SchematicNode.NodeOwner AS EffectiveOwner,
SchematicNode.ParentNode AS ParentNode
FROM SchematicNode
),
R AS (
SELECT NodeId, ParentNode
FROM ResolvedNodes
WHERE NodeId = ?
UNION
SELECT E.NodeId, E.ParentNode
FROM R
INNER JOIN ResolvedNodes E ON R.ParentNode = E.NodeId
WHERE E.EffectiveOwner = ?
)
SELECT SN.NodeId, SN.NodeOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.Config
FROM R
INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId
""".trimIndent(),
"WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.Config FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId",
listOf(
IntegerColumnType() to id,
IntegerColumnType() to user.getId()
@@ -372,7 +284,7 @@ class SchematicNode(id: EntityID<Int>) : IntEntity(id) {
val list = mutableListOf<String>()
if (s.contains("/")) {
val preTab = s.take(s.lastIndexOf("/") + 1)
val pa = getNodeFromPath(user, preTab) ?: return mutableListOf()
val pa = getNodeFromPath(user, preTab) ?: return emptyList()
val nodes: List<SchematicNode> = list(user, pa.getId())
val br = pa.generateBreadcrumbs(user)
nodes.forEach(Consumer { node: SchematicNode? -> list.add((if (sws) "/" else "") + br + node!!.name + (if (node.isDir()) "/" else "")) })
@@ -19,7 +19,11 @@
package de.steamwar.sql
import java.io.File
import java.util.*
import java.util.Locale
import java.util.Locale.getDefault
import java.util.stream.Collectors
data class SchematicType(
val name: String,
@@ -43,65 +47,58 @@ data class SchematicType(
@JvmField
val Normal = SchematicType("Normal", "", Type.NORMAL, null, "STONE_BUTTON", false)
private val types: MutableList<SchematicType> = mutableListOf()
private val fromDB: MutableMap<String, SchematicType> = mutableMapOf()
private val types: List<SchematicType>
private val fromDB: Map<String, SchematicType>?
init {
GameModeConfig.init()
init()
}
val tmpTypes = mutableListOf<SchematicType>()
val tmpFromDB = mutableMapOf<String, SchematicType>()
@JvmStatic
fun init() {
types.clear()
fromDB.clear()
tmpTypes.add(Normal)
tmpFromDB[Normal.toDB()] = Normal
types.add(Normal)
fromDB[Normal.toDB()] = Normal
for (gameModeConfig in GameModeConfig.getAll<Any>()) {
val type = gameModeConfig.Schematic.Type
?: continue
if (fromDB.containsKey(type.toDB())) continue
types.add(type)
fromDB[type.toDB()] = type
if (gameModeConfig.CheckQuestions.isNotEmpty() && type.checkType != null) {
types.add(type.checkType)
fromDB[type.checkType.toDB()] = type.checkType
val folder = SQLWrapper.impl.schemTypesFolder
if (folder.exists()) {
for (configFile in Arrays.stream<File?>(folder.listFiles { _, name ->
name.endsWith(
".yml"
) && !name.endsWith(".kits.yml")
}).sorted().collect(Collectors.toList())) {
val gameModeConfig = SQLWrapper.impl.loadGameModeConfig(configFile)
if (gameModeConfig.Schematic.Type == null) continue
if (tmpFromDB.containsKey(gameModeConfig.Schematic.Type.toDB())) continue
val current = gameModeConfig.Schematic.Type
if (gameModeConfig.CheckQuestions.isNotEmpty()) {
val checkType = current.checkType
tmpTypes.add(checkType!!)
tmpFromDB[checkType.toDB()] = checkType
}
tmpTypes.add(current)
tmpFromDB[current.toDB()] = current
SQLWrapper.impl.processSchematicType(gameModeConfig)
}
}
types = tmpTypes.toList()
fromDB = tmpFromDB.toMap()
}
@JvmStatic
fun values() =
types
fun values() = types
@JvmStatic
fun fromDB(value: String) =
fromDB[value.lowercase()]
fun fromDB(value: String) = fromDB?.let { it[value.lowercase()] }
}
fun name() =
name
fun name() = name
fun toDB() = name.lowercase()
fun toDB() =
name.lowercase()
fun check() = type == Type.CHECK_TYPE
fun fightType() = type == Type.FIGHT_TYPE
fun writeable() = type == Type.NORMAL
fun check() =
type == Type.CHECK_TYPE
fun fightType() =
type == Type.FIGHT_TYPE
fun writeable() =
type == Type.NORMAL
fun checkType() =
if (manualCheck) checkType else this
fun isAssignable() =
type == Type.NORMAL || (type == Type.FIGHT_TYPE && checkType != null) || !manualCheck
fun checkType() = if (manualCheck) checkType else this
fun isAssignable() = type == Type.NORMAL || (type == Type.FIGHT_TYPE && checkType != null) || !manualCheck
enum class Type {
NORMAL,
+1 -5
View File
@@ -28,13 +28,9 @@ import org.jetbrains.exposed.v1.dao.IntEntity
import org.jetbrains.exposed.v1.dao.IntEntityClass
object ScriptTable: IntIdTable("Script") {
val userId = reference("UserId", SteamwarUserTable).index()
val userId = reference("UserId", SteamwarUserTable)
val name = varchar("Name", 64)
val code = text("Code")
init {
uniqueIndex(userId, name)
}
}
class Script(id: EntityID<Int>) : IntEntity(id) {
@@ -28,7 +28,7 @@ import org.jetbrains.exposed.v1.jdbc.insert
import java.sql.Timestamp
object SessionTable: Table("Session") {
val userId = reference("UserId", SteamwarUserTable).index()
val userId = reference("UserId", SteamwarUserTable)
val startTime = timestamp("StartTime")
val endTime = timestamp("EndTime").defaultExpression(CurrentTimestamp)
}
@@ -37,15 +37,15 @@ import javax.crypto.SecretKeyFactory
import javax.crypto.spec.PBEKeySpec
object SteamwarUserTable : IntIdTable("UserData", "id") {
val uuid = varchar("UUID", 36).uniqueIndex()
val username = varchar("UserName", 32).index()
val team = reference("Team", TeamTable).index()
val uuid = varchar("UUID", 36)
val username = varchar("UserName", 32)
val team = reference("Team", TeamTable)
val leader = bool("Leader")
val locale = varchar("Locale", 16).nullable()
val manualLocale = bool("ManualLocale")
val bedrock = bool("Bedrock")
val password = text("Password").nullable()
val discordId = long("DiscordId").nullable().uniqueIndex()
val discordId = long("DiscordId").nullable()
}
class SteamwarUser(id: EntityID<Int>): IntEntity(id) {
@@ -186,10 +186,10 @@ class SteamwarUser(id: EntityID<Int>): IntEntity(id) {
val salt = ByteArray(16)
random.nextBytes(salt)
val saltString = Base64.getEncoder().encodeToString(salt)
val saltString = Base64.getEncoder().encode(salt)
val hash = generateHash(value, salt)
val hashString = Base64.getEncoder().encodeToString(hash)
val hashString = Base64.getEncoder().encode(hash)
useDb {
passwordInternal = "$hashString:$saltString"
+18 -2
View File
@@ -28,10 +28,12 @@ import org.jetbrains.exposed.v1.dao.IntEntityClass
import org.jetbrains.exposed.v1.jdbc.select
object TeamTable : IntIdTable("Team", "TeamID") {
val kuerzel = varchar("TeamKuerzel", 10).index()
val kuerzel = varchar("TeamKuerzel", 10)
val color = char("TeamColor", 1).default("8")
val name = varchar("TeamName", 16).index()
val name = varchar("TeamName", 16)
val deleted = bool("TeamDeleted").default(false)
val address = text("Address").nullable()
val port = ushort("Port").default(25565u)
}
class Team(id: EntityID<Int>) : IntEntity(id) {
@@ -65,6 +67,8 @@ class Team(id: EntityID<Int>) : IntEntity(id) {
private var name by TeamTable.name
var deleted by TeamTable.deleted
private set
private var teamAddress by TeamTable.address
private var teamPort by TeamTable.port
val members by lazy { useDb { SteamwarUserTable.select(SteamwarUserTable.id).where { SteamwarUserTable.team eq teamId }.map { it[SteamwarUserTable.id].value } } }
fun size() = useDb { SteamwarUser.find { SteamwarUserTable.team eq teamId }.count().toInt() }
@@ -92,4 +96,16 @@ class Team(id: EntityID<Int>) : IntEntity(id) {
set(value) = useDb {
name = value
}
var address: String?
get() = teamAddress
set(value) = useDb {
teamAddress = value
}
var port: Int
get() = teamPort.toInt()
set(value) = useDb {
teamPort = value.toUShort()
}
}
@@ -32,8 +32,8 @@ import org.jetbrains.exposed.v1.jdbc.deleteWhere
import org.jetbrains.exposed.v1.jdbc.insertIgnore
object TeamTeilnahmeTable : CompositeIdTable("TeamTeilnahme") {
val teamId = reference("teamId", TeamTable).index()
val eventId = reference("eventId", EventTable).index()
val teamId = reference("teamId", TeamTable)
val eventId = reference("eventId", EventTable)
val placement = integer("Placement").nullable()
override val primaryKey = PrimaryKey(teamId, eventId)
+3 -3
View File
@@ -33,10 +33,10 @@ import java.sql.Timestamp
import java.util.*
object TokenTable: IntIdTable("Token") {
val name = varchar("Name", 64).uniqueIndex()
val owner = reference("Owner", SteamwarUserTable).index()
val name = varchar("Name", 64)
val owner = reference("Owner", SteamwarUserTable)
val created = timestamp("Created").defaultExpression(CurrentTimestamp)
val hash = varchar("Hash", 88).uniqueIndex()
val hash = varchar("Hash", 88)
}
class Token(id: EntityID<Int>): IntEntity(id) {
@@ -28,7 +28,7 @@ import org.jetbrains.exposed.v1.jdbc.insert
import org.jetbrains.exposed.v1.jdbc.selectAll
object UserPermTable: Table("UserPerm") {
val user = reference("User", SteamwarUserTable.id).index()
val user = reference("User", SteamwarUserTable.id)
val perm = enumerationByName("Perm", 32, UserPerm::class)
override val primaryKey = PrimaryKey(user, perm)
@@ -24,7 +24,10 @@ import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -157,22 +160,6 @@ final class YMLWrapper<M, W> {
}
}
public <K, V> Map<K, V> getMap(String path, Function<String, K> keyFunction, Function<String, V> valueFunction) {
Object data = this.document.get(path);
if (data instanceof Map) {
Map<K, V> result = new HashMap<>();
((Map<String, String>) data).forEach((keyString, valueString) -> {
K key = keyFunction.apply(keyString.toUpperCase());
V value = valueFunction.apply(valueString.toUpperCase());
if (key == null || value == null) return;
result.put(key, value);
});
return Collections.unmodifiableMap(result);
} else {
return Collections.emptyMap();
}
}
public List<Map<?, ?>> getMapList(String path) {
Object value = this.document.get(path);
if (value instanceof List) {
@@ -67,7 +67,7 @@ object KotlinDatabase {
}
}
fun <T> useDb(statement: JdbcTransaction.() -> T): T {
fun <T: Any?> useDb(statement: JdbcTransaction.() -> T): T {
KotlinDatabase.ensureConnected()
return TransactionManager.currentOrNull()?.statement() ?: transaction(KotlinDatabase.db) {
statement()
@@ -42,5 +42,4 @@ dependencies {
compileOnly(libs.fastutil)
compileOnly(libs.authlib)
compileOnly(project(":FightSystem:FightSystem_14"))
}
@@ -1,51 +0,0 @@
/*
* 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.fightsystem.listener;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentTask;
import net.minecraft.world.entity.projectile.windcharge.WindCharge;
import org.bukkit.Location;
public class WindchargeStopper21 implements WindchargeStopper.IWindchargeStopper {
public WindchargeStopper21() {
new StateDependentTask(true, FightState.Running, this::run, 1, 1);
}
private static final int middleLine = Config.SpecSpawn.getBlockZ();
private static final Class<?> windChargeClass = WindCharge.class;
private void run() {
Recording.iterateOverEntities(windChargeClass::isInstance, entity -> {
Location location = entity.getLocation();
Location prevLocation = location.clone().subtract(entity.getVelocity());
boolean passedMiddle = location.getBlockZ() > middleLine && prevLocation.getBlockZ() > middleLine ||
location.getBlockZ() < middleLine && prevLocation.getBlockZ() < middleLine;
if(!passedMiddle) {
entity.remove();
}
});
}
}
@@ -1,29 +0,0 @@
/*
* 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.fightsystem.utils;
import org.bukkit.inventory.ItemStack;
public class FlatteningWrapper21 extends FlatteningWrapper14 {
@Override
public boolean hasAttributeModifier(ItemStack stack) {
return stack.hasItemMeta() && stack.getItemMeta() != null && stack.getItemMeta().hasAttributeModifiers();
}
}
@@ -38,27 +38,6 @@ public class ReflectionWrapper21 implements ReflectionWrapper {
FORBIDDEN_TYPES.add(DataComponentTypes.BLOCKS_ATTACKS);
FORBIDDEN_TYPES.add(DataComponentTypes.BUNDLE_CONTENTS);
FORBIDDEN_TYPES.add(DataComponentTypes.CUSTOM_MODEL_DATA);
FORBIDDEN_TYPES.add(DataComponentTypes.ATTRIBUTE_MODIFIERS);
FORBIDDEN_TYPES.add(DataComponentTypes.TOOL);
FORBIDDEN_TYPES.add(DataComponentTypes.WEAPON);
FORBIDDEN_TYPES.add(DataComponentTypes.FOOD);
FORBIDDEN_TYPES.add(DataComponentTypes.CONSUMABLE);
FORBIDDEN_TYPES.add(DataComponentTypes.POTION_CONTENTS);
FORBIDDEN_TYPES.add(DataComponentTypes.STORED_ENCHANTMENTS);
FORBIDDEN_TYPES.add(DataComponentTypes.CAN_BREAK);
FORBIDDEN_TYPES.add(DataComponentTypes.CAN_PLACE_ON);
FORBIDDEN_TYPES.add(DataComponentTypes.MAX_DAMAGE);
FORBIDDEN_TYPES.add(DataComponentTypes.USE_REMAINDER);
FORBIDDEN_TYPES.add(DataComponentTypes.USE_COOLDOWN);
FORBIDDEN_TYPES.add(DataComponentTypes.SUSPICIOUS_STEW_EFFECTS);
FORBIDDEN_TYPES.add(DataComponentTypes.CHARGED_PROJECTILES);
FORBIDDEN_TYPES.add(DataComponentTypes.INTANGIBLE_PROJECTILE);
FORBIDDEN_TYPES.add(DataComponentTypes.FIREWORKS);
FORBIDDEN_TYPES.add(DataComponentTypes.FIREWORK_EXPLOSION);
FORBIDDEN_TYPES.add(DataComponentTypes.EQUIPPABLE);
FORBIDDEN_TYPES.add(DataComponentTypes.REPAIR_COST);
FORBIDDEN_TYPES.add(DataComponentTypes.ENCHANTABLE);
}
@Override
@@ -1,23 +0,0 @@
/*
* 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.fightsystem.listener;
public class WindchargeStopper8 implements WindchargeStopper.IWindchargeStopper {
}
@@ -33,6 +33,9 @@ import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.OneShotStateDependent;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.utils.*;
import de.steamwar.fightsystem.winconditions.Wincondition;
import de.steamwar.fightsystem.winconditions.WinconditionComparisonTimeout;
import de.steamwar.fightsystem.winconditions.Winconditions;
import de.steamwar.linkage.AbstractLinker;
import de.steamwar.linkage.SpigotLinker;
import de.steamwar.message.Message;
@@ -40,7 +43,6 @@ import de.steamwar.sql.NodeData;
import de.steamwar.sql.SchematicNode;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.GameRule;
import org.bukkit.plugin.java.JavaPlugin;
public class FightSystem extends JavaPlugin {
@@ -98,13 +100,6 @@ public class FightSystem extends JavaPlugin {
new StateDependentListener(ArenaMode.All, FightState.All, BountifulWrapper.impl.newDenyArrowPickupListener());
new OneShotStateDependent(ArenaMode.All, FightState.PreSchemSetup, () -> Fight.playSound(SWSound.BLOCK_NOTE_PLING.getSound(), 100.0f, 2.0f));
new OneShotStateDependent(ArenaMode.Test, FightState.All, WorldEditRendererCUIEditor::new);
if (Core.getVersion() >= 19) {
try {
Bukkit.getWorlds().get(0).setGameRule(GameRule.REDUCED_DEBUG_INFO, ArenaMode.AntiTest.contains(Config.mode));
} catch (Exception e) {
// Ignore if failed!
}
}
techHider = new TechHiderWrapper();
hullHider = new HullHider();
@@ -45,7 +45,6 @@ import org.bukkit.util.Vector;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.logging.Level;
@@ -180,24 +179,18 @@ public class FightSchematic extends StateDependent {
@Override
public void disable() {
if (Config.mode == ArenaMode.PREPARE) {
if(!Config.GameModeConfig.Schematic.ReplaceObsidianBedrock || Config.mode == ArenaMode.PREPARE)
return;
}
FreezeWorld freezer = null;
if (!Config.GameModeConfig.Schematic.ReplacementsWithoutBlockUpdates.isEmpty()) {
if(!Config.GameModeConfig.Schematic.ReplaceWithBlockupdates)
freezer = new FreezeWorld();
}
for (Map.Entry<Material, Material> replacement : Config.GameModeConfig.Schematic.ReplacementsWithoutBlockUpdates.entrySet()) {
replaceSync(replacement.getKey(), replacement.getValue());
}
if (freezer != null) {
freezer.disable();
}
for (Map.Entry<Material, Material> replacement : Config.GameModeConfig.Schematic.ReplacementsWithBlockUpdates.entrySet()) {
replaceSync(replacement.getKey(), replacement.getValue());
}
replaceSync(Material.OBSIDIAN, Material.TNT);
replaceSync(Material.BEDROCK, Material.SLIME_BLOCK);
if(!Config.GameModeConfig.Schematic.ReplaceWithBlockupdates)
freezer.disable();
}
public void pasteTeamName(){
@@ -1,44 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.listener;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockFormEvent;
@Linked
public class BlockFormListener implements Listener {
public BlockFormListener() {
new StateDependentListener(Config.GameModeConfig.Arena.DisableIceForm, FightState.All, this);
}
@EventHandler
public void onBlockForm(BlockFormEvent event) {
if (Config.ArenaRegion.inRegion(event.getBlock()) && event.getNewState().getType() == Material.ICE) {
event.setCancelled(true);
}
}
}
@@ -181,13 +181,7 @@ public class Permanent implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onExplosion(EntityExplodeEvent e) {
if (!(e.getEntity() instanceof TNTPrimed)) {
if (Config.GameModeConfig.Schematic.Type.toDB().equals("wargearseason26")) {
e.blockList().clear();
}
return;
}
if (!Config.GameModeConfig.Arena.WaterDamage) return;
if (!(e.getEntity() instanceof TNTPrimed)) return;
e.blockList().removeIf(block -> {
if(block.getType() == Material.TNT) {
return false;
@@ -35,7 +35,10 @@ import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.*;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.ItemStack;
@@ -78,8 +81,25 @@ public class PersonalKitCreator implements Listener {
if(!openKitCreators.containsKey(e.getWhoClicked()))
return;
Player player = (Player) e.getWhoClicked();
//Deny bad items
if(Kit.isBadItem(e.getCursor()))
e.setCancelled(true);
/* Should the inventory reset? */
if(e.getAction() != InventoryAction.PLACE_ALL)
return;
ItemStack[] items = e.getWhoClicked().getInventory().getContents();
for(int i = 0; i < items.length; i++){
ItemStack stack = items[i];
if(stack != null && i != e.getSlot())
return;
}
FightPlayer fightPlayer = Fight.getFightPlayer(player);
assert fightPlayer != null;
Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> fightPlayer.getKit().loadToPlayer(player), 1);
}
@EventHandler
@@ -97,10 +117,7 @@ public class PersonalKitCreator implements Listener {
if(backup == null)
return;
InventoryType type = e.getInventory().getType();
if(type != InventoryType.PLAYER && type != InventoryType.CREATIVE) {
backup.close();
}
backup.close();
}
@EventHandler
@@ -109,7 +126,7 @@ public class PersonalKitCreator implements Listener {
if(backup == null)
return;
Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), backup::close, 1);
backup.close();
}
@EventHandler
@@ -134,11 +151,9 @@ public class PersonalKitCreator implements Listener {
}
private void close(){
openKitCreators.remove(player);
Kit kit1 = new Kit(kit.getName(), player);
kit1.removeBadItems();
openKitCreators.remove(player);
kit1.toPersonalKit(kit);
backup.loadToPlayer(player);
player.setGameMode(GameMode.SURVIVAL);
@@ -73,7 +73,7 @@ public class WaterRemover implements Listener {
event.setYield(0); //No drops (additionally to world config)
FightTeam spawn = tnt.remove(event.getEntity().getEntityId());
if(Config.GameModeConfig.Arena.WaterDamage && spawn != null && !spawn.getExtendRegion().inRegion(event.getLocation())) {
if(spawn != null && !spawn.getExtendRegion().inRegion(event.getLocation())) {
Block b = event.getLocation().getBlock();
for(int y = -1; y <= 1; y++) {
for(int z = -1; z <= 1; z++) {
@@ -1,35 +0,0 @@
/*
* 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.fightsystem.listener;
import de.steamwar.core.VersionDependent;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.linkage.Linked;
@Linked
public class WindchargeStopper {
static {
VersionDependent.getVersionImpl(FightSystem.getPlugin());
}
public interface IWindchargeStopper {
}
}
@@ -36,6 +36,7 @@ import de.steamwar.fightsystem.fight.FreezeWorld;
import de.steamwar.fightsystem.listener.FightScoreboard;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.utils.*;
import de.steamwar.sql.SchematicData;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.Team;
@@ -519,12 +520,12 @@ public class PacketProcessor implements Listener {
private void pasteEmbeddedSchem(FightTeam team) throws IOException {
int schemId = source.readInt();
Clipboard clipboard = WorldEditWrapper.impl.getClipboard(new FilterInputStream(source) {
Clipboard clipboard = SchematicData.clipboardFromStream(new FilterInputStream(source) {
@Override
public void close() {
// FAWE 1.12 calls close...
}
});
}, WorldEditWrapper.impl.getNativeFormat());
execSync(() -> team.pasteSchem(schemId, clipboard));
}
@@ -283,7 +283,7 @@ public interface Recorder {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try{
copy(NodeData.getLatest(SchematicNode.getSchematicNode(schemId)).schemData(true), buffer);
copy(NodeData.getLatest(SchematicNode.getSchematicNode(schemId)).schemData(), buffer);
}catch (EOFException e) {
Bukkit.getLogger().log(Level.INFO, "EOFException ignored");
} catch (IOException e) {
@@ -53,7 +53,7 @@ public class AutoChecker15 implements AutoChecker.IAutoChecker {
checkInventory(result, block, material, new BlockPos(x, y, z));
}
if(x == min.getBlockX() || x == max.getBlockX() || y == max.getBlockY() || z == min.getBlockZ() || z == max.getBlockZ()) {
if(x == 0 || x == max.getBlockX() - 1 || y == max.getBlockY() - 1 || z == 0 || z == max.getBlockZ() - 1) {
result.getDesignBlocks().computeIfAbsent(material, m -> new ArrayList<>()).add(new BlockPos(x, y, z));
}
}
@@ -1,37 +0,0 @@
/*
* 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/>.
*/
plugins {
steamwar.java
}
dependencies {
compileOnly(project(":SpigotCore", "default"))
compileOnly(project(":SchematicSystem:SchematicSystem_Core", "default"))
compileOnly(libs.paperapi21) {
attributes {
// Very Hacky, but it works
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
}
}
compileOnly(libs.nms21)
compileOnly(libs.fawe21)
}
@@ -1,137 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.schematicsystem.autocheck;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BaseBlock;
import de.steamwar.core.Core;
import de.steamwar.sql.GameModeConfig;
import org.bukkit.Material;
import java.util.*;
import java.util.stream.Collectors;
public class AutoChecker21 implements AutoChecker.IAutoChecker {
public AutoChecker.BlockScanResult scan(Clipboard clipboard, GameModeConfig<Material, String> type) {
AutoChecker.BlockScanResult result = new AutoChecker.BlockScanResult();
BlockVector3 min = clipboard.getMinimumPoint();
BlockVector3 max = clipboard.getMaximumPoint();
for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
final BaseBlock block = clipboard.getFullBlock(BlockVector3.at(x, y, z));
final Material material = Material.matchMaterial(block.getBlockType().getId());
if (material == null) {
continue;
}
result.getBlockCounts().merge(material, 1, Integer::sum);
if (AutoCheckerItems.impl.getInventoryMaterials().contains(material)) {
checkInventory(result, block, material, new BlockPos(x, y, z), type);
}
if (x == min.getBlockX() || x == max.getBlockX() || y == max.getBlockY() || z == min.getBlockZ() || z == max.getBlockZ()) {
result.getDesignBlocks().computeIfAbsent(material, m -> new ArrayList<>()).add(new BlockPos(x, y, z));
}
}
}
}
return result;
}
private static final Map<Material, Set<Material>> itemsInInv = new EnumMap<>(Material.class);
static {
itemsInInv.put(Material.BUCKET, EnumSet.of(Material.DISPENSER));
itemsInInv.put(Material.TNT, EnumSet.of(Material.CHEST, Material.BARREL, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX,
Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX,
Material.LIGHT_GRAY_SHULKER_BOX, Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX,
Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX));
itemsInInv.put(Material.FIRE_CHARGE, EnumSet.of(Material.DISPENSER));
itemsInInv.put(Material.ARROW, EnumSet.of(Material.DISPENSER));
AutoCheckerItems.impl.getAllowedMaterialsInInventory().forEach(material -> itemsInInv.put(material, AutoCheckerItems.impl.getInventoryMaterials()));
}
private void checkInventory(AutoChecker.BlockScanResult result, BaseBlock block, Material material, BlockPos pos, GameModeConfig<Material, String> type) {
CompoundTag nbt = block.getNbtData();
if (nbt == null) {
result.getDefunctNbt().add(pos);
return;
}
if (material == Material.JUKEBOX && nbt.getValue().containsKey("RecordItem")) {
result.getRecords().add(pos);
return;
}
List<CompoundTag> items = nbt.getList("Items", CompoundTag.class);
if (items.isEmpty())
return; // Leeres Inventar
int counter = 0;
int windChargeCount = 0;
for (CompoundTag item : items) {
if (!item.containsKey("id")) {
result.getDefunctNbt().add(pos);
continue;
}
Material itemType = Material.matchMaterial(item.getString("id"));
if (itemType == null) // Leere Slots
continue;
if(type.Schematic.Type.getName().equals("wargearseason26") && material == Material.DISPENSER && itemType == Material.WIND_CHARGE) {
windChargeCount += item.getInt("count");
}
else if (!itemsInInv.getOrDefault(itemType, EnumSet.noneOf(Material.class)).contains(material)) {
result.getForbiddenItems().computeIfAbsent(pos, blockVector3 -> new HashSet<>()).add(itemType);
} else if (material == Material.DISPENSER && (itemType == Material.ARROW || itemType == Material.FIRE_CHARGE)) {
counter += Core.getVersion() >= 21 ? item.getInt("count") : item.getByte("Count");
}
if (item.containsKey("tag")) {
result.getForbiddenNbt().computeIfAbsent(pos, blockVector3 -> new HashSet<>()).add(itemType);
}
}
result.getDispenserItems().put(pos, counter);
result.getWindChargeCount().put(pos, windChargeCount);
}
@Override
public AutoCheckerResult check(Clipboard clipboard, GameModeConfig<Material, String> type) {
return AutoCheckerResult.builder().type(type).height(clipboard.getDimensions().getBlockY()).width(clipboard.getDimensions().getBlockX())
.depth(clipboard.getDimensions().getBlockZ()).blockScanResult(scan(clipboard, type))
.entities(clipboard.getEntities().stream().map(Entity::getLocation)
.map(blockVector3 -> new BlockPos(blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ()))
.collect(Collectors.toList()))
.build();
}
@Override
public AutoCheckerResult sizeCheck(Clipboard clipboard, GameModeConfig<Material, String> type) {
return AutoCheckerResult.builder().type(type).height(clipboard.getDimensions().getBlockY()).width(clipboard.getDimensions().getBlockX())
.depth(clipboard.getDimensions().getBlockZ()).build();
}
}
@@ -1,49 +0,0 @@
/*
* 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.schematicsystem.autocheck;
import org.bukkit.Material;
import java.util.EnumSet;
import java.util.Set;
public class AutoCheckerItems21 implements AutoCheckerItems {
private static final Set<Material> INVENTORY = EnumSet.of(Material.BARREL, Material.BLAST_FURNACE, Material.BREWING_STAND, Material.CAMPFIRE,
Material.CHEST, Material.DISPENSER, Material.DROPPER, Material.FURNACE, Material.HOPPER, Material.JUKEBOX, Material.SHULKER_BOX,
Material.WHITE_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX,
Material.LIME_SHULKER_BOX, Material.PINK_SHULKER_BOX, Material.GRAY_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX, Material.CYAN_SHULKER_BOX,
Material.PURPLE_SHULKER_BOX, Material.BLUE_SHULKER_BOX, Material.BROWN_SHULKER_BOX, Material.GREEN_SHULKER_BOX, Material.RED_SHULKER_BOX,
Material.BLACK_SHULKER_BOX, Material.SMOKER, Material.TRAPPED_CHEST);
private static final Set<Material> FLOWERS = EnumSet.of(Material.CORNFLOWER, Material.POPPY, Material.FERN, Material.DANDELION, Material.BLUE_ORCHID,
Material.ALLIUM, Material.AZURE_BLUET, Material.RED_TULIP, Material.ORANGE_TULIP, Material.WHITE_TULIP, Material.PINK_TULIP, Material.OXEYE_DAISY,
Material.LILY_OF_THE_VALLEY, Material.WITHER_ROSE, Material.SUNFLOWER, Material.DIAMOND_HORSE_ARMOR, Material.IRON_HORSE_ARMOR,
Material.GOLDEN_HORSE_ARMOR, 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() {
return INVENTORY;
}
@Override
public Set<Material> getAllowedMaterialsInInventory() {
return FLOWERS;
}
}
@@ -262,8 +262,6 @@ AUTO_CHECKER_RESULT_BLOCKS=§7Blocks: §c{0}§7, Max: §e{1}
AUTO_CHECKER_RESULT_UNKNOWN_MATERIAL=§7Unknown block: §c{0}
AUTO_CHECKER_RESULT_TOO_MANY_BLOCK=§7{0}: §c{1}§7, Max: §e{2}
AUTO_CHECKER_RESULT_FORBIDDEN_BLOCK=§7Forbidden block: §c{0}
AUTO_CHECKER_RESULT_WIND_CHARGES=§7Windcharges: §c{0}§7, Max: §e2048
AUTO_CHECKER_RESULT_WIND_CHARGES_DISPENSER=§7Dispenser: §c[{0}, {1}, {2}]§7, Windcharges: §c{3}§7
AUTO_CHECKER_RESULT_FORBIDDEN_ITEM=§7Forbidden Item: [{0}, {1}, {2}] -> §c{3}
AUTO_CHECKER_RESULT_DEFUNCT_NBT=§7Defunct NBT: §7[{0}, {1}, {2}]
AUTO_CHECKER_RESULT_DESIGN_BLOCK=§7{0} in Design: [{1}, {2}, {3}]
@@ -242,8 +242,6 @@ AUTO_CHECKER_RESULT_BLOCKS=§7Blöcke: §c{0}§7, Max: §e{1}
AUTO_CHECKER_RESULT_UNKNOWN_MATERIAL=§7Unbekannter Block: §c{0}
AUTO_CHECKER_RESULT_TOO_MANY_BLOCK=§7{0}: §c{1}§7, Max: §e{2}
AUTO_CHECKER_RESULT_FORBIDDEN_BLOCK=§7Verbotener Block: §c{0}
AUTO_CHECKER_RESULT_WIND_CHARGES=§7Windcharges: §c{0}§7, Max: §e2048
AUTO_CHECKER_RESULT_WIND_CHARGES_DISPENSER=§7Werfer: §c[{0}, {1}, {2}]§7, Windcharges: §c{3}§7
AUTO_CHECKER_RESULT_FORBIDDEN_ITEM=§7Verbotener gegenstand: [{0}, {1}, {2}] -> §c{3}
AUTO_CHECKER_RESULT_DEFUNCT_NBT=§7Keine NBT-Daten: §c[{0}, {1}, {2}]
AUTO_CHECKER_RESULT_DESIGN_BLOCK=§7{0} im Design: [{1}, {2}, {3}]
@@ -55,7 +55,6 @@ public class AutoChecker {
private final List<BlockPos> records = new ArrayList<>();
private final Map<Material, List<BlockPos>> designBlocks = new EnumMap<>(Material.class);
private final Map<BlockPos, Integer> dispenserItems = new HashMap<>();
private final Map<BlockPos, Integer> windChargeCount = new HashMap<>();
private final Map<BlockPos, Set<Material>> forbiddenItems = new HashMap<>();
private final Map<BlockPos, Set<Material>> forbiddenNbt = new HashMap<>();
}
@@ -20,8 +20,9 @@
package de.steamwar.schematicsystem.autocheck;
import de.steamwar.core.Core;
import de.steamwar.schematicsystem.SchematicSystem;
import de.steamwar.sql.GameModeConfig;
import de.steamwar.schematicsystem.SchematicSystem;
import de.steamwar.sql.SchematicType;
import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
@@ -52,7 +53,6 @@ public class AutoCheckerResult {
isBlockCountOk() &&
isLimitedBlocksOK() &&
isDispenserItemsOK() &&
isWindchargeCountOK() &&
!type.isAfterDeadline() &&
entities.isEmpty() &&
isDesignBlastResistanceOK();
@@ -63,18 +63,8 @@ public class AutoCheckerResult {
!type.isAfterDeadline();
}
public boolean isWindchargeCountOK() {
if( type.Schematic.Type.getName().equals("wargearseason26")) {
int windChargesCount = blockScanResult.getWindChargeCount().values().stream().reduce(Integer::sum).orElse(0);
return windChargesCount <= 2048;
}
else {
return true;
}
}
public boolean isDispenserItemsOK() {
return blockScanResult.getDispenserItems().values().stream().allMatch(i -> i <= type.Schematic.MaxDispenserItems);
return blockScanResult.getDispenserItems().values().stream().allMatch(i -> i <= type.Schematic.MaxDispenserItems);
}
public boolean hasWarnings() {
@@ -112,9 +102,7 @@ public class AutoCheckerResult {
}
public boolean isDesignBlastResistanceOK() {
return blockScanResult.getDesignBlocks().keySet().stream()
.filter(material -> material != Material.WATER && material != Material.LAVA)
.map(Material::getBlastResistance).noneMatch(i -> i > type.Schematic.MaxDesignBlastResistance);
return blockScanResult.getDesignBlocks().keySet().stream().map(Material::getBlastResistance).noneMatch(i -> i > type.Schematic.MaxDesignBlastResistance);
}
public void sendErrorMessage(Player p, String schemName) {
@@ -138,19 +126,6 @@ public class AutoCheckerResult {
}
});
}
if(!isWindchargeCountOK()) {
int windChargesCount = blockScanResult.getWindChargeCount().values().stream().reduce(Integer::sum).orElse(0);
SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_WIND_CHARGES", p, windChargesCount, 2048);
blockScanResult.getWindChargeCount().entrySet().stream().filter(blockVector3IntegerEntry -> blockVector3IntegerEntry.getValue() > 0).forEach(blockVector3IntegerEntry -> {
SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_WIND_CHARGES_DISPENSER", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3IntegerEntry.getKey()),
blockVector3IntegerEntry.getKey().getBlockX(),
blockVector3IntegerEntry.getKey().getBlockY(),
blockVector3IntegerEntry.getKey().getBlockZ(),
blockVector3IntegerEntry.getValue());
});
}
blockScanResult.getDispenserItems().entrySet().stream().filter(blockVector3IntegerEntry -> blockVector3IntegerEntry.getValue() > type.Schematic.MaxDispenserItems).forEach(blockVector3IntegerEntry -> {
SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_TOO_MANY_DISPENSER_ITEMS", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3IntegerEntry.getKey()),
blockVector3IntegerEntry.getKey().getBlockX(),
@@ -159,7 +134,6 @@ public class AutoCheckerResult {
blockVector3IntegerEntry.getValue(),
type.Schematic.MaxDispenserItems);
});
blockScanResult.getRecords().forEach(blockVector3 -> {
SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_RECORD", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(blockVector3), blockVector3.getBlockX(), blockVector3.getBlockY(), blockVector3.getBlockZ());
});
@@ -174,7 +148,6 @@ public class AutoCheckerResult {
});
if(Core.getVersion() > 12) {
blockScanResult.getDesignBlocks().forEach((material, poss) -> {
if (material == Material.WATER || material == Material.LAVA) return;
if(material.getBlastResistance() > type.Schematic.MaxDesignBlastResistance) {
poss.forEach(pos -> {
SchematicSystem.MESSAGE.sendPrefixless("AUTO_CHECKER_RESULT_DESIGN_BLOCK", p, SchematicSystem.MESSAGE.parse("AUTO_CHECKER_RESULT_TELEPORT_HERE", p), tpCommandTo(pos), material.name(), pos.getBlockX(), pos.getBlockY(), pos.getBlockZ());
-1
View File
@@ -32,5 +32,4 @@ dependencies {
implementation(project(":SchematicSystem:SchematicSystem_15"))
implementation(project(":SchematicSystem:SchematicSystem_19"))
implementation(project(":SchematicSystem:SchematicSystem_20"))
implementation(project(":SchematicSystem:SchematicSystem_21"))
}
@@ -0,0 +1,355 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.core
import com.sk89q.jnbt.ByteArrayTag
import com.sk89q.jnbt.ByteTag
import com.sk89q.jnbt.CompoundTag
import com.sk89q.jnbt.DoubleTag
import com.sk89q.jnbt.EndTag
import com.sk89q.jnbt.FloatTag
import com.sk89q.jnbt.IntArrayTag
import com.sk89q.jnbt.IntTag
import com.sk89q.jnbt.ListTag
import com.sk89q.jnbt.LongArrayTag
import com.sk89q.jnbt.LongTag
import com.sk89q.jnbt.ShortTag
import com.sk89q.jnbt.StringTag
import com.sk89q.jnbt.Tag
import com.sk89q.worldedit.WorldEdit
import com.sk89q.worldedit.WorldEditException
import com.sk89q.worldedit.extension.input.ParserContext
import com.sk89q.worldedit.extension.platform.Capability
import com.sk89q.worldedit.extension.platform.Platform
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard
import com.sk89q.worldedit.math.BlockVector3
import com.sk89q.worldedit.regions.CuboidRegion
import com.sk89q.worldedit.world.DataFixer
import com.sk89q.worldedit.world.block.BaseBlock
import com.sk89q.worldedit.world.block.BlockState
import com.sk89q.worldedit.world.block.BlockTypes
import java.io.DataInputStream
import java.io.IOException
import kotlin.collections.map
import kotlin.collections.set
class ChaosSchematicReader(
val stream: DataInputStream,
val wrapper: WorldEditWrapper14
) {
init {
println("ChaosSchematicReader init")
}
/**
* In reinen Unit-Tests (ohne Bukkit/WorldEdit-Plugin-Lifecycle) ist keine WorldEdit-Platform registriert.
* Daher darf der Reader beim Laden nicht hart daran scheitern.
*/
private val platform: Platform? = runCatching {
WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING)
}.getOrNull()
private val liveDataVersion: Int? = platform?.dataVersion
private var wrapped = false
var schematicVersion: Int? = null
var dataVersion: Int? = null
var metadata: Map<String, Any>? = null
var width: Short? = null
var height: Short? = null
var length: Short? = null
var offset: IntArray? = null
val blocks: Blocks = Blocks(null, null, null)
val entities = mutableListOf<Any>()
var fixer: DataFixer? = null
fun read(): BlockArrayClipboard {
require(stream.readByte() == 0x0A.toByte())
val tagName = stream.readUTF()
if (tagName != "Schematic") {
wrapped = true
stream.readByte()
stream.readUTF()
}
while (stream.readByte() != 0.toByte()) {
val name = stream.readUTF()
when (name) {
"Version" -> schematicVersion = stream.readInt()
"DataVersion" -> {
dataVersion = stream.readInt()
val targetVersion = liveDataVersion
if (targetVersion != null && dataVersion!! < targetVersion) {
fixer = platform?.dataFixer
}
}
"Metadata" -> metadata = readCompoundTag()
"Width" -> width = stream.readShort()
"Height" -> height = stream.readShort()
"Length" -> length = stream.readShort()
"Blocks" -> {
while (stream.readByte() != 0.toByte()) {
val n = stream.readUTF()
when (n) {
"Palette" -> blocks.palette = readCompoundTag() as Map<String, Int>
"Data" -> blocks.data = readTag(7.toByte()) as ByteArray
"BlockEntities" -> blocks.blockEntities = readTagCompoundList()
}
}
}
"PaletteMax" -> stream.readInt()
"Palette" -> blocks.palette = readCompoundTag() as Map<String, Int>
"BlockEntities" -> blocks.blockEntities = readTagCompoundList()
"BlockData" -> blocks.data = readTag(7.toByte()) as ByteArray
"Offset" -> offset = readTag(11.toByte()) as IntArray
"Entities" -> entities.addAll(readTagCompoundList() as List<Any>)
"BiomePaletteMax" -> stream.readInt()
"BiomePalette" -> readCompoundTag()
"BiomeData" -> readTag(7.toByte())
"Biomes" -> {
while (stream.readByte() != 0.toByte()) {
val n = stream.readUTF()
when (n) {
"Palette" -> readCompoundTag()
"Data" -> readTag(7.toByte()) as ByteArray
}
}
}
else -> {
println(this)
error("Unknown tag $name")
}
}
}
if (wrapped) {
stream.readByte()
}
val parserContext = ParserContext()
parserContext.setRestricted(false)
parserContext.setTryLegacy(false)
parserContext.setPreferringWildcard(false)
val dv = dataVersion
val blockStates = blocks.palette!!.map {
val fixed = if (fixer != null && dv != null) {
fixer!!.fixUp(DataFixer.FixTypes.BLOCK_STATE, it.key, dv)
} else {
it.key
}
val blockstate = try {
WorldEdit.getInstance().blockFactory.parseFromInput(fixed, parserContext).toImmutableState()
} catch (e: Exception) {
BlockTypes.AIR!!.defaultState
}
it.value to blockstate
}.toMap()
val tileEntities = blocks.blockEntities!!.map {
val entity = it as? Map<String, Any?> ?: error("Invalid entity")
val pos = entity["Pos"] as? IntArray ?: error("Invalid pos")
val x = pos[0]
val y = pos[1]
val z = pos[2]
val data = mutableMapOf<String, Any?>()
data.putAll(entity)
if (entity.containsKey("Data")) {
//data.putAll(entity["Data"] as Map<String, Any?>)
}
val fixed = if (fixer != null) {
wrapper.applyDataFixer(fixer!!, dataVersion!!, (wrapNbt(data) as CompoundTag).value)
} else (wrapNbt(data) as CompoundTag).value
BlockVector3.at(x, y, z) to fixed
}.toMap()
val offset = BlockVector3.at(offset!![0], offset!![1], offset!![2])
val region = CuboidRegion(offset, offset.add(width!! - 1, height!! - 1, length!! - 1))
val clipboard = BlockArrayClipboard(region)
clipboard.setOrigin(offset)
var index = 0
var i = 0
var value: Int
var varintLength: Int
while (i < blocks.data!!.size) {
value = 0
varintLength = 0
while (true) {
value = value or ((blocks.data!![i].toInt() and 127) shl (varintLength++ * 7))
if (varintLength > 5) {
throw IOException("VarInt too big (probably corrupted data)")
}
if ((blocks.data!![i].toInt() and 128) != 128) {
i++
break
}
i++
}
// index = (y * length * width) + (z * width) + x
val y = index / (width!! * length!!)
val z = (index % (width!! * length!!)) / width!!
val x = (index % (width!! * length!!)) % width!!
val state: BlockState = blockStates[value] ?: error("Unknown block state $value")
val pt = BlockVector3.at(x, y, z)
try {
if (tileEntities.containsKey(pt)) {
clipboard.setBlock<BaseBlock?>(
clipboard.minimumPoint.add(pt),
state.toBaseBlock(CompoundTag(tileEntities[pt])
))
} else {
clipboard.setBlock<BlockState?>(clipboard.minimumPoint.add(pt), state)
}
} catch (e: WorldEditException) {
throw IOException("Failed to load a block in the schematic")
}
index++
}
return clipboard
}
private fun readCompoundTag(): Map<String, Any> {
var tagId = 0.toByte()
val map = mutableMapOf<String, Any>()
while (stream.readByte().also { tagId = it } != 0.toByte()) {
val name = stream.readUTF()
map[name] = readTag(tagId)!!
}
return map
}
private fun readTagCompoundList(): List<Any?> {
val typeId = stream.readByte()
val length = stream.readInt()
if (typeId == 0.toByte()) {
if (length != 0) {
throw IOException("Invalid TAG_List: typeId=TAG_End but length=$length")
}
return emptyList()
}
if (typeId != 10.toByte()) {
throw IOException("Invalid TAG_List element type for (Block)Entities: expected TAG_Compound(10) but got $typeId")
}
val list = ArrayList<Any?>(length)
repeat(length) { list.add(readCompoundTag()) }
return list
}
private fun readTag(tagId: Byte): Any? = when (tagId.toInt()) {
0 -> null
1 -> stream.readByte()
2 -> stream.readShort()
3 -> stream.readInt()
4 -> stream.readLong()
5 -> stream.readFloat()
6 -> stream.readDouble()
7 -> {
val length = stream.readInt()
val ba = ByteArray(length)
stream.readFully(ba)
ba
}
8 -> stream.readUTF()
9 -> {
val typeId = stream.readByte()
val length = stream.readInt()
if (typeId == 0.toByte() && length != 0) {
throw IOException("Invalid TAG_List: typeId=TAG_End but length=$length")
}
val list = mutableListOf<Any?>()
repeat(length) { list.add(readTag(typeId)) }
list
}
10 -> readCompoundTag()
11 -> {
val length = stream.readInt()
IntArray(length) { stream.readInt() }
}
12 -> {
val length = stream.readInt()
LongArray(length) { stream.readLong() }
}
else -> error("Unknown tag type $tagId")
}
private fun wrapNbt(data: Any): Tag = when (data) {
is Byte -> ByteTag(data)
is Short -> ShortTag(data)
is Int -> IntTag(data)
is Long -> LongTag(data)
is Float -> FloatTag(data)
is Double -> DoubleTag(data)
is String -> StringTag(data)
is ByteArray -> ByteArrayTag(data)
is IntArray -> IntArrayTag(data)
is LongArray -> LongArrayTag(data)
is Map<*, *> -> CompoundTag(data.map { it.key as String to wrapNbt(it.value!!) }.toMap())
is List<*> -> ListTag(data.firstOrNull()?.let { nbtClass(it) } ?: EndTag::class.java, data.map { wrapNbt(it!!) })
else -> error("Unknown tag type $data")
}
private fun nbtClass(data: Any): Class<out Tag> = when (data) {
is Byte -> ByteTag::class.java
is Short -> ShortTag::class.java
is Int -> IntTag::class.java
is Long -> LongTag::class.java
is Float -> FloatTag::class.java
is Double -> DoubleTag::class.java
is String -> StringTag::class.java
is ByteArray -> ByteArrayTag::class.java
is IntArray -> IntArrayTag::class.java
is LongArray -> LongArrayTag::class.java
is Map<*, *> -> CompoundTag::class.java
is List<*> -> ListTag::class.java
else -> error("Unknown tag type $data, ${data::class.java.simpleName}")
}
override fun toString(): String {
return "ChaosSchematicReader(platform=$platform, liveDataVersion=$liveDataVersion, wrapped=$wrapped, schematicVersion=$schematicVersion, dataVersion=$dataVersion, metadata=$metadata, width=$width, height=$height, length=$length, offset=${offset.contentToString()}, blocks=$blocks, entities=$entities, fixer=$fixer)"
}
data class Blocks(
var data: ByteArray?,
var palette: Map<String, Int>?,
var blockEntities: List<Any?>?
)
}
@@ -67,31 +67,36 @@ public class WorldEditWrapper14 implements WorldEditWrapper {
}
@Override
public void setPlayerClipboard(Player player, Clipboard clipboard) {
public void setPlayerClipboard(Player player, InputStream is, NodeData.SchematicFormat schemFormat) {
Clipboard clipboard = null;
try {
clipboard = getClipboard(is, schemFormat);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
if (clipboard == null)
throw new NoClipboardException();
Actor actor = WorldEditWrapper.getWorldEditPlugin().wrapCommandSender(player);
WorldEditWrapper.getWorldEditPlugin().getWorldEdit().getSessionManager().get(actor).setClipboard(new ClipboardHolder(clipboard));
}
@Override
public Clipboard getClipboard(NodeData data) throws IOException {
InputStream is = data.schemData(true);
return readClipboard(is, data.getNodeFormat());
}
public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException {
try {
@Override
public Clipboard getClipboard(InputStream inputStream) throws IOException {
return readClipboard(inputStream, getNativeFormat());
}
private Clipboard readClipboard(InputStream is, NodeData.SchematicFormat format) throws IOException {
switch (format) {
case SPONGE_V2:
case SPONGE_V3:
return new SpongeSchematicReader(new NBTInputStream(is), this).read();
case MCEDIT:
return new MCEditSchematicReader(new NBTInputStream(is)).read();
default:
throw new IOException("This schematic format is currently not supported");
switch (schemFormat) {
case SPONGE_V2:
case SPONGE_V3:
return new ChaosSchematicReader(new DataInputStream(is), this).read();
case MCEDIT:
return new MCEditSchematicReader(new NBTInputStream(is)).read();
default:
throw new IOException("This schematic format is currently not supported");
}
} catch (NullPointerException e) {
throw new NoClipboardException();
}
}
@@ -571,8 +576,6 @@ public class WorldEditWrapper14 implements WorldEditWrapper {
values.putIfAbsent("z", new IntTag(pt.getBlockZ()));
}
values.putIfAbsent("id", values.get("Id"));
values.remove("Id");
values.remove("Pos");
if (fixer != null) {
tileEntity = wrapper.applyDataFixer(fixer, dataVersion, values);
} else {
@@ -93,7 +93,7 @@ public class ChunkHider18 implements ChunkHider {
private static final Reflection.Method getKey = Reflection.getTypedMethod(IRegistry.class, null, MinecraftKey.class, Object.class);
private static final Reflection.Method getName = Reflection.getTypedMethod(MinecraftKey.class, null, String.class);
protected boolean tileEntityVisible(Set<String> hiddenBlockEntities, Object tile) {
return !hiddenBlockEntities.contains(TechHider.normalizeBlockEntityId((String) getName.invoke(getKey.invoke(tileEntityTypes, entityType.get(tile)))));
return !hiddenBlockEntities.contains((String) getName.invoke(getKey.invoke(tileEntityTypes, entityType.get(tile))));
}
private void blocks(SectionHider section) {
@@ -20,11 +20,8 @@
package de.steamwar.techhider;
import de.steamwar.Reflection;
import de.steamwar.core.Core;
import net.minecraft.core.IRegistry;
import net.minecraft.core.SectionPosition;
import net.minecraft.network.protocol.game.PacketPlayOutBlockBreak;
import net.minecraft.resources.MinecraftKey;
import net.minecraft.world.level.block.entity.TileEntitySign;
import net.minecraft.world.level.block.entity.TileEntityTypes;
import net.minecraft.world.level.block.state.IBlockData;
@@ -91,14 +88,6 @@ public class ProtocolWrapper18 implements ProtocolWrapper {
return tileEntityType.get(packet) != signType;
}
private static final IRegistry<?> tileEntityTypes = Reflection.getField(Core.getVersion() > 18 ? Reflection.getClass("net.minecraft.core.registries.BuiltInRegistries") : IRegistry.class, IRegistry.class, 0, TileEntityTypes.class).get(null);
private static final Reflection.Method getKey = Reflection.getTypedMethod(IRegistry.class, null, MinecraftKey.class, Object.class);
private static final Reflection.Method getName = Reflection.getTypedMethod(MinecraftKey.class, null, String.class);
@Override
public String tileEntityDataType(Object packet) {
return TechHider.normalizeBlockEntityId((String) getName.invoke(getKey.invoke(tileEntityTypes, tileEntityType.get(packet))));
}
@Override
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, TechHider techHider) {
return (p, packet) -> {
@@ -19,7 +19,6 @@
package de.steamwar.techhider;
import de.steamwar.Reflection;
import org.bukkit.entity.Player;
import java.util.function.BiFunction;
@@ -28,7 +27,6 @@ public class ProtocolWrapper19 extends ProtocolWrapper18 {
@Override
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, TechHider techHider) {
Reflection.Field<?> blockBreakPosition = Reflection.getField(blockBreakPacket, TechHider.blockPosition, 0);
return (p, packet) -> techHider.getLocationEvaluator().checkBlockPos(p, blockBreakPosition.get(packet)) == TechHider.State.SKIP ? packet : null;
return null;
}
}
@@ -19,33 +19,33 @@
package de.steamwar.core;
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV2;
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV3;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.*;
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV1Reader;
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV2Reader;
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader;
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.world.DataFixer;
import de.steamwar.sql.NodeData;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.enginehub.linbus.stream.LinBinaryIO;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinTag;
import java.io.DataInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Function;
import java.util.Map;
public class WorldEditWrapper21 implements WorldEditWrapper {
public class WorldEditWrapper21 extends WorldEditWrapper18 {
@Override
public InputStream getPlayerClipboard(Player player) {
@@ -57,68 +57,31 @@ public class WorldEditWrapper21 implements WorldEditWrapper {
}
@Override
public void setPlayerClipboard(Player player, Clipboard clipboard) {
public void setPlayerClipboard(Player player, InputStream is, NodeData.SchematicFormat schemFormat) {
Clipboard clipboard = null;
try {
clipboard = getClipboard(is, schemFormat);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
if (clipboard == null)
throw new SecurityException("Clipboard is null");
Actor actor = WorldEditWrapper.getWorldEditPlugin().wrapCommandSender(player);
WorldEditWrapper.getWorldEditPlugin().getWorldEdit().getSessionManager().get(actor).setClipboard(new ClipboardHolder(clipboard));
}
@Override
public Clipboard getClipboard(NodeData data) throws IOException {
ResetableInputStream is = new ResetableInputStream(data.schemData(false));
for (ClipboardFormat clipboardFormat : ClipboardFormats.getAll()) {
FilterInputStream fis = new FilterInputStream(is) {
@Override
public void close() throws IOException {
// Ignore close call!
}
};
boolean canBeRead = clipboardFormat.isFormat(fis);
is.reset();
if (!canBeRead) continue;
return clipboardFormat.load(is);
}
throw new IOException("No clipboard found");
@SuppressWarnings("removal")
public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat ignored) throws IOException {
return switch (ignored) {
case MCEDIT -> new MCEditSchematicReader(new NBTInputStream(is)).read();
case SPONGE_V2, SPONGE_V3 -> new ChaosSchematicReader(new DataInputStream(is), this).read();
};
}
private static final Function<InputStream, ClipboardReader> FastV3 = FastSchematicReaderV3::new;
@SuppressWarnings("removal")
private static final Function<InputStream, ClipboardReader> FastV2 = inputStream -> new FastSchematicReaderV2(new NBTInputStream(inputStream));
@SuppressWarnings("removal")
private static final Function<InputStream, ClipboardReader> McEdit = inputStream -> new MCEditSchematicReader(new NBTInputStream(inputStream));
private static final Function<InputStream, ClipboardReader> SpongeV3 = inputStream -> new SpongeSchematicV3Reader(LinBinaryIO.read(new DataInputStream(inputStream)));
private static final Function<InputStream, ClipboardReader> SpongeV2 = inputStream -> new SpongeSchematicV2Reader(LinBinaryIO.read(new DataInputStream(inputStream)));
private static final Function<InputStream, ClipboardReader> SpongeV1 = inputStream -> new SpongeSchematicV1Reader(LinBinaryIO.read(new DataInputStream(inputStream)));
private static final Function<InputStream, ClipboardReader>[] READERS = new Function[]{
FastV3,
FastV2,
SpongeV3,
SpongeV2,
SpongeV1,
McEdit
};
@Override
public Clipboard getClipboard(InputStream inputStream) throws IOException {
ResetableInputStream is = new ResetableInputStream(inputStream);
for (Function<InputStream, ClipboardReader> reader : READERS) {
FilterInputStream fis = new FilterInputStream(is) {
@Override
public void close() throws IOException {
// Ignore close call!
}
};
try {
return reader.apply(fis).read();
} catch (Exception e) {
is.reset();
}
}
is.close();
throw new IOException("No clipboard found");
}
private static class ResetableInputStream extends InputStream {
private class ResetableInputStream extends InputStream {
private InputStream inputStream;
private int pointer = 0;
@@ -25,20 +25,16 @@ import io.netty.buffer.Unpooled;
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.util.SimpleBitStorage;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Set;
import java.util.function.IntUnaryOperator;
import java.util.function.BiFunction;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
public class ChunkHider21 implements ChunkHider {
private static final int DIRECT_BLOCK_BITS = Math.max(9, Integer.SIZE - Integer.numberOfLeadingZeros(Block.BLOCK_STATE_REGISTRY.size() - 1));
@Override
public Class<?> mapChunkPacket() {
return ClientboundLevelChunkWithLightPacket.class;
@@ -100,70 +96,33 @@ public class ChunkHider21 implements ChunkHider {
private static final Reflection.Method getKey = Reflection.getTypedMethod(registry, "getKey", resourceLocation, Object.class);
private static final Reflection.Method getName = Reflection.getTypedMethod(resourceLocation, "getPath", String.class);
protected boolean tileEntityVisible(Set<String> hiddenBlockEntities, Object tile) {
return !hiddenBlockEntities.contains(TechHider.normalizeBlockEntityId((String) getName.invoke(getKey.invoke(nameField.get(null), entityType.get(tile)))));
return !hiddenBlockEntities.contains(getName.invoke(getKey.invoke(nameField.get(null), entityType.get(tile))));
}
private void blocks(SectionHider section) {
int sourceBitsPerBlock = section.readBitsPerBlock();
section.copyBitsPerBlock();
if(section.isSkipSection()) {
section.writeBitsPerBlock(sourceBitsPerBlock);
copyBlockStorage(section);
return;
}
boolean singleValued = sourceBitsPerBlock == 0;
boolean singleValued = section.getBitsPerBlock() == 0;
if (singleValued) {
int value = ProtocolUtils.readVarInt(section.getIn());
if(section.blockPrecise()) {
writeDirectBlocks(section, DIRECT_BLOCK_BITS, ignored -> value);
} else {
section.writeBitsPerBlock(sourceBitsPerBlock);
ProtocolUtils.writeVarInt(section.getOut(), section.getObfuscate().contains(value) ? section.getTarget() : value);
}
ProtocolUtils.writeVarInt(section.getOut(), !section.isSkipSection() && section.getObfuscate().contains(value) ? section.getTarget() : value);
return;
} else if (sourceBitsPerBlock < 9) {
if(section.blockPrecise()) {
int[] palette = section.readPalette();
SimpleBitStorage values = new SimpleBitStorage(sourceBitsPerBlock, 4096, section.readNewDataArray(4096));
writeDirectBlocks(section, DIRECT_BLOCK_BITS, pos -> palette[values.get(pos)]);
return;
}
section.writeBitsPerBlock(sourceBitsPerBlock);
} else if (section.getBitsPerBlock() < 9) {
// Indirect (paletted) storage – only present when bitsPerBlock < 9 in 1.21+
section.processPalette();
}
if (!section.blockPrecise() && section.isPaletted()) {
if (section.isSkipSection() || (!section.blockPrecise() && section.isPaletted())) {
section.skipNewDataArray(4096);
return;
}
SimpleBitStorage values = new SimpleBitStorage(sourceBitsPerBlock, 4096, section.readNewDataArray(4096));
writeDirectBlocks(section, sourceBitsPerBlock, values::get);
}
private void copyBlockStorage(SectionHider section) {
if(section.getBitsPerBlock() == 0) {
section.copyVarInt();
} else {
if(section.getBitsPerBlock() < 9)
section.skipPalette();
section.skipNewDataArray(4096);
}
}
private void writeDirectBlocks(SectionHider section, int bitsPerBlock, IntUnaryOperator source) {
section.writeBitsPerBlock(bitsPerBlock);
SimpleBitStorage values = new SimpleBitStorage(bitsPerBlock, 4096);
SimpleBitStorage values = new SimpleBitStorage(section.getBitsPerBlock(), 4096, section.readNewDataArray(4096));
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int pos = (((y * 16) + z) * 16) + x;
int value = source.applyAsInt(pos);
TechHider.State test = section.test(x, y, z);
@@ -171,17 +130,15 @@ public class ChunkHider21 implements ChunkHider {
case SKIP:
break;
case CHECK:
if (!section.getObfuscate().contains(value))
if (!section.getObfuscate().contains(values.get(pos)))
break;
case HIDE:
value = section.getTarget();
values.set(pos, section.getTarget());
break;
case HIDE_AIR:
default:
value = section.getAir();
values.set(pos, section.getAir());
}
values.set(pos, value);
}
}
}
@@ -1,104 +0,0 @@
/*
* 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.techhider;
import de.steamwar.Reflection;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.function.BiFunction;
public class ProtocolWrapper21 implements ProtocolWrapper {
private static final Reflection.Field<SectionPos> multiBlockChangeChunk = Reflection.getField(TechHider.multiBlockChangePacket, SectionPos.class, 0);
private static final Reflection.Field<short[]> multiBlockChangePos = Reflection.getField(TechHider.multiBlockChangePacket, short[].class, 0);
private static final Reflection.Field<BlockState[]> multiBlockChangeBlocks = Reflection.getField(TechHider.multiBlockChangePacket, BlockState[].class, 0);
@Override
public BiFunction<Player, Object, Object> multiBlockChangeGenerator(TechHider techHider) {
return (p, packet) -> {
TechHider.LocationEvaluator locationEvaluator = techHider.getLocationEvaluator();
SectionPos sectionPos = multiBlockChangeChunk.get(packet);
int chunkX = sectionPos.x();
int chunkY = sectionPos.y();
int chunkZ = sectionPos.z();
if(locationEvaluator.skipChunkSection(p, chunkX, chunkY, chunkZ))
return packet;
packet = TechHider.multiBlockChangeCloner.apply(packet);
final short[] oldPos = multiBlockChangePos.get(packet);
final BlockState[] oldBlocks = multiBlockChangeBlocks.get(packet);
ArrayList<Short> poss = new ArrayList<>(oldPos.length);
ArrayList<BlockState> blocks = new ArrayList<>(oldPos.length);
for(int i = 0; i < oldPos.length; i++) {
short pos = oldPos[i];
BlockState block = oldBlocks[i];
switch(locationEvaluator.check(p, 16*chunkX + SectionPos.sectionRelativeX(pos), 16*chunkY + SectionPos.sectionRelativeY(pos), 16*chunkZ + SectionPos.sectionRelativeZ(pos))) {
case SKIP:
poss.add(pos);
blocks.add(block);
break;
case CHECK:
poss.add(pos);
blocks.add(techHider.iBlockDataHidden(block) ? (BlockState) techHider.getObfuscationTarget() : block);
break;
default:
break;
}
}
if(blocks.isEmpty())
return null;
short[] newPos = new short[poss.size()];
for(int i = 0; i < newPos.length; i++)
newPos[i] = poss.get(i);
multiBlockChangePos.set(packet, newPos);
multiBlockChangeBlocks.set(packet, blocks.toArray(new BlockState[0]));
return packet;
};
}
private static final Reflection.Field<BlockEntityType> tileEntityType = Reflection.getField(TechHider.tileEntityDataPacket, BlockEntityType.class, 0);
@Override
public boolean unfilteredTileEntityDataAction(Object packet) {
BlockEntityType type = tileEntityType.get(packet);
return type != BlockEntityType.SIGN && type != BlockEntityType.HANGING_SIGN;
}
@Override
public String tileEntityDataType(Object packet) {
return BlockEntityType.getKey(tileEntityType.get(packet)).getPath();
}
private static final Reflection.Field<BlockPos> blockBreakPosition = Reflection.getField(ClientboundBlockDestructionPacket.class, BlockPos.class, 0);
@Override
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, TechHider techHider) {
return (p, packet) -> techHider.getLocationEvaluator().checkBlockPos(p, blockBreakPosition.get(packet)) == TechHider.State.SKIP ? packet : null;
}
}
@@ -22,10 +22,7 @@ package de.steamwar.core;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.sk89q.jnbt.*;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.extension.input.ParserContext;
@@ -60,25 +57,22 @@ public class WorldEditWrapper8 implements WorldEditWrapper {
}
@Override
public void setPlayerClipboard(Player player, Clipboard clipboard) {
public void setPlayerClipboard(Player player, InputStream is, NodeData.SchematicFormat schemFormat) {
WorldData world = new BukkitWorld(player.getWorld()).getWorldData();
Clipboard clipboard;
try {
clipboard = getClipboard(is, schemFormat);
} catch (IOException e) {
throw new RuntimeException(e);
}
Actor actor = WorldEditWrapper.getWorldEditPlugin().wrapCommandSender(player);
WorldEditWrapper.getWorldEditPlugin().getWorldEdit().getSessionManager().get(actor).setClipboard(new ClipboardHolder(clipboard, world));
}
@Override
public Clipboard getClipboard(NodeData data) throws IOException {
InputStream is = data.schemData(true);
return readClipboard(is, data.getNodeFormat());
}
@Override
public Clipboard getClipboard(InputStream inputStream) throws IOException {
return readClipboard(inputStream, getNativeFormat());
}
private Clipboard readClipboard(InputStream is, NodeData.SchematicFormat format) throws IOException {
switch (format) {
public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException {
switch (schemFormat) {
case MCEDIT:
return new SchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData());
case SPONGE_V2:
@@ -54,7 +54,7 @@ public class ChunkHider9 extends ChunkHider8 {
packet = mapChunkCloner.apply(packet);
Set<String> hiddenBlockEntities = techHider.getHiddenBlockEntities();
mapChunkBlockEntities.set(packet, ((List<?>)mapChunkBlockEntities.get(packet)).stream().filter(
nbttag -> !hiddenBlockEntities.contains(TechHider.normalizeBlockEntityId((String) nbtTagGetString.invoke(nbttag, "id")))
nbttag -> !hiddenBlockEntities.contains((String) nbtTagGetString.invoke(nbttag, "id"))
).collect(Collectors.toList()));
int primaryBitMask = mapChunkBitMask.get(packet);
@@ -23,7 +23,6 @@ import de.steamwar.Reflection;
import de.steamwar.Reflection.Field;
import de.steamwar.core.Core;
import io.netty.channel.*;
import io.netty.util.ReferenceCountUtil;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -38,7 +37,6 @@ import org.bukkit.plugin.Plugin;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.logging.Level;
@@ -59,29 +57,17 @@ public class TinyProtocol implements Listener {
public static final Field<List> networkManagers = Reflection.getField(serverConnection, List.class, 0, networkManager);
private static final String HANDLER_NAME = "tiny-steamwar";
private static final Class<?> bundlePacket = getOptionalClass("net.minecraft.network.protocol.BundlePacket");
private static final Class<?> clientboundBundlePacket = getOptionalClass("net.minecraft.network.protocol.game.ClientboundBundlePacket");
private static final Reflection.Method bundleSubPackets = bundlePacket == null ? null : Reflection.getTypedMethod(bundlePacket, null, Iterable.class);
private static final Reflection.Constructor clientboundBundleConstructor = clientboundBundlePacket == null ? null : Reflection.getConstructor(clientboundBundlePacket, Iterable.class);
public static final TinyProtocol instance = new TinyProtocol(Core.getInstance());
public static void init() {
//enforce init
}
private static Class<?> getOptionalClass(String className) {
try {
return Reflection.getClass(className);
} catch (IllegalArgumentException ignored) {
return null;
}
}
private final Plugin plugin;
private final List<?> connections;
private boolean closed;
private final Map<Class<?>, List<BiFunction<Player, Object, Object>>> packetFilters = new ConcurrentHashMap<>();
private final Map<Class<?>, List<BiFunction<Player, Object, Object>>> packetFilters = new HashMap<>();
@Getter
private final Map<Player, PacketInterceptor> playerInterceptors = new HashMap<>();
@@ -221,51 +207,31 @@ public class TinyProtocol implements Listener {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Object originalMsg = msg;
try {
msg = filterPacket(player, msg);
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Error during incoming packet processing", e);
msg = null;
}
if (msg != null) {
super.channelRead(ctx, msg);
} else {
ReferenceCountUtil.release(originalMsg);
}
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
Object originalMsg = msg;
try {
msg = filterPacket(player, msg);
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Error during outgoing packet processing", e);
msg = null;
}
if (msg != null) {
super.write(ctx, msg, promise);
} else {
ReferenceCountUtil.release(originalMsg);
promise.trySuccess();
}
}
private Object filterPacket(Player player, Object packet) {
packet = filterSinglePacket(player, packet);
if(packet == null)
return null;
if(clientboundBundlePacket != null && clientboundBundlePacket.isInstance(packet))
return filterBundlePacket(player, packet);
return packet;
}
private Object filterSinglePacket(Player player, Object packet) {
List<BiFunction<Player, Object, Object>> filters = packetFilters.getOrDefault(packet.getClass(), Collections.emptyList());
for(BiFunction<Player, Object, Object> filter : filters) {
@@ -277,33 +243,5 @@ public class TinyProtocol implements Listener {
return packet;
}
private Object filterBundlePacket(Player player, Object packet) {
if(bundleSubPackets == null || clientboundBundleConstructor == null)
throw new IllegalStateException("Cannot filter bundled packet " + packet.getClass().getName());
ArrayList<Object> filteredPackets = new ArrayList<>();
boolean changed = false;
for(Object subPacket : (Iterable<?>) bundleSubPackets.invoke(packet)) {
Object filteredPacket = filterPacket(player, subPacket);
if(filteredPacket == null) {
changed = true;
continue;
}
if(filteredPacket != subPacket)
changed = true;
filteredPackets.add(filteredPacket);
}
if(!changed)
return packet;
if(filteredPackets.isEmpty())
return null;
return clientboundBundleConstructor.invoke(filteredPackets);
}
}
}
@@ -22,10 +22,10 @@ package de.steamwar.core;
import com.sk89q.worldedit.EmptyClipboardException;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder;
import de.steamwar.sql.NoClipboardException;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.Region;
import de.steamwar.sql.NodeData;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -38,10 +38,8 @@ public interface WorldEditWrapper {
WorldEditWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
InputStream getPlayerClipboard(Player player);
void setPlayerClipboard(Player player, Clipboard clipboard);
Clipboard getClipboard(NodeData data) throws IOException;
Clipboard getClipboard(InputStream inputStream) throws IOException;
void setPlayerClipboard(Player player, InputStream is, NodeData.SchematicFormat schemFormat);
Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException;
Vector getOrigin(Clipboard clipboard);
Vector getMinimum(Region region);
@@ -29,6 +29,14 @@ import java.io.InputStream;
public class SchematicData {
public static Clipboard clipboardFromStream(InputStream is, NodeData.SchematicFormat schemFormat) {
try {
return WorldEditWrapper.impl.getClipboard(is, schemFormat);
} catch (IOException e) {
throw new SecurityException("Could not read schem", e);
}
}
private final NodeData data;
public SchematicData(SchematicNode node) {
@@ -52,11 +60,11 @@ public class SchematicData {
}
public Clipboard load() throws IOException, NoClipboardException {
return WorldEditWrapper.impl.getClipboard(data);
return WorldEditWrapper.impl.getClipboard(data.schemData(), data.getNodeFormat());
}
public void loadToPlayer(Player player) throws IOException, NoClipboardException {
WorldEditWrapper.impl.setPlayerClipboard(player, WorldEditWrapper.impl.getClipboard(data));
WorldEditWrapper.impl.setPlayerClipboard(player, data.schemData(), data.getNodeFormat());
}
public static void saveFromPlayer(Player player, SchematicNode node) throws IOException, NoClipboardException {
@@ -92,17 +92,7 @@ public interface ChunkHider {
}
public void copyBitsPerBlock() {
bitsPerBlock = in.readUnsignedByte();
out.writeByte(bitsPerBlock);
}
public int readBitsPerBlock() {
bitsPerBlock = in.readUnsignedByte();
return bitsPerBlock;
}
public void writeBitsPerBlock(int bitsPerBlock) {
this.bitsPerBlock = bitsPerBlock;
bitsPerBlock = in.readByte();
out.writeByte(bitsPerBlock);
}
@@ -118,15 +108,6 @@ public interface ChunkHider {
copyVarInt();
}
public int[] readPalette() {
int paletteLength = ProtocolUtils.readVarInt(in);
int[] palette = new int[paletteLength];
for(int i = 0; i < paletteLength; i++)
palette[i] = ProtocolUtils.readVarInt(in);
return palette;
}
public void processPalette() {
if(skipSection) {
skipPalette();
@@ -98,7 +98,10 @@ public class ProtocolUtils {
}
public static int posToChunk(int c){
return Math.floorDiv(c, 16);
int chunk = c / 16;
if(c < 0)
chunk--;
return chunk;
}
@Deprecated
@@ -31,10 +31,6 @@ public interface ProtocolWrapper {
boolean unfilteredTileEntityDataAction(Object packet);
default String tileEntityDataType(Object packet) {
return null;
}
BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, TechHider techHider);
BiFunction<Player, Object, Object> multiBlockChangeGenerator(TechHider techHider);
@@ -27,7 +27,6 @@ import org.bukkit.Material;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
@@ -68,12 +67,11 @@ public class TechHider {
private final Set<Integer> obfuscateIds;
@Getter
private final Set<String> hiddenBlockEntities;
private boolean enabled;
public TechHider(LocationEvaluator locationEvaluator, Material obfuscationTarget, Set<Material> obfuscate, Set<String> hiddenBlockEntities) {
this.locationEvaluator = locationEvaluator;
this.obfuscateIds = obfuscate.stream().flatMap(m -> BlockIds.impl.materialToAllIds(m).stream()).collect(Collectors.toSet());
this.hiddenBlockEntities = hiddenBlockEntities.stream().map(TechHider::normalizeBlockEntityId).collect(Collectors.toSet());
this.hiddenBlockEntities = hiddenBlockEntities;
this.obfuscationTarget = getBlockDataByBlock.invoke(getBlockByMaterial.invoke(null, obfuscationTarget));
this.obfuscationTargetId = BlockIds.impl.materialToId(obfuscationTarget);
@@ -83,11 +81,9 @@ public class TechHider {
techhiders.put(multiBlockChangePacket, ProtocolWrapper.impl.multiBlockChangeGenerator(this));
techhiders.put(ChunkHider.impl.mapChunkPacket(), ChunkHider.impl.chunkHiderGenerator(this));
if(Core.getVersion() > 12 && Core.getVersion() < 19 || Core.getVersion() >= 21) {
if(Core.getVersion() > 12 && Core.getVersion() < 19) {
Class<?> blockBreakClass = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket");
BiFunction<Player, Object, Object> blockBreakHider = ProtocolWrapper.impl.blockBreakHiderGenerator(blockBreakClass, this);
if(blockBreakHider != null)
techhiders.put(blockBreakClass, blockBreakHider);
techhiders.put(blockBreakClass, ProtocolWrapper.impl.blockBreakHiderGenerator(blockBreakClass, this));
}
if(Core.getVersion() > 8){
@@ -98,18 +94,10 @@ public class TechHider {
}
public void enable() {
if(enabled)
return;
enabled = true;
techhiders.forEach(TinyProtocol.instance::addFilter);
}
public void disable() {
if(!enabled)
return;
enabled = false;
techhiders.forEach(TinyProtocol.instance::removeFilter);
}
@@ -154,8 +142,6 @@ public class TechHider {
case SKIP:
return packet;
case CHECK:
if(isHiddenBlockEntity(ProtocolWrapper.impl.tileEntityDataType(packet)))
return null;
if(ProtocolWrapper.impl.unfilteredTileEntityDataAction(packet))
return packet;
default:
@@ -163,19 +149,6 @@ public class TechHider {
}
}
public boolean isHiddenBlockEntity(String id) {
return hiddenBlockEntities.contains(normalizeBlockEntityId(id));
}
public static String normalizeBlockEntityId(String id) {
if(id == null)
return "";
id = id.toLowerCase(Locale.ROOT);
int namespaceSeparator = id.indexOf(':');
return namespaceSeparator < 0 ? id : id.substring(namespaceSeparator + 1);
}
public enum State {
SKIP,
CHECK,
@@ -0,0 +1,181 @@
/*
* 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.teamserver.listener;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.world.World;
import de.steamwar.core.WorldEditRenderer;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.MinVersion;
import de.steamwar.teamserver.Builder;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.Vector;
import java.util.*;
import java.util.function.Predicate;
@Linked
@MinVersion(20)
public class SelectAdjacent implements Listener {
private Vector[] FACES = {
new Vector(1, 0, 0),
new Vector(-1, 0, 0),
new Vector(0, 1, 0),
new Vector(0, -1, 0),
new Vector(0, 0, 1),
new Vector(0, 0, -1),
new Vector(1, 1, 0),
new Vector(1, -1, 0),
new Vector(1, 0, 1),
new Vector(1, 0, -1),
new Vector(-1, 1, 0),
new Vector(-1, -1, 0),
new Vector(-1, 0, 1),
new Vector(-1, 0, -1),
new Vector(0, 1, 1),
new Vector(0, 1, -1),
new Vector(0, -1, 1),
new Vector(0, -1, -1),
};
private Map<Player, Selector> selectors = new HashMap<>();
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if (!event.hasItem()) return;
if (event.getItem().getType() != Material.WOODEN_AXE) return;
if (!event.getPlayer().isSneaking()) return;
if (event.getAction() != Action.LEFT_CLICK_BLOCK) return;
Selector selector = selectors.get(event.getPlayer());
if (selector != null) selector.cancel();
Material material = event.getPlayer().getInventory().getItemInOffHand().getType();
if (material.isAir()) {
selector = new Selector(event.getClickedBlock(), event.getPlayer(), __ -> true);
} else {
selector = new Selector(event.getClickedBlock(), event.getPlayer(), type -> type == material);
}
selectors.put(event.getPlayer(), selector);
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
Selector selector = selectors.remove(event.getPlayer());
if (selector != null) selector.cancel();
}
private static final WorldEditPlugin WORLDEDIT_PLUGIN = Objects.requireNonNull((WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit"));
private static final World BUKKITWORLD = new BukkitWorld(Bukkit.getWorlds().get(0));
private class Selector {
private static final int MAX_BLOCKS = 1_000_000;
private int minX;
private int minY;
private int minZ;
private int maxX;
private int maxY;
private int maxZ;
private BukkitTask bukkitTask;
private Predicate<Material> predicate;
private Set<Location> seen = new HashSet<>();
private Set<Location> toCalc = new HashSet<>();
public Selector(Block block, Player player, Predicate<Material> predicate) {
this.predicate = predicate;
toCalc.add(block.getLocation());
minX = block.getX();
minY = block.getY();
minZ = block.getZ();
maxX = block.getX();
maxY = block.getY();
maxZ = block.getZ();
bukkitTask = Bukkit.getScheduler().runTaskTimer(Builder.getInstance(), () -> {
run();
long volume = (long)(maxX - minX + 1) * (long)(maxY - minY + 1) * (long)(maxZ - minZ + 1);
player.sendTitle("", "§e" + volume + " §7Blocks", 0, 5, 0);
WORLDEDIT_PLUGIN.getSession(player).setRegionSelector(BUKKITWORLD, new CuboidRegionSelector(BUKKITWORLD, BlockVector3.at(minX, minY, minZ), BlockVector3.at(maxX, maxY, maxZ)));
WorldEditRenderer.renderPlayer(player);
// boolean finished = toCalc.stream().allMatch(location -> {
// return location.getBlockX() >= minX && location.getBlockY() >= minY && location.getBlockZ() >= minZ &&
// location.getBlockX() <= maxX && location.getBlockY() <= maxY && location.getBlockZ() <= maxZ;
// });
if (toCalc.isEmpty() || seen.size() > MAX_BLOCKS) {
bukkitTask.cancel();
player.sendTitle("§aDone", "§e" + volume + " §7Blocks", 0, 20, 5);
}
}, 1, 1);
}
private void cancel() {
bukkitTask.cancel();
}
private void run() {
Set<Location> current = toCalc;
toCalc = new HashSet<>();
for (Location location : current) {
Block block = location.getBlock();
if (block.isEmpty() || block.isLiquid()) continue;
if (!predicate.test(block.getType())) continue;
seen.add(location);
minX = Math.min(minX, location.getBlockX());
maxX = Math.max(maxX, location.getBlockX());
minY = Math.min(minY, location.getBlockY());
maxY = Math.max(maxY, location.getBlockY());
minZ = Math.min(minZ, location.getBlockZ());
maxZ = Math.max(maxZ, location.getBlockZ());
for (Vector face : FACES) {
Block next = block.getRelative(face.getBlockX(), face.getBlockY(), face.getBlockZ());
if (next.isEmpty() || next.isLiquid()) continue;
if (!predicate.test(next.getType())) continue;
Location loc = next.getLocation();
if (seen.contains(loc)) continue;
toCalc.add(loc);
}
}
}
}
}
@@ -22,7 +22,6 @@ package de.steamwar.towerrun.commands;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeValidator;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.LinkedInstance;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserPerm;
import de.steamwar.towerrun.TowerRun;
@@ -31,8 +30,6 @@ import org.bukkit.entity.Player;
@Linked
public class StartCommand extends SWCommand {
@LinkedInstance
private LobbyCountdown countdown;
public StartCommand() {
@@ -159,8 +159,8 @@ public class TowerGenerator {
noKeyFloors--;
if (!chestBlocks.isEmpty() && noKeyFloors < 0 && random.nextDouble() < config.keyChance) {
noKeyFloors = random.nextInt(config.maxNoKeyFloors - config.minNoKeyFloors) + config.minNoKeyFloors;
for (int i = 0; i < 2 && !chestBlocks.isEmpty(); i++) {
Container container = chestBlocks.remove(random.nextInt(chestBlocks.size()));
for (int i = 0; i < 2; i++) {
Container container = chestBlocks.get(random.nextInt(chestBlocks.size()));
keys.add(container.getLocation());
}
@@ -42,7 +42,6 @@ import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
@@ -159,16 +158,10 @@ public class IngameListener extends GameStateBukkitListener {
public void onKeyUse(PlayerInteractEvent event) {
if (!event.hasItem()) return;
if (event.getItem().getType() != Material.LEVER) return;
event.setCancelled(true);
if (!event.hasBlock()) return;
if (event.getClickedBlock().getType() != Material.IRON_DOOR) return;
if (event.getHand() == null) return;
event.setCancelled(true);
ItemStack itemStack = event.getItem();
itemStack.setAmount(event.getItem().getAmount() - 1);
switch (event.getHand()) {
case OFF_HAND -> event.getPlayer().getInventory().setItemInOffHand(itemStack);
case HAND -> event.getPlayer().getInventory().setItemInMainHand(itemStack);
}
event.getPlayer().getInventory().setItemInMainHand(null);
event.getClickedBlock().breakNaturally();
}
@@ -230,8 +223,6 @@ public class IngameListener extends GameStateBukkitListener {
shouldMelt(block.getRelative(0, 0, -1));
}
private static final Random RANDOM = new Random();
private void shouldMelt(Block block) {
if (block.getType().isBurnable()) return;
if (block.getType().isAir()) return;
@@ -278,9 +269,7 @@ public class IngameListener extends GameStateBukkitListener {
break;
}
Pos pos = new Pos(block.getLocation().getBlockX(), block.getLocation().getBlockY(), block.getLocation().getBlockZ());
int delay = meltingTime + 1 + RANDOM.nextInt(30*20)-30*10;
if (delay < 0) delay = meltingTime + 1;
blocksToMelt.putIfAbsent(pos, time + delay);
blocksToMelt.putIfAbsent(pos, time + meltingTime + 1);
}
@EventHandler
@@ -42,10 +42,6 @@ public abstract class OutsideWincondition extends WinCondition {
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
if (event.getTo().getY() > WorldConfig.ESCAPE_HEIGHT) {
if (event.getTo().getY() > WorldConfig.ESCAPE_HEIGHT + 10 && Arrays.stream(WorldConfig.REGIONS).noneMatch(region -> region.contains(event.getTo().toVector()))) {
TowerRunPlayer tPlayer = TowerRunPlayer.get(event.getPlayer());
tPlayer.player().damage(Integer.MAX_VALUE);
}
return;
}
@@ -57,6 +57,7 @@ dependencies {
implementation(libs.mysql)
implementation(libs.msgpack)
implementation(libs.apolloprotos)
implementation(libs.nbt)
@@ -419,6 +419,7 @@ TEAM_NOT_IN_EVENT=§cThis is not possible during an event.
TEAM_HELP_HEADER=§7Manage your team with §e/team.
TEAM_HELP_LIST=§8/§7team list §8- §7List all teams.
TEAM_HELP_INFO=§8/§7team info §8- §7Get information on a team.
TEAM_HELP_TP=§8/§7team tp §8(§7Team§8) §8- §7Teleport to a team server.
TEAM_HELP_CREATE=§8/§7team create §8- §7Create your own team.
TEAM_HELP_JOIN=§8/§7team join §8- §7Join a team.
TEAM_HELP_CHAT=§8/§7teamchat §8- §7Send messages to your team.
@@ -391,6 +391,7 @@ TEAM_NOT_IN_EVENT=§cDies ist während eines Events nicht möglich.
TEAM_HELP_HEADER=§7Mit §e/team §7verwaltest du dein Team.
TEAM_HELP_LIST=§8/§7team list §8- §7Liste alle Teams auf.
TEAM_HELP_INFO=§8/§7team info §8- §7Informiere dich über ein Team.
TEAM_HELP_TP=§8/§7team tp §8(§7Team§8) §8- §7Teleportiert zum Teamserver.
TEAM_HELP_CREATE=§8/§7team create §8- §7Erstelle dein eigenes Team.
TEAM_HELP_JOIN=§8/§7team join §8- §7Trete einem Team bei.
TEAM_HELP_CHAT=§8/§7teamchat §8- §7Sende Nachrichten an dein Team.
@@ -22,6 +22,7 @@ package de.steamwar.sql;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.commands.CheckCommand;
import java.io.File;
@@ -37,6 +38,15 @@ public class SQLWrapperImpl implements SQLWrapper<String> {
return new GameModeConfig<>(file, GameModeConfig.ToString, GameModeConfig.ToString, GameModeConfig.ToInternalName, true);
}
@Override
public void processSchematicType(GameModeConfig<?, String> gameModeConfig) {
SchematicType type = gameModeConfig.Schematic.Type;
if (type.checkType() != null) {
CheckCommand.setCheckQuestions(type.checkType(), gameModeConfig.CheckQuestions);
CheckCommand.addFightType(type.checkType(), type);
}
}
@Override
public void additionalExceptionMetadata(StringBuilder builder) {
builder.append("\nServers: ");
@@ -25,10 +25,7 @@ import lombok.Getter;
import lombok.experimental.UtilityClass;
import java.io.File;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.*;
@UtilityClass
public class ArenaMode {
@@ -53,12 +50,12 @@ public class ArenaMode {
if(!folder.exists())
return;
GameModeConfig.init();
SchematicType.init();
for (GameModeConfig<String, String> gameModeConfig : GameModeConfig.<String>getAll()) {
for(File file : Arrays.stream(folder.listFiles((file, name) -> name.endsWith(".yml") && !name.endsWith(".kits.yml") && !name.equals("config.yml"))).sorted().toList()) {
GameModeConfig<String, String> gameModeConfig = new GameModeConfig<>(file, GameModeConfig.ToString, GameModeConfig.ToString, GameModeConfig.ToInternalName, false);
if (!gameModeConfig.Server.loaded) continue;
allModes.add(gameModeConfig);
byInternal.put(gameModeConfig.configFile.getName().replace(".yml", ""), gameModeConfig);
byInternal.put(file.getName().replace(".yml", ""), gameModeConfig);
for (String name : gameModeConfig.Server.ChatNames) {
byChat.put(name.toLowerCase(), gameModeConfig);
}
@@ -40,7 +40,6 @@ import net.kyori.adventure.text.format.NamedTextColor;
import java.awt.*;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -49,9 +48,20 @@ import java.util.logging.Level;
@Linked
public class CheckCommand extends SWCommand {
private static final Map<SchematicType, SchematicType> fightTypes = new HashMap<>();
private static final Map<SchematicType, List<String>> checkQuestions = new HashMap<>();
private static final Map<UUID, CheckSession> currentCheckers = new HashMap<>();
private static final Map<Integer, CheckSession> currentSchems = new HashMap<>();
public static void setCheckQuestions(SchematicType checkType, List<String> checkQuestions) {
CheckCommand.checkQuestions.put(checkType, checkQuestions);
}
public static void addFightType(SchematicType checkType, SchematicType fightType) {
fightTypes.put(checkType, fightType);
}
public static boolean isChecking(Player player){
return currentCheckers.containsKey(player.getUniqueId());
}
@@ -137,7 +147,7 @@ public class CheckCommand extends SWCommand {
if(!schem.getSchemtype().check()){
VelocityCore.getLogger().log(Level.SEVERE, () -> sender.user().getUserName() + " tried to check an uncheckable schematic!");
return;
}else if(schem.getOwner() == sender.user().getId() && !sender.user().hasPerm(UserPerm.ADMINISTRATION)) {
}else if(schem.getOwner() == sender.user().getId()) {
sender.system("CHECK_SCHEMATIC_OWN");
return;
}
@@ -238,9 +248,9 @@ public class CheckCommand extends SWCommand {
this.checker = checker;
this.schematic = schematic;
this.startTime = Timestamp.from(Instant.now());
this.checkList = GameModeConfig.getBySchematicType(schematic.getSchemtype()).CheckQuestions.listIterator();
this.checkList = checkQuestions.get(schematic.getSchemtype()).listIterator();
GameModeConfig<String, String> mode = GameModeConfig.getBySchematicType(schematic.getSchemtype());
GameModeConfig<String, String> mode = ArenaMode.getBySchemType(fightTypes.get(schematic.getSchemtype()));
new ServerStarter().test(mode, mode.getRandomMap(), checker.getPlayer()).check(schematic.getId()).callback(subserver -> {
currentCheckers.put(checker.user().getUUID(), this);
currentSchems.put(schematic.getId(), this);
@@ -294,50 +304,7 @@ public class CheckCommand extends SWCommand {
}
private void accept(){
// TODO: This Code is only for the WGS and because YoyoNow is not available this can be removed or changed after the WGS!
if (schematic.getSchemtype().toDB().equals("cwargearseason26")) {
int userId = schematic.getOwner();
SteamwarUser user = SteamwarUser.byId(userId);
int teamId = user.getTeam();
SchematicNode teamFolder = SchematicNode.getSchematicNodeInNode(172325)
.stream()
.filter(schematicNode -> schematicNode.getName().startsWith(teamId + "_"))
.findFirst()
.orElse(null);
if (teamFolder == null) {
internalAccept();
return;
}
// Copy Schem into team folder of -1 user
String name = DateTimeFormatter.ofPattern("yyyy.MM.dd_HH:mm:ss").format(schematic.getLastUpdate().toLocalDateTime());
NodeData data = NodeData.getLatest(schematic);
SchematicNode node = SchematicNode.createSchematic(-1, name, teamFolder.getNodeId());
NodeData.saveFromStream(node, data.schemData(false), data.getNodeFormat());
// Accept the team folder schematic and set other to Normal
node.setSchemtype(GameModeConfig.getBySchematicType(schematic.getSchemtype()).Schematic.Type);
// Conclude by setting send in schematic to normal and broadcast
concludeCheckSession("freigegeben", SchematicType.Normal, () -> {
Chatter owner = Chatter.of(SteamwarUser.byId(schematic.getOwner()).getUUID());
owner.withPlayerOrOffline(
player -> owner.system("CHECK_ACCEPTED", schematic.getSchemtype().name(), schematic.getName()),
() -> DiscordAlert.send(owner, Color.GREEN, new Message("DC_TITLE_SCHEMINFO"), new Message("DC_SCHEM_ACCEPT", schematic.getName()), true)
);
notifyTeam(new Message("CHECK_ACCEPTED_TEAM", schematic.getName(), owner.user().getUserName()));
return owner.getPlayer() != null;
});
return;
}
internalAccept();
}
private void internalAccept() {
concludeCheckSession("freigegeben", GameModeConfig.getBySchematicType(schematic.getSchemtype()).Schematic.Type, () -> {
concludeCheckSession("freigegeben", fightTypes.get(schematic.getSchemtype()), () -> {
Chatter owner = Chatter.of(SteamwarUser.byId(schematic.getOwner()).getUUID());
owner.withPlayerOrOffline(
player -> owner.system("CHECK_ACCEPTED", schematic.getSchemtype().name(), schematic.getName()),
@@ -128,10 +128,8 @@ public class DevCommand extends SWCommand {
if (serverFiles != null) {
for (String serverFile : serverFiles) {
String[] server = serverFile.split("\\.");
int version = Integer.parseInt(server[2]);
if (version == 0) continue;
devServerPorts.put(server[0], Integer.parseInt(server[1]));
devServerVersions.put(server[0], version);
devServerVersions.put(server[0], Integer.parseInt(server[2]));
}
}

Some files were not shown because too many files have changed in this diff Show More