diff --git a/.gitignore b/.gitignore index e038e02a..b0a7fe1b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,8 @@ bin/ .vscode # Other -lib \ No newline at end of file +lib +/WebsiteBackend/data +/WebsiteBackend/logs +/WebsiteBackend/skins +/WebsiteBackend/config.json \ No newline at end of file diff --git a/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/TickManager15.java b/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/TickManager15.java new file mode 100644 index 00000000..a56a2e35 --- /dev/null +++ b/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/TickManager15.java @@ -0,0 +1,140 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bausystem.utils; + +import de.steamwar.bausystem.region.GlobalRegion; +import de.steamwar.bausystem.utils.bossbar.BossBarService; +import de.steamwar.bausystem.utils.tps.TPSFreezeUtils; +import de.steamwar.bausystem.utils.tps.TPSLimitUtils; +import de.steamwar.core.TPSWarpUtils; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class TickManager15 implements TickManager, Listener { + + private static float currentTPSLimit = 20; + private boolean currentlyStepping = false; + private float currentLimit; + private int stepsTotal; + private int stepsLeft; + + @Override + public boolean canFreeze() { + return TPSFreezeUtils.isCanFreeze(); + } + + @Override + public void setTickRate(float tickRate) { + if (currentlyStepping) { + currentlyStepping = false; + Bukkit.getOnlinePlayers().forEach(player -> { + BossBarService.instance.remove(player, GlobalRegion.getInstance(), "TickStep"); + }); + } + TPSWarpUtils.warp(tickRate); + if (currentTPSLimit == 0 && tickRate != 0) { + TPSFreezeUtils.unfreeze(); + } + currentTPSLimit = tickRate; + if (tickRate == 0) { + TPSLimitUtils.unlimit(); + TPSFreezeUtils.freeze(); + } else if (tickRate < 20.0) { + TPSLimitUtils.limit(tickRate); + } else if (tickRate >= 20) { + TPSLimitUtils.unlimit(); + } + } + + @Override + public boolean isFrozen() { + return TPSFreezeUtils.frozen(); + } + + @Override + public void setFreeze(boolean freeze) { + if (freeze) { + setTickRate(0); + } + } + + @Override + public void stepTicks(int ticks) { + currentLimit = 0; + setTickRate(20); + stepsLeft = ticks; + stepsTotal = ticks; + currentlyStepping = true; + } + + @Override + public void sprintTicks(int ticks) { + currentLimit = currentTPSLimit; + setTickRate(4000); + stepsLeft = ticks; + stepsTotal = ticks; + currentlyStepping = true; + } + + @Override + public boolean isSprinting() { + return currentlyStepping && currentTPSLimit > 20; + } + + @Override + public boolean isStepping() { + return currentlyStepping && currentTPSLimit <= 20; + } + + @Override + public float getTickRate() { + return currentTPSLimit; + } + + @Override + public void setBlockTpsPacket(boolean block) { + + } + + @Override + public long getTotalTicks() { + return stepsTotal; + } + + @Override + public long getDoneTicks() { + return stepsTotal - stepsLeft; + } + + @Override + public long getRemainingTicks() { + return stepsLeft; + } + + @EventHandler + public void onTickEnd(TickEndEvent event) { + if (!currentlyStepping) return; + stepsLeft--; + if (stepsLeft <= 0) { + setTickRate(currentLimit); + } + } +} diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/PacketCache.java b/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/tps/PacketCache.java similarity index 83% rename from BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/PacketCache.java rename to BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/tps/PacketCache.java index a53bd819..63308284 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/PacketCache.java +++ b/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/tps/PacketCache.java @@ -1,23 +1,23 @@ /* - * This file is a part of the SteamWar software. + * This file is a part of the SteamWar software. * - * Copyright (C) 2023 SteamWar.de-Serverteam + * Copyright (C) 2020 SteamWar.de-Serverteam * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ -package de.steamwar.bausystem.features.tpslimit; +package de.steamwar.bausystem.utils.tps; import de.steamwar.Reflection; import com.comphenix.tinyprotocol.TinyProtocol; diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSFreezeUtils.java b/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/tps/TPSFreezeUtils.java similarity index 65% rename from BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSFreezeUtils.java rename to BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/tps/TPSFreezeUtils.java index cb79f6fb..bed7f7e6 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSFreezeUtils.java +++ b/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/tps/TPSFreezeUtils.java @@ -1,23 +1,23 @@ /* - * This file is a part of the SteamWar software. + * This file is a part of the SteamWar software. * - * Copyright (C) 2023 SteamWar.de-Serverteam + * Copyright (C) 2020 SteamWar.de-Serverteam * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ -package de.steamwar.bausystem.features.tpslimit; +package de.steamwar.bausystem.utils.tps; import de.steamwar.Reflection; import lombok.Getter; diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSLimitUtils.java b/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/tps/TPSLimitUtils.java similarity index 98% rename from BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSLimitUtils.java rename to BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/tps/TPSLimitUtils.java index 29068ace..8b58b00a 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSLimitUtils.java +++ b/BauSystem/BauSystem_15/src/de/steamwar/bausystem/utils/tps/TPSLimitUtils.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package de.steamwar.bausystem.features.tpslimit; +package de.steamwar.bausystem.utils.tps; import de.steamwar.Reflection; import com.comphenix.tinyprotocol.TinyProtocol; diff --git a/BauSystem/BauSystem_19/src/de/steamwar/bausystem/utils/TickListener19.java b/BauSystem/BauSystem_19/src/de/steamwar/bausystem/utils/TickListener19.java index 5191b38b..211c004b 100644 --- a/BauSystem/BauSystem_19/src/de/steamwar/bausystem/utils/TickListener19.java +++ b/BauSystem/BauSystem_19/src/de/steamwar/bausystem/utils/TickListener19.java @@ -22,7 +22,6 @@ package de.steamwar.bausystem.utils; import com.destroystokyo.paper.event.server.ServerTickEndEvent; import com.destroystokyo.paper.event.server.ServerTickStartEvent; import de.steamwar.bausystem.BauSystem; -import de.steamwar.bausystem.features.tpslimit.TPSFreezeUtils; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -37,7 +36,7 @@ public class TickListener19 implements TickListener, Listener { @EventHandler public void onServerTickStart(ServerTickStartEvent event) { - if (TPSFreezeUtils.isFrozen()) return; + if (TickManager.impl.isFrozen()) return; Bukkit.getPluginManager().callEvent(new TickStartEvent()); tickStartRan = true; } diff --git a/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/NMSWrapper21.java b/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/NMSWrapper21.java index e6308e43..816b9bd7 100644 --- a/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/NMSWrapper21.java +++ b/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/NMSWrapper21.java @@ -21,41 +21,39 @@ package de.steamwar.bausystem.utils; import de.steamwar.Reflection; import de.steamwar.bausystem.features.util.NoClipCommand; -import net.minecraft.core.component.DataComponents; -import net.minecraft.nbt.NBTBase; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot; -import net.minecraft.network.protocol.game.PacketPlayOutExplosion; -import net.minecraft.network.protocol.game.PacketPlayOutGameStateChange; -import net.minecraft.server.level.EntityPlayer; -import net.minecraft.server.level.PlayerInteractManager; -import net.minecraft.world.entity.player.EntityHuman; -import net.minecraft.world.entity.player.PlayerAbilities; -import net.minecraft.world.item.component.CustomData; -import net.minecraft.world.level.EnumGamemode; +import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.ItemContainerContents; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.network.protocol.game.ClientboundExplodePacket; +import net.minecraft.network.protocol.game.ClientboundGameEventPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ServerPlayerGameMode; +import net.minecraft.world.entity.player.Abilities; +import net.minecraft.world.level.GameType; import org.bukkit.GameMode; import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_21_R2.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_21_R2.inventory.CraftItemStack; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerGameModeChangeEvent; import org.bukkit.inventory.ItemStack; +import java.util.List; import java.util.Optional; public class NMSWrapper21 implements NMSWrapper { - private static final Reflection.Field playerInteractManager = Reflection.getField(EntityPlayer.class, null, PlayerInteractManager.class); + private static final Reflection.Field playerInteractManager = Reflection.getField(ServerPlayer.class, null, ServerPlayerGameMode.class); @Override public void setInternalGameMode(Player player, GameMode gameMode) { - playerInteractManager.get(((CraftPlayer) player).getHandle()).a(EnumGamemode.a(gameMode.getValue())); + playerInteractManager.get(((CraftPlayer) player).getHandle()).changeGameModeForPlayer(GameType.byId(gameMode.getValue()), PlayerGameModeChangeEvent.Cause.UNKNOWN, null); } @Override public void setSlotToItemStack(Player player, Object o) { - PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o; - int index = packetPlayInSetCreativeSlot.b(); + ClientboundContainerSetSlotPacket packetPlayInSetCreativeSlot = (ClientboundContainerSetSlotPacket) o; + int index = packetPlayInSetCreativeSlot.getSlot(); if (index >= 36 && index <= 44) { index -= 36; } else if (index > 44) { @@ -63,25 +61,23 @@ public class NMSWrapper21 implements NMSWrapper { } else if (index <= 8) { index = index - 8 + 36; } - player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.e())); + player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.getItem())); if (index < 9) player.getInventory().setHeldItemSlot(index); player.updateInventory(); } - private static final Reflection.Field gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, PacketPlayOutGameStateChange.a.class, 12); + private static final Reflection.Field gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, ClientboundGameEventPacket.Type.class, 12); @Override public void setGameStateChangeReason(Object packet) { - gameStateChangeReason.set(packet, PacketPlayOutGameStateChange.d); + gameStateChangeReason.set(packet, ClientboundGameEventPacket.CHANGE_GAME_MODE); } - private static final Reflection.Field playerAbilities = Reflection.getField(EntityHuman.class, null, PlayerAbilities.class); - @Override public void setPlayerBuildAbilities(Player player) { - PlayerAbilities abilities = playerAbilities.get(((CraftPlayer) player).getHandle()); - abilities.d = true; - abilities.e = true; + Abilities abilities = (((CraftPlayer) player).getHandle()).getAbilities(); + abilities.mayBuild = true; + abilities.mayfly = true; } @Override @@ -93,49 +89,45 @@ public class NMSWrapper21 implements NMSWrapper { @Override public boolean checkItemStack(ItemStack item) { - net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item); - NBTTagCompound tag = nmsItem.a(DataComponents.b, CustomData.a).c(); - if (tag.e("BlockEntityTag")) { - NBTTagCompound blockTag = tag.p("BlockEntityTag"); - if (blockTag.e("Items")) { - return drillDown(blockTag.c("Items", 10), 0, 0) > threshold; - } + ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER); + if (data == null) { + return false; } - return false; + return drillDown(data.contents(), 0, 0) > threshold; } - private int drillDown(NBTTagList items, int layer, int start) { + private int drillDown(List items, int layer, int start) { if (layer > 2) return start + threshold; int invalid = start; - for (NBTBase nbtBase : items) { - if (!(nbtBase instanceof NBTTagCompound slot)) + for (int i = start; i < items.size(); i++) { + ItemStack item = items.get(i); + if (item.isEmpty()) continue; + + invalid += item.getAmount(); + + ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER); + if (data == null) { continue; - if (slot.e("tag")) { - invalid += slot.f("Count"); - NBTTagCompound iTag = slot.p("tag"); - if (iTag.e("BlockEntityTag")) { - NBTTagCompound blockTag = iTag.p("BlockEntityTag"); - if (blockTag.e("Items")) { - invalid = drillDown(blockTag.c("Items", 10), layer + 1, invalid); - } - } } - if (invalid > threshold) - break; + + List subItems = data.contents(); + if (subItems.size() > 1) { + invalid = drillDown(subItems, layer + 1, invalid); + } } return invalid; } @Override public Object resetExplosionKnockback(Object packet) { - PacketPlayOutExplosion explosion = (PacketPlayOutExplosion) packet; + ClientboundExplodePacket explosion = (ClientboundExplodePacket) packet; - return new PacketPlayOutExplosion( - explosion.b(), + return new ClientboundExplodePacket( + explosion.center(), Optional.empty(), - explosion.f(), - explosion.g() + explosion.explosionParticle(), + explosion.explosionSound() ); } } diff --git a/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/TickManager21.java b/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/TickManager21.java new file mode 100644 index 00000000..af3792f7 --- /dev/null +++ b/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/TickManager21.java @@ -0,0 +1,150 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2025 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bausystem.utils; + +import com.comphenix.tinyprotocol.TinyProtocol; +import de.steamwar.Reflection; +import de.steamwar.bausystem.BauSystem; +import net.minecraft.network.protocol.game.ClientboundTickingStatePacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.ServerTickRateManager; +import net.minecraft.world.TickRateManager; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +public class TickManager21 implements TickManager { + private static final ServerTickRateManager manager = MinecraftServer.getServer().tickRateManager(); + private static final Reflection.Field frozenTicksToRun = Reflection.getField(TickRateManager.class, int.class, 0); + private static final Reflection.Field remainingSprintTicks = Reflection.getField(ServerTickRateManager.class, long.class, 0); + + private boolean blockTpsPacket = true; + private int totalSteps; + + public TickManager21() { + TinyProtocol.instance.addFilter(ClientboundTickingStatePacket.class, this::blockPacket); + } + + private Object blockPacket(Player player, Object packet) { + if (blockTpsPacket) { + return new ClientboundTickingStatePacket(20, manager.isFrozen()); + } else { + return packet; + } + } + + @Override + public boolean canFreeze() { + return true; + } + + @Override + public void setBlockTpsPacket(boolean block) { + blockTpsPacket = block; + if (blockTpsPacket) { + ClientboundTickingStatePacket packet = new ClientboundTickingStatePacket(20, manager.isFrozen()); + Bukkit.getOnlinePlayers().forEach(player -> TinyProtocol.instance.sendPacket(player, packet)); + } else { + ClientboundTickingStatePacket packet = new ClientboundTickingStatePacket(manager.tickrate(), manager.isFrozen()); + Bukkit.getOnlinePlayers().forEach(player -> TinyProtocol.instance.sendPacket(player, packet)); + } + } + + @Override + public void setTickRate(float tickRate) { + if (isFrozen()) { + setFreeze(false); + } + manager.setTickRate(tickRate); + } + + @Override + public boolean isFrozen() { + return manager.isFrozen(); + } + + @Override + public void setFreeze(boolean freeze) { + manager.setFrozen(freeze); + } + + @Override + public void stepTicks(int ticks) { + if (manager.isSprinting()) { + manager.stopSprinting(); + } else if (manager.isSteppingForward()) { + manager.stopStepping(); + } + this.totalSteps = ticks; + manager.setFrozen(true); + manager.stepGameIfPaused(ticks); + manager.setFrozen(false); + Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), (bukkitTask) -> { + if (manager.isSteppingForward()) return; + manager.setFrozen(true); + bukkitTask.cancel(); + }, 1, 1); + manager.tick(); + } + + @Override + public void sprintTicks(int ticks) { + if (manager.isSteppingForward()) { + manager.stopStepping(); + } else if (manager.isSprinting()) { + manager.stopSprinting(); + } + this.totalSteps = ticks; + manager.requestGameToSprint(ticks, true); + } + + @Override + public boolean isSprinting() { + return manager.isSprinting(); + } + + @Override + public boolean isStepping() { + return manager.isSteppingForward(); + } + + @Override + public float getTickRate() { + return manager.tickrate(); + } + + @Override + public long getRemainingTicks() { + if (isSprinting()) { + return remainingSprintTicks.get(manager); + } else { + return frozenTicksToRun.get(manager); + } + } + + @Override + public long getDoneTicks() { + return totalSteps - getRemainingTicks(); + } + + @Override + public long getTotalTicks() { + return totalSteps; + } +} diff --git a/BauSystem/BauSystem_Main/src/BauSystem.properties b/BauSystem/BauSystem_Main/src/BauSystem.properties index 90f1d4cf..e1cce9bf 100644 --- a/BauSystem/BauSystem_Main/src/BauSystem.properties +++ b/BauSystem/BauSystem_Main/src/BauSystem.properties @@ -38,6 +38,7 @@ SCOREBOARD_TRACE_TICKS=Ticks SCOREBOARD_TECHHIDER=TechHider§8: §aOn SCOREBOARD_XRAY=XRay§8: §aOn SCOREBOARD_LOCK_TEAM=Bau Lock§8: §eTeam +SCOREBOARD_LOCK_SUPERVISOR=Bau Lock§8: §eSupervisor SCOREBOARD_LOCK_TEAM_AND_SERVERTEAM=Bau Lock§8: §e(Server) Team SCOREBOARD_LOCK_SERVERTEAM=Bau Lock§8: §eServer Team SCOREBOARD_LOCK_NOBODY=Bau Lock§8: §cNobody @@ -514,7 +515,7 @@ LOADER_HELP_GUI=§8/§7loader gui §8- §7Shows Loader gui LOADER_HELP_STOP=§8/§eloader stop §8- §7Stops recording/playback LOADER_HELP_WAIT=§8/§7loader wait §8[§7Ticks§8] - §7Sets wait time between shots LOADER_HELP_SPEED=§8/§7loader speed §8[§7Ticks§8] - §7Sets wait time between actions -LOADER_NO_LOADER=§cYou have no Laoder. Create one with /loader setup +LOADER_NO_LOADER=§cYou have no Loader. Create one with /loader setup LOADER_NEW=§7Load your cannon and fire it once, to initialise the loader. LOADER_HOW_TO_START=§7Then, execute /§eloader start§7 to start the Loader LOADER_ACTIVE=§7The Loader is now active. @@ -846,7 +847,7 @@ LAUFBAU_SETTINGS_INACTIVE=§cInactive LAUFBAU_SETTINGS_MIXED=§e{0}§8/§e{1} §aActive LAUFBAU_SETTINGS_GUI_BACK=§eBack LAUFBAU_SETTINGS_TOGGLE=§eClick §8-§7 Toggle -LAUFBAU_SETTINGS_ADVANCED=§eMiddle-Click §8-§7 Advanced settings +LAUFBAU_SETTINGS_ADVANCED=§eLeft-Click §8-§7 Advanced settings LAUFBAU_BLOCK_COBWEB=§eCobweb LAUFBAU_BLOCK_GRASS_PATH=§eGrass Path LAUFBAU_BLOCK_SOUL_SAND=§eSoul Sand diff --git a/BauSystem/BauSystem_Main/src/BauSystem_de.properties b/BauSystem/BauSystem_Main/src/BauSystem_de.properties index fca76eb9..a8f67bcb 100644 --- a/BauSystem/BauSystem_Main/src/BauSystem_de.properties +++ b/BauSystem/BauSystem_Main/src/BauSystem_de.properties @@ -792,7 +792,7 @@ LAUFBAU_SETTINGS_INACTIVE=§cInaktiv LAUFBAU_SETTINGS_MIXED=§e{0}§8/§e{1} §aAktiv LAUFBAU_SETTINGS_GUI_BACK=§eBack LAUFBAU_SETTINGS_TOGGLE=§eClick §8-§7 Toggle -LAUFBAU_SETTINGS_ADVANCED=§eMiddle-Click §8-§7 Erweiterte Einstellung +LAUFBAU_SETTINGS_ADVANCED=§eLinks-Click §8-§7 Erweiterte Einstellung LAUFBAU_BLOCK_COBWEB=§eCobweb LAUFBAU_BLOCK_GRASS_PATH=§eGrass Path LAUFBAU_BLOCK_SOUL_SAND=§eSoul Sand diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/BauSystem.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/BauSystem.java index 0d5fa43c..1d47beb8 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/BauSystem.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/BauSystem.java @@ -28,7 +28,6 @@ import de.steamwar.bausystem.features.script.lua.libs.LuaLib; import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader; import de.steamwar.bausystem.features.slaves.panzern.Panzern; import de.steamwar.bausystem.features.slaves.panzern.PanzernAlgorithm; -import de.steamwar.bausystem.features.tpslimit.TPSFreezeUtils; import de.steamwar.bausystem.features.tracer.TraceManager; import de.steamwar.bausystem.features.tracer.TraceRecorder; import de.steamwar.bausystem.features.world.BauScoreboard; @@ -38,11 +37,13 @@ import de.steamwar.bausystem.region.loader.RegionLoader; import de.steamwar.bausystem.region.loader.Updater; import de.steamwar.bausystem.utils.ScoreboardElement; import de.steamwar.bausystem.utils.TickListener; +import de.steamwar.bausystem.utils.TickManager; import de.steamwar.bausystem.worlddata.WorldData; import de.steamwar.command.AbstractValidator; import de.steamwar.command.SWCommand; import de.steamwar.command.SWCommandUtils; import de.steamwar.core.Core; +import de.steamwar.core.WorldEditRendererCUIEditor; import de.steamwar.linkage.LinkedInstance; import de.steamwar.linkage.MaxVersion; import de.steamwar.linkage.MinVersion; @@ -206,6 +207,8 @@ public class BauSystem extends JavaPlugin { TraceManager.instance.init(); TraceRecorder.instance.init(); + + new WorldEditRendererCUIEditor(); } @Override @@ -263,7 +266,7 @@ public class BauSystem extends JavaPlugin { @Override public void run() { - if (TPSFreezeUtils.isFrozen()) return; + if (TickManager.impl.isFrozen()) return; if (counter >= delay) { runnable.run(); cancel(); @@ -281,7 +284,7 @@ public class BauSystem extends JavaPlugin { @Override public void run() { - if (TPSFreezeUtils.isFrozen()) return; + if (TickManager.impl.isFrozen()) return; if (counter >= (first ? delay : period)) { first = false; runnable.run(); diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/gui/editor/BauGuiEditor.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/gui/editor/BauGuiEditor.java index e40b01f3..b548b60e 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/gui/editor/BauGuiEditor.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/gui/editor/BauGuiEditor.java @@ -23,6 +23,7 @@ import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.features.gui.BauGUI; import de.steamwar.bausystem.linkage.specific.BauGuiItem; import de.steamwar.core.TrickyTrialsWrapper; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import de.steamwar.inventory.SWListInv; import de.steamwar.linkage.Linked; @@ -74,7 +75,7 @@ public class BauGuiEditor implements Listener { inv.setItem(mapping.getSize() + 5, new SWItem(Material.BARRIER, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH", p), Arrays.asList(BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH_LORE", p)), false, clickType -> { }).getItemStack()); inv.setItem(mapping.getSize() + 6, new SWItem(TrickyTrialsWrapper.impl.getTurtleScute(), BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_MORE", p)).getItemStack()); - inv.setItem(mapping.getSize() + 8, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_CLOSE", p)).getItemStack()); + inv.setItem(mapping.getSize() + 8, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_CLOSE", p)).setCustomModelData(CMDs.BACK).getItemStack()); p.openInventory(inv); p.getOpenInventory().setCursor(cursor == null ? new SWItem().getItemStack() : cursor); diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loader/elements/LoaderInteractionElement.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loader/elements/LoaderInteractionElement.java index 67539fd8..2caacbc4 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loader/elements/LoaderInteractionElement.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loader/elements/LoaderInteractionElement.java @@ -20,6 +20,7 @@ package de.steamwar.bausystem.features.loader.elements; import de.steamwar.bausystem.BauSystem; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWAnvilInv; import de.steamwar.inventory.SWInventory; import de.steamwar.inventory.SWItem; @@ -113,7 +114,7 @@ public abstract class LoaderInteractionElement & LoaderSetting }); listInv.setItem(48, new SWItem(Material.ARROW, "§7Back", clickType -> { backAction.run(); - })); + }).setCustomModelData(CMDs.BACK)); listInv.setItem(50, new SWItem(Material.GHAST_SPAWN_EGG, "§7Insert another Setting", clickType -> { elements.add(defaultSetting); extraPower.add(0); @@ -150,7 +151,7 @@ public abstract class LoaderInteractionElement & LoaderSetting SWInventory swInventory = new SWInventory(player, guiSize, BauSystem.MESSAGE.parse("LOADER_GUI_SETTINGS_TITLE", player)); for (int i = guiSize - 9; i < guiSize; i++) swInventory.setItem(i, new SWItem(Material.GRAY_STAINED_GLASS_PANE, "§7", clickType -> {})); - swInventory.setItem(guiSize - 9, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("LOADER_GUI_SETTINGS_BACK", player)).getItemStack(), clickType -> back.run()); + swInventory.setItem(guiSize - 9, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("LOADER_GUI_SETTINGS_BACK", player)).setCustomModelData(CMDs.BACK).getItemStack(), clickType -> back.run()); swInventory.setItem(guiSize - 5, new SWItem(Material.WOODEN_AXE, BauSystem.MESSAGE.parse("LOADER_GUI_SETTINGS_COPY", player)).getItemStack(), clickType -> { SWAnvilInv swAnvilInv = new SWAnvilInv(player, BauSystem.MESSAGE.parse("LOADER_GUI_COPY_TITLE", player), "1"); swAnvilInv.setCallback(s -> { diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loader/elements/impl/LoaderWait.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loader/elements/impl/LoaderWait.java index 41fcb977..618be768 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loader/elements/impl/LoaderWait.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/loader/elements/impl/LoaderWait.java @@ -21,6 +21,7 @@ package de.steamwar.bausystem.features.loader.elements.impl; import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.features.loader.elements.LoaderElement; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWAnvilInv; import de.steamwar.inventory.SWInventory; import de.steamwar.inventory.SWItem; @@ -60,7 +61,7 @@ public class LoaderWait implements LoaderElement { public void click(Player player, Runnable backAction) { SWInventory swInventory = new SWInventory(player, 18, BauSystem.MESSAGE.parse("LOADER_GUI_WAIT_TITLE", player)); for (int i = 9; i < 18; i++) swInventory.setItem(i, new SWItem(Material.GRAY_STAINED_GLASS_PANE, "§7")); - swInventory.setItem(9, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("LOADER_GUI_WAIT_BACK", player)).getItemStack(), clickType -> backAction.run()); + swInventory.setItem(9, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("LOADER_GUI_WAIT_BACK", player)).setCustomModelData(CMDs.BACK).getItemStack(), clickType -> backAction.run()); swInventory.setItem(3, new SWItem(SWItem.getDye(1), BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE_SHIFT", player)), false, clickType -> {}).getItemStack(), clickType -> { delay -= clickType.isShiftClick() ? 5 : 1; diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/SteamWarLuaPlugin.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/SteamWarLuaPlugin.java index c047531c..c3370904 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/SteamWarLuaPlugin.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/SteamWarLuaPlugin.java @@ -166,6 +166,8 @@ public class SteamWarLuaPlugin extends TwoArgFunction { env.set("rawlen", NIL); env.set("rawset", NIL); env.set("xpcall", NIL); + env.set("require", NIL); + env.set("package", NIL); return null; } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/TpsLib.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/TpsLib.java index 6b9435e1..44d9a378 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/TpsLib.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/lua/libs/TpsLib.java @@ -20,6 +20,7 @@ package de.steamwar.bausystem.features.script.lua.libs; import de.steamwar.bausystem.features.tpslimit.TPSSystem; +import de.steamwar.bausystem.utils.TickManager; import de.steamwar.core.TPSWatcher; import de.steamwar.linkage.Linked; import de.steamwar.linkage.LinkedInstance; @@ -51,7 +52,7 @@ public class TpsLib implements LuaLib { tpsLib.set("fiveMinute", getter(() -> TPSWatcher.getTPS(TPSWatcher.TPSType.FIVE_MINUTES))); tpsLib.set("tenMinute", getter(() -> TPSWatcher.getTPS(TPSWatcher.TPSType.TEN_MINUTES))); tpsLib.set("current", getter(TPSWatcher::getTPS)); - tpsLib.set("limit", getter(TPSSystem::getCurrentTPSLimit)); + tpsLib.set("limit", getter(() -> (double) TickManager.impl.getTickRate())); return tpsLib; } } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCommand.java index bf329b3b..646d22a9 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCommand.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCommand.java @@ -76,7 +76,7 @@ public class SimulatorCommand extends SWCommand { @Register(value = "start", description = "SIMULATOR_START_HELP") public void start(@Validator Player p, @ErrorMessage("SIMULATOR_NOT_EXISTS") Simulator simulator) { - SimulatorExecutor.run(simulator, () -> {}); + SimulatorExecutor.run(p, simulator, null); } @Register(value = "rename", description = "SIMULATOR_RENAME_HELP") diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java index f9629c3d..8ffca7a9 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java @@ -367,7 +367,7 @@ public class SimulatorCursor implements Listener { if (simulator == null) { return; } - SimulatorExecutor.run(simulator, () -> {}); + SimulatorExecutor.run(event.getPlayer(), simulator, null); return; } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/Simulator.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/Simulator.java index 8dcb8321..5cb4de3c 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/Simulator.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/Simulator.java @@ -40,9 +40,11 @@ public final class Simulator { private SimulatorStabGenerator stabGenerator = null; private Material material = Material.BARREL; private final String name; - private boolean autoTrace = false; private final List groups = new ArrayList<>(); + private boolean autoTrace = false; + private boolean autoTestblock = false; + public void move(int x, int y, int z) { groups.forEach(simulatorGroup -> { simulatorGroup.move(x, y, z); diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/SimulatorExecutor.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/SimulatorExecutor.java index b052e4c8..5192fde8 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/SimulatorExecutor.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/SimulatorExecutor.java @@ -31,6 +31,7 @@ import de.steamwar.linkage.Linked; import de.steamwar.linkage.MinVersion; import org.bukkit.Bukkit; import org.bukkit.World; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -46,7 +47,7 @@ public class SimulatorExecutor implements Listener { private static Map>> tickStartActions = new HashMap<>(); private static Map> tickEndActions = new HashMap<>(); - public static boolean run(Simulator simulator, Runnable onEnd) { + public static boolean run(Player player, Simulator simulator, Runnable onEnd) { if (currentlyRunning.contains(simulator)) return false; currentlyRunning.add(simulator); @@ -83,10 +84,15 @@ public class SimulatorExecutor implements Listener { }); } - onEnd.run(); + if (onEnd != null) { + onEnd.run(); + } } }); + if (player != null && simulator.isAutoTestblock()) { + player.performCommand("tb"); + } if (simulator.isAutoTrace() && onEnd == null) { simulator.getGroups() .stream() diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabStep.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabStep.java index ad0d05ee..6a0e1a2f 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabStep.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/execute/StabStep.java @@ -58,7 +58,7 @@ public abstract class StabStep { protected abstract void start(); protected final void runSimulator(Runnable onFinish) { - SimulatorExecutor.run(data.simulator, () -> { + SimulatorExecutor.run(null, data.simulator, () -> { Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> { if (this instanceof Listener) { HandlerList.unregisterAll((Listener) this); diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorGroupGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorGroupGui.java index c3b8ee1a..e18ef66e 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorGroupGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorGroupGui.java @@ -25,6 +25,7 @@ import de.steamwar.bausystem.features.simulator.data.SimulatorElement; import de.steamwar.bausystem.features.simulator.data.SimulatorGroup; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorPageGui; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -70,12 +71,12 @@ public class SimulatorGroupGui extends SimulatorPageGui> { inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> { back.open(); - })); + }).setCustomModelData(CMDs.BACK)); inventory.setItem(8, new SWItem(Material.BARRIER, "§eDelete", clickType -> { simulatorGroup.getElements().clear(); SimulatorWatcher.update(simulator); - })); + }).setCustomModelData(CMDs.Simulator.DELETE)); inventory.setItem(4, simulatorGroup.toItem(player, clickType -> { if (simulatorGroup.getMaterial() == null) return; @@ -85,7 +86,7 @@ public class SimulatorGroupGui extends SimulatorPageGui> { inventory.setItem(48, new SWItem(Material.REPEATER, "§eSettings", clickType -> { new SimulatorGroupSettingsGui(player, simulator, simulatorGroup, this).open(); - })); + }).setCustomModelData(CMDs.Simulator.SETTINGS)); boolean disabled = simulatorGroup.getMaterial() == null ? simulatorGroup.getElements().stream().allMatch(SimulatorElement::isDisabled) : simulatorGroup.isDisabled(); inventory.setItem(50, new SWItem(disabled ? Material.ENDER_PEARL : Material.ENDER_EYE, simulatorGroup.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> { if (simulatorGroup.getMaterial() == null) { @@ -96,7 +97,7 @@ public class SimulatorGroupGui extends SimulatorPageGui> { simulatorGroup.setDisabled(!disabled); } SimulatorWatcher.update(simulator); - })); + }).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED)); } @Override diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorGroupSettingsGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorGroupSettingsGui.java index ba5b984e..acb80f2f 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorGroupSettingsGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorGroupSettingsGui.java @@ -25,10 +25,10 @@ import de.steamwar.bausystem.features.simulator.data.SimulatorGroup; import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.Material; import org.bukkit.entity.Player; -import org.bukkit.util.Vector; import java.util.Arrays; @@ -58,7 +58,7 @@ public class SimulatorGroupSettingsGui extends SimulatorBaseGui { // Back Arrow inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> { back.open(); - })); + }).setCustomModelData(CMDs.BACK)); // Material Chooser inventory.setItem(4, simulatorGroup.toItem(player, clickType -> { @@ -69,10 +69,10 @@ public class SimulatorGroupSettingsGui extends SimulatorBaseGui { // Base Tick int baseTicks = simulatorGroup.getBaseTick(); - inventory.setItem(9, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { simulatorGroup.changeBaseTicks(clickType.isShiftClick() ? 5 : 1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); SWItem baseTick = new SWItem(Material.REPEATER, "§eTicks§8:§7 " + baseTicks, clickType -> { new SimulatorAnvilGui<>(player, "Ticks", baseTicks + "", Integer::parseInt, integer -> { if (integer < 0) return false; @@ -83,14 +83,14 @@ public class SimulatorGroupSettingsGui extends SimulatorBaseGui { }); baseTick.getItemStack().setAmount(Math.max(1, Math.min(baseTicks, 64))); inventory.setItem(18, baseTick); - inventory.setItem(27, SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(27, new SWItem(SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { if (baseTicks - (clickType.isShiftClick() ? 5 : 1) < 0) { simulatorGroup.changeBaseTicks(-baseTicks); } else { simulatorGroup.changeBaseTicks(clickType.isShiftClick() ? -5 : -1); } SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); boolean allTNT = simulatorGroup.getElements().stream().allMatch(TNTElement.class::isInstance); @@ -163,10 +163,10 @@ public class SimulatorGroupSettingsGui extends SimulatorBaseGui { } //Pos X - inventory.setItem(15, SWItem.getDye(10), "§e+1", Arrays.asList(allTNT ? "§7Shift§8: §e+0.0625" : "§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList(allTNT ? "§7Shift§8: §e+0.0625" : "§7Shift§8: §e+5"), false, clickType -> { simulatorGroup.move(clickType.isShiftClick() ? (allTNT ? 0.0625 : 5) : 1, 0, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); inventory.setItem(24, new SWItem(Material.PAPER, "§eX", clickType -> { new SimulatorAnvilGui<>(player, "Relative X", "", Double::parseDouble, number -> { if(!allTNT){ @@ -177,16 +177,16 @@ public class SimulatorGroupSettingsGui extends SimulatorBaseGui { return true; }, this).setItem(Material.PAPER).open(); })); - inventory.setItem(33, SWItem.getDye(1), "§e-1", Arrays.asList(allTNT ? "§7Shift§8: §e-0.0625" : "§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList(allTNT ? "§7Shift§8: §e-0.0625" : "§7Shift§8: §e-5"), false, clickType -> { simulatorGroup.move(clickType.isShiftClick() ? (allTNT ? -0.0625 : -5) : -1, 0, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Pos Y - inventory.setItem(16, SWItem.getDye(10), "§e+1", Arrays.asList(allTNT ? "§7Shift§8: §e+0.0625" : "§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList(allTNT ? "§7Shift§8: §e+0.0625" : "§7Shift§8: §e+5"), false, clickType -> { simulatorGroup.move(0, clickType.isShiftClick() ? (allTNT ? 0.0625 : 5) : 1, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); inventory.setItem(25, new SWItem(Material.PAPER, "§eY", clickType -> { new SimulatorAnvilGui<>(player, "Relative Y", "", Double::parseDouble, number -> { if(!allTNT){ @@ -197,16 +197,16 @@ public class SimulatorGroupSettingsGui extends SimulatorBaseGui { return true; }, this).setItem(Material.PAPER).open(); })); - inventory.setItem(34, SWItem.getDye(1), "§e-1", Arrays.asList(allTNT ? "§7Shift§8: §e-0.0625" : "§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList(allTNT ? "§7Shift§8: §e-0.0625" : "§7Shift§8: §e-5"), false, clickType -> { simulatorGroup.move(0, clickType.isShiftClick() ? (allTNT ? -0.0625 : -5) : -1, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED)); //Pos Z - inventory.setItem(17, SWItem.getDye(10), "§e+1", Arrays.asList(allTNT ? "§7Shift§8: §e+0.0625" : "§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList(allTNT ? "§7Shift§8: §e+0.0625" : "§7Shift§8: §e+5"), false, clickType -> { simulatorGroup.move(0, 0, clickType.isShiftClick() ? (allTNT ? 0.0625 : 5) : 1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); inventory.setItem(26, new SWItem(Material.PAPER, "§eZ", clickType -> { new SimulatorAnvilGui<>(player, "Relative Z", "", Double::parseDouble, number -> { if(!allTNT){ @@ -217,9 +217,9 @@ public class SimulatorGroupSettingsGui extends SimulatorBaseGui { return true; }, this).setItem(Material.PAPER).open(); })); - inventory.setItem(35, SWItem.getDye(1), "§e-1", Arrays.asList(allTNT ? "§7Shift§8: §e-0.0625" : "§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList(allTNT ? "§7Shift§8: §e-0.0625" : "§7Shift§8: §e-5"), false, clickType -> { simulatorGroup.move(0, 0, clickType.isShiftClick() ? (allTNT ? -0.0625 : -5) : -1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); } } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorGui.java index e35f0eaa..c53e6613 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorGui.java @@ -24,6 +24,7 @@ import de.steamwar.bausystem.features.simulator.data.Simulator; import de.steamwar.bausystem.features.simulator.data.SimulatorElement; import de.steamwar.bausystem.features.simulator.data.SimulatorGroup; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorPageGui; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -50,7 +51,7 @@ public class SimulatorGui extends SimulatorPageGui { })); inventory.setItem(49, new SWItem(Material.REPEATER, "§eSettings", clickType -> { new SimulatorSettingsGui(player, simulator, this).open(); - })); + }).setCustomModelData(CMDs.Simulator.SETTINGS)); } @Override diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorMaterialGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorMaterialGui.java index f081374d..5d509a99 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorMaterialGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorMaterialGui.java @@ -23,6 +23,7 @@ import de.steamwar.bausystem.features.simulator.SimulatorWatcher; import de.steamwar.bausystem.features.simulator.data.Simulator; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorPageGui; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -75,7 +76,7 @@ public class SimulatorMaterialGui extends SimulatorPageGui { })); inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> { back.open(); - })); + }).setCustomModelData(CMDs.BACK)); } @Override diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverGui.java index 42669387..ef41229f 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverGui.java @@ -26,6 +26,7 @@ import de.steamwar.bausystem.features.simulator.data.observer.ObserverElement; import de.steamwar.bausystem.features.simulator.data.observer.ObserverPhase; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorScrollGui; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -82,12 +83,12 @@ public class SimulatorObserverGui extends SimulatorScrollGui { new SimulatorGroupGui(player, simulator, newParent, simulatorGui).open(); } } - })); + }).setCustomModelData(CMDs.BACK)); inventory.setItem(8, new SWItem(Material.BARRIER, "§eDelete", clickType -> { observer.getPhases().clear(); SimulatorWatcher.update(simulator); - })); + }).setCustomModelData(CMDs.Simulator.DELETE)); // Material Chooser inventory.setItem(4, observer.toItem(player, clickType -> { @@ -97,18 +98,18 @@ public class SimulatorObserverGui extends SimulatorScrollGui { // Settings inventory.setItem(47, new SWItem(Material.REPEATER, "§eSettings", clickType -> { new SimulatorObserverSettingsGui(player, simulator, observer, this).open(); - })); + }).setCustomModelData(CMDs.Simulator.SETTINGS)); // Enable/Disable inventory.setItem(48, new SWItem(observer.isDisabled() ? Material.ENDER_PEARL : Material.ENDER_EYE, observer.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> { observer.setDisabled(!observer.isDisabled()); SimulatorWatcher.update(simulator); - })); + }).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED)); // Group chooser inventory.setItem(51, new SWItem(Material.LEAD, "§eJoin Group", clickType -> { new SimulatorGroupChooserGui(player, simulator, observer, observer.getGroup(simulator), this).open(); - })); + }).setCustomModelData(CMDs.Simulator.JOIN_GROUP)); } @Override @@ -151,15 +152,15 @@ public class SimulatorObserverGui extends SimulatorScrollGui { new SWItem(SWItem.getDye(getter.get() < max ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> { 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 -> { setter.accept(Math.max(min, getter.get() - (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }), + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED), new SWItem(Material.ANVIL, "§eEdit Activation", clickType -> { new SimulatorObserverPhaseSettingsGui(player, simulator, this.observer, observerPhase, this).open(); - }), + }).setCustomModelData(CMDs.Simulator.EDIT_ACTIVATION), }; } @@ -168,12 +169,12 @@ public class SimulatorObserverGui extends SimulatorScrollGui { return new SWItem[]{ new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> { addNewPhase(clickType.isShiftClick()); - }), + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED), new SWItem(Material.QUARTZ, "§eObserver§8:§a New Phase", clickType -> { addNewPhase(false); - }), + }).setCustomModelData(CMDs.Simulator.NEW_PHASE), new SWItem(SWItem.getDye(8), "§7", clickType -> { - }), + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED), }; } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverPhaseSettingsGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverPhaseSettingsGui.java index f7925c34..503d5957 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverPhaseSettingsGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverPhaseSettingsGui.java @@ -27,6 +27,7 @@ import de.steamwar.bausystem.features.simulator.data.observer.ObserverPhase; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; import de.steamwar.core.Core; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.Material; import org.bukkit.block.BlockFace; @@ -62,7 +63,7 @@ public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui { // Back Arrow inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> { back.open(); - })); + }).setCustomModelData(CMDs.BACK)); // Material Chooser inventory.setItem(4, observerElement.toItem(player, clickType -> { @@ -74,7 +75,7 @@ public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui { observerElement.getPhases().remove(observer); back.open(); SimulatorWatcher.update(simulator); - })); + }).setCustomModelData(CMDs.Simulator.DELETE)); int index = observerElement.getPhases().indexOf(observer); int min; @@ -95,10 +96,10 @@ public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui { //Tick Offset int offset = observer.getTickOffset(); - inventory.setItem(10, SWItem.getDye(offset < max ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(10, new SWItem(SWItem.getDye(offset < max ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { observer.setTickOffset(Math.min(max, offset + (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); SWItem offsetItem = new SWItem(Material.REPEATER, "§eStart at§8:§7 " + offset, clickType -> { new SimulatorAnvilGui<>(player, "Start at", offset + "", Integer::parseInt, integer -> { @@ -111,17 +112,17 @@ public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui { offsetItem.getItemStack().setAmount(Math.max(1, Math.min(offset, 64))); inventory.setItem(19, offsetItem); - inventory.setItem(28, SWItem.getDye(offset > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(28, new SWItem(SWItem.getDye(offset > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { observer.setTickOffset(Math.max(min, offset - (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Order int order = observer.getOrder(); - inventory.setItem(13, SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(13, new SWItem(SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { observer.setOrder(Math.min(SimulatorPhase.ORDER_LIMIT, order + (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); Material negativeNumbers = Material.getMaterial(Core.getVersion() >= 19 ? "RECOVERY_COMPASS" : "FIREWORK_STAR"); SWItem orderItem = new SWItem(order >= 0 ? Material.COMPASS : negativeNumbers, "§eActivation Order§8:§7 " + order, clickType -> { @@ -136,10 +137,10 @@ public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui { orderItem.getItemStack().setAmount(Math.max(1, Math.min(Math.abs(order), 30))); inventory.setItem(22, orderItem); - inventory.setItem(31, SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(31, new SWItem(SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { observer.setOrder(Math.max(-SimulatorPhase.ORDER_LIMIT, order - (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); // Update orientation inventory.setItem(25, new SWItem(Material.SUNFLOWER, "§7", clickType -> { diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverSettingsGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverSettingsGui.java index 8084c7b1..1abfc090 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverSettingsGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverSettingsGui.java @@ -24,6 +24,7 @@ import de.steamwar.bausystem.features.simulator.data.Simulator; import de.steamwar.bausystem.features.simulator.data.observer.ObserverElement; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -56,7 +57,7 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui { // Back Arrow inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> { back.open(); - })); + }).setCustomModelData(CMDs.BACK)); // Material Chooser inventory.setItem(4, observer.toItem(player, clickType -> { @@ -65,10 +66,10 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui { // Base Tick int baseTicks = observer.getBaseTick(); - inventory.setItem(9, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { observer.changeBaseTicks(clickType.isShiftClick() ? 5 : 1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); SWItem baseTick = new SWItem(Material.REPEATER, "§eTicks§8:§7 " + baseTicks, clickType -> { new SimulatorAnvilGui<>(player, "Ticks", baseTicks + "", Integer::parseInt, integer -> { if (integer < 0) return false; @@ -79,20 +80,20 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui { }); baseTick.getItemStack().setAmount(Math.max(1, Math.min(baseTicks, 64))); inventory.setItem(18, baseTick); - inventory.setItem(27, SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(27, new SWItem(SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { if (baseTicks - (clickType.isShiftClick() ? 5 : 1) < 0) { observer.changeBaseTicks(-baseTicks); } else { observer.changeBaseTicks(clickType.isShiftClick() ? -5 : -1); } SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Pos X - inventory.setItem(15, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { observer.move(clickType.isShiftClick() ? 5 : 1, 0, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); inventory.setItem(24, new SWItem(Material.PAPER, "§eX§8:§7 " + observer.getPosition().getBlockX(), clickType -> { new SimulatorAnvilGui<>(player, "X", observer.getPosition().getBlockX() + "", Integer::parseInt, i -> { observer.getPosition().setX(i); @@ -100,16 +101,16 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui { return true; }, this).open(); })); - inventory.setItem(33, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { observer.move(clickType.isShiftClick() ? -5 : -1, 0, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Pos Y - inventory.setItem(16, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { observer.move(0, clickType.isShiftClick() ? 5 : 1, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED)); inventory.setItem(25, new SWItem(Material.PAPER, "§eY§8:§7 " + observer.getPosition().getBlockY(), clickType -> { new SimulatorAnvilGui<>(player, "Y", observer.getPosition().getBlockY() + "", Integer::parseInt, i -> { observer.getPosition().setY(i); @@ -117,16 +118,16 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui { return true; }, this).open(); })); - inventory.setItem(34, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { observer.move(0, clickType.isShiftClick() ? -5 : -1, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Pos Z - inventory.setItem(17, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { observer.move(0, 0, clickType.isShiftClick() ? 5 : 1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED)); inventory.setItem(26, new SWItem(Material.PAPER, "§eZ§8:§7 " + observer.getPosition().getBlockZ(), clickType -> { new SimulatorAnvilGui<>(player, "Z", observer.getPosition().getBlockZ() + "", Integer::parseInt, i -> { observer.getPosition().setZ(i); @@ -134,9 +135,9 @@ public class SimulatorObserverSettingsGui extends SimulatorBaseGui { return true; }, this).open(); })); - inventory.setItem(35, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { observer.move(0, 0, clickType.isShiftClick() ? -5 : -1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); } } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorRedstoneGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorRedstoneGui.java index 2e288895..29589b8e 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorRedstoneGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorRedstoneGui.java @@ -26,6 +26,7 @@ import de.steamwar.bausystem.features.simulator.data.redstone.RedstoneElement; import de.steamwar.bausystem.features.simulator.data.redstone.RedstonePhase; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorScrollGui; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import lombok.AllArgsConstructor; import org.bukkit.Material; @@ -88,12 +89,12 @@ public class SimulatorRedstoneGui extends SimulatorScrollGui { redstone.getPhases().clear(); SimulatorWatcher.update(simulator); - })); + }).setCustomModelData(CMDs.Simulator.DELETE)); // Material Chooser inventory.setItem(4, redstone.toItem(player, clickType -> { @@ -103,18 +104,18 @@ public class SimulatorRedstoneGui extends SimulatorScrollGui { new SimulatorRedstoneSettingsGui(player, simulator, redstone, this).open(); - })); + }).setCustomModelData(CMDs.Simulator.SETTINGS)); // Enable/Disable inventory.setItem(48, new SWItem(redstone.isDisabled() ? Material.ENDER_PEARL : Material.ENDER_EYE, redstone.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> { redstone.setDisabled(!redstone.isDisabled()); SimulatorWatcher.update(simulator); - })); + }).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED)); // Group chooser inventory.setItem(51, new SWItem(Material.LEAD, "§eJoin Group", clickType -> { new SimulatorGroupChooserGui(player, simulator, redstone, redstone.getGroup(simulator), this).open(); - })); + }).setCustomModelData(CMDs.Simulator.JOIN_GROUP)); } @Override @@ -166,15 +167,15 @@ public class SimulatorRedstoneGui extends SimulatorScrollGui { 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 -> { setter.accept(Math.max(min, getter.get() - (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }), + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED), new SWItem(Material.ANVIL, "§eEdit Activation", clickType -> { new SimulatorRedstonePhaseSettingsGui(player, simulator, this.redstone, redstoneSubPhase.phase, this).open(); - }), + }).setCustomModelData(CMDs.Simulator.EDIT_ACTIVATION), }; } @@ -183,12 +184,12 @@ public class SimulatorRedstoneGui extends SimulatorScrollGui { addNewPhase(clickType.isShiftClick()); - }), + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED), new SWItem(Material.REDSTONE, "§eRedstone§8:§a New Phase", clickType -> { addNewPhase(false); - }), + }).setCustomModelData(CMDs.Simulator.NEW_PHASE), new SWItem(SWItem.getDye(8), "§7", clickType -> { - }), + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED), }; } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorRedstonePhaseSettingsGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorRedstonePhaseSettingsGui.java index 27901b09..6994d4e8 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorRedstonePhaseSettingsGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorRedstonePhaseSettingsGui.java @@ -27,6 +27,7 @@ import de.steamwar.bausystem.features.simulator.data.redstone.RedstonePhase; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; import de.steamwar.core.Core; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -60,7 +61,7 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui { // Back Arrow inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> { back.open(); - })); + }).setCustomModelData(CMDs.BACK)); // Material Chooser inventory.setItem(4, redstoneElement.toItem(player, clickType -> { @@ -72,7 +73,7 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui { redstoneElement.getPhases().remove(redstone); back.open(); SimulatorWatcher.update(simulator); - })); + }).setCustomModelData(CMDs.Simulator.DELETE)); int index = redstoneElement.getPhases().indexOf(redstone); int min; @@ -96,10 +97,10 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui { //Tick Offset int offset = redstone.getTickOffset(); - inventory.setItem(10, SWItem.getDye(offset < maxOffset ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(10, new SWItem(SWItem.getDye(offset < maxOffset ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { redstone.setTickOffset(Math.min(maxOffset, offset + (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); SWItem offsetItem = new SWItem(Material.REPEATER, "§eStart at§8:§7 " + offset, clickType -> { new SimulatorAnvilGui<>(player, "Start at", offset + "", Integer::parseInt, integer -> { @@ -112,17 +113,17 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui { offsetItem.getItemStack().setAmount(Math.max(1, Math.min(offset, 64))); inventory.setItem(19, offsetItem); - inventory.setItem(28, SWItem.getDye(offset > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(28, new SWItem(SWItem.getDye(offset > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { redstone.setTickOffset(Math.max(min, offset - (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Lifetime int lifetime = redstone.getLifetime(); - inventory.setItem(11, SWItem.getDye(lifetime < maxLifetime ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(11, new SWItem(SWItem.getDye(lifetime < maxLifetime ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { redstone.setLifetime(Math.min(maxLifetime, lifetime + (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); SWItem lifetimeItem = new SWItem(Material.CLOCK, "§eActivation Time§8:§7 " + lifetime, clickType -> { new SimulatorAnvilGui<>(player, "Activation Time", lifetime + "", Integer::parseInt, integer -> { @@ -135,17 +136,17 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui { lifetimeItem.getItemStack().setAmount(Math.max(1, Math.min(lifetime, 64))); inventory.setItem(20, lifetimeItem); - inventory.setItem(29, SWItem.getDye(lifetime > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(29, new SWItem(SWItem.getDye(lifetime > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { redstone.setLifetime(Math.max(0, lifetime - (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Order int order = redstone.getOrder(); - inventory.setItem(13, SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(13, new SWItem(SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { redstone.setOrder(Math.min(SimulatorPhase.ORDER_LIMIT, order + (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); Material negativeNumbers = Material.getMaterial(Core.getVersion() >= 19 ? "RECOVERY_COMPASS" : "FIREWORK_STAR"); SWItem orderItem = new SWItem(order >= 0 ? Material.COMPASS : negativeNumbers, "§eActivation Order§8:§7 " + order, clickType -> { @@ -160,9 +161,9 @@ public class SimulatorRedstonePhaseSettingsGui extends SimulatorBaseGui { orderItem.getItemStack().setAmount(Math.max(1, Math.min(Math.abs(order), 30))); inventory.setItem(22, orderItem); - inventory.setItem(31, SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(31, new SWItem(SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { redstone.setOrder(Math.max(-SimulatorPhase.ORDER_LIMIT, order - (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); } } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorRedstoneSettingsGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorRedstoneSettingsGui.java index 184d73a1..629e2aa5 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorRedstoneSettingsGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorRedstoneSettingsGui.java @@ -24,6 +24,7 @@ import de.steamwar.bausystem.features.simulator.data.Simulator; import de.steamwar.bausystem.features.simulator.data.redstone.RedstoneElement; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -55,7 +56,7 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui { // Back Arrow inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> { back.open(); - })); + }).setCustomModelData(CMDs.BACK)); // Material Chooser inventory.setItem(4, redstone.toItem(player, clickType -> { @@ -64,10 +65,10 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui { // Base Tick int baseTicks = redstone.getBaseTick(); - inventory.setItem(9, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { redstone.changeBaseTicks(clickType.isShiftClick() ? 5 : 1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); SWItem baseTick = new SWItem(Material.REPEATER, "§eTicks§8:§7 " + baseTicks, clickType -> { new SimulatorAnvilGui<>(player, "Ticks", baseTicks + "", Integer::parseInt, integer -> { if (integer < 0) return false; @@ -78,20 +79,20 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui { }); baseTick.getItemStack().setAmount(Math.max(1, Math.min(baseTicks, 64))); inventory.setItem(18, baseTick); - inventory.setItem(27, SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(27, new SWItem(SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { if (baseTicks - (clickType.isShiftClick() ? 5 : 1) < 0) { redstone.changeBaseTicks(-baseTicks); } else { redstone.changeBaseTicks(clickType.isShiftClick() ? -5 : -1); } SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Pos X - inventory.setItem(15, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { redstone.move(clickType.isShiftClick() ? 5 : 1, 0, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); inventory.setItem(24, new SWItem(Material.PAPER, "§eX§8:§7 " + redstone.getPosition().getBlockX(), clickType -> { new SimulatorAnvilGui<>(player, "X", redstone.getPosition().getBlockX() + "", Integer::parseInt, i -> { redstone.getPosition().setX(i); @@ -99,16 +100,16 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui { return true; }, this).open(); })); - inventory.setItem(33, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { redstone.move(clickType.isShiftClick() ? -5 : -1, 0, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Pos Y - inventory.setItem(16, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { redstone.move(0, clickType.isShiftClick() ? 5 : 1, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); inventory.setItem(25, new SWItem(Material.PAPER, "§eY§8:§7 " + redstone.getPosition().getBlockY(), clickType -> { new SimulatorAnvilGui<>(player, "Y", redstone.getPosition().getBlockY() + "", Integer::parseInt, i -> { redstone.getPosition().setY(i); @@ -116,16 +117,16 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui { return true; }, this).open(); })); - inventory.setItem(34, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { redstone.move(0, clickType.isShiftClick() ? -5 : -1, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Pos Z - inventory.setItem(17, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { redstone.move(0, 0, clickType.isShiftClick() ? 5 : 1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); inventory.setItem(26, new SWItem(Material.PAPER, "§eZ§8:§7 " + redstone.getPosition().getBlockZ(), clickType -> { new SimulatorAnvilGui<>(player, "Z", redstone.getPosition().getBlockZ() + "", Integer::parseInt, i -> { redstone.getPosition().setZ(i); @@ -133,9 +134,9 @@ public class SimulatorRedstoneSettingsGui extends SimulatorBaseGui { return true; }, this).open(); })); - inventory.setItem(35, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { redstone.move(0, 0, clickType.isShiftClick() ? -5 : -1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); } } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorSettingsGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorSettingsGui.java index ccb00412..b69ca41b 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorSettingsGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorSettingsGui.java @@ -22,6 +22,7 @@ package de.steamwar.bausystem.features.simulator.gui; import de.steamwar.bausystem.features.simulator.SimulatorWatcher; import de.steamwar.bausystem.features.simulator.data.Simulator; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -47,7 +48,7 @@ public class SimulatorSettingsGui extends SimulatorBaseGui { // Back Arrow inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> { back.open(); - })); + }).setCustomModelData(CMDs.BACK)); // Material Chooser inventory.setItem(4, simulator.toItem(player, clickType -> { @@ -55,45 +56,49 @@ public class SimulatorSettingsGui extends SimulatorBaseGui { })); //AutoTrace - inventory.setItem(20, new SWItem(simulator.isAutoTrace() ? Material.CHAIN_COMMAND_BLOCK : Material.COMMAND_BLOCK, "§eAutoTrace§8: " + (simulator.isAutoTrace() ? "§aOn" : "§cOff"), clickType -> { + inventory.setItem(19, new SWItem(simulator.isAutoTrace() ? Material.CHAIN_COMMAND_BLOCK : Material.COMMAND_BLOCK, "§eAutoTrace§8: " + (simulator.isAutoTrace() ? "§aOn" : "§cOff"), clickType -> { simulator.setAutoTrace(!simulator.isAutoTrace()); SimulatorWatcher.update(simulator); })); + inventory.setItem(20, new SWItem(simulator.isAutoTestblock() ? Material.END_STONE : Material.BARRIER, "§eTestblock§8: " + (simulator.isAutoTestblock() ? "§aOn" : "§cOff"), clickType -> { + simulator.setAutoTestblock(!simulator.isAutoTestblock()); + SimulatorWatcher.update(simulator); + })); //Pos X - inventory.setItem(15, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { simulator.move(clickType.isShiftClick() ? 5 : 1, 0, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); inventory.setItem(24, new SWItem(Material.PAPER, "§eX", clickType -> { })); - inventory.setItem(33, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { simulator.move(clickType.isShiftClick() ? -5 : -1, 0, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Pos Y - inventory.setItem(16, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { simulator.move(0, clickType.isShiftClick() ? 5 : 1, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); inventory.setItem(25, new SWItem(Material.PAPER, "§eY", clickType -> { })); - inventory.setItem(34, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { simulator.move(0, clickType.isShiftClick() ? -5 : -1, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Pos Z - inventory.setItem(17, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { simulator.move(0, 0, clickType.isShiftClick() ? 5 : 1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); inventory.setItem(26, new SWItem(Material.PAPER, "§eZ", clickType -> { })); - inventory.setItem(35, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { simulator.move(0, 0, clickType.isShiftClick() ? -5 : -1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); } } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTGui.java index 3520720e..471270c9 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTGui.java @@ -29,6 +29,8 @@ import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorScrollGui; import de.steamwar.bausystem.region.Region; +import de.steamwar.core.Core; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -81,12 +83,12 @@ public class SimulatorTNTGui extends SimulatorScrollGui { new SimulatorGroupGui(player, simulator, newParent, simulatorGui).open(); } } - })); + }).setCustomModelData(CMDs.BACK)); inventory.setItem(8, new SWItem(Material.BARRIER, "§eDelete", clickType -> { tnt.getPhases().clear(); SimulatorWatcher.update(simulator); - })); + }).setCustomModelData(CMDs.Simulator.DELETE)); // Material Chooser inventory.setItem(4, tnt.toItem(player, clickType -> { @@ -95,29 +97,31 @@ public class SimulatorTNTGui extends SimulatorScrollGui { inventory.setItem(47, new SWItem(Material.REPEATER, "§eSettings", clickType -> { new SimulatorTNTSettingsGui(player, simulator, tnt, this).open(); - })); + }).setCustomModelData(CMDs.Simulator.SETTINGS)); inventory.setItem(48, new SWItem(tnt.isDisabled() ? Material.ENDER_PEARL : Material.ENDER_EYE, tnt.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> { tnt.setDisabled(!tnt.isDisabled()); SimulatorWatcher.update(simulator); - })); - inventory.setItem(49, new SWItem(Material.CALIBRATED_SCULK_SENSOR, "§eCreate Stab", click -> { - new SimulatorAnvilGui<>(player, "Depth Limit", "", Integer::parseInt, depthLimit -> { - if (depthLimit <= 0) return false; - simulator.setStabGenerator(new SimulatorStabGenerator(Region.getRegion(player.getLocation()), simulator, tnt, depthLimit)); - SimulatorWatcher.update(simulator); - return true; - }, null).open(); - })); + }).setCustomModelData(CMDs.Simulator.ENABLED_OR_DISABLED)); + if (Core.getVersion() > 19) { + inventory.setItem(49, new SWItem(Material.CALIBRATED_SCULK_SENSOR, "§eCreate Stab", click -> { + new SimulatorAnvilGui<>(player, "Depth Limit", "", Integer::parseInt, depthLimit -> { + if (depthLimit <= 0) return false; + simulator.setStabGenerator(new SimulatorStabGenerator(Region.getRegion(player.getLocation()), simulator, tnt, depthLimit)); + SimulatorWatcher.update(simulator); + return true; + }, null).open(); + }).setCustomModelData(CMDs.Simulator.CREATE_STAB)); + } inventory.setItem(50, new SWItem(Material.CHEST, parent.getElements().size() == 1 ? "§eMake Group" : "§eAdd another TNT to Group", clickType -> { TNTElement tntElement = new TNTElement(tnt.getPosition().clone()); tntElement.add(new TNTPhase()); parent.add(tntElement); new SimulatorGroupGui(player, simulator, parent, new SimulatorGui(player, simulator)).open(); SimulatorWatcher.update(simulator); - })); + }).setCustomModelData(CMDs.Simulator.MAKE_GROUP)); inventory.setItem(51, new SWItem(Material.LEAD, "§eJoin Group", clickType -> { new SimulatorGroupChooserGui(player, simulator, tnt, tnt.getGroup(simulator), this).open(); - })); + }).setCustomModelData(CMDs.Simulator.JOIN_GROUP)); } @Override @@ -136,15 +140,15 @@ public class SimulatorTNTGui extends SimulatorScrollGui { new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> { 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 -> { tntSetting.setCount(Math.max(1, tntSetting.getCount() - (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }), + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED), new SWItem(Material.ANVIL, "§eEdit Phase", clickType -> { new SimulatorTNTPhaseSettingsGui(player, simulator, this.tnt, tntSetting, this).open(); - }), + }).setCustomModelData(CMDs.Simulator.EDIT_ACTIVATION), }; } @@ -153,12 +157,12 @@ public class SimulatorTNTGui extends SimulatorScrollGui { return new SWItem[]{ new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> { addNewPhase(clickType.isShiftClick()); - }), + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED), new SWItem(Material.GUNPOWDER, "§eTNT§8:§a New Phase", clickType -> { addNewPhase(false); - }), + }).setCustomModelData(CMDs.Simulator.NEW_PHASE), new SWItem(SWItem.getDye(8), "§7", clickType -> { - }), + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED), }; } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTPhaseSettingsGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTPhaseSettingsGui.java index 9bfc4fe5..5b4775d3 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTPhaseSettingsGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTPhaseSettingsGui.java @@ -27,6 +27,7 @@ import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; import de.steamwar.core.Core; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -60,7 +61,7 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui { // Back Arrow inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> { back.open(); - })); + }).setCustomModelData(CMDs.BACK)); // Material Chooser inventory.setItem(4, tntElement.toItem(player, clickType -> { @@ -72,14 +73,14 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui { tntElement.getPhases().remove(tnt); back.open(); SimulatorWatcher.update(simulator); - })); + }).setCustomModelData(CMDs.Simulator.DELETE)); //Count int count = tnt.getCount(); - inventory.setItem(9, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { tnt.setCount(count + (clickType.isShiftClick() ? 5 : 1)); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); SWItem countItem = new SWItem(Material.TNT, "§eCount§8:§7 " + count, clickType -> { new SimulatorAnvilGui<>(player, "Count", count + "", Integer::parseInt, integer -> { @@ -92,17 +93,17 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui { countItem.getItemStack().setAmount(Math.max(1, Math.min(count, 64))); inventory.setItem(18, countItem); - inventory.setItem(27, SWItem.getDye(count > 1 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(27, new SWItem(SWItem.getDye(count > 1 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { tnt.setCount(Math.max(1, count - (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Tick Offset int offset = tnt.getTickOffset(); - inventory.setItem(10, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(10, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { tnt.setTickOffset(offset + (clickType.isShiftClick() ? 5 : 1)); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); SWItem offsetItem = new SWItem(Material.REPEATER, "§eStart at§8:§7 " + offset, clickType -> { new SimulatorAnvilGui<>(player, "Start at", offset + "", Integer::parseInt, integer -> { @@ -115,17 +116,17 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui { offsetItem.getItemStack().setAmount(Math.max(1, Math.min(offset, 64))); inventory.setItem(19, offsetItem); - inventory.setItem(28, SWItem.getDye(offset > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(28, new SWItem(SWItem.getDye(offset > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { tnt.setTickOffset(Math.max(0, offset - (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Lifetime int lifetime = tnt.getLifetime(); - inventory.setItem(11, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(11, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { tnt.setLifetime(lifetime + (clickType.isShiftClick() ? 5 : 1)); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); SWItem lifetimeItem = new SWItem(Material.CLOCK, "§eLifetime§8:§7 " + lifetime, clickType -> { new SimulatorAnvilGui<>(player, "Lifetime", lifetime + "", Integer::parseInt, integer -> { @@ -138,17 +139,17 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui { lifetimeItem.getItemStack().setAmount(Math.max(1, Math.min(lifetime, 64))); inventory.setItem(20, lifetimeItem); - inventory.setItem(29, SWItem.getDye(lifetime > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(29, new SWItem(SWItem.getDye(lifetime > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { tnt.setLifetime(Math.max(1, lifetime - (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); //Order int order = tnt.getOrder(); - inventory.setItem(13, SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(13, new SWItem(SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { tnt.setOrder(Math.min(SimulatorPhase.ORDER_LIMIT, order + (clickType.isShiftClick() ? 5 : 1))); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); Material negativeNumbers = Material.getMaterial(Core.getVersion() >= 19 ? "RECOVERY_COMPASS" : "FIREWORK_STAR"); SWItem orderItem = new SWItem(order >= 0 ? Material.COMPASS : negativeNumbers, "§eCalculation Order§8:§7 " + order, clickType -> { @@ -163,10 +164,10 @@ public class SimulatorTNTPhaseSettingsGui extends SimulatorBaseGui { orderItem.getItemStack().setAmount(Math.max(1, Math.min(Math.abs(order), 30))); inventory.setItem(22, orderItem); - inventory.setItem(31, SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(31, new SWItem(SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { 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 -> { diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTSettingsGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTSettingsGui.java index 24dbb22e..04a3334e 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTSettingsGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorTNTSettingsGui.java @@ -24,10 +24,10 @@ import de.steamwar.bausystem.features.simulator.data.Simulator; import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.Material; import org.bukkit.entity.Player; -import org.bukkit.util.Vector; import java.util.ArrayList; import java.util.Arrays; @@ -58,7 +58,7 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui { // Back Arrow inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> { back.open(); - })); + }).setCustomModelData(CMDs.BACK)); // Material Chooser List lore = new ArrayList<>(); @@ -74,10 +74,10 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui { // Base Tick int baseTicks = tnt.getBaseTick(); - inventory.setItem(9, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { + inventory.setItem(9, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> { tnt.changeBaseTicks(clickType.isShiftClick() ? 5 : 1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); SWItem baseTick = new SWItem(Material.REPEATER, "§eTicks§8:§7 " + baseTicks, clickType -> { new SimulatorAnvilGui<>(player, "Ticks", baseTicks + "", Integer::parseInt, integer -> { if (integer < 0) return false; @@ -88,14 +88,14 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui { }); baseTick.getItemStack().setAmount(Math.max(1, Math.min(baseTicks, 64))); inventory.setItem(18, baseTick); - inventory.setItem(27, SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { + inventory.setItem(27, new SWItem(SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> { if (baseTicks - (clickType.isShiftClick() ? 5 : 1) < 0) { tnt.changeBaseTicks(-baseTicks); } else { tnt.changeBaseTicks(clickType.isShiftClick() ? -5 : -1); } SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); // Subpixel Alignment inventory.setItem(21, new SWItem(Material.SUNFLOWER, "§7Align§8: §eCenter", clickType -> { @@ -135,10 +135,10 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui { inventory.setItem(30, positivXItem); // Pos X - inventory.setItem(15, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+0.0625"), false, clickType -> { + inventory.setItem(15, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+0.0625"), false, clickType -> { tnt.move(clickType.isShiftClick() ? 0.0625 : 1, 0, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); inventory.setItem(24, new SWItem(Material.PAPER, "§eX§8:§7 " + tnt.getPosition().getX(), clickType -> { new SimulatorAnvilGui<>(player, "X", tnt.getPosition().getX() + "", Double::parseDouble, d -> { tnt.getPosition().setX(d); @@ -146,16 +146,16 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui { return true; }, this).open(); })); - inventory.setItem(33, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-0.0625"), false, clickType -> { + inventory.setItem(33, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-0.0625"), false, clickType -> { tnt.move(clickType.isShiftClick() ? -0.0625 : -1, 0, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); // Pos Y - inventory.setItem(16, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+0.0625"), false, clickType -> { + inventory.setItem(16, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+0.0625"), false, clickType -> { tnt.move(0, clickType.isShiftClick() ? 0.0625 : 1, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); inventory.setItem(25, new SWItem(Material.PAPER, "§eY§8:§7 " + tnt.getPosition().getY(), clickType -> { new SimulatorAnvilGui<>(player, "Y", tnt.getPosition().getY() + "", Double::parseDouble, d -> { tnt.getPosition().setY(d); @@ -163,16 +163,16 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui { return true; }, this).open(); })); - inventory.setItem(34, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-0.0625"), false, clickType -> { + inventory.setItem(34, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-0.0625"), false, clickType -> { tnt.move(0, clickType.isShiftClick() ? -0.0625 : -1, 0); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); // Pos Z - inventory.setItem(17, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+0.0625"), false, clickType -> { + inventory.setItem(17, new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+0.0625"), false, clickType -> { tnt.move(0, 0, clickType.isShiftClick() ? 0.0625 : 1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.INCREMENT_OR_DISABLED)); inventory.setItem(26, new SWItem(Material.PAPER, "§eZ§8:§7 " + tnt.getPosition().getZ(), clickType -> { new SimulatorAnvilGui<>(player, "Z", tnt.getPosition().getZ() + "", Double::parseDouble, d -> { tnt.getPosition().setZ(d); @@ -180,9 +180,9 @@ public class SimulatorTNTSettingsGui extends SimulatorBaseGui { return true; }, this).open(); })); - inventory.setItem(35, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-0.0625"), false, clickType -> { + inventory.setItem(35, new SWItem(SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-0.0625"), false, clickType -> { tnt.move(0, 0, clickType.isShiftClick() ? -0.0625 : -1); SimulatorWatcher.update(simulator); - }); + }).setCustomModelData(CMDs.Simulator.DECREMENT_OR_DISABLED)); } } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorPageGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorPageGui.java index e3c3ccbd..a6ff9f15 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorPageGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorPageGui.java @@ -21,6 +21,7 @@ package de.steamwar.bausystem.features.simulator.gui.base; import de.steamwar.bausystem.features.simulator.data.Simulator; import de.steamwar.core.Core; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.entity.Player; @@ -50,19 +51,19 @@ public abstract class SimulatorPageGui extends SimulatorBaseGui { headerAndFooter(); page = Math.min(page, maxPage()); - inventory.setItem(size - 9, SWItem.getDye(page > 0 ? 10 : 8), page > 0 ? (byte) 10 : (byte) 8, Core.MESSAGE.parse(page > 0 ? "SWLISINV_PREVIOUS_PAGE_ACTIVE" : "SWLISINV_PREVIOUS_PAGE_INACTIVE", player), clickType -> { + inventory.setItem(size - 9, new SWItem(SWItem.getDye(page > 0 ? 10 : 8), page > 0 ? (byte) 10 : (byte) 8, Core.MESSAGE.parse(page > 0 ? "SWLISINV_PREVIOUS_PAGE_ACTIVE" : "SWLISINV_PREVIOUS_PAGE_INACTIVE", player), clickType -> { if (page > 0) { page--; open(); } - }); + }).setCustomModelData(CMDs.PREVIOUS_PAGE)); boolean hasNext = page < maxPage() - (data.size() % (size - 18) == 0 ? 1 : 0); - inventory.setItem(size - 1, SWItem.getDye(hasNext ? 10 : 8), hasNext ? (byte) 10 : (byte) 8, Core.MESSAGE.parse(hasNext ? "SWLISINV_NEXT_PAGE_ACTIVE" : "SWLISINV_NEXT_PAGE_INACTIVE", player), clickType -> { + inventory.setItem(size - 1, new SWItem(SWItem.getDye(hasNext ? 10 : 8), hasNext ? (byte) 10 : (byte) 8, Core.MESSAGE.parse(hasNext ? "SWLISINV_NEXT_PAGE_ACTIVE" : "SWLISINV_NEXT_PAGE_INACTIVE", player), clickType -> { if (hasNext) { page++; open(); } - }); + }).setCustomModelData(CMDs.NEXT_PAGE)); int minElement = page * (size - 18); int maxElement = Math.min(data.size(), (page + 1) * (size - 18)); diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorScrollGui.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorScrollGui.java index a4cfbb5d..974f64ed 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorScrollGui.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/base/SimulatorScrollGui.java @@ -22,6 +22,7 @@ package de.steamwar.bausystem.features.simulator.gui.base; import de.steamwar.bausystem.features.simulator.data.Simulator; import de.steamwar.core.Core; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import org.bukkit.entity.Player; @@ -50,19 +51,19 @@ public abstract class SimulatorScrollGui extends SimulatorBaseGui { headerAndFooter(); scroll = maxScroll(); - inventory.setItem(size - 9, SWItem.getDye(scroll > 0 ? 10 : 8), scroll > 0 ? (byte) 10 : (byte) 8, Core.MESSAGE.parse(scroll > 0 ? "SWLISINV_PREVIOUS_PAGE_ACTIVE" : "SWLISINV_PREVIOUS_PAGE_INACTIVE", player), clickType -> { + inventory.setItem(size - 9, new SWItem(SWItem.getDye(scroll > 0 ? 10 : 8), scroll > 0 ? (byte) 10 : (byte) 8, Core.MESSAGE.parse(scroll > 0 ? "SWLISINV_PREVIOUS_PAGE_ACTIVE" : "SWLISINV_PREVIOUS_PAGE_INACTIVE", player), clickType -> { if (scroll > 0) { scroll = Math.max(0, scroll - 9); open(); } - }); + }).setCustomModelData(CMDs.PREVIOUS_PAGE)); boolean hasNext = (data.size() + 1) - scroll > 9; - inventory.setItem(size - 1, SWItem.getDye(hasNext ? 10 : 8), hasNext ? (byte) 10 : (byte) 8, Core.MESSAGE.parse(hasNext ? "SWLISINV_NEXT_PAGE_ACTIVE" : "SWLISINV_NEXT_PAGE_INACTIVE", player), clickType -> { + inventory.setItem(size - 1, new SWItem(SWItem.getDye(hasNext ? 10 : 8), hasNext ? (byte) 10 : (byte) 8, Core.MESSAGE.parse(hasNext ? "SWLISINV_NEXT_PAGE_ACTIVE" : "SWLISINV_NEXT_PAGE_INACTIVE", player), clickType -> { if (hasNext) { scroll = Math.min(scroll + 9, data.size() + 1 - 9); open(); } - }); + }).setCustomModelData(CMDs.NEXT_PAGE)); for (int i = 0; i < 9; i++) { if (scroll + i < data.size()) { diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/SimFormatSimulatorLoader.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/SimFormatSimulatorLoader.java index 218c89a4..f213227e 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/SimFormatSimulatorLoader.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/SimFormatSimulatorLoader.java @@ -68,6 +68,7 @@ public class SimFormatSimulatorLoader implements SimulatorLoader { private void loadSimulator(YAPIONObject simulatorObject, Simulator simulator) { simulator.setMaterial(Material.valueOf(simulatorObject.getPlainValue("material"))); simulator.setAutoTrace(simulatorObject.getPlainValue("autoTrace")); + simulator.setAutoTestblock(simulatorObject.getPlainValueOrDefault("autoTestblock", false)); YAPIONArray groups = simulatorObject.getArray("groups"); groups.streamObject().forEach(groupObject -> { diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/SimulatorSaver.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/SimulatorSaver.java index 48ccfd7a..9a5f5285 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/SimulatorSaver.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/SimulatorSaver.java @@ -39,6 +39,7 @@ public class SimulatorSaver { YAPIONObject simulatorObject = new YAPIONObject(); simulatorObject.add("material", simulator.getMaterial().name()); simulatorObject.add("autoTrace", simulator.isAutoTrace()); + simulatorObject.add("autoTestblock", simulator.isAutoTestblock()); YAPIONArray groups = new YAPIONArray(); simulator.getGroups().forEach(group -> { diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/laufbau/LaufbauSettings.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/laufbau/LaufbauSettings.java index c52f9a1d..17de9c68 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/laufbau/LaufbauSettings.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/slaves/laufbau/LaufbauSettings.java @@ -21,6 +21,7 @@ package de.steamwar.bausystem.features.slaves.laufbau; import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.shared.Pair; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWItem; import de.steamwar.inventory.SWListInv; import org.bukkit.Material; @@ -59,7 +60,7 @@ public class LaufbauSettings { open(); return; } - if (clickType.isCreativeAction()) { + if (clickType.isLeftClick()) { open(entry.getKey()); return; } @@ -91,7 +92,7 @@ public class LaufbauSettings { }); inv.setItem(49, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("LAUFBAU_SETTINGS_GUI_BACK", p), clickType -> { open(); - })); + }).setCustomModelData(CMDs.BACK)); inv.open(); } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java index 17e0d9f3..d2c8e683 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/smartplace/SmartPlaceListener.java @@ -57,6 +57,7 @@ public class SmartPlaceListener implements Listener { static { World world = Bukkit.getWorlds().get(0); Block block = world.getBlockAt(0, 0, 0); + block.setType(Material.AIR); BlockState state = block.getState(); for (Material material : Material.values()) { if (material.isLegacy()) continue; @@ -68,6 +69,7 @@ public class SmartPlaceListener implements Listener { } else if (blockData instanceof Stairs) { CONTAINERS.add(material); } + state.update(true, false); } CONTAINERS.add(Material.GRINDSTONE); CONTAINERS.remove(Material.COMPARATOR); diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSCommand.java index c1d09c63..f3f4cc62 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSCommand.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSCommand.java @@ -1,20 +1,20 @@ /* - * This file is a part of the SteamWar software. + * This file is a part of the SteamWar software. * - * Copyright (C) 2023 SteamWar.de-Serverteam + * Copyright (C) 2020 SteamWar.de-Serverteam * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ package de.steamwar.bausystem.features.tpslimit; diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java index ac393e57..f84ab72e 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java @@ -27,19 +27,17 @@ import de.steamwar.bausystem.region.GlobalRegion; import de.steamwar.bausystem.region.Region; import de.steamwar.bausystem.utils.ScoreboardElement; import de.steamwar.bausystem.utils.TickEndEvent; +import de.steamwar.bausystem.utils.TickManager; import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar; import de.steamwar.bausystem.utils.bossbar.BossBarService; import de.steamwar.command.AbstractSWCommand; import de.steamwar.command.SWCommand; import de.steamwar.core.Core; -import de.steamwar.core.TPSWarpUtils; import de.steamwar.core.TPSWatcher; import de.steamwar.inventory.SWAnvilInv; import de.steamwar.inventory.SWItem; import de.steamwar.linkage.Linked; import de.steamwar.linkage.LinkedInstance; -import de.steamwar.linkage.MaxVersion; -import lombok.Getter; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.boss.BarColor; @@ -52,91 +50,61 @@ import org.bukkit.inventory.ItemStack; import java.util.Arrays; @Linked -@MaxVersion(20) // Hotfix for 1.21 tps limit! -> Backport coming later public class TPSSystem implements Listener { - @Getter - private static double currentTPSLimit = 20; - public TPSSystem() { - if (TPSFreezeUtils.isCanFreeze()) { + if (TickManager.impl.canFreeze()) { new TPSFreezeCommand(); new TickFreezeCommand(); new TickStepCommand(); } new TPSLimitCommand(); new TickLimitCommand(); - if (Core.getVersion() >= 15 && Core.getVersion() <= 20) { // If 1.21 support is not directly present + if (Core.getVersion() >= 15) { new TPSWarpCommand(); new TickWarpCommand(); - if (TPSFreezeUtils.isCanFreeze()) { + if (TickManager.impl.canFreeze()) { new TickWarpingCommand(); } } + if (Core.getVersion() >= 21) { + new Tick21Command(); + } new TPSDefaultCommand(); new TickDefaultCommand(); new TPSBaseCommand(); new TickBaseCommand(); - } - - private void setTPS(double tps) { - if (currentlyStepping) { - currentlyStepping = false; - Bukkit.getOnlinePlayers().forEach(player -> { - BossBarService.instance.remove(player, GlobalRegion.getInstance(), "TickStep"); - }); - } - TPSWarpUtils.warp(tps); - if (currentTPSLimit == 0 && tps != 0) { - TPSFreezeUtils.unfreeze(); - } - currentTPSLimit = tps; - if (tps == 0) { - TPSLimitUtils.unlimit(); - TPSFreezeUtils.freeze(); - } else if (tps < 20.0) { - TPSLimitUtils.limit(tps); - } else if (tps >= 20) { - TPSLimitUtils.unlimit(); - } - - Bukkit.getOnlinePlayers().forEach(player -> { - if (currentTPSLimit == 0) { - SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("TPSLIMIT_FROZEN", player)); - } else { - SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("TPSLIMIT_SET", player, currentTPSLimit)); - } - }); - } - - private boolean currentlyStepping = false; - private double currentLimit; - private int stepsTotal; - private int stepsLeft; - - private void setSkip(int steps, double tpsLimitToUse) { - currentLimit = tpsLimitToUse == 20 ? 0 : currentTPSLimit; - setTPS(tpsLimitToUse); - stepsLeft = steps; - stepsTotal = steps; - currentlyStepping = true; + Bukkit.getPluginManager().registerEvents(TickManager.impl, BauSystem.getInstance()); } @EventHandler public void onTickEnd(TickEndEvent event) { - if (!currentlyStepping) return; - if (stepsTotal > 1) { + bossbar(); + } + + private void bossbar() { + if ((TickManager.impl.isStepping() || TickManager.impl.isSprinting()) && TickManager.impl.getRemainingTicks() > 0) { Bukkit.getOnlinePlayers().forEach(player -> { BauSystemBossbar bossbar = BossBarService.instance.get(player, GlobalRegion.getInstance(), "TickStep"); bossbar.setColor(BarColor.YELLOW); - bossbar.setTitle(BauSystem.MESSAGE.parse("TICK_BOSSBAR", player, (stepsTotal - stepsLeft), stepsTotal)); - bossbar.setProgress((stepsTotal - stepsLeft) / (double) stepsTotal); + bossbar.setTitle(BauSystem.MESSAGE.parse("TICK_BOSSBAR", player, TickManager.impl.getDoneTicks(), TickManager.impl.getTotalTicks())); + bossbar.setProgress(TickManager.impl.getDoneTicks() / (double) TickManager.impl.getTotalTicks()); + }); + } else { + Bukkit.getOnlinePlayers().forEach(player -> { + BossBarService.instance.remove(player, GlobalRegion.getInstance(), "TickStep"); }); } - stepsLeft--; - if (stepsLeft <= 0) { - setTPS(currentLimit); - } + } + + public static void sendTickRateChange() { + Bukkit.getOnlinePlayers().forEach(player -> { + if (TickManager.impl.isFrozen()) { + SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("TPSLIMIT_FROZEN", player)); + } else { + SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("TPSLIMIT_SET", player, TickManager.impl.getTickRate())); + } + }); } private class TPSBaseCommand extends SWCommand { @@ -157,7 +125,8 @@ public class TPSSystem implements Listener { @Register(value = "0", description = "TPSLIMIT_FREEZE_HELP") public void freeze(@Validator Player player) { - setTPS(0); + TickManager.impl.setFreeze(true); + sendTickRateChange(); } } @@ -169,8 +138,9 @@ public class TPSSystem implements Listener { } @Register(description = "TPSLIMIT_LIMIT_HELP") - public void limit(@Validator Player player, @Min(doubleValue = 0.5) @Max(doubleValue = 20.0) double tpsLimit) { - setTPS(tpsLimit); + public void limit(@Validator Player player, @Min(doubleValue = 0.5) @Max(doubleValue = 20.0) float tpsLimit) { + TickManager.impl.setTickRate(tpsLimit); + sendTickRateChange(); } } @@ -182,8 +152,9 @@ public class TPSSystem implements Listener { } @Register(description = "TPSLIMIT_WARP_HELP") - public void warp(@Validator Player player, @Min(doubleValue = 20.0, inclusive = false) double tpsLimit) { - setTPS(tpsLimit); + public void warp(@Validator Player player, @Min(doubleValue = 20.0, inclusive = false) float tpsLimit) { + TickManager.impl.setTickRate(tpsLimit); + sendTickRateChange(); } } @@ -196,12 +167,13 @@ public class TPSSystem implements Listener { @Register(description = "TPSLIMIT_HELP") public void currentLimit(Player player) { - BauSystem.MESSAGE.send("TPSLIMIT_CURRENT", player, currentTPSLimit); + BauSystem.MESSAGE.send("TPSLIMIT_CURRENT", player, TickManager.impl.getTickRate()); } @Register(value = "default", description = "TPSLIMIT_DEFAULT_HELP") public void reset(@Validator Player player) { - setTPS(20); + TickManager.impl.setTickRate(20.0F); + sendTickRateChange(); } } @@ -223,12 +195,14 @@ public class TPSSystem implements Listener { @Register(value = {"rate", "0"}, description = "TICK_FREEZE_HELP") @Register(value = "freeze", description = "TICK_FREEZE_HELP_2") public void freeze(@Validator Player player) { - setTPS(0); + TickManager.impl.setFreeze(true); + sendTickRateChange(); } @Register(value = "unfreeze", description = "TICK_UNFREEZE_HELP") public void unfreeze(@Validator Player player) { - setTPS(20); + TickManager.impl.setTickRate(20.0F); + sendTickRateChange(); } } @@ -241,7 +215,9 @@ public class TPSSystem implements Listener { @Register(value = "step", description = "TICK_STEPPING_HELP") public void step(@Validator Player player, @Min(intValue = 1) @OptionalValue("1") int steps) { - setSkip(steps, 20); + TickManager.impl.stepTicks(steps); + sendTickRateChange(); + bossbar(); } } @@ -253,8 +229,9 @@ public class TPSSystem implements Listener { } @Register(value = "warp", description = "TICK_WARPING_HELP") - public void warp(@Validator Player player, @Min(intValue = 1) @OptionalValue("1") int steps, @Min(doubleValue = 20) @OptionalValue("4000") double tps) { - setSkip(steps, tps); + public void warp(@Validator Player player, @Min(intValue = 1) @OptionalValue("1") int steps) { + TickManager.impl.sprintTicks(steps); + sendTickRateChange(); } } @@ -266,8 +243,9 @@ public class TPSSystem implements Listener { } @Register(value = "rate", description = "TICK_LIMIT_HELP") - public void limit(@Validator Player player, @Min(doubleValue = 0.5, inclusive = false) @Max(doubleValue = 20.0) double tpsLimit) { - setTPS(tpsLimit); + public void limit(@Validator Player player, @Min(doubleValue = 0.5, inclusive = false) @Max(doubleValue = 20.0) float tpsLimit) { + TickManager.impl.setTickRate(tpsLimit); + sendTickRateChange(); } } @@ -279,8 +257,9 @@ public class TPSSystem implements Listener { } @Register(value = "rate", description = "TICK_WARP_HELP") - public void warp(@Validator Player player, @Min(doubleValue = 20.0, inclusive = false) double tpsLimit) { - setTPS(tpsLimit); + public void warp(@Validator Player player, @Min(doubleValue = 20.0, inclusive = false) float tpsLimit) { + TickManager.impl.setTickRate(tpsLimit); + sendTickRateChange(); } } @@ -293,12 +272,31 @@ public class TPSSystem implements Listener { @Register(value = "rate", description = "TICK_HELP") public void currentLimit(Player player) { - BauSystem.MESSAGE.send("TPSLIMIT_CURRENT", player, currentTPSLimit); + BauSystem.MESSAGE.send("TPSLIMIT_CURRENT", player, TickManager.impl.getTickRate()); } @Register(value = {"rate", "default"}, description = "TICK_DEFAULT_HELP") public void reset(@Validator Player player) { - setTPS(20); + TickManager.impl.setTickRate(20.0F); + sendTickRateChange(); + } + } + + @AbstractSWCommand.PartOf(TickBaseCommand.class) + private class Tick21Command extends SWCommand { + + private Tick21Command() { + super(""); + } + + @Register(value = "normalclient") + public void smooth(@Validator Player player) { + TickManager.impl.setBlockTpsPacket(true); + } + + @Register(value = "slowclient") + public void unsmooth(@Validator Player player) { + TickManager.impl.setBlockTpsPacket(false); } } @@ -320,7 +318,10 @@ public class TPSSystem implements Listener { @Override public String get(Region region, Player p) { - if (tpsSystem != null && tpsSystem.currentlyStepping) { + boolean isWarping = TickManager.impl.isSprinting(); + boolean isFrozen = TickManager.impl.isFrozen(); + + if (tpsSystem != null && isWarping) { long time = System.currentTimeMillis() % 1000; if (time < 250) { return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: §7•••"; @@ -331,7 +332,7 @@ public class TPSSystem implements Listener { } else { return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: §7••§e•"; } - } else if (TPSFreezeUtils.frozen()) { + } else if (isFrozen) { return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: " + BauSystem.MESSAGE.parse("SCOREBOARD_TPS_FROZEN", p); } else { return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: " + tpsColor() + TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.ONE_SECOND) + tpsLimit(); @@ -340,20 +341,20 @@ public class TPSSystem implements Listener { private String tpsColor() { double tps = TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.ONE_SECOND); - if (tps > TPSSystem.getCurrentTPSLimit() * 0.9) { + if (tps > TickManager.impl.getTickRate() * 0.9) { return "§a"; } - if (tps > TPSSystem.getCurrentTPSLimit() * 0.5) { + if (tps > TickManager.impl.getTickRate() * 0.5) { return "§e"; } return "§c"; } private String tpsLimit() { - if (TPSSystem.getCurrentTPSLimit() == 20) { + if (TickManager.impl.getTickRate() == 20) { return ""; } - return "§8/§7" + TPSSystem.getCurrentTPSLimit(); + return "§8/§7" + TickManager.impl.getTickRate(); } } @@ -369,7 +370,7 @@ public class TPSSystem implements Listener { @Override public ItemStack getItem(Player player) { - return new SWItem(Material.CLOCK, BauSystem.MESSAGE.parse("TPSLIMIT_GUI_ITEM_NAME", player), Arrays.asList(BauSystem.MESSAGE.parse("TPSLIMIT_GUI_ITEM_LORE", player, tpsSystem.currentTPSLimit)), false, clickType -> { + return new SWItem(Material.CLOCK, BauSystem.MESSAGE.parse("TPSLIMIT_GUI_ITEM_NAME", player), Arrays.asList(BauSystem.MESSAGE.parse("TPSLIMIT_GUI_ITEM_LORE", player, TickManager.impl.getTickRate())), false, clickType -> { }).getItemStack(); } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TNTPoint.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TNTPoint.java index 1e9fd38d..a33c52f0 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TNTPoint.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TNTPoint.java @@ -22,19 +22,15 @@ package de.steamwar.bausystem.features.tracer; import de.steamwar.bausystem.region.Region; import de.steamwar.bausystem.region.utils.RegionExtensionType; import de.steamwar.bausystem.region.utils.RegionType; +import de.steamwar.core.Core; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.entity.TNTPrimed; import org.bukkit.util.Vector; -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; import java.util.List; import java.util.Optional; @@ -106,7 +102,11 @@ public class TNTPoint{ List history, List destroyedBlocks) { this.tntId = tntId; this.explosion = explosion; - this.inWater = tnt.isInWater(); + if (Core.getVersion() > 15) { + this.inWater = tnt.isInWater(); + } else { + this.inWater = false; + } this.afterFirstExplosion = afterFirstExplosion; this.ticksSinceStart = ticksSinceStart; fuse = tnt.getFuseTicks(); diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java index 9628570a..2c7cf22c 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java @@ -50,12 +50,6 @@ public class Trace { @Getter private final File recordsSaveFile; - /** - * File the metadata are saved in - */ - @Getter - private final File metadataSaveFile; - /** * Region the trace was recorded in */ @@ -75,7 +69,7 @@ public class Trace { @Setter @Getter - private int recordsCount; + private int tntIdCount; /** * A map of all REntityServers rendering this trace @@ -95,21 +89,19 @@ public class Trace { this.date = new Date(); records = new SoftReference<>(recordList); recordsSaveFile = new File(TraceRepository.tracesFolder, uuid + ".records"); - metadataSaveFile = new File(TraceRepository.tracesFolder, uuid + ".meta"); } /** * Constructor for deserialising a trace from the file system */ @SneakyThrows - protected Trace(UUID uuid, Region region, Date date, File metadataFile, File recordsFile, int recordsCount) { - this.metadataSaveFile = metadataFile; + protected Trace(UUID uuid, Region region, Date date, File recordsFile, int tntIdCount) { recordsSaveFile = recordsFile; this.uuid = uuid; this.region = region; this.date = date; this.records = new SoftReference<>(null); - this.recordsCount = recordsCount; + this.tntIdCount = tntIdCount; } /** @@ -311,7 +303,7 @@ public class Trace { ", region=" + region + ", creationTime=" + date + ", recordsSaveFile=" + recordsSaveFile.getName() + - ", recordCount=" + recordsCount + + ", tntCount=" + tntIdCount + ", records=" + getRecords() + '}'; } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java index 213d5e8e..060db33b 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceManager.java @@ -57,19 +57,26 @@ public class TraceManager implements Listener { if (traceFiles == null) return; + boolean hasMetaFiles = false; for (File traceFile : traceFiles) { - if (traceFile.getName().contains(".records")) - continue; - - if (TraceRepository.getVersion(traceFile) == TraceRepository.SERIALISATION_VERSION) { - add(TraceRepository.readTrace(traceFile)); - } else { - String uuid = traceFile.getName().replace(".meta", ""); - - new File(tracesFolder, uuid + ".records").deleteOnExit(); - new File(tracesFolder, uuid + ".meta").deleteOnExit(); + if (traceFile.getName().contains(".meta")) { + hasMetaFiles = true; } + } + if (hasMetaFiles) { + for (File traceFile : traceFiles) { + traceFile.delete(); + } + traceFiles = new File[0]; + } + for (File traceFile : traceFiles) { + Trace trace = TraceRepository.readTrace(traceFile); + if (trace == null) { + traceFile.delete(); + continue; + } + add(trace); } } @@ -152,7 +159,6 @@ public class TraceManager implements Listener { if (traceId == null) throw new RuntimeException("Trace not found while trying to remove see (c978eb98-b0b2-4009-91d8-acfa34e2831a)"); traces.remove(traceId); trace.hide(); - trace.getMetadataSaveFile().delete(); trace.getRecordsSaveFile().delete(); } @@ -172,7 +178,6 @@ public class TraceManager implements Listener { tracesByRegion.getOrDefault(region, new HashMap<>()) .forEach((i, trace) -> { if (trace.getRegion() != region) return; - trace.getMetadataSaveFile().delete(); trace.getRecordsSaveFile().delete(); }); tracesByRegion.getOrDefault(region, new HashMap<>()).clear(); diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecorder.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecorder.java index 208b49e8..aef9f12c 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecorder.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecorder.java @@ -23,6 +23,7 @@ import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.features.tpslimit.TPSUtils; import de.steamwar.bausystem.region.Region; import de.steamwar.linkage.Linked; +import de.steamwar.linkage.LinkedInstance; import org.bukkit.Bukkit; import org.bukkit.block.Block; import org.bukkit.entity.TNTPrimed; @@ -31,7 +32,6 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntitySpawnEvent; -import org.bukkit.event.server.PluginEnableEvent; import java.util.*; import java.util.logging.Level; @@ -40,12 +40,9 @@ import java.util.logging.Logger; @Linked public class TraceRecorder implements Listener { + @LinkedInstance public static TraceRecorder instance; - { - instance = this; - } - /** * Map for all traces being actively recorded */ diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecordingWrapper.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecordingWrapper.java index 82eb3019..38cde80d 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecordingWrapper.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRecordingWrapper.java @@ -65,7 +65,7 @@ public class TraceRecordingWrapper { TraceManager.instance.showPartial(trace, recordsToAdd); recordList.addAll(recordsToAdd); - trace.setRecordsCount(recordList.size()); + trace.setTntIdCount((int) recordList.stream().map(TNTPoint::getTntId).distinct().count()); recordsToAdd.clear(); } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRepository.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRepository.java index 39f50fe1..899ea5f1 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRepository.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TraceRepository.java @@ -9,95 +9,125 @@ import org.bukkit.util.Vector; import java.io.*; import java.util.*; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; public class TraceRepository { /** * Increment this when changing serialisation format */ - public static final int SERIALISATION_VERSION = 1; + public static final int SERIALISATION_VERSION = 2; + public static final int WRITE_TICK_DATA = 0b00000001; + public static final int EXPLOSION = 0b00000010; + public static final int IN_WATER = 0b00000100; + public static final int AFTER_FIRST_EXPLOSION = 0b00001000; + public static final int DESTROYED_BUILD_AREA = 0b00010000; + public static final int DESTROYED_TEST_BLOCK = 0b00100000; public static File tracesFolder = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "traces"); @SneakyThrows - protected static int getVersion(File metadataFile) { + public static Trace readTrace(File recordsFile) { @Cleanup - ObjectInputStream reader = new ObjectInputStream(new FileInputStream(metadataFile)); - reader.readUTF(); - reader.readUTF(); - reader.readObject(); - try { - int version = reader.readInt(); - return version; - } catch (EOFException e) { - return 0; - } - } - - @SneakyThrows - public static Trace readTrace(File metadataFile) { - @Cleanup - ObjectInputStream reader = new ObjectInputStream(new FileInputStream(metadataFile)); + ObjectInputStream reader = new ObjectInputStream(new GZIPInputStream(new FileInputStream(recordsFile))); UUID uuid = UUID.fromString(reader.readUTF()); Region region = Region.getREGION_MAP().get(reader.readUTF()); Date date = (Date) reader.readObject(); - File recordsFile = new File(tracesFolder,uuid + ".records"); int serialisationVersion = reader.readInt(); - int recordsCount = reader.readInt(); + if (serialisationVersion != SERIALISATION_VERSION) { + return null; + } + int tntIdCount = reader.readInt(); - return new Trace(uuid, region, date, metadataFile, recordsFile, recordsCount); + return new Trace(uuid, region, date, recordsFile, tntIdCount); } @SneakyThrows protected static void writeTrace(Trace trace, List records) { - ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(trace.getMetadataSaveFile())); + ObjectOutputStream outputStream = new ObjectOutputStream(new GZIPOutputStream(new FileOutputStream(trace.getRecordsSaveFile()))); outputStream.writeUTF(trace.getUuid().toString()); outputStream.writeUTF(trace.getRegion().getName()); outputStream.writeObject(trace.getDate()); outputStream.writeInt(SERIALISATION_VERSION); - outputStream.writeInt(records.size()); - outputStream.flush(); - outputStream.close(); + Map> pointsByTNTId = new HashMap<>(); + records.forEach(tntPoint -> { + pointsByTNTId.computeIfAbsent(tntPoint.getTntId(), integer -> new ArrayList<>()).add(tntPoint); + }); - writeTraceRecords(trace.getRecordsSaveFile(), records); - } + outputStream.writeInt(pointsByTNTId.size()); + for (Map.Entry> entry : pointsByTNTId.entrySet()) { + outputStream.writeInt(entry.getKey()); + outputStream.writeInt(entry.getValue().size()); - @SneakyThrows - protected static void writeTraceRecords(File recordsFile, List records) { - DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(recordsFile)); - for (TNTPoint record : records) { - outputStream.writeInt(record.getTntId()); - outputStream.writeBoolean(record.isExplosion()); - outputStream.writeBoolean(record.isInWater()); - outputStream.writeBoolean(record.isAfterFirstExplosion()); - outputStream.writeBoolean(record.isDestroyedBuildArea()); - outputStream.writeBoolean(record.isDestroyedTestBlock()); - outputStream.writeLong(record.getTicksSinceStart()); - outputStream.writeInt(record.getFuse()); - Location location = record.getLocation(); - outputStream.writeDouble(location.getX()); - outputStream.writeDouble(location.getY()); - outputStream.writeDouble(location.getZ()); - Vector velocity = record.getVelocity(); - outputStream.writeDouble(velocity.getX()); - outputStream.writeDouble(velocity.getY()); - outputStream.writeDouble(velocity.getZ()); + for (int i = 0; i < entry.getValue().size(); i++) { + TNTPoint current = entry.getValue().get(i); + if (i == 0) { + writeTNTPoint(outputStream, current, true); + continue; + } + + TNTPoint last = entry.getValue().get(i - 1); + + boolean writeTickData = true; + if (last.getTicksSinceStart() + 1 == current.getTicksSinceStart() && last.getFuse() - 1 == current.getFuse()) { + writeTickData = false; + } + + writeTNTPoint(outputStream, current, writeTickData); + } } + outputStream.flush(); outputStream.close(); } @SneakyThrows - protected static TNTPoint readTraceRecord(DataInputStream objectInput) { + private static void writeTNTPoint(ObjectOutputStream outputStream, TNTPoint tntPoint, boolean writeTickData) { + byte data = 0; + if (writeTickData) data |= WRITE_TICK_DATA; + if (tntPoint.isExplosion()) data |= EXPLOSION; + if (tntPoint.isInWater()) data |= IN_WATER; + if (tntPoint.isAfterFirstExplosion()) data |= AFTER_FIRST_EXPLOSION; + if (tntPoint.isDestroyedBuildArea()) data |= DESTROYED_BUILD_AREA; + if (tntPoint.isDestroyedTestBlock()) data |= DESTROYED_TEST_BLOCK; + outputStream.write(data); - int tntId = objectInput.readInt(); - boolean explosion = objectInput.readBoolean(); - boolean inWater = objectInput.readBoolean(); - boolean afterFirstExplosion = objectInput.readBoolean(); - boolean destroyedBuildArea = objectInput.readBoolean(); - boolean destroyedTestBlock = objectInput.readBoolean(); - long ticksSinceStart = objectInput.readLong(); - int fuse = objectInput.readInt(); + if (writeTickData) { + outputStream.writeLong(tntPoint.getTicksSinceStart()); + outputStream.writeInt(tntPoint.getFuse()); + } + + Location location = tntPoint.getLocation(); + outputStream.writeDouble(location.getX()); + outputStream.writeDouble(location.getY()); + outputStream.writeDouble(location.getZ()); + + Vector velocity = tntPoint.getVelocity(); + outputStream.writeDouble(velocity.getX()); + outputStream.writeDouble(velocity.getY()); + outputStream.writeDouble(velocity.getZ()); + } + + @SneakyThrows + protected static TNTPoint readTraceRecord(int tntId, TNTPoint last, ObjectInputStream objectInput) { + + int data = objectInput.read(); + boolean explosion = (data & EXPLOSION) > 0; + boolean inWater = (data & IN_WATER) > 0; + boolean afterFirstExplosion = (data & AFTER_FIRST_EXPLOSION) > 0; + boolean destroyedBuildArea = (data & DESTROYED_BUILD_AREA) > 0; + boolean destroyedTestBlock = (data & DESTROYED_TEST_BLOCK) > 0; + + long ticksSinceStart; + int fuse; + if ((data & WRITE_TICK_DATA) > 0) { + ticksSinceStart = objectInput.readLong(); + fuse = objectInput.readInt(); + } else { + ticksSinceStart = last.getTicksSinceStart() + 1; + fuse = last.getFuse() - 1; + } double locX = objectInput.readDouble(); double locY = objectInput.readDouble(); @@ -116,21 +146,29 @@ public class TraceRepository { protected static List readTraceRecords(Trace trace) { File recordsFile = trace.getRecordsSaveFile(); @Cleanup - DataInputStream inputStream = new DataInputStream(new FileInputStream(recordsFile)); + ObjectInputStream inputStream = new ObjectInputStream(new GZIPInputStream(new FileInputStream(recordsFile))); + inputStream.readUTF(); + inputStream.readUTF(); + inputStream.readObject(); + inputStream.readInt(); + inputStream.readInt(); List records = new ArrayList<>(); - for (int i = 0; i < trace.getRecordsCount(); i++) { - records.add(readTraceRecord(inputStream)); - } - Map> histories = new HashMap<>(); - for (TNTPoint record : records) { - int tntId = record.getTntId(); - List history = histories.computeIfAbsent(tntId, id -> new ArrayList<>()); - history.add(record); - record.setHistory(history); - } + for (int i = 0; i < trace.getTntIdCount(); i++) { + int tntId = inputStream.readInt(); + int size = inputStream.readInt(); + List points = histories.computeIfAbsent(tntId, id -> new ArrayList<>()); + TNTPoint last = null; + for (int j = 0; j < size; j++) { + TNTPoint point = readTraceRecord(tntId, last, inputStream); + point.setHistory(points); + points.add(point); + last = point; + records.add(point); + } + } return records; } } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/MaterialCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/MaterialCommand.java index 7893b8c4..5993eeec 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/MaterialCommand.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/util/MaterialCommand.java @@ -26,6 +26,7 @@ import de.steamwar.bausystem.shared.EnumDisplay; import de.steamwar.command.PreviousArguments; import de.steamwar.command.SWCommand; import de.steamwar.command.TypeMapper; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWAnvilInv; import de.steamwar.inventory.SWInventory; import de.steamwar.inventory.SWItem; @@ -202,9 +203,9 @@ public class MaterialCommand extends SWCommand implements Listener { private void searchGUI(Player p) { SWInventory swInventory = new SWInventory(p, 54, BauSystem.MESSAGE.parse("MATERIAL_SEARCH", p)); Search search = searchMap.get(p); - swInventory.setItem(45, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("MATERIAL_BACK", p), clickType -> { + swInventory.setItem(0, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("MATERIAL_BACK", p), clickType -> { materialGUI(p); - })); + }).setCustomModelData(CMDs.BACK)); swInventory.setItem(10, new SWItem(Material.NAME_TAG, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_NAME", p) + BauSystem.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, search.name), clickType -> { SWAnvilInv swAnvilInv = new SWAnvilInv(p, BauSystem.MESSAGE.parse("MATERIAL_SEARCH_NAME", p), search.name); swAnvilInv.setCallback(s -> { diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/warp/Warp.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/warp/Warp.java index 4ccddf76..a1392917 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/warp/Warp.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/warp/Warp.java @@ -36,7 +36,7 @@ public class Warp { public static void enable() { Warp worldSpawn = new Warp("WorldSpawn"); - worldSpawn.setLocation(Bukkit.getWorlds().get(0).getSpawnLocation().clone().add(0.5, Core.getVersion() == 20 ? 124 : 1, 0.5)); + worldSpawn.setLocation(Bukkit.getWorlds().get(0).getSpawnLocation().clone().add(0.5, Core.getVersion() >= 20 ? 124 : 1, 0.5)); worldSpawn.setMat(Material.NETHER_STAR); warpMap.put("WorldSpawn", worldSpawn); } diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/BauLockStateScoreboard.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/BauLockStateScoreboard.java index ab3630d4..3e159311 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/BauLockStateScoreboard.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/BauLockStateScoreboard.java @@ -59,6 +59,7 @@ public class BauLockStateScoreboard implements ScoreboardElement { public enum BauLockState { NOBODY, + SUPERVISOR, SERVERTEAM, TEAM_AND_SERVERTEAM, TEAM, diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/ClipboardListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/ClipboardListener.java index 90cd94ec..2cb2cc7b 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/ClipboardListener.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/world/ClipboardListener.java @@ -21,6 +21,7 @@ package de.steamwar.bausystem.features.world; import de.steamwar.bausystem.Permission; import de.steamwar.linkage.Linked; +import de.steamwar.sql.NodeData; import de.steamwar.sql.SchematicData; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SteamwarUser; @@ -65,7 +66,8 @@ public class ClipboardListener implements Listener { } try { - new SchematicData(schematic).saveFromPlayer(e.getPlayer()); + NodeData.get(schematic).forEach(NodeData::delete); + SchematicData.saveFromPlayer(e.getPlayer(), schematic); } catch (Exception ex) { if (newSchem) { schematic.delete(); diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/TickManager.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/TickManager.java new file mode 100644 index 00000000..6570a03f --- /dev/null +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/TickManager.java @@ -0,0 +1,46 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2025 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bausystem.utils; + +import de.steamwar.bausystem.BauSystem; +import de.steamwar.core.VersionDependent; +import org.bukkit.event.Listener; + +public interface TickManager extends Listener { + TickManager impl = VersionDependent.getVersionImpl(BauSystem.getInstance()); + + void setTickRate(float tickRate); + float getTickRate(); + + boolean canFreeze(); + void setFreeze(boolean freeze); + boolean isFrozen(); + + void stepTicks(int ticks); + boolean isStepping(); + + void sprintTicks(int ticks); + boolean isSprinting(); + + void setBlockTpsPacket(boolean block); + long getRemainingTicks(); + long getDoneTicks(); + long getTotalTicks(); +} diff --git a/BauSystem/build.gradle.kts b/BauSystem/build.gradle.kts index fd9dca11..ebb9422d 100644 --- a/BauSystem/build.gradle.kts +++ b/BauSystem/build.gradle.kts @@ -40,6 +40,7 @@ tasks.register("DevBau20") { description = "Run a 1.20 Dev Bau" dependsOn(":SpigotCore:shadowJar") dependsOn(":BauSystem:shadowJar") + dependsOn(":SchematicSystem:shadowJar") template = "Bau20" } diff --git a/TutorialSystem/build.gradle.kts b/CommonCore/Data/build.gradle.kts similarity index 91% rename from TutorialSystem/build.gradle.kts rename to CommonCore/Data/build.gradle.kts index 0336de23..da326bfe 100644 --- a/TutorialSystem/build.gradle.kts +++ b/CommonCore/Data/build.gradle.kts @@ -22,7 +22,4 @@ plugins { } dependencies { - compileOnly(project(":SpigotCore", "default")) - - compileOnly(libs.nms15) -} +} \ No newline at end of file diff --git a/CommonCore/Data/src/de/steamwar/data/CMDs.java b/CommonCore/Data/src/de/steamwar/data/CMDs.java new file mode 100644 index 00000000..996df130 --- /dev/null +++ b/CommonCore/Data/src/de/steamwar/data/CMDs.java @@ -0,0 +1,92 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.data; + +// Custom Model Data Constants +public interface CMDs { + + // Material.ARROW + int BACK = 1; + + // Material.DYE (Color 10/8) + int PREVIOUS_PAGE = 1; + + // Material.DYE (Color 10/8) + int NEXT_PAGE = 2; + + // BauSystem Simulator + interface Simulator { + + // Material.BARRIER + int DELETE = 1; + + // Material.REPEATER + int SETTINGS = 1; + + // Material.ENDER_PEARL and Material.ENDER_EYE + int ENABLED_OR_DISABLED = 1; + + // Material.DYE (Color 10/8) + int INCREMENT_OR_DISABLED = 3; + + // Material.DYE (Color 1/8) + int DECREMENT_OR_DISABLED = 3; + + // Material.LEAD + int JOIN_GROUP = 1; + + // Material.ANVIL + int EDIT_ACTIVATION = 1; + + // Material.QUARTZ, Material.REDSTONE, Material.GUNPOWDER + int NEW_PHASE = 1; + + // Material.CALIBRATED_SCULK_SENSOR + int CREATE_STAB = 1; + + // Material.CHEST + int MAKE_GROUP = 1; + } + + // Schematic System + interface Schematic { + + // Material.LEAD + int BACK = 2; + + // Material.BUCKET + int OWN_SCHEMS = 1; + + // Material.GLASS + int PUBLIC_SCHEMS = 1; + + // Material.CHEST + int NEW_DIR = 2; + + // Material.NAME_TAG + int FILTER = 3; + + // Material.PAPER, Material.CAULDRON, Material.CLOCK + int SORT_ASCENDING = 3; + + // Material.PAPER, Material.CAULDRON, Material.CLOCK + int SORT_DESCENDING = 4; + } +} diff --git a/CommonCore/Network/src/de/steamwar/network/packets/common/PlayerSkinRequestPacket.java b/CommonCore/Network/src/de/steamwar/network/packets/common/PlayerSkinRequestPacket.java new file mode 100644 index 00000000..4916e0f1 --- /dev/null +++ b/CommonCore/Network/src/de/steamwar/network/packets/common/PlayerSkinRequestPacket.java @@ -0,0 +1,36 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.network.packets.common; + +import de.steamwar.network.packets.NetworkPacket; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; + +import java.util.UUID; + +@AllArgsConstructor +@Getter +@ToString +public class PlayerSkinRequestPacket extends NetworkPacket { + + private static final long serialVersionUID = 277267302555671765L; + private UUID uuid; +} diff --git a/CommonCore/Network/src/de/steamwar/network/packets/common/PlayerSkinResponsePacket.java b/CommonCore/Network/src/de/steamwar/network/packets/common/PlayerSkinResponsePacket.java new file mode 100644 index 00000000..5c3767ca --- /dev/null +++ b/CommonCore/Network/src/de/steamwar/network/packets/common/PlayerSkinResponsePacket.java @@ -0,0 +1,38 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.network.packets.common; + +import de.steamwar.network.packets.NetworkPacket; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; + +import java.util.UUID; + +@AllArgsConstructor +@Getter +@ToString +public class PlayerSkinResponsePacket extends NetworkPacket { + + private static final long serialVersionUID = 5792855362547625112L; + private UUID uuid; + private String skin; + private String signature; +} diff --git a/CommonCore/Network/src/de/steamwar/network/packets/server/ClientVersionPacket.java b/CommonCore/Network/src/de/steamwar/network/packets/server/ClientVersionPacket.java new file mode 100644 index 00000000..c8f43446 --- /dev/null +++ b/CommonCore/Network/src/de/steamwar/network/packets/server/ClientVersionPacket.java @@ -0,0 +1,37 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.network.packets.server; + +import de.steamwar.network.packets.NetworkPacket; +import lombok.*; + +import java.util.UUID; + +@EqualsAndHashCode(callSuper = true) +@Getter +@AllArgsConstructor +@NoArgsConstructor +@ToString +public class ClientVersionPacket extends NetworkPacket { + private static final long serialVersionUID = 3686482311704273200L; + + private UUID player; + private int version; +} diff --git a/CommonCore/SQL/src/de/steamwar/sql/AuditLog.java b/CommonCore/SQL/src/de/steamwar/sql/AuditLog.java new file mode 100644 index 00000000..ffe093a0 --- /dev/null +++ b/CommonCore/SQL/src/de/steamwar/sql/AuditLog.java @@ -0,0 +1,125 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.sql; + +import de.steamwar.sql.internal.Field; +import de.steamwar.sql.internal.SqlTypeMapper; +import de.steamwar.sql.internal.Statement; +import de.steamwar.sql.internal.Table; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NonNull; + +import java.sql.Timestamp; +import java.time.Instant; + +@AllArgsConstructor +public class AuditLog { + + static { + SqlTypeMapper.nameEnumMapper(AuditLog.Type.class); + } + + public static final String SERVER_NAME_VELOCITY = "Velocity"; + + private static final Table table = new Table<>(AuditLog.class); + + private static final Statement create = table.insertFields(true, "time", "serverName", "serverOwner", "actor", "actionType", "actionText"); + + @Getter + @Field + private final Timestamp time; + + @Getter + @Field + private final String serverName; + + @Field(nullable = true) + private final int serverOwner; + + @Field + private final int actor; + + @Getter + @Field + private final Type actionType; + + @Getter + @Field + private final String actionText; + + public enum Type { + JOIN, + LEAVE, + COMMAND, + SENSITIVE_COMMAND, + + CHAT, + GUI_OPEN, + GUI_CLOSE, + GUI_CLICK, + } + + private static void create(String serverName, SteamwarUser serverOwner, SteamwarUser actor, Type actionType, String text) { + create.insertGetKey(Timestamp.from(Instant.now()), serverName, serverOwner, actor, actionType, text); + } + + public static void createJoin(@NonNull String jointServerName, SteamwarUser serverOwner, @NonNull SteamwarUser joinedPlayer) { + create(jointServerName, serverOwner, joinedPlayer, Type.JOIN, ""); + } + + public static void createLeave(@NonNull String leftServerName, SteamwarUser serverOwner, @NonNull SteamwarUser joinedPlayer) { + create(leftServerName, serverOwner, joinedPlayer, Type.LEAVE, ""); + } + + public static void createCommand(@NonNull String serverName, SteamwarUser serverOwner, SteamwarUser player, @NonNull String command) { + if (player == null) return; + create(serverName, serverOwner, player, Type.COMMAND, command); + } + + public static void createSensitiveCommand(@NonNull String serverName, SteamwarUser serverOwner, SteamwarUser player, @NonNull String command) { + if (player == null) return; + create(serverName, serverOwner, player, Type.SENSITIVE_COMMAND, command); + } + + public static void createChat(@NonNull String serverName, SteamwarUser serverOwner, @NonNull SteamwarUser chatter, @NonNull String chat) { + create(serverName, serverOwner, chatter, Type.CHAT, chat); + } + + public static void createGuiOpen(@NonNull String serverName, SteamwarUser serverOwner, @NonNull SteamwarUser player, @NonNull String guiName) { + create(serverName, serverOwner, player, Type.GUI_OPEN, guiName); + } + + public static void createGuiClick(@NonNull String serverName, SteamwarUser serverOwner, @NonNull SteamwarUser player, @NonNull String guiName, @NonNull String clickType, int slot, @NonNull String itemName) { + create(serverName, serverOwner, player, Type.GUI_CLICK, "Gui: " + guiName + "\nSlot: " + slot + "\nClickType: " + clickType + "\nItemName: " + itemName); + } + + public static void createGuiClose(@NonNull String serverName, SteamwarUser serverOwner, @NonNull SteamwarUser player, @NonNull String guiName) { + create(serverName, serverOwner, player, Type.GUI_CLOSE, guiName); + } + + public SteamwarUser getServerOwner() { + return SteamwarUser.get(serverOwner); + } + + public SteamwarUser getActor() { + return SteamwarUser.get(actor); + } +} diff --git a/CommonCore/SQL/src/de/steamwar/sql/CheckedSchematic.java b/CommonCore/SQL/src/de/steamwar/sql/CheckedSchematic.java index 6d4aa452..aa1e0986 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/CheckedSchematic.java +++ b/CommonCore/SQL/src/de/steamwar/sql/CheckedSchematic.java @@ -28,36 +28,33 @@ import lombok.Getter; import java.sql.Timestamp; import java.util.List; -import java.util.Optional; +import java.util.concurrent.CompletableFuture; @AllArgsConstructor public class CheckedSchematic { - public static final String INVESTIGATION_PENDING_KEY = "$invest:"; - private static final Table table = new Table<>(CheckedSchematic.class); - private static final SelectStatement statusOfNode = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE NodeId = ? AND DeclineReason != 'Prüfvorgang abgebrochen' AND DeclineReason NOT LIKE '" + INVESTIGATION_PENDING_KEY + "%' ORDER BY EndTime DESC"); - private static final SelectStatement lastCheck = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE NodeId = ? AND DeclineReason != 'Prüfvorgang abgebrochen' ORDER BY EndTime DESC LIMIT 1"); + private static final SelectStatement statusOfNode = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE NodeId = ? AND DeclineReason != 'Prüfvorgang abgebrochen' ORDER BY EndTime DESC"); + private static final SelectStatement nodeHistory = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE NodeId = ? AND DeclineReason != '' AND DeclineReason != 'Prüfvorgang abgebrochen' ORDER BY EndTime DESC"); private static final Statement insert = table.insertAll(); - public static void create(int nodeId, String name, int owner, int validator, Timestamp startTime, Timestamp endTime, String reason){ - insert.update(nodeId, owner, name, validator, startTime, endTime, reason); + private static final SelectStatement getUnseen = new SelectStatement<>(table, "SELECT * FROM CheckedSchematic WHERE Seen = 0 AND NodeOwner = ? ORDER BY StartTime DESC"); + private static final Statement updateSeen = new Statement("UPDATE CheckedSchematic SET Seen = ? WHERE StartTime = ? AND EndTime = ? AND NodeName = ?"); + + public static void create(SchematicNode node, int validator, Timestamp startTime, Timestamp endTime, String reason, boolean seen) { + insert.update(node.getId(), node.getOwner(), node.getName(), validator, startTime, endTime, reason, seen, node.getSchemtype().toDB().substring(1)); } - public static void create(SchematicNode node, int validator, Timestamp startTime, Timestamp endTime, String reason){ - create(node.getId(), node.getName(), node.getOwner(), validator, startTime, endTime, reason); - } - - public static void createInvestigationPending(SchematicNode node, Timestamp startTime, Timestamp endTime, int validator, String reason){ - create(node, validator, startTime, endTime, INVESTIGATION_PENDING_KEY + reason); - } - - public static List getLastDeclinedOfNode(int node){ + public static List getLastDeclinedOfNode(int node) { return statusOfNode.listSelect(node); } - public static Optional getLastCheck(int node){ - return Optional.ofNullable(lastCheck.select(node)); + public static List previousChecks(SchematicNode node) { + return nodeHistory.listSelect(node.getId()); + } + + public static List getUnseen(SteamwarUser owner) { + return getUnseen.listSelect(owner); } @Field(nullable = true) @@ -78,6 +75,12 @@ public class CheckedSchematic { @Getter @Field private final String declineReason; + @Getter + @Field + private boolean seen; + @Getter + @Field + private final String nodeType; public int getNode() { return nodeId; @@ -91,19 +94,8 @@ public class CheckedSchematic { return nodeOwner; } - public boolean isInvestigationPending() { - return declineReason.startsWith(INVESTIGATION_PENDING_KEY); - } - - public String getInvestigationPendingReason() { - return declineReason.substring(INVESTIGATION_PENDING_KEY.length()); - } - - public Optional castToUserSafe() { - if (isInvestigationPending()) { - return Optional.empty(); - } else { - return Optional.of(this); - } + public void setSeen(boolean seen) { + this.seen = seen; + updateSeen.update(seen, startTime, endTime, nodeName); } } diff --git a/CommonCore/SQL/src/de/steamwar/sql/EventFight.java b/CommonCore/SQL/src/de/steamwar/sql/EventFight.java index fe91e3be..4143c596 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/EventFight.java +++ b/CommonCore/SQL/src/de/steamwar/sql/EventFight.java @@ -37,14 +37,18 @@ public class EventFight implements Comparable { private static final Table table = new Table<>(EventFight.class); private static final SelectStatement byId = table.select(Table.PRIMARY); + private static final SelectStatement byGroup = new SelectStatement(table, "SELECT * FROM EventFight WHERE GroupID = ? ORDER BY StartTime ASC"); + private static final SelectStatement byGroupLast = new SelectStatement(table, "SELECT * FROM EventFight WHERE GroupID = ? ORDER BY StartTime DESC LIMIT 1"); private static final SelectStatement allComing = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE StartTime > now() ORDER BY StartTime ASC"); private static final SelectStatement event = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE EventID = ? ORDER BY StartTime ASC"); + private static final SelectStatement activeFights = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE Fight IS NOT NULL AND StartTime < now() AND DATEDIFF(StartTime, now()) < 0"); private static final Statement reschedule = table.update(Table.PRIMARY, "StartTime"); private static final Statement setResult = table.update(Table.PRIMARY, "Ergebnis"); private static final Statement setFight = table.update(Table.PRIMARY, "Fight"); private static final Statement create = table.insertFields(true, "eventID", "startTime", "spielmodus", "map", "teamBlue", "teamRed", "spectatePort"); private static final Statement update = table.update(Table.PRIMARY, "startTime", "spielModus", "map", "teamBlue", "teamRed", "spectatePort"); + private static final Statement setGroup = table.update(Table.PRIMARY, "GroupID"); private static final Statement delete = table.delete(Table.PRIMARY); @Getter @@ -54,6 +58,14 @@ public class EventFight implements Comparable { return byId.select(fightID); } + public static List get(EventGroup group) { + return byGroup.listSelect(group.getId()); + } + + public static Optional getLast(EventGroup group) { + return Optional.ofNullable(byGroupLast.select(group.getId())); + } + public static void loadAllComingFights() { fights.clear(); fights.addAll(allComing.listSelect()); @@ -63,6 +75,19 @@ public class EventFight implements Comparable { return event.listSelect(eventID); } + private static List activeFightsCache = null; + + public static void clearActiveFightsCache() { + activeFightsCache = null; + } + + public static List getActiveFights() { + if (activeFightsCache == null) { + activeFightsCache = activeFights.listSelect(); + } + return activeFightsCache; + } + public static EventFight create(int event, Timestamp from, String spielmodus, String map, int blueTeam, int redTeam, Integer spectatePort) { return get(create.insertGetKey(event, from, spielmodus, map, blueTeam, redTeam, spectatePort)); } @@ -75,6 +100,10 @@ public class EventFight implements Comparable { private final int fightID; @Getter @Setter + @Field(nullable = true, def = "null") + private Integer groupId; + @Getter + @Setter @Field private Timestamp startTime; @Getter @@ -98,11 +127,35 @@ public class EventFight implements Comparable { @Field(nullable = true) private Integer spectatePort; @Getter + @Setter + @Field(def = "1") + private int bestOf; + @Getter @Field(def = "0") private int ergebnis; @Field(nullable = true) private int fight; + public Optional getGroup() { + return Optional.ofNullable(groupId).flatMap(EventGroup::get); + } + + public Optional getWinner() { + if(ergebnis == 0) + return Optional.empty(); + return Optional.ofNullable(ergebnis == 1 ? Team.get(teamBlue) : Team.get(teamRed)); + } + + public Optional getLosser() { + if(ergebnis == 0) + return Optional.empty(); + return Optional.ofNullable(ergebnis == 1 ? Team.get(teamRed) : Team.get(teamBlue)); + } + + public List getDependents() { + return EventRelation.getFightRelations(this); + } + public void setErgebnis(int winner) { this.ergebnis = winner; setResult.update(winner, fightID); @@ -114,6 +167,11 @@ public class EventFight implements Comparable { setFight.update(fight, fightID); } + public void setGroup(Integer group) { + setGroup.update(group, fightID); + this.groupId = group; + } + public boolean hasFinished() { return fight != 0 || ergebnis != 0; } diff --git a/CommonCore/SQL/src/de/steamwar/sql/EventGroup.java b/CommonCore/SQL/src/de/steamwar/sql/EventGroup.java new file mode 100644 index 00000000..68934765 --- /dev/null +++ b/CommonCore/SQL/src/de/steamwar/sql/EventGroup.java @@ -0,0 +1,173 @@ +/* + * 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 . + */ + +package de.steamwar.sql; + +import de.steamwar.sql.internal.*; +import lombok.Getter; +import lombok.Setter; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Getter +@Setter +public class EventGroup { + static { + SqlTypeMapper.ordinalEnumMapper(EventGroupType.class); + } + + private static final Table table = new Table<>(EventGroup.class); + + private static final SelectStatement get = table.select(Table.PRIMARY); + private static final SelectStatement byEvent = new SelectStatement<>(table, "SELECT * FROM EventGroup WHERE EventID = ?"); + + private static final Statement insert = table.insertFields(true, "EventID", "Name", "Type"); + private static final Statement update = table.update(Table.PRIMARY, "Name", "Type", "PointsPerWin", "PointsPerLoss", "PointsPerDraw"); + private static final Statement delete = table.delete(Table.PRIMARY); + + public static List get(Event eventID) { + return byEvent.listSelect(eventID.getEventID()); + } + + public static EventGroup create(Event event, String name, EventGroupType type) { + int key = insert.insertGetKey(event.getEventID(), name, type); + return EventGroup.get(key).get(); + } + + public static Optional get(int id) { + return Optional.ofNullable(get.select(id)); + } + + @Field(keys = Table.PRIMARY) + private final int id; + + @Field(keys = "EVENT_NAME") + private int eventID; + + @Field(keys = "EVENT_NAME") + private String name; + + @Field + private EventGroupType type; + + @Field + private int pointsPerWin; + + @Field + private int pointsPerLoss; + + @Field + private int pointsPerDraw; + + public EventGroup(int id, int eventID, String name, EventGroupType type, int pointsPerWin, int pointsPerLoss, int pointsPerDraw) { + this.id = id; + this.eventID = eventID; + this.name = name; + this.type = type; + this.pointsPerWin = pointsPerWin; + this.pointsPerLoss = pointsPerLoss; + this.pointsPerDraw = pointsPerDraw; + } + + private Map points; + + public List getFights() { + return EventFight.get(this); + } + + public Set getTeamsId() { + return getFights().stream().flatMap(fight -> Stream.of(fight.getTeamBlue(), fight.getTeamRed())) + .collect(Collectors.toSet()); + } + + public Set getTeams() { + return getTeamsId().stream().map(Team::get).collect(Collectors.toSet()); + } + + public Optional getLastFight() { + return EventFight.getLast(this); + } + + public List getDependents() { + return EventRelation.getGroupRelations(this); + } + + public Map calculatePoints() { + if (points == null) { + Map p = getTeamsId().stream().collect(Collectors.toMap(team -> team, team -> 0)); + + for (EventFight fight : getFights()) { + int blueTeamAdd = 0; + int redTeamAdd = 0; + + if (!fight.hasFinished()) { + continue; + } + + switch (fight.getErgebnis()) { + case 1: + blueTeamAdd += pointsPerWin; + redTeamAdd += pointsPerLoss; + break; + case 2: + blueTeamAdd += pointsPerLoss; + redTeamAdd += pointsPerWin; + break; + case 0: + if (fight.getFightID() != 0) { + blueTeamAdd += pointsPerDraw; + redTeamAdd += pointsPerDraw; + } + break; + } + + p.put(fight.getTeamBlue(), p.get(fight.getTeamBlue()) + blueTeamAdd); + p.put(fight.getTeamRed(), p.get(fight.getTeamRed()) + redTeamAdd); + } + + points = p.entrySet().stream().collect(Collectors.toMap(integerIntegerEntry -> Team.get(integerIntegerEntry.getKey()), Map.Entry::getValue)); + } + + return points; + } + + public void update(String name, EventGroupType type, int pointsPerWin, int pointsPerLoss, int pointsPerDraw) { + update.update(name, type, pointsPerWin, pointsPerLoss, pointsPerDraw, id); + this.name = name; + this.type = type; + this.pointsPerWin = pointsPerWin; + this.pointsPerLoss = pointsPerLoss; + this.pointsPerDraw = pointsPerDraw; + } + + public boolean needsTieBreak() { + return calculatePoints().values().stream().sorted().limit(2).distinct().count() < 2; + } + + public void delete() { + delete.update(id); + } + + public static enum EventGroupType { + GROUP_STAGE, + ELIMINATION_STAGE + } +} diff --git a/CommonCore/SQL/src/de/steamwar/sql/EventRelation.java b/CommonCore/SQL/src/de/steamwar/sql/EventRelation.java new file mode 100644 index 00000000..7d142805 --- /dev/null +++ b/CommonCore/SQL/src/de/steamwar/sql/EventRelation.java @@ -0,0 +1,192 @@ +/* + * 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 . + */ + +package de.steamwar.sql; + +import de.steamwar.sql.internal.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@AllArgsConstructor +@Getter +@Setter +public class EventRelation { + + static { + SqlTypeMapper.ordinalEnumMapper(FightTeam.class); + SqlTypeMapper.ordinalEnumMapper(FromType.class); + } + + private static final Table table = new Table<>(EventRelation.class); + + private static final SelectStatement get = new SelectStatement<>(table, "SELECT * FROM EventRelation WHERE FromType = ? AND FromId = ?"); + private static final SelectStatement byId = new SelectStatement<>(table, "SELECT * FROM EventRelation WHERE id = ?"); + private static final SelectStatement byEvent = new SelectStatement<>(table, "SELECT ER.* FROM EventRelation ER JOIN EventFight EF ON EF.id = ER.fightId WHERE EF.EventID = ?"); + private static final Statement insert = table.insertAll(true); + private static final Statement update = table.update(Table.PRIMARY, "fromType", "fromId", "fromPlace"); + private static final Statement updateTeam = table.update(Table.PRIMARY, "fightTeam"); + private static final Statement delete = table.delete(Table.PRIMARY); + + public static List get(Event event) { + return byId.listSelect(event.getEventID()); + } + + public static EventRelation get(int id) { + return byId.select(id); + } + + public static List getFightRelations(EventFight fight) { + return get.listSelect(FromType.FIGHT, fight.getFightID()); + } + + public static List getGroupRelations(EventGroup group) { + return get.listSelect(FromType.GROUP, group.getId()); + } + + public static EventRelation create(EventFight fight, FightTeam fightTeam, FromType fromType, int fromId, int fromPlace) { + int id = insert.insertGetKey(fight.getFightID(), fightTeam, fromType, fromId, fromPlace); + return get(id); + } + + @Field(keys = Table.PRIMARY) + private final int id; + + @Field + private int fightId; + + @Field + private FightTeam fightTeam; + + @Field + private FromType fromType; + + @Field + private int fromId; + + @Field + private int fromPlace; + + public EventFight getFight() { + return EventFight.get(fightId); + } + + public Optional getFromFight() { + if(fromType == FromType.FIGHT) { + return Optional.of(EventFight.get(fromId)); + } else { + return Optional.empty(); + } + } + + public Optional getFromGroup() { + if(fromType == FromType.GROUP) { + return EventGroup.get(fromId); + } else { + return Optional.empty(); + } + } + + public void delete() { + delete.update(id); + } + + public void setUpdateTeam(FightTeam team) { + updateTeam.update(id, team); + this.fightTeam = team; + } + + public void setFromFight(EventFight fight, int place) { + setFrom(fight.getFightID(), place, FromType.FIGHT); + } + + public void setFromGroup(EventGroup group, int place) { + setFrom(group.getId(), place, FromType.GROUP); + } + + private void setFrom(int id, int place, FromType type) { + update.update(id, type, id, place); + this.fromType = type; + this.fromId = id; + this.fromPlace = place; + } + + public Optional getAdvancingTeam() { + if (fromType == FromType.FIGHT) { + if (fromPlace == 0) { + return getFromFight().flatMap(EventFight::getWinner); + } else { + return getFromFight().flatMap(EventFight::getLosser); + } + } else if (fromType == FromType.GROUP) { + return getFromGroup().map(EventGroup::calculatePoints) + .flatMap(points -> points.entrySet().stream() + .sorted(Map.Entry.comparingByValue().reversed()) + .skip(fromPlace) + .findFirst() + .map(Map.Entry::getKey)); + } else { + return Optional.empty(); + } + } + + public boolean apply() { + Optional team = getAdvancingTeam().map(Team::getTeamId); + if(!team.isPresent()) + return false; + + EventFight fight = getFight(); + if(fightTeam == FightTeam.RED) { + fight.update( + fight.getStartTime(), + fight.getSpielmodus(), + fight.getMap(), + team.get(), + fight.getTeamBlue(), + fight.getSpectatePort() + ); + } else { + fight.update( + fight.getStartTime(), + fight.getSpielmodus(), + fight.getMap(), + fight.getTeamRed(), + team.get(), + fight.getSpectatePort() + ); + } + + return true; + } + + public static enum FightTeam { + RED, + BLUE + } + + public static enum FromType { + FIGHT, + GROUP + } +} diff --git a/CommonCore/SQL/src/de/steamwar/sql/NodeData.java b/CommonCore/SQL/src/de/steamwar/sql/NodeData.java index 08179979..bd543be0 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/NodeData.java +++ b/CommonCore/SQL/src/de/steamwar/sql/NodeData.java @@ -23,8 +23,13 @@ import de.steamwar.sql.internal.*; import lombok.AllArgsConstructor; import lombok.Getter; +import javax.swing.plaf.nimbus.State; import java.io.*; import java.sql.PreparedStatement; +import java.sql.Timestamp; +import java.time.Instant; +import java.util.List; +import java.util.Optional; import java.util.zip.GZIPInputStream; @AllArgsConstructor @@ -40,26 +45,47 @@ public class NodeData { private static final Table table = new Table<>(NodeData.class); - private static final Statement updateDatabase = new Statement("INSERT INTO NodeData(NodeId, NodeFormat, SchemData) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE NodeFormat = VALUES(NodeFormat), SchemData = VALUES(SchemData)"); - private static final Statement selSchemData = new Statement("SELECT SchemData FROM NodeData WHERE NodeId = ?"); + private static final Statement updateDatabase = new Statement("INSERT INTO NodeData(NodeId, NodeFormat, SchemData) VALUES (?, ?, ?)", true); + private static final Statement selSchemData = new Statement("SELECT SchemData FROM NodeData WHERE NodeId = ? AND CreatedAt = ?"); + private static final Statement delete = table.delete(Table.PRIMARY); - private static final SelectStatement get = table.select(Table.PRIMARY); + private static final SelectStatement get = new SelectStatement<>(table, "SELECT NodeId, CreatedAt, NodeFormat FROM NodeData WHERE NodeId = ? ORDER BY CreatedAt "); + private static final Statement getRevisions = new Statement("SELECT COUNT(DISTINCT CreatedAt) as CNT FROM NodeData WHERE NodeId = ?"); + private static final SelectStatement getLatest = new SelectStatement<>(table, "SELECT NodeId, CreatedAt, NodeFormat FROM NodeData WHERE NodeId = ? ORDER BY CreatedAt DESC LIMIT 1"); - public static NodeData get(SchematicNode node) { - if(node.isDir()) - throw new IllegalArgumentException("Node is a directory"); - return get.select(rs -> { - if(rs.next()) { - return new NodeData(node.getId(), SchematicFormat.values()[rs.getInt("NodeFormat")]); + public static NodeData getLatest(SchematicNode node) { + if (node.isDir()) throw new IllegalArgumentException("Node is dir"); + return Optional.ofNullable(getLatest.select(node)).orElseGet(() -> new NodeData(node.getId(), Timestamp.from(Instant.now()), SchematicFormat.MCEDIT)); + } + + public static List get(SchematicNode node) { + return get.listSelect(node); + } + + public static NodeData get(SchematicNode node, int revision) { + return get.listSelect(node).get(revision - 1); + } + + public static int getRevisions(SchematicNode node) { + return getRevisions.select(rs -> { + if (rs.next()) { + return rs.getInt("CNT"); } else { - return new NodeData(node.getId(), SchematicFormat.MCEDIT); + return 0; } }, node); } + public static void saveFromStream(SchematicNode node, InputStream blob, SchematicFormat format) { + updateDatabase.update(node.getId(), format, blob); + } + @Field(keys = {Table.PRIMARY}) private final int nodeId; + @Field + private Timestamp createdAt; + @Field private SchematicFormat nodeFormat; @@ -84,15 +110,19 @@ public class NodeData { } catch (IOException e) { throw new SecurityException("SchemData is wrong", e); } - }, nodeId); + }, nodeId, createdAt); } catch (Exception e) { throw new IOException(e); } } + @Deprecated public void saveFromStream(InputStream blob, SchematicFormat newFormat) { - updateDatabase.update(nodeId, newFormat, blob); - nodeFormat = newFormat; + saveFromStream(SchematicNode.getSchematicNode(nodeId), blob, newFormat); + } + + public void delete() { + delete.update(nodeId, createdAt); } @AllArgsConstructor diff --git a/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java b/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java index 87b7cac4..e355419b 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java +++ b/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java @@ -42,13 +42,13 @@ public class SchematicNode { TAB_CACHE.clear(); } - private static final String nodeSelector = "SELECT NodeId, NodeOwner, NodeOwner AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode "; + private static final String nodeSelector = "SELECT NodeId, NodeOwner, NodeOwner AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode "; private static final Table table = new Table<>(SchematicNode.class); private static final Statement create = table.insertFields(true, "NodeOwner", "NodeName", "ParentNode", "NodeItem", "NodeType"); private static final Statement update = table.update(Table.PRIMARY, "NodeName", "ParentNode", "NodeItem", - "NodeType", "NodeRank", "ReplaceColor", "AllowReplay"); + "NodeType", "NodeRank", "Config"); private static final Statement delete = table.delete(Table.PRIMARY); private static final SelectStatement byId = new SelectStatement<>(table, @@ -66,13 +66,13 @@ public class SchematicNode { private static final SelectStatement all = new SelectStatement<>(table, "WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId"); private static final SelectStatement list = new SelectStatement<>(table, - "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS - + "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName"); + + "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName"); private static final SelectStatement byParentName = new SelectStatement<>(table, - "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS - + "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?"); + + "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?"); private static final SelectStatement schematicAccessibleForUser = new SelectStatement<>(table, "WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeId = ?"); private static final SelectStatement accessibleByUserTypeInParent = new SelectStatement<>(table, @@ -81,7 +81,7 @@ public class SchematicNode { private static final SelectStatement accessibleByUserType = new SelectStatement<>(table, "WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeType = ?"); private static final SelectStatement byIdAndUser = new SelectStatement<>(table, - "SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE NodeId = ?"); + "SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config FROM SchematicNode WHERE NodeId = ?"); private static final SelectStatement allParentsOfNode = new SelectStatement<>(table, "WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? AND EffectiveOwner = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.ReplaceColor, SN.AllowReplay FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId"); @@ -108,10 +108,8 @@ public class SchematicNode { private SchematicType nodeType; @Field(def = "0") private int nodeRank; - @Field(def = "1") - private boolean replaceColor; - @Field(def = "1") - private boolean allowReplay; + @Field + private int config; private String brCache; @@ -125,8 +123,7 @@ public class SchematicNode { String nodeItem, SchematicType nodeType, int nodeRank, - boolean replaceColor, - boolean allowReplay) { + int config) { this.nodeId = nodeId; this.nodeOwner = nodeOwner; this.effectiveOwner = effectiveOwner; @@ -136,8 +133,7 @@ public class SchematicNode { this.nodeType = nodeType; this.lastUpdate = lastUpdate; this.nodeRank = nodeRank; - this.replaceColor = replaceColor; - this.allowReplay = allowReplay; + this.config = config; } public static List getAll(SteamwarUser user) { @@ -407,7 +403,7 @@ public class SchematicNode { public String getFileEnding() { if (isDir()) throw new SecurityException("Node is Directory"); - return NodeData.get(this).getNodeFormat().getFileEnding(); + return NodeData.getLatest(this).getNodeFormat().getFileEnding(); } public int getRank() { @@ -441,24 +437,45 @@ public class SchematicNode { } public boolean replaceColor() { - return replaceColor; + return getConfig(ConfigFlags.REPLACE_COLOR); } public void setReplaceColor(boolean replaceColor) { if (isDir()) throw new SecurityException("Is Directory"); - this.replaceColor = replaceColor; - updateDB(); + setConfig(ConfigFlags.REPLACE_COLOR, replaceColor); } public boolean allowReplay() { - return allowReplay; + return getConfig(ConfigFlags.ALLOW_REPLAY); } public void setAllowReplay(boolean allowReplay) { if (isDir()) throw new SecurityException("Is Directory"); - this.allowReplay = allowReplay; + setConfig(ConfigFlags.ALLOW_REPLAY, allowReplay); + } + + public boolean isPrepared() { + return getConfig(ConfigFlags.IS_PREPARED); + } + + public void setPrepared(boolean prepared) { + if (isDir()) + throw new SecurityException("Is Directory"); + setConfig(ConfigFlags.IS_PREPARED, prepared); + } + + public boolean getConfig(ConfigFlags flag) { + return (config & (1 << flag.ordinal())) != 0; + } + + public void setConfig(ConfigFlags flag, boolean value) { + if (value) { + config |= (1 << flag.ordinal()); + } else { + config &= ~(1 << flag.ordinal()); + } updateDB(); } @@ -486,7 +503,7 @@ public class SchematicNode { private void updateDB() { this.lastUpdate = Timestamp.from(Instant.now()); - update.update(nodeName, parentNode, nodeItem, nodeType, nodeRank, replaceColor, allowReplay, nodeId); + update.update(nodeName, parentNode, nodeItem, nodeType, nodeRank, config, nodeId); TAB_CACHE.clear(); } @@ -608,4 +625,10 @@ public class SchematicNode { TAB_CACHE.computeIfAbsent(user.getId(), integer -> new HashMap<>()).putIfAbsent(cacheKey, list); return list; } + + public static enum ConfigFlags { + REPLACE_COLOR, + ALLOW_REPLAY, + IS_PREPARED + } } diff --git a/CommonCore/SQL/src/de/steamwar/sql/Tutorial.java b/CommonCore/SQL/src/de/steamwar/sql/Tutorial.java deleted file mode 100644 index 9febcba5..00000000 --- a/CommonCore/SQL/src/de/steamwar/sql/Tutorial.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2023 SteamWar.de-Serverteam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package de.steamwar.sql; - -import de.steamwar.sql.internal.Field; -import de.steamwar.sql.internal.SelectStatement; -import de.steamwar.sql.internal.Statement; -import de.steamwar.sql.internal.Table; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.List; -import java.util.stream.Collectors; - -@AllArgsConstructor -public class Tutorial { - - private static final Table table = new Table<>(Tutorial.class); - private static final SelectStatement by_popularity = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Released = ? GROUP BY t.TutorialID ORDER BY SUM(r.Stars) DESC LIMIT ?, ?"); - private static final SelectStatement own = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Creator = ? GROUP BY t.TutorialID ORDER BY t.TutorialID ASC LIMIT ?, ?"); - private static final SelectStatement by_creator_name = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Creator = ? AND t.Name = ? GROUP BY t.TutorialID"); - private static final SelectStatement by_id = new SelectStatement<>(table, "SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.TutorialID = ? GROUP BY t.TutorialID"); - private static final Statement rate = new Statement("INSERT INTO TutorialRating (TutorialID, UserID, Stars) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE Stars = VALUES(Stars)"); - private static final Statement create = new Statement("INSERT INTO Tutorial (Creator, Name, Item) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE Item = VALUES(Item), Released = 0"); - private static final Statement release = table.update(Table.PRIMARY, "released"); - private static final Statement delete = table.delete(Table.PRIMARY); - - public static List getPage(int page, int elementsPerPage, boolean released) { - List tutorials = by_popularity.listSelect(released, page * elementsPerPage, elementsPerPage); - SteamwarUser.batchCache(tutorials.stream().map(tutorial -> tutorial.creator).collect(Collectors.toSet())); - return tutorials; - } - - public static List getOwn(int user, int page, int elementsPerPage) { - return own.listSelect(user, page * elementsPerPage, elementsPerPage); - } - - public static Tutorial create(int creator, String name, String item) { - create.update(creator, name, item); - return by_creator_name.select(creator, name); - } - - public static Tutorial get(int id) { - return by_id.select(id); - } - - @Getter - @Field(keys = {Table.PRIMARY}, autoincrement = true) - private final int tutorialId; - @Getter - @Field(keys = {"CreatorName"}) - private final int creator; - @Getter - @Field(keys = {"CreatorName"}) - private final String name; - @Getter - @Field(def = "'BOOK'") - private final String item; - @Getter - @Field(def = "0") - private final boolean released; - @Getter - @Field(def = "0") // Not really a field, but necessary for select generation - private final double stars; - - public void release() { - release.update(1, tutorialId); - } - - public void delete() { - delete.update(tutorialId); - } - - public void rate(int user, int rating) { - rate.update(tutorialId, user, rating); - } -} diff --git a/CommonCore/SQL/src/de/steamwar/sql/UserPerm.java b/CommonCore/SQL/src/de/steamwar/sql/UserPerm.java index ed842d54..50181063 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/UserPerm.java +++ b/CommonCore/SQL/src/de/steamwar/sql/UserPerm.java @@ -48,18 +48,19 @@ public enum UserPerm { public static final Map prefixes; public static final Prefix emptyPrefix; static { + // https://www.digminecraft.com/lists/color_list_pc.php SqlTypeMapper.nameEnumMapper(UserPerm.class); Map p = new EnumMap<>(UserPerm.class); emptyPrefix = new Prefix("§7", ""); p.put(PREFIX_NONE, emptyPrefix); p.put(PREFIX_YOUTUBER, new Prefix("§7", "YT")); - p.put(PREFIX_GUIDE, new Prefix("§a", "Guide")); + p.put(PREFIX_GUIDE, new Prefix("§x§E§5§F§F§8§4", "Guide")); // E5FF84 - p.put(PREFIX_SUPPORTER, new Prefix("§6", "Sup")); - p.put(PREFIX_MODERATOR, new Prefix("§6", "Mod")); - p.put(PREFIX_BUILDER, new Prefix("§e", "Arch")); - p.put(PREFIX_DEVELOPER, new Prefix("§e", "Dev")); - p.put(PREFIX_ADMIN, new Prefix("§e", "Admin")); + p.put(PREFIX_SUPPORTER, new Prefix("§x§6§0§9§5§F§F", "Sup")); // 6095FF + p.put(PREFIX_MODERATOR, new Prefix("§x§F§F§A§2§5§0", "Mod")); // FFA250 + p.put(PREFIX_BUILDER, new Prefix("§x§6§0§F§F§6§9", "Arch")); // 60FF69 + p.put(PREFIX_DEVELOPER, new Prefix("§x§0§B§B§C§B§9", "Dev")); // 0BBCB9 + p.put(PREFIX_ADMIN, new Prefix("§x§F§F§2§B§2§B", "Admin")); // FF2B2B prefixes = Collections.unmodifiableMap(p); } diff --git a/CommonCore/build.gradle.kts b/CommonCore/build.gradle.kts index 91b10d6f..8e2df2bc 100644 --- a/CommonCore/build.gradle.kts +++ b/CommonCore/build.gradle.kts @@ -24,4 +24,5 @@ plugins { dependencies { api(project(":CommonCore:SQL")) api(project(":CommonCore:Network")) + api(project(":CommonCore:Data")) } diff --git a/FightSystem/FightSystem_14/src/de/steamwar/fightsystem/utils/WorldeditWrapper14.java b/FightSystem/FightSystem_14/src/de/steamwar/fightsystem/utils/WorldeditWrapper14.java index 9a0ae4b5..072afaff 100644 --- a/FightSystem/FightSystem_14/src/de/steamwar/fightsystem/utils/WorldeditWrapper14.java +++ b/FightSystem/FightSystem_14/src/de/steamwar/fightsystem/utils/WorldeditWrapper14.java @@ -145,6 +145,6 @@ public class WorldeditWrapper14 implements WorldeditWrapper { throw new SecurityException(e); } - new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), NodeData.SchematicFormat.SPONGE_V2); + SchematicData.saveFromBytes(schem, outputStream.toByteArray(), NodeData.SchematicFormat.SPONGE_V2); } } diff --git a/FightSystem/FightSystem_21/src/de/steamwar/fightsystem/utils/CraftbukkitWrapper21.java b/FightSystem/FightSystem_21/src/de/steamwar/fightsystem/utils/CraftbukkitWrapper21.java index 9e52bb36..b5c920a7 100644 --- a/FightSystem/FightSystem_21/src/de/steamwar/fightsystem/utils/CraftbukkitWrapper21.java +++ b/FightSystem/FightSystem_21/src/de/steamwar/fightsystem/utils/CraftbukkitWrapper21.java @@ -25,6 +25,6 @@ public class CraftbukkitWrapper21 extends CraftbukkitWrapper18 { @Override public float headRotation(Entity e) { - return getEntity(e).bS(); + return getEntity(e).getYHeadRot(); } } diff --git a/FightSystem/FightSystem_8/src/de/steamwar/fightsystem/utils/WorldeditWrapper8.java b/FightSystem/FightSystem_8/src/de/steamwar/fightsystem/utils/WorldeditWrapper8.java index 018552f2..1fdd34b7 100644 --- a/FightSystem/FightSystem_8/src/de/steamwar/fightsystem/utils/WorldeditWrapper8.java +++ b/FightSystem/FightSystem_8/src/de/steamwar/fightsystem/utils/WorldeditWrapper8.java @@ -20,10 +20,7 @@ package de.steamwar.fightsystem.utils; import com.sk89q.jnbt.NBTInputStream; -import com.sk89q.worldedit.EditSession; -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.extent.clipboard.BlockArrayClipboard; @@ -143,6 +140,6 @@ public class WorldeditWrapper8 implements WorldeditWrapper { throw new SecurityException(e); } - new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), NodeData.SchematicFormat.MCEDIT); + SchematicData.saveFromBytes(schem, outputStream.toByteArray(), NodeData.SchematicFormat.MCEDIT); } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/Config.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/Config.java index 7bac2bee..d7ce5f9e 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/Config.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/Config.java @@ -59,6 +59,7 @@ public class Config { public static final Region RedExtendRegion; public static final Region ArenaRegion; public static final Region PlayerRegion; + public static final Region BlueInsetRegion; public static final Location TeamBlueSpawn; public static final Location TeamRedSpawn; @@ -107,6 +108,7 @@ public class Config { public static final boolean PercentEntern; public static final boolean PercentBlocksWhitelist; public static final Set PercentBlocks; + public static final int TechKoTime; //default kits public static final String MemberDefault; @@ -193,6 +195,11 @@ public class Config { ReplaceWithBlockupdates = config.getBoolean("Schematic.ReplaceWithBlockupdates", false); UnlimitedPrepare = config.getBoolean("Schematic.UnlimitedPrepare", false); + int schemInsetX = config.getInt("Schematic.Inset.x", 0); + int schemInsetZ = config.getInt("Schematic.Inset.z", 0); + int schemInsetBottom = config.getInt("Schematic.Inset.bottom", 0); + int schemInsetTop = config.getInt("Schematic.Inset.top", 0); + GameName = config.getString("GameName", "WarGear"); TeamChatDetection = config.getString("TeamChatPrefix", "+"); @@ -203,6 +210,7 @@ public class Config { PercentEntern = config.getBoolean("WinConditionParams.PercentEntern", true); PercentBlocksWhitelist = config.getBoolean("WinConditionParams.BlocksWhitelist", false); PercentBlocks = Collections.unmodifiableSet(config.getStringList("WinConditionParams.Blocks").stream().map(Material::valueOf).collect(Collectors.toSet())); + TechKoTime = config.getInt("WinConditionParams.TechKoTime", 90); EnterStages = Collections.unmodifiableList(config.getIntegerList("EnterStages")); AllowMissiles = config.getBoolean("Arena.AllowMissiles", !EnterStages.isEmpty()); @@ -318,6 +326,8 @@ public class Config { ArenaRegion = Region.withExtension(arenaMinX, blueCornerY, arenaMinZ, arenaMaxX - arenaMinX, schemsizeY, arenaMaxZ - arenaMinZ, 0, PreperationArea, 0); PlayerRegion = new Region(arenaMinX, underBorder, arenaMinZ, arenaMaxX, world.getMaxHeight(), arenaMaxZ); + BlueInsetRegion = new Region(BluePasteRegion.getMinX() + schemInsetX, BluePasteRegion.getMinY() + schemInsetBottom, BluePasteRegion.getMinZ() + schemInsetZ, BluePasteRegion.getMaxX() - schemInsetX, BluePasteRegion.getMaxY() - schemInsetTop, BluePasteRegion.getMaxZ() - schemInsetZ); + int eventKampfID = Integer.parseInt(System.getProperty("fightID", "0")); if(eventKampfID >= 1){ EventKampf = EventFight.get(eventKampfID); @@ -359,7 +369,7 @@ public class Config { }else{ //No event TeamRedColor = config.getString("Red.Prefix", "§c"); - TeamBlueColor = config.getString("Blue.Prefix", "§3"); + TeamBlueColor = config.getString("Blue.Prefix", "§9"); TeamRedName = config.getString("Red.Name", "Rot"); TeamBlueName = config.getString("Blue.Name", "Blau"); OnlyPublicSchematics = config.getBoolean("Schematic.OnlyPublicSchematics", false); diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java index bff38170..1ff85e23 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java @@ -20,6 +20,7 @@ package de.steamwar.fightsystem; import com.comphenix.tinyprotocol.TinyProtocol; +import de.steamwar.core.WorldEditRendererCUIEditor; import de.steamwar.core.Core; import de.steamwar.fightsystem.commands.*; import de.steamwar.fightsystem.countdown.*; @@ -28,8 +29,8 @@ import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.fight.FightWorld; import de.steamwar.fightsystem.fight.HotbarKit; -import de.steamwar.fightsystem.listener.Shutdown; import de.steamwar.fightsystem.listener.*; +import de.steamwar.fightsystem.listener.Shutdown; import de.steamwar.fightsystem.record.FileRecorder; import de.steamwar.fightsystem.record.FileSource; import de.steamwar.fightsystem.record.GlobalRecorder; @@ -40,6 +41,7 @@ import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.fightsystem.utils.*; import de.steamwar.fightsystem.winconditions.*; import de.steamwar.message.Message; +import de.steamwar.sql.NodeData; import de.steamwar.sql.SchematicNode; import lombok.Getter; import org.bukkit.Bukkit; @@ -67,6 +69,11 @@ public class FightSystem extends JavaPlugin { Core.setInstance(this); TinyProtocol.init(); } + if (Config.SpectatePort != 0) { + Core.setServerName("Spectate"); + } else if (Config.ReplayID != 0) { + Core.setServerName("Replay"); + } message = new Message("de.steamwar.fightsystem.FightSystem", FightSystem.class.getClassLoader()); @@ -106,6 +113,7 @@ public class FightSystem extends JavaPlugin { new HotbarKit.HotbarKitListener(); new JoinRequestListener(); 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); new EnterHandler(); techHider = new TechHiderWrapper(); @@ -124,6 +132,7 @@ public class FightSystem extends JavaPlugin { new WinconditionPointsAirShip(); new WinconditionTimeout(); new WinconditionTimeTechKO(); + new WinconditionTimedDamageTechKO(); new EventTeamOffWincondition(); new WinconditionComparisonTimeout(Winconditions.HEART_RATIO_TIMEOUT, "HeartTimeout", "WIN_MORE_HEALTH", FightTeam::getHeartRatio); new WinconditionComparisonTimeout(Winconditions.PERCENT_TIMEOUT, "PercentTimeout", "WIN_LESS_DAMAGE", team -> -Wincondition.getPercentWincondition().getPercent(team)); @@ -171,12 +180,11 @@ public class FightSystem extends JavaPlugin { SchematicNode checkSchematicNode = SchematicNode.getSchematicNode(Config.CheckSchemID); Fight.getBlueTeam().setSchem(checkSchematicNode); - if (checkSchematicNode.getName().endsWith("-prepared")) { - SchematicNode unpreparedSchematicNode = SchematicNode.getSchematicNode(checkSchematicNode.getOwner(), checkSchematicNode.getName().substring(0, checkSchematicNode.getName().length() - 9), checkSchematicNode.getParent()); - if (unpreparedSchematicNode != null) { - Fight.getRedTeam().setSchem(unpreparedSchematicNode); - } + if (checkSchematicNode.isPrepared()) { + Fight.getRedTeam().setSchem(checkSchematicNode, NodeData.getRevisions(checkSchematicNode) - 1); } + + new TechareaCommand(); }else if(Config.mode == ArenaMode.PREPARE) { Fight.getUnrotated().setSchem(SchematicNode.getSchematicNode(Config.PrepareSchemID)); } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties index 455e0444..22babff0 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties @@ -191,6 +191,7 @@ BAR_POINTS_OF={0}§8/§7{1} §8Points BAR_PERCENT={0}§8% BAR_CANNONS={0} §8Cannons BAR_WATER={0} §8Water +BAR_SECONDS={0}§8s # Winconditions diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechareaCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechareaCommand.java new file mode 100644 index 00000000..880e1843 --- /dev/null +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/TechareaCommand.java @@ -0,0 +1,60 @@ +/* + * 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 . + */ + +package de.steamwar.fightsystem.commands; + +import de.steamwar.command.SWCommand; +import de.steamwar.entity.CWireframe; +import de.steamwar.entity.REntityServer; +import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.FightSystem; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class TechareaCommand extends SWCommand { + private final Map servers = new HashMap<>(); + + public TechareaCommand() { + super("techarea"); + + Bukkit.getScheduler().runTaskTimer(FightSystem.getPlugin(), () -> servers.forEach((uuid, rEntityServer) -> rEntityServer.tick()), 2, 2); + } + + @Register + public void genericCommand(Player player) { + if (servers.containsKey(player.getUniqueId())) { + servers.get(player.getUniqueId()).close(); + } else { + REntityServer server = new REntityServer(); + CWireframe wireframe = new CWireframe(server); + + wireframe.setPos1(Config.BlueInsetRegion.getMinLocation(Config.world)); + wireframe.setPos2(Config.BlueInsetRegion.getMaxLocation(Config.world).subtract(1, 1, 1)); + wireframe.setBlock(Material.RED_CONCRETE.createBlockData()); + + server.addPlayer(player); + servers.put(player.getUniqueId(), server); + } + } +} diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/WGCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/WGCommand.java index edb891fc..1ffe7dce 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/WGCommand.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/WGCommand.java @@ -21,6 +21,7 @@ package de.steamwar.fightsystem.commands; import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.fight.Fight; +import de.steamwar.fightsystem.fight.FightWorld; import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.StateDependentCommand; import org.bukkit.command.Command; @@ -39,7 +40,9 @@ public class WGCommand implements CommandExecutor { if(!(sender instanceof Player)) { return false; } + FightWorld.resetWorld(); Fight.getBlueTeam().pasteSchem(); + Fight.getRedTeam().pasteSchem(); return false; } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/Fight.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/Fight.java index 1f205122..61f6a162 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/Fight.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/Fight.java @@ -19,20 +19,14 @@ package de.steamwar.fightsystem.fight; -import com.comphenix.tinyprotocol.TinyProtocol; -import com.mojang.authlib.GameProfile; import de.steamwar.core.Core; -import de.steamwar.core.ProtocolWrapper; import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.Config; -import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.record.GlobalRecorder; import lombok.Getter; import org.bukkit.Bukkit; -import org.bukkit.GameMode; import org.bukkit.Sound; import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; import java.util.Collection; import java.util.HashSet; diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightSchematic.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightSchematic.java index 5e84ccdc..7591d4bc 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightSchematic.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightSchematic.java @@ -31,6 +31,7 @@ import de.steamwar.fightsystem.states.StateDependent; import de.steamwar.fightsystem.utils.ColorConverter; import de.steamwar.fightsystem.utils.Region; import de.steamwar.fightsystem.utils.WorldeditWrapper; +import de.steamwar.fightsystem.winconditions.Winconditions; import de.steamwar.sql.SchematicData; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SchematicType; @@ -51,20 +52,28 @@ public class FightSchematic extends StateDependent { private final FightTeam team; private final Region region; + private final boolean rotate; + @Getter + private boolean usedRotate; @Getter private Clipboard clipboard = null; private int schematic = 0; - public FightSchematic(FightTeam team, boolean rotate) { + public FightSchematic(FightTeam team, boolean usedRotate) { super(ArenaMode.All, FightState.PostSchemSetup); this.team = team; this.region = team.getSchemRegion(); - this.rotate = rotate; + this.rotate = usedRotate; + this.usedRotate = usedRotate; register(); } + public void setChangeRotate(boolean rotate) { + this.usedRotate = this.rotate ^ rotate; + } + public boolean hasSchematic() { return clipboard != null; } @@ -74,9 +83,13 @@ public class FightSchematic extends StateDependent { } public void setSchematic(SchematicNode schem) { + setSchematic(schem, -1); + } + + public void setSchematic(SchematicNode schem, int revision) { schematic = schem.getId(); try { - clipboard = new SchematicData(schem).load(); + clipboard = new SchematicData(schem, revision).load(); if(schem.replaceColor()) replaceTeamColor(clipboard); @@ -119,10 +132,15 @@ public class FightSchematic extends StateDependent { } if(ArenaMode.AntiReplay.contains(Config.mode)) { + boolean changeRotation = false; + if (Config.ActiveWinconditions.contains(Winconditions.RANDOM_ROTATE)) { + changeRotation = new Random().nextBoolean(); + usedRotate = rotate ^ changeRotation; + } if(team.isBlue()) - GlobalRecorder.getInstance().blueSchem(schematic); + GlobalRecorder.getInstance().blueSchem(schematic, changeRotation); else - GlobalRecorder.getInstance().redSchem(schematic); + GlobalRecorder.getInstance().redSchem(schematic, changeRotation); } Bukkit.getScheduler().runTask(FightSystem.getPlugin(), this::paste); @@ -148,8 +166,8 @@ public class FightSchematic extends StateDependent { Config.PasteAligned && Config.BlueToRedX != 0 ? region.getSizeX()/2.0 - dims.getBlockX() : -dims.getBlockX()/2.0, Config.WaterDepth != 0 ? Config.WaterDepth - WorldeditWrapper.impl.getWaterDepth(clipboard) : 0, Config.PasteAligned && Config.BlueToRedZ != 0 ? region.getSizeZ()/2.0 - dims.getBlockZ() : -dims.getBlockZ()/2.0 - ).add(new Vector(rotate ? 1 : 0, 0, rotate ? 1 : 0)), - new AffineTransform().rotateY(rotate ? 180 : 0) + ).add(new Vector(usedRotate ? 1 : 0, 0, usedRotate ? 1 : 0)), + new AffineTransform().rotateY(usedRotate ? 180 : 0) ); FightSystem.getHullHider().initialize(team); team.getPlayers().forEach(fightPlayer -> fightPlayer.ifAI(ai -> ai.schematic(clipboard))); diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java index 0cb68f71..47f73649 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java @@ -412,7 +412,11 @@ public class FightTeam { } public void setSchem(SchematicNode schematic){ - this.schematic.setSchematic(schematic); + setSchem(schematic, -1); + } + + public void setSchem(SchematicNode schematic, int revision){ + this.schematic.setSchematic(schematic, revision); broadcast("SCHEMATIC_CHOSEN", Config.GameName, schematic.getName()); } @@ -458,6 +462,10 @@ public class FightTeam { return schematic.getId(); } + public void setSchematicChangeRotate(boolean rotate) { + schematic.setChangeRotate(rotate); + } + public Clipboard getClipboard() { return schematic.getClipboard(); } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/PrepareSchem.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/PrepareSchem.java index 29ccc434..f02beeed 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/PrepareSchem.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/PrepareSchem.java @@ -83,13 +83,8 @@ public class PrepareSchem implements Listener { return; } - if(schemExists(schem)) - return; - - SchematicNode old = schem; - schem = SchematicNode.createSchematicNode(schem.getOwner(), preparedName(schem), schem.getParent(), Config.SchematicType.checkType().toDB(), schem.getItem()); - schem.setReplaceColor(old.replaceColor()); - schem.setAllowReplay(old.allowReplay()); + schem.setSchemtype(Config.SchematicType.checkType()); + schem.setPrepared(true); try{ WorldeditWrapper.impl.saveSchem(schem, region, minY); @@ -119,20 +114,5 @@ public class PrepareSchem implements Listener { FightState.setFightState(FightState.PRE_SCHEM_SETUP); FightState.setFightState(FightState.POST_SCHEM_SETUP); } - - schemExists(SchematicNode.getSchematicNode(Config.PrepareSchemID)); - } - - private boolean schemExists(SchematicNode schem) { - if(SchematicNode.getSchematicNode(schem.getOwner(), preparedName(schem), schem.getParent()) != null) { - FightSystem.getMessage().broadcast("PREPARE_SCHEM_EXISTS"); - Bukkit.shutdown(); - return true; - } - return false; - } - - private String preparedName(SchematicNode schem) { - return schem.getName() + "-prepared"; } } diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java index 47efc09d..f4906f42 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java @@ -20,7 +20,6 @@ package de.steamwar.fightsystem.record; import com.sk89q.worldedit.extent.clipboard.Clipboard; -import de.steamwar.core.Core; import de.steamwar.core.TrickyTrialsWrapper; import de.steamwar.core.WorldEditWrapper; import de.steamwar.entity.REntity; @@ -144,6 +143,8 @@ public class PacketProcessor implements Listener { packetDecoder[0xb2] = this::teams; packetDecoder[0xb3] = () -> pasteEmbeddedSchem(Fight.getBlueTeam()); packetDecoder[0xb4] = () -> pasteEmbeddedSchem(Fight.getRedTeam()); + packetDecoder[0xb5] = () -> rotateSchem(Fight.getBlueTeam()); + packetDecoder[0xb6] = () -> rotateSchem(Fight.getRedTeam()); packetDecoder[0xc0] = this::scoreboardTitle; packetDecoder[0xc1] = this::scoreboardData; packetDecoder[0xc2] = this::bossBar; @@ -529,6 +530,14 @@ public class PacketProcessor implements Listener { execSync(() -> team.pasteSchem(schemId, clipboard)); } + private void rotateSchem(FightTeam team) throws IOException { + boolean changeRotate = source.readBoolean(); + + execSync(() -> { + team.setSchematicChangeRotate(changeRotate); + }); + } + private void teams() throws IOException { int blueId = source.readInt(); int redId = source.readInt(); diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/Recorder.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/Recorder.java index 73821e6f..d0e1439c 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/Recorder.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/Recorder.java @@ -61,9 +61,9 @@ public interface Recorder { default void enableTeam(FightTeam team){ if(FightState.Schem.contains(FightState.getFightState())){ if(team.isBlue()) - blueSchem(team.getSchematic()); + blueSchem(team.getSchematic(), false); else - redSchem(team.getSchematic()); + redSchem(team.getSchematic(), false); } if(FightState.AntiSpectate.contains(FightState.getFightState())){ @@ -123,6 +123,8 @@ public interface Recorder { * TeamIDPacket (0xb2) + int blueTeamId, redTeamId * BlueEmbeddedSchemPacket (0xb3) + int blueSchemId + gzipt NBT blob * RedEmbeddedSchemPacket (0xb4) + int redSchemId + gzipt NBT blob + * BlueSchemRotatePacket (0xb5) + boolean changeRotate + * RedSchemRotatePacket (0xb6) + boolean changeRotate * * DEPRECATED ScoreboardTitlePacket (0xc0) + String scoreboardTitle * DEPRECATED ScoreboardDataPacket (0xc1) + String key + int value @@ -259,14 +261,20 @@ public interface Recorder { write(0xb2, blueTeamId, redTeamId); } - default void blueSchem(int schemId) { + default void blueSchem(int schemId, boolean changeRotate) { + rotate(0xb5, changeRotate); schem(0xb3, 0xb0, schemId); } - default void redSchem(int schemId) { + default void redSchem(int schemId, boolean changeRotate) { + rotate(0xb6, changeRotate); schem(0xb4, 0xb1, schemId); } + default void rotate(int packetId, boolean changeRotate) { + write(packetId, changeRotate); + } + default void schem(int embedId, int noEmbedId, int schemId){ if(schemId == 0) { write(noEmbedId, schemId); @@ -275,7 +283,7 @@ public interface Recorder { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); try{ - copy(NodeData.get(SchematicNode.getSchematicNode(schemId)).schemData(), buffer); + copy(NodeData.getLatest(SchematicNode.getSchematicNode(schemId)).schemData(), buffer); }catch (EOFException e) { Bukkit.getLogger().log(Level.INFO, "EOFException ignored"); } catch (IOException e) { @@ -339,6 +347,8 @@ public interface Recorder { stream.writeShort((Short)o); else if(o instanceof Integer) stream.writeInt((Integer)o); + else if(o instanceof Long) + stream.writeLong((Long)o); else if(o instanceof Float) stream.writeFloat((Float)o); else if(o instanceof Double) diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/FightStatistics.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/FightStatistics.java index ae9a56ac..3d6c5cac 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/FightStatistics.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/FightStatistics.java @@ -33,6 +33,8 @@ import de.steamwar.fightsystem.states.OneShotStateDependent; import de.steamwar.fightsystem.winconditions.Wincondition; import de.steamwar.network.NetworkSender; import de.steamwar.network.packets.common.FightEndsPacket; +import de.steamwar.sql.EventFight; +import de.steamwar.sql.EventRelation; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SteamwarUser; import lombok.Getter; @@ -70,12 +72,21 @@ public class FightStatistics { } private void setEventResult() { - if (FightSystem.getLastWinner() == null) + if (FightSystem.getLastWinner() == null) { Config.EventKampf.setErgebnis(0); - else if (FightSystem.getLastWinner().isBlue()) + } else if (FightSystem.getLastWinner().isBlue()) { Config.EventKampf.setErgebnis(1); - else + } else { Config.EventKampf.setErgebnis(2); + } + + Config.EventKampf.getDependents().forEach(EventRelation::apply); + + Config.EventKampf.getGroup().ifPresent(group -> { + if (group.getLastFight().map(EventFight::getFightID).orElse(-1) == Config.EventKampf.getFightID() && !group.needsTieBreak()) { + group.getDependents().forEach(EventRelation::apply); + } + }); } private void disable() { diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Region.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Region.java index 60d37be8..2d881513 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Region.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/Region.java @@ -23,6 +23,7 @@ import de.steamwar.techhider.ProtocolUtils; import lombok.AllArgsConstructor; import lombok.Getter; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.Block; import java.util.function.ObjIntConsumer; @@ -77,6 +78,14 @@ public class Region { return ProtocolUtils.posToChunk(maxZ); } + public Location getMinLocation(World world) { + return new Location(world, minX, minY, minZ); + } + + public Location getMaxLocation(World world) { + return new Location(world, maxX, maxY, maxZ); + } + public boolean chunkOutside(int cX, int cZ) { return getMinChunkX() > cX || cX > getMaxChunkX() || getMinChunkZ() > cZ || cZ > getMaxChunkZ(); diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionTimeTechKO.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionTimeTechKO.java index f1177afa..789b130f 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionTimeTechKO.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionTimeTechKO.java @@ -20,6 +20,7 @@ package de.steamwar.fightsystem.winconditions; import de.steamwar.core.TrickyTrialsWrapper; +import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.countdown.Countdown; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; @@ -30,7 +31,6 @@ import de.steamwar.fightsystem.states.StateDependentTask; import de.steamwar.fightsystem.utils.Message; import de.steamwar.fightsystem.utils.SWSound; import org.bukkit.Location; -import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityExplodeEvent; @@ -41,8 +41,7 @@ import java.util.Map; public class WinconditionTimeTechKO extends Wincondition implements Listener { - private static final int TECH_KO_TIME_IN_S = 90; - private static final int TECH_KO_HALF_TIME = TECH_KO_TIME_IN_S/2; + private static final int TECH_KO_HALF_TIME = Config.TechKoTime/2; private final Map spawnLocations = new HashMap<>(); private final Map countdowns = new HashMap<>(); diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionTimedDamageTechKO.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionTimedDamageTechKO.java new file mode 100644 index 00000000..c561400c --- /dev/null +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/WinconditionTimedDamageTechKO.java @@ -0,0 +1,115 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.fightsystem.winconditions; + +import de.steamwar.core.TrickyTrialsWrapper; +import de.steamwar.fightsystem.Config; +import de.steamwar.fightsystem.countdown.Countdown; +import de.steamwar.fightsystem.fight.Fight; +import de.steamwar.fightsystem.fight.FightTeam; +import de.steamwar.fightsystem.states.FightState; +import de.steamwar.fightsystem.states.StateDependent; +import de.steamwar.fightsystem.states.StateDependentListener; +import de.steamwar.fightsystem.utils.Message; +import de.steamwar.fightsystem.utils.SWSound; +import org.bukkit.Location; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityExplodeEvent; + +import java.util.HashMap; +import java.util.Map; + +public class WinconditionTimedDamageTechKO extends Wincondition implements PrintableWincondition, Listener { + + private final Map countdowns = new HashMap<>(); + + public WinconditionTimedDamageTechKO() { + super("TechKO"); + + new StateDependentListener(Winconditions.TIMED_DAMAGE_TECH_KO, FightState.Running, this); + new StateDependent(Winconditions.TIMED_DAMAGE_TECH_KO, FightState.Running) { + @Override + public void enable() { + Fight.teams().forEach(team -> { + TechKOCountdown countdown = new TechKOCountdown(team, Config.TechKoTime); + countdowns.put(team, countdown); + countdown.enable(); + }); + } + + @Override + public void disable() { + countdowns.values().forEach(Countdown::disable); + countdowns.clear(); + } + }.register(); + } + + @Override + public Message getDisplay(FightTeam team) { + return new Message("BAR_SECONDS", team.getPrefix() + countdowns.get(team).getTimeLeft()); + } + + @EventHandler + public void onExplode(EntityExplodeEvent e) { + if (e.getEntityType() != TrickyTrialsWrapper.impl.getTntEntityType()) + return; + + Location location = e.getLocation(); + TechKOCountdown countdown = null; + FightTeam fightTeam = null; + for (FightTeam team : Fight.teams()) { + FightTeam current = Fight.getOpposite(team); + if (current.getExtendRegion().inRegion(location)) { + fightTeam = current; + countdown = countdowns.get(team); + break; + } + } + if (fightTeam == null) { + return; + } + + FightTeam finalFightTeam = fightTeam; + TechKOCountdown finalCountdown = countdown; + e.blockList().forEach(block -> { + if (block.isEmpty()) return; + if (finalFightTeam.getExtendRegion().inRegion(block)) { + finalCountdown.disable(); + finalCountdown.enable(); + } + }); + } + + private class TechKOCountdown extends Countdown { + private final FightTeam team; + + public TechKOCountdown(FightTeam team, int countdownTime) { + super(countdownTime, new Message("TECHKO_COUNTDOWN", team.getColoredName()), SWSound.BLOCK_NOTE_PLING, false); + this.team = team; + } + + @Override + public void countdownFinished() { + win(Fight.getOpposite(team), "WIN_TECHKO", team.getColoredName()); + } + } +} diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/Winconditions.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/Winconditions.java index 2aaecae6..4ba66cf3 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/Winconditions.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/winconditions/Winconditions.java @@ -31,6 +31,7 @@ public enum Winconditions { POINTS, POINTS_AIRSHIP, + TIMED_DAMAGE_TECH_KO, TIME_TECH_KO, WATER_TECH_KO, PUMPKIN_TECH_KO, @@ -41,4 +42,5 @@ public enum Winconditions { PERSISTENT_DAMAGE, TNT_DISTRIBUTION, NO_GRAVITY, + RANDOM_ROTATE, } diff --git a/LegacyBauSystem/src/de/steamwar/bausystem/BauSystem.java b/LegacyBauSystem/src/de/steamwar/bausystem/BauSystem.java index 56af8fd7..6712e45a 100644 --- a/LegacyBauSystem/src/de/steamwar/bausystem/BauSystem.java +++ b/LegacyBauSystem/src/de/steamwar/bausystem/BauSystem.java @@ -53,6 +53,7 @@ public class BauSystem extends JavaPlugin implements Listener { @Override public void onEnable() { + Core.setServerName("Dev"); plugin = this; Mapper.init(); diff --git a/LegacyBauSystem/src/de/steamwar/bausystem/world/ClipboardListener.java b/LegacyBauSystem/src/de/steamwar/bausystem/world/ClipboardListener.java index 6ab68478..0ff91d44 100644 --- a/LegacyBauSystem/src/de/steamwar/bausystem/world/ClipboardListener.java +++ b/LegacyBauSystem/src/de/steamwar/bausystem/world/ClipboardListener.java @@ -53,7 +53,7 @@ public class ClipboardListener implements Listener { } try { - new SchematicData(schematic).saveFromPlayer(e.getPlayer()); + SchematicData.saveFromPlayer(e.getPlayer(), schematic); } catch (Exception ex) { if (newSchem) { schematic.delete(); diff --git a/LobbySystem/build.gradle.kts b/LobbySystem/build.gradle.kts index aa511a0c..8662545c 100644 --- a/LobbySystem/build.gradle.kts +++ b/LobbySystem/build.gradle.kts @@ -34,3 +34,12 @@ dependencies { compileOnly(libs.nms20) compileOnly(libs.worldedit15) } + +tasks.register("DevLobby20") { + group = "run" + description = "Run a 1.20 Dev Lobby" + dependsOn(":SpigotCore:shadowJar") + dependsOn(":LobbySystem:jar") + template = "Lobby20" + worldName = "Lobby" +} diff --git a/LobbySystem/src/de/steamwar/lobby/LobbySystem.java b/LobbySystem/src/de/steamwar/lobby/LobbySystem.java index 4d198d4b..900d0941 100644 --- a/LobbySystem/src/de/steamwar/lobby/LobbySystem.java +++ b/LobbySystem/src/de/steamwar/lobby/LobbySystem.java @@ -19,6 +19,7 @@ package de.steamwar.lobby; +import de.steamwar.core.Core; import de.steamwar.entity.REntityServer; import de.steamwar.lobby.command.FlyCommand; import de.steamwar.lobby.command.HologramCommand; @@ -52,6 +53,7 @@ public class LobbySystem extends JavaPlugin { message = new Message("de.steamwar.lobby.LobbySystem", getClassLoader()); entityServer = new REntityServer(); debugEntityServer = new REntityServer(); + Core.setServerName("Lobby"); CustomMap.init(); diff --git a/TutorialSystem/src/de/steamwar/tutorial/listener/BasicListener.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/None.java similarity index 67% rename from TutorialSystem/src/de/steamwar/tutorial/listener/BasicListener.java rename to LobbySystem/src/de/steamwar/lobby/particle/elements/None.java index 4ef5f8c7..42bb013d 100644 --- a/TutorialSystem/src/de/steamwar/tutorial/listener/BasicListener.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/elements/None.java @@ -1,7 +1,7 @@ /* * This file is a part of the SteamWar software. * - * Copyright (C) 2022 SteamWar.de-Serverteam + * Copyright (C) 2020 SteamWar.de-Serverteam * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -17,15 +17,14 @@ * along with this program. If not, see . */ -package de.steamwar.tutorial.listener; +package de.steamwar.lobby.particle.elements; -import de.steamwar.tutorial.TutorialSystem; -import org.bukkit.Bukkit; -import org.bukkit.event.Listener; +import de.steamwar.lobby.particle.ParticleElement; +import de.steamwar.lobby.particle.ParticleTickData; -public abstract class BasicListener implements Listener { +public class None implements ParticleElement { - public BasicListener() { - Bukkit.getPluginManager().registerEvents(this, TutorialSystem.getPlugin()); + @Override + public void tick(ParticleTickData particleTickData) { } } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/particles/custom/CustomEasterParticle.java b/LobbySystem/src/de/steamwar/lobby/particle/particles/custom/CustomEasterParticle.java index 3c8d43c5..da207081 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/particles/custom/CustomEasterParticle.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/particles/custom/CustomEasterParticle.java @@ -78,14 +78,17 @@ public enum CustomEasterParticle implements ParticleEnum { // TODO: Implement TheReaper22122! // TODO: Implement Bosslar! // TODO: Implement ATOM65! - PLAYER_3266(new ParticleData(Material.CHORUS_FRUIT, "PARTICLE_PLAYER_3266", ParticleRequirement.easterEventSpecificPlayer(3266), - new Always(new NonFlying(new Cloud(new LocationMutator(new TrippleCircle( - new DustParticle(Particle.REDSTONE, new Gradient(Color.CYAN, Color.BLUE, Color.MAGENTA.darker(), Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN)), - new DustParticle(Particle.REDSTONE, new Gradient(Color.CYAN, Color.BLUE, Color.MAGENTA.darker(), Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN)), - new DustParticle(Particle.REDSTONE, new Gradient(Color.CYAN, Color.BLUE, Color.MAGENTA.darker(), Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN)), - 0.7, - 0.5), location -> location.add(0, 0.6, 0) - ))))) + PLAYER_3266(new ParticleData(Material.BREAD, "PARTICLE_PLAYER_3266", ParticleRequirement.easterEventSpecificPlayer(3266), + new Group( + new Always(new Sneaking(new LocationMutator(new None(), location -> location))), + new Always(new NonFlying(new LocationMutator(new TrippleCircle( + new DustParticle(Particle.REDSTONE, new Gradient(Color.CYAN, Color.BLUE, Color.MAGENTA.darker(), Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN)), + new DustParticle(Particle.REDSTONE, new Gradient(Color.CYAN, Color.BLUE, Color.MAGENTA.darker(), Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN)), + new DustParticle(Particle.REDSTONE, new Gradient(Color.CYAN, Color.BLUE, Color.MAGENTA.darker(), Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN)), + 0.7, + 0.5), location -> location.add(0, 0.6, 0) + )))) + ) ), // TODO: Implement Gehfxhler! // TODO: Implement SchwarzerFuerst diff --git a/MissileWars/src/de/steamwar/misslewars/Config.java b/MissileWars/src/de/steamwar/misslewars/Config.java index b50ec741..1838126c 100644 --- a/MissileWars/src/de/steamwar/misslewars/Config.java +++ b/MissileWars/src/de/steamwar/misslewars/Config.java @@ -158,7 +158,7 @@ public class Config { EventKampf = null; TeamBlueName = "Blau"; TeamRedName = "Rot"; - TeamBlueColor = "§3"; + TeamBlueColor = "§9"; TeamRedColor = "§c"; EventTeamBlueID = 0; EventTeamRedID = 0; diff --git a/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems15.java b/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems15.java index 0d853c16..ee3f2827 100644 --- a/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems15.java +++ b/SchematicSystem/SchematicSystem_15/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems15.java @@ -76,7 +76,13 @@ public class AutoCheckerItems15 implements AutoCheckerItems { Material.DIAMOND_HORSE_ARMOR, Material.IRON_HORSE_ARMOR, Material.GOLDEN_HORSE_ARMOR, - Material.HONEY_BOTTLE); + Material.LEATHER_HORSE_ARMOR, + Material.HONEY_BOTTLE, + Material.LILAC, + Material.ROSE_BUSH, + Material.PEONY, + Material.TALL_GRASS, + Material.LARGE_FERN); @Override public Set getInventoryMaterials() { diff --git a/SchematicSystem/SchematicSystem_19/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems19.java b/SchematicSystem/SchematicSystem_19/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems19.java index 0c004cfe..7aaa26b9 100644 --- a/SchematicSystem/SchematicSystem_19/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems19.java +++ b/SchematicSystem/SchematicSystem_19/src/de/steamwar/schematicsystem/autocheck/AutoCheckerItems19.java @@ -43,12 +43,19 @@ public class AutoCheckerItems19 extends AutoCheckerItems15 { Material.LILY_OF_THE_VALLEY, Material.WITHER_ROSE, Material.SUNFLOWER, + Material.LILAC, + Material.ROSE_BUSH, + Material.PEONY, + Material.TALL_GRASS, + Material.LARGE_FERN, + Material.TORCHFLOWER, // 16-stackable Items Material.HONEY_BOTTLE, // Non-stackable items Material.DIAMOND_HORSE_ARMOR, Material.IRON_HORSE_ARMOR, Material.GOLDEN_HORSE_ARMOR, + Material.LEATHER_HORSE_ARMOR, // Disks Material.MUSIC_DISC_11, Material.MUSIC_DISC_13, diff --git a/SchematicSystem/SchematicSystem_Core/src/SchematicSystem.properties b/SchematicSystem/SchematicSystem_Core/src/SchematicSystem.properties index 29cb8829..5b8aee8f 100644 --- a/SchematicSystem/SchematicSystem_Core/src/SchematicSystem.properties +++ b/SchematicSystem/SchematicSystem_Core/src/SchematicSystem.properties @@ -26,6 +26,7 @@ CLICK_DRAG_ITEM=§7Click or drag item here CURRENT=§7Current: {0} CONFIRM=§aConfirm CANCEL=§cCancel +BLANK={0} UTIL_NAME_REQUIRED=§cFolder name required UTIL_NAME_TOO_LONG=§cSchematic name too long @@ -49,6 +50,7 @@ UTIL_LIST_NEXT=Page ({0}/{1}) »» UTIL_LIST_NEXT_HOVER=§eNext page UTIL_INFO_SCHEM=§7Schematic: §e{0} UTIL_INFO_NAME=§7Name: §e{0} +UTIL_INFO_REVISIONS=§7Revisions: §e{0} UTIL_INFO_OWNER=§7Owner: §e{0} UTIL_INFO_PARENT=§7Directory: §e{0} UTIL_INFO_UPDATED=§7Last update: §e{0} @@ -70,6 +72,7 @@ UTIL_INFO_ACTION_TYPE_HOVER=§eChange schematic type UTIL_INFO_ACTION_ADD_HOVER=§eAdd member UTIL_INFO_ACTION_REMOVE_HOVER=§eRemove {0} UTIL_INFO_ACTION_MOVE_HOVER=§eMove schematic +UTIL_INFO_ACTION_REVISIONS_HOVER=§eList revisions UTIL_INFO_ACTION_RENAME_HOVER=§eRename schematic UTIL_INFO_ACTION_DELETE=(Delete) UTIL_INFO_ACTION_DELETE_HOVER=§eDelete schematic @@ -79,6 +82,7 @@ UTIL_LOAD_DIR=§cYou cannot load folders UTIL_LOAD_DONE=§7Schematic §e{0} loaded UTIL_LOAD_NO_DATA=§cNo data could be found in the Schematic UTIL_LOAD_ERROR=§cThe schematic could not be loaded +UTIL_LOAD_ILLEGAL_REVISION=§cThe schematic doesn't have {0} revisions UTIL_DOWNLOAD_PUNISHED=§cYou are not allowed to download schematics: §f§l{0} UTIL_DOWNLOAD_NOT_OWN=§cYou may download only your own schematics UTIL_DOWNLOAD_LINK=Your download link: @@ -224,6 +228,9 @@ GUI_DELETE_MEMBER_TITLE=Remove {0} GUI_DELETE_MEMBER_DONE=Access to Schematic §e{0} §7removed GUI_DELETE_MEMBERS_TITLE=Remove members GUI_CHANGE_ITEM=Change item +GUI_LOAD_LATEST=§eLeft §7Click → §eLoad latest +GUI_LOAD_REVISION=§eRight §7Click → §eList Revisions +GUI_LOAD_REVISION_TITLE=Select Revision AUTO_CHECK_RESULT_NOT_LOAD=The schematic could not be loaded AUTO_CHECK_RESULT_TOO_WIDE=The schematic is too wide ({0} > {1}) @@ -263,4 +270,8 @@ AUTO_CHECKER_RESULT_RECORD=§7Record: §c[{0}, {1}, {2}] AUTO_CHECKER_RESULT_TOO_MANY_DISPENSER_ITEMS=§7Dispenser: §c[{0}, {1}, {2}]§7, §c{3} §7items, Max: §e{4} AUTO_CHECKER_RESULT_FORBIDDEN_ITEM_NBT=§7Forbidden Item NBT: [{0}, {1}, {2}] -> §c{3} AUTO_CHECKER_RESULT_TELEPORT_HERE=§7Teleport to block -AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cThe deadline has expired: {0} \ No newline at end of file +AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cThe deadline has expired: {0} + +REVISIONS_TITLE=§7Revisions: +REVISIONS_REVISION_NUMBER=§7#{0}: §e{1} +REVISIONS_EMPTY=§cNo Revisions \ No newline at end of file diff --git a/SchematicSystem/SchematicSystem_Core/src/SchematicSystem_de.properties b/SchematicSystem/SchematicSystem_Core/src/SchematicSystem_de.properties index 5e85d346..20205eee 100644 --- a/SchematicSystem/SchematicSystem_Core/src/SchematicSystem_de.properties +++ b/SchematicSystem/SchematicSystem_Core/src/SchematicSystem_de.properties @@ -90,6 +90,9 @@ UTIL_SUBMIT_DIRECT=§eDirekt einsenden UTIL_SUBMIT_DIRECT_DONE=§aDie Schematic wird zeitnah überprüft UTIL_SUBMIT_EXTEND=§eSchematic ausfahren UTIL_SUBMIT_EXTEND_DONE=§aDer Vorbereitungsserver wird gestartet +UTIL_INFO_ACTION_REVISIONS_HOVER=§eVersionen anzeigen +UTIL_LOAD_ILLEGAL_REVISION=§cDie schematic hat nicht {0} Versionen +UTIL_INFO_REVISIONS=§7Versionen: §e{0} COMMAND_INVALID_NODE=§cDie Schematic konnte nicht gefunden werden COMMAND_NOT_OWN=§cDas darfst du nur bei deinen eigenen Schematics machen @@ -204,6 +207,9 @@ GUI_DELETE_MEMBER_TITLE={0} entfernen GUI_DELETE_MEMBER_DONE=Zugriff zu Schematic §e{0} §7entfernt GUI_DELETE_MEMBERS_TITLE=Mitglieder entfernen GUI_CHANGE_ITEM=Item ändern +GUI_LOAD_LATEST=§eLinks §7Klick → §eLetzte Laden +GUI_LOAD_REVISION=§eRechts §7Klick → §eVersionen anzeigen +GUI_LOAD_REVISION_TITLE=Version Laden AUTO_CHECK_RESULT_NOT_LOAD=Die Schematic konnte nicht geladen werden AUTO_CHECK_RESULT_TOO_WIDE=Die Schematic ist zu breit ({0} > {1}) @@ -242,4 +248,7 @@ AUTO_CHECKER_RESULT_RECORD=§7Schallplatte: §c[{0}, {1}, {2}] AUTO_CHECKER_RESULT_TOO_MANY_DISPENSER_ITEMS=§7Dispenser: §c[{0}, {1}, {2}]§7, §c{3} §7gegenstände, Max: §e{4} AUTO_CHECKER_RESULT_FORBIDDEN_ITEM_NBT=§7Verbotene NBT-Daten: [{0}, {1}, {2}] -> §c{3} AUTO_CHECKER_RESULT_TELEPORT_HERE=§7Zum block teleportieren -AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cDer einsendeschluss ist bereits vorbei: {0} \ No newline at end of file +AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cDer einsendeschluss ist bereits vorbei: {0} + +REVISIONS_TITLE=§7Versionen: +REVISIONS_EMPTY=§cKeine Versionen \ No newline at end of file diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/DownloadCommand.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/DownloadCommand.java index 31c29bd0..3e2f009d 100644 --- a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/DownloadCommand.java +++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/DownloadCommand.java @@ -43,7 +43,7 @@ public class DownloadCommand extends SWCommand { } try { - new SchematicData(copyNode).saveFromPlayer(player); + SchematicData.saveFromPlayer(player, copyNode); } catch (IOException e) { SchematicSystem.MESSAGE.send("DOWNLOAD_ERROR", player); if (newSchem) { diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/GUI.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/GUI.java index 9722aece..2c1b6f4f 100644 --- a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/GUI.java +++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/GUI.java @@ -21,12 +21,12 @@ package de.steamwar.schematicsystem.commands.schematiccommand; import com.sk89q.worldedit.extent.clipboard.Clipboard; import de.steamwar.core.Core; +import de.steamwar.data.CMDs; import de.steamwar.inventory.*; import de.steamwar.schematicsystem.CheckSchemType; import de.steamwar.schematicsystem.SafeSchematicNode; import de.steamwar.schematicsystem.SchematicSystem; import de.steamwar.schematicsystem.autocheck.AutoChecker; -import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils; import de.steamwar.sql.*; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -38,7 +38,7 @@ import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; -import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.*; +import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.getUser; public class GUI { private GUI() {} @@ -95,15 +95,34 @@ public class GUI { SteamwarUser user = getUser(player); SWInventory inv = new SWInventory(player, 9 * 2, node.generateBreadcrumbs()); if(!node.isDir()) { - inv.setItem(0, SWItem.getMaterial("WOOD_AXE"), SchematicSystem.MESSAGE.parse("GUI_INFO_LOAD", player), click -> { - player.closeInventory(); - SchematicCommandUtils.loadSchem(player, node); + inv.setItem(0, SWItem.getMaterial("WOOD_AXE"), SchematicSystem.MESSAGE.parse("GUI_INFO_LOAD", player), Arrays.asList( + SchematicSystem.MESSAGE.parse("GUI_LOAD_LATEST", player), + SchematicSystem.MESSAGE.parse("GUI_LOAD_REVISION", player) + ), false, click -> { + if (click.isLeftClick()) { + player.closeInventory(); + SchematicCommandUtils.loadSchem(player, node, -1); + } else if (click.isRightClick()) { + List> entries = new ArrayList<>(); + List datas = NodeData.get(node); + for (int i = 0; i < datas.size(); i++) { + entries.add(new SWListInv.SWListEntry<>(new SWItem(SWItem.getMaterial(node.getItem()), "§e" + SchematicSystem.MESSAGE.parse("BLANK", player, datas.get(i).getCreatedAt())), i)); + } + + SWListInv listInv = new SWListInv<>(player, SchematicSystem.MESSAGE.parse("GUI_LOAD_REVISION_TITLE", player, node.generateBreadcrumbs()), entries, (clickType, revision) -> { + if(revision == null) return; + player.closeInventory(); + SchematicCommandUtils.loadSchem(player, node, revision); + }); + listInv.setCallback(-999, click2 -> player.closeInventory()); + listInv.open(); + } }); } - inv.setItem(9, SWItem.getMaterial("LEASH"), SchematicSystem.MESSAGE.parse("GUI_INFO_BACK", player), clickType -> { + inv.setItem(9, new SWItem(SWItem.getMaterial("LEASH"), SchematicSystem.MESSAGE.parse("GUI_INFO_BACK", player), clickType -> { back.reOpen(); - }); + }).setCustomModelData(CMDs.Schematic.BACK)); if(node.getOwner() == user.getId()){ if(!node.isDir() && node.getSchemtype().writeable()){ diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java index 5f27d8b7..66d22817 100644 --- a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java +++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/SchematicCommandUtils.java @@ -223,6 +223,11 @@ public class SchematicCommandUtils { } else { SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_PARENT", player, node.getParent() == null ? "/" : node.getParentNode().generateBreadcrumbs()); } + player.spigot().sendMessage( + new ComponentBuilder(SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_REVISIONS", false, player, NodeData.getRevisions(node))) + .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[] {SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_REVISIONS_HOVER", false, player)})) + .event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem revisions " + node.generateBreadcrumbs())) + .create()); SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_UPDATED", player, node.getLastUpdate()); if (!node.isDir()) { if(node.getOwner() == user.getId()) { @@ -357,7 +362,7 @@ public class SchematicCommandUtils { PUBLIC_TOGGLED.remove(player); } - public static void loadSchem(Player player, SchematicNode node) { + public static void loadSchem(Player player, SchematicNode node, int revision) { SteamwarUser user = getUser(player); if(BauServerInfo.isBauServer() && BauServerInfo.getOwnerId() != user.getId() && (Punishment.isPunished(user, Punishment.PunishmentType.NoSchemSharing, punishment -> @@ -372,11 +377,13 @@ public class SchematicCommandUtils { } try { - new SchematicData(node).loadToPlayer(player); + new SchematicData(node, revision).loadToPlayer(player); SchematicSystem.MESSAGE.send("UTIL_LOAD_DONE", player, node.getName()); Bukkit.getLogger().log(Level.INFO, "{0} has loaded Schematic {1} {2}", new Object[]{player.getName(), node.getId(), node.getName()}); } catch (NoClipboardException e) { SchematicSystem.MESSAGE.send("UTIL_LOAD_NO_DATA", player); + } catch (IllegalArgumentException e) { + SchematicSystem.MESSAGE.send("UTIL_LOAD_ILLEGAL_REVISION", player, revision); } catch (Exception e) { SchematicSystem.MESSAGE.send("UTIL_LOAD_ERROR", player); Bukkit.getLogger().log(Level.INFO, e.getMessage(), e); @@ -421,6 +428,8 @@ public class SchematicCommandUtils { return; } + node.setPrepared(false); + if (type.writeable()) { node.setSchemtype(type); SchematicSystem.MESSAGE.send("UTIL_TYPE_DONE", player); @@ -483,7 +492,7 @@ public class SchematicCommandUtils { node.setAllowReplay(!node.allowReplay()); submitSchemGUI(player, node, type); }); - inv.setItem(1, SWItem.getMaterial(node.replaceColor() ? "PINK_WOOL" : "LIGHT_GRAY_WOOL"), SchematicSystem.MESSAGE.parse(node.allowReplay()?"UTIL_SUBMIT_COLOR_ON":"UTIL_SUBMIT_COLOR_OFF", player), click -> { + inv.setItem(1, SWItem.getMaterial(node.replaceColor() ? "PINK_WOOL" : "LIGHT_GRAY_WOOL"), SchematicSystem.MESSAGE.parse(node.replaceColor()?"UTIL_SUBMIT_COLOR_ON":"UTIL_SUBMIT_COLOR_OFF", player), click -> { node.setReplaceColor(!node.replaceColor()); submitSchemGUI(player, node, type); }); diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ModifyPart.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ModifyPart.java index cee2cbc3..bc1e89c6 100644 --- a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ModifyPart.java +++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ModifyPart.java @@ -46,6 +46,7 @@ public class ModifyPart extends SWCommand { } @Register("changetype") + @Register("submit") public void changeType(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node) { TextComponent base = new TextComponent(); @@ -74,11 +75,13 @@ public class ModifyPart extends SWCommand { } @Register("changetype") + @Register("submit") public void changeType(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node, SchematicType type) { changeType(player, node, type, null); } @Register("changetype") + @Register("submit") public void changeType(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node, SchematicType type, SchematicCommand.Extend extend) { SchematicCommandUtils.changeType(player, node, type, extend); } diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/SavePart.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/SavePart.java index 31695f73..3ae0dd6c 100644 --- a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/SavePart.java +++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/SavePart.java @@ -49,11 +49,11 @@ public class SavePart extends SWCommand { SchematicSelector selector = new SchematicSelector(player, SchematicSelector.selectSchematicNode(), schematicNode -> { if(schematicNode == null || schematicNode.isDir()) { SWAnvilInv anvilInv = new SWAnvilInv(player, SchematicSystem.MESSAGE.parse("COMMAND_ENTER_NAME", player)); - anvilInv.setCallback(s -> saveSchem(player, schematicNode==null?s:(schematicNode.generateBreadcrumbs() + s), true)); + anvilInv.setCallback(s -> saveSchem(player, schematicNode==null?s:(schematicNode.generateBreadcrumbs() + s))); anvilInv.setItem(Material.CAULDRON); anvilInv.open(); } else { - saveSchem(player, schematicNode.generateBreadcrumbs(), true); + saveSchem(player, schematicNode.generateBreadcrumbs()); } }); selector.setSingleDirOpen(false); @@ -62,7 +62,7 @@ public class SavePart extends SWCommand { @Register("save") @Register("s") - public void saveSchem(Player player, @AbstractSWCommand.Mapper("stringMapper") String name, @AbstractSWCommand.StaticValue(value = {"", "-f"}, allowISE=true) @AbstractSWCommand.OptionalValue("") boolean overwrite) { + public void saveSchem(Player player, @AbstractSWCommand.Mapper("stringMapper") String name) { SteamwarUser user = getUser(player); if(BauServerInfo.isBauServer() && BauServerInfo.getOwnerId() != user.getId() && (Punishment.isPunished(user, Punishment.PunishmentType.NoSchemReceiving, punishment -> @@ -88,9 +88,6 @@ public class SavePart extends SWCommand { } else if (!node.getSchemtype().writeable() || node.getOwner() != user.getId()) { SchematicSystem.MESSAGE.send("COMMAND_SAVE_NO_OVERWRITE", player); return; - } else if(!overwrite) { - SchematicSystem.MESSAGE.send("COMMAND_SAVE_OVERWRITE_CONFIRM", player, SchematicSystem.MESSAGE.parse("COMMAND_SAVE_OVERWRITE_CONFIRM_HOVER", player), new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem s " + name + " -f"), node.generateBreadcrumbs()); - return; } } @@ -101,7 +98,7 @@ public class SavePart extends SWCommand { } try { - new SchematicData(node).saveFromPlayer(player); + SchematicData.saveFromPlayer(player, node); } catch (NoClipboardException e) { SchematicSystem.MESSAGE.send("COMMAND_SAVE_CLIPBOARD_EMPTY", player); if (newSchem) diff --git a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ViewPart.java b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ViewPart.java index 60146d4e..a22c1813 100644 --- a/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ViewPart.java +++ b/SchematicSystem/SchematicSystem_Core/src/de/steamwar/schematicsystem/commands/schematiccommand/parts/ViewPart.java @@ -21,13 +21,23 @@ package de.steamwar.schematicsystem.commands.schematiccommand.parts; import de.steamwar.command.AbstractSWCommand; import de.steamwar.command.SWCommand; +import de.steamwar.schematicsystem.SchematicSystem; import de.steamwar.schematicsystem.commands.schematiccommand.GUI; import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils; import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand; +import de.steamwar.sql.NodeData; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SteamwarUser; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.entity.Player; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.List; + import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.*; @AbstractSWCommand.PartOf(SchematicCommand.class) @@ -69,6 +79,25 @@ public class ViewPart extends SWCommand { printSchemInfo(player, node); } + @Register("revisions") + public void revisions(Player player, @Validator("isSchemValidator") SchematicNode node) { + List revisions = NodeData.get(node); + if(revisions.isEmpty()) { + SchematicSystem.MESSAGE.send("REVISIONS_EMPTY", player); + return; + } + + SchematicSystem.MESSAGE.send("REVISIONS_TITLE", player); + for (int j = Math.max(0, revisions.size() - 10); j < revisions.size(); j++) { + player.spigot().sendMessage( + new ComponentBuilder(SchematicSystem.MESSAGE.parseToComponent("REVISIONS_REVISION_NUMBER", false, player, j + 1, revisions.get(j).getCreatedAt())) + .event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem load " + (node.getOwner() == 0 ? "public " : "") + node.generateBreadcrumbs() + " " + (j + 1))) + .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[]{SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_LOAD_HOVER", false, player)})) + .create() + ); + } + } + @Register(value = "page", noTabComplete = true) public void pageCommand(Player player, int page) { cachedSchemList(player, page); @@ -76,14 +105,14 @@ public class ViewPart extends SWCommand { @Register({"l", "public"}) @Register({"load", "public"}) - public void loadSchemPublic(Player player, @Validator("isSchemValidator") @Mapper("publicMapper") SchematicNode node) { - loadSchem(player, node); + public void loadSchemPublic(Player player, @Validator("isSchemValidator") @Mapper("publicMapper") SchematicNode node, @OptionalValue("-1") int revision) { + loadSchem(player, node, revision); } @Register("l") @Register("load") - public void loadSchem(Player player, @Validator("isSchemValidator") SchematicNode node) { - SchematicCommandUtils.loadSchem(player, node); + public void loadSchem(Player player, @Validator("isSchemValidator") SchematicNode node, @OptionalValue("-1") int revision) { + SchematicCommandUtils.loadSchem(player, node, revision); } @Register("gui") @@ -92,7 +121,7 @@ public class ViewPart extends SWCommand { } @Register("download") - public void download(Player player, @Validator("isOwnerSchematicValidator") SchematicNode node) { + public void download(Player player, @Validator("isSchemValidator") SchematicNode node) { SchematicCommandUtils.download(player, node); } } diff --git a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java index 3251e5bc..b682dad3 100644 --- a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java +++ b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java @@ -565,17 +565,17 @@ public class WorldEditWrapper14 implements WorldEditWrapper { for (Map tileEntity : tileEntityTags) { int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue(); final BlockVector3 pt = BlockVector3.at(pos[0], pos[1], pos[2]); - Map values = Maps.newHashMap(tileEntity); + Map values = Maps.newHashMap(v3Mode ? requireTag(tileEntity, "Data", CompoundTag.class).getValue() : tileEntity); if(faweSchem){ values.put("x", new IntTag(pt.getBlockX() - offsetX)); values.put("y", new IntTag(pt.getBlockY() - offsetY)); values.put("z", new IntTag(pt.getBlockZ() - offsetZ)); }else{ - values.put("x", new IntTag(pt.getBlockX())); - values.put("y", new IntTag(pt.getBlockY())); - values.put("z", new IntTag(pt.getBlockZ())); + values.putIfAbsent("x", new IntTag(pt.getBlockX())); + values.putIfAbsent("y", new IntTag(pt.getBlockY())); + values.putIfAbsent("z", new IntTag(pt.getBlockZ())); } - values.put("id", values.get("Id")); + values.putIfAbsent("id", values.get("Id")); values.remove("Id"); values.remove("Pos"); if (fixer != null) { diff --git a/SpigotCore/SpigotCore_20/build.gradle.kts b/SpigotCore/SpigotCore_20/build.gradle.kts index 3e894ccc..79f667e0 100644 --- a/SpigotCore/SpigotCore_20/build.gradle.kts +++ b/SpigotCore/SpigotCore_20/build.gradle.kts @@ -26,5 +26,6 @@ dependencies { compileOnly(libs.spigotapi) + compileOnly(libs.fawe18) compileOnly(libs.nms20) } diff --git a/SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRendererWrapper20.java b/SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRendererWrapper20.java new file mode 100644 index 00000000..36ded8ef --- /dev/null +++ b/SpigotCore/SpigotCore_20/src/de/steamwar/core/WorldEditRendererWrapper20.java @@ -0,0 +1,119 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.core; + +import de.steamwar.entity.CWireframe; +import de.steamwar.entity.REntityServer; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import java.util.HashMap; +import java.util.Map; + +public class WorldEditRendererWrapper20 implements WorldEditRendererWrapper { + + private static final class BoxPair { + private CWireframe regionBox; + private CWireframe clipboardBox; + + public CWireframe get(boolean clipboard) { + if (clipboard) { + return clipboardBox; + } else { + return regionBox; + } + } + + public void set(boolean clipboard, CWireframe box) { + if (clipboard) { + this.clipboardBox = box; + } else { + this.regionBox = box; + } + } + + public void die() { + if (clipboardBox != null) { + clipboardBox.die(); + } + if (regionBox != null) { + regionBox.die(); + } + } + } + + private static final Map servers = new HashMap<>(); + private static final Map boxes = new HashMap<>(); + + @Override + public void draw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2) { + REntityServer server = servers.computeIfAbsent(player, __ -> { + REntityServer entityServer = new REntityServer(); + entityServer.addPlayer(player); + return entityServer; + }); + + WorldEditRendererCUIEditor.Type type = clipboard ? WorldEditRendererCUIEditor.Type.CLIPBOARD : WorldEditRendererCUIEditor.Type.SELECTION; + float width = type.getWidth(player).value; + Material material = type.getMaterial(player); + if (material == Material.BARRIER) { + hide(player, clipboard, true); + return; + } + BlockData block = material.createBlockData(); + + BoxPair boxPair = boxes.computeIfAbsent(player, __ -> new BoxPair()); + CWireframe box = boxPair.get(clipboard); + if (box == null) { + box = new CWireframe(server); + boxPair.set(clipboard, box); + } + box.setPos1(null).setPos2(null); + box.setPos1(pos1.toLocation(player.getWorld())); + box.setPos2(pos2.toLocation(player.getWorld())); + box.setWidth(width); + box.setBlock(block); + } + + @Override + public void tick(Player player) { + REntityServer server = servers.get(player); + if (server != null) server.tick(); + } + + @Override + public void hide(Player player, boolean clipboard, boolean hide) { + BoxPair boxPair = boxes.get(player); + if (boxPair == null) return; + CWireframe box = boxPair.get(clipboard); + if (box == null) return; + box.hide(hide); + } + + @Override + public void remove(Player player) { + BoxPair boxPair = boxes.remove(player); + if (boxPair != null) boxPair.die(); + REntityServer server = servers.remove(player); + if (server != null) server.close(); + } +} diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/BountifulWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/BountifulWrapper21.java index e01a06fc..be404e30 100644 --- a/SpigotCore/SpigotCore_21/src/de/steamwar/core/BountifulWrapper21.java +++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/BountifulWrapper21.java @@ -21,7 +21,7 @@ package de.steamwar.core; import de.steamwar.Reflection; import net.minecraft.world.entity.PositionMoveRotation; -import net.minecraft.world.phys.Vec3D; +import net.minecraft.world.phys.Vec3; public class BountifulWrapper21 extends BountifulWrapper9 { @@ -33,7 +33,7 @@ public class BountifulWrapper21 extends BountifulWrapper9 { return (packet, x, y, z, pitch, yaw) -> { PositionMoveRotation pos = field.get(packet); - field.set(packet, new PositionMoveRotation(new Vec3D(x, y, z), pos.b(), yaw, pitch)); + field.set(packet, new PositionMoveRotation(new Vec3(x, y, z), pos.deltaMovement(), yaw, pitch)); }; } catch (IllegalArgumentException e) { return super.getPositionSetter(packetClass, fieldOffset); diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChatWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChatWrapper21.java index 760ba393..64757bbe 100644 --- a/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChatWrapper21.java +++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChatWrapper21.java @@ -19,26 +19,26 @@ package de.steamwar.core; -import net.minecraft.network.chat.IChatMutableComponent; -import net.minecraft.network.chat.contents.LiteralContents; -import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata; -import net.minecraft.network.syncher.DataWatcher; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.contents.PlainTextContents; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.syncher.SynchedEntityData; import java.util.ArrayList; public class ChatWrapper21 implements ChatWrapper { @Override public Object stringToChatComponent(String text) { - return IChatMutableComponent.a(LiteralContents.a(text)); + return MutableComponent.create(PlainTextContents.create(text)); } @Override public Object getDataWatcherPacket(int entityId, Object... dataWatcherKeyValues) { - ArrayList> nativeWatchers = new ArrayList<>(1); + ArrayList> nativeWatchers = new ArrayList<>(1); for(int i = 0; i < dataWatcherKeyValues.length; i+=2) { - nativeWatchers.add(((DataWatcher.Item) BountifulWrapper.impl.getDataWatcherItem(dataWatcherKeyValues[i], dataWatcherKeyValues[i+1])).e()); + nativeWatchers.add(((SynchedEntityData.DataItem) BountifulWrapper.impl.getDataWatcherItem(dataWatcherKeyValues[i], dataWatcherKeyValues[i+1])).value()); } - return new PacketPlayOutEntityMetadata(entityId, nativeWatchers); + return new ClientboundSetEntityDataPacket(entityId, nativeWatchers); } } diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/CraftbukkitWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/CraftbukkitWrapper21.java index 337ee1db..a774c401 100644 --- a/SpigotCore/SpigotCore_21/src/de/steamwar/core/CraftbukkitWrapper21.java +++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/CraftbukkitWrapper21.java @@ -22,20 +22,18 @@ package de.steamwar.core; import de.steamwar.Reflection; import com.comphenix.tinyprotocol.TinyProtocol; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.world.level.World; -import net.minecraft.world.level.chunk.Chunk; +import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.craftbukkit.CraftChunk; import org.bukkit.entity.Player; public class CraftbukkitWrapper21 implements CraftbukkitWrapper.ICraftbukkitWrapper { private static final Reflection.Method getHandle = Reflection.getMethod("org.bukkit.craftbukkit.CraftChunk", "getHandle", ChunkStatus.class); - private static final Reflection.Method getLightEngine = Reflection.getTypedMethod(World.class, null, LevelLightEngine.class); @Override public void sendChunk(Player p, int chunkX, int chunkZ) { - Chunk chunk = (Chunk) getHandle.invoke(p.getWorld().getChunkAt(chunkX, chunkZ), ChunkStatus.n); - TinyProtocol.instance.sendPacket(p, new ClientboundLevelChunkWithLightPacket(chunk, (LevelLightEngine) getLightEngine.invoke(chunk.r), null, null, true)); + LevelChunk chunk = (LevelChunk) ((CraftChunk) p.getWorld().getChunkAt(chunkX, chunkZ)).getHandle(ChunkStatus.FULL); + TinyProtocol.instance.sendPacket(p, new ClientboundLevelChunkWithLightPacket(chunk, chunk.level.getLightEngine(), null, null, true)); } } diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/entity/PacketConstructor21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/entity/PacketConstructor21.java new file mode 100644 index 00000000..67e501e4 --- /dev/null +++ b/SpigotCore/SpigotCore_21/src/de/steamwar/entity/PacketConstructor21.java @@ -0,0 +1,34 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2025 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.entity; + +import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.phys.Vec3; + +import java.util.Collections; + +public class PacketConstructor21 implements PacketConstructor{ + @Override + public Object teleportPacket(int entityId, double x, double y, double z, float yaw, float pitch) { + PositionMoveRotation rot = new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, pitch, yaw); + return new ClientboundTeleportEntityPacket(entityId, rot, Collections.emptySet(), false); + } +} diff --git a/TutorialSystem/src/de/steamwar/tutorial/listener/Joining.java b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditRendererWrapper8.java similarity index 53% rename from TutorialSystem/src/de/steamwar/tutorial/listener/Joining.java rename to SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditRendererWrapper8.java index d347a262..68f64c46 100644 --- a/TutorialSystem/src/de/steamwar/tutorial/listener/Joining.java +++ b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditRendererWrapper8.java @@ -1,7 +1,7 @@ /* * This file is a part of the SteamWar software. * - * Copyright (C) 2021 SteamWar.de-Serverteam + * Copyright (C) 2020 SteamWar.de-Serverteam * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -17,24 +17,26 @@ * along with this program. If not, see . */ -package de.steamwar.tutorial.listener; +package de.steamwar.core; -import org.bukkit.Bukkit; -import org.bukkit.event.EventHandler; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; -public class Joining extends BasicListener { +public class WorldEditRendererWrapper8 implements WorldEditRendererWrapper { - @EventHandler - public void onJoin(PlayerJoinEvent event) { - event.getPlayer().setOp(true); + @Override + public void draw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2) { } - @EventHandler - public void onQuit(PlayerQuitEvent event) { - if (Bukkit.getOnlinePlayers().isEmpty() || (Bukkit.getOnlinePlayers().size() == 1 && Bukkit.getOnlinePlayers().contains(event.getPlayer()))) { - Bukkit.shutdown(); - } + @Override + public void tick(Player player) { + } + + @Override + public void hide(Player player, boolean clipboard, boolean hide) { + } + + @Override + public void remove(Player player) { } } diff --git a/SpigotCore/SpigotCore_9/build.gradle.kts b/SpigotCore/SpigotCore_9/build.gradle.kts index a888faf1..c149a3fd 100644 --- a/SpigotCore/SpigotCore_9/build.gradle.kts +++ b/SpigotCore/SpigotCore_9/build.gradle.kts @@ -26,4 +26,5 @@ dependencies { compileOnly(project(":SpigotCore:SpigotCore_8", "default")) compileOnly(libs.nms9) + compileOnly(libs.worldedit12) } diff --git a/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java b/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java index ce7f6170..156662a8 100644 --- a/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java +++ b/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java @@ -85,11 +85,12 @@ public class BountifulWrapper9 implements BountifulWrapper.IBountifulWrapper { @Override public BountifulWrapper.PositionSetter getRelMoveSetter(Class packetClass) { Class type = Core.getVersion() > 12 ? short.class : int.class; - Reflection.Field moveX = Reflection.getField(packetClass, "b", type); - Reflection.Field moveY = Reflection.getField(packetClass, "c", type); - Reflection.Field moveZ = Reflection.getField(packetClass, "d", type); - Reflection.Field moveYaw = Reflection.getField(packetClass, "e", byte.class); - Reflection.Field movePitch = Reflection.getField(packetClass, "f", byte.class); + int fieldOffset = Core.getVersion() > 12 ? 0 : 1; + Reflection.Field moveX = Reflection.getField(packetClass, type, 0 + fieldOffset); + Reflection.Field moveY = Reflection.getField(packetClass, type, 1 + fieldOffset); + Reflection.Field moveZ = Reflection.getField(packetClass, type, 2 + fieldOffset); + Reflection.Field moveYaw = Reflection.getField(packetClass, byte.class, 0); + Reflection.Field movePitch = Reflection.getField(packetClass, byte.class, 1); return (packet, x, y, z, pitch, yaw) -> { moveX.set(packet, (short)(x*4096)); diff --git a/SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRendererWrapper9.java b/SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRendererWrapper9.java new file mode 100644 index 00000000..5da6104a --- /dev/null +++ b/SpigotCore/SpigotCore_9/src/de/steamwar/core/WorldEditRendererWrapper9.java @@ -0,0 +1,92 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.core; + +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +public class WorldEditRendererWrapper9 implements WorldEditRendererWrapper { + + private static final int VIEW_DISTANCE = 64; + private static final int SQ_VIEW_DISTANCE = VIEW_DISTANCE * VIEW_DISTANCE; + + private static final double STEP_SIZE = 0.5; + private static final Vector ONES = new Vector(1, 1, 1); + private static final Vector STEPS = new Vector(STEP_SIZE, STEP_SIZE, STEP_SIZE); + + @Override + public void draw(Player player, boolean scheduled, boolean clipboard, Vector min, Vector max) { + if (!scheduled) return; + + max = max.clone().add(ONES); + drawLine(player, clipboard, new Vector(min.getX(), min.getY(), min.getZ()), new Vector(max.getX(), min.getY(), min.getZ())); + drawLine(player, clipboard, new Vector(min.getX(), max.getY(), min.getZ()), new Vector(max.getX(), max.getY(), min.getZ())); + drawLine(player, clipboard, new Vector(min.getX(), min.getY(), max.getZ()), new Vector(max.getX(), min.getY(), max.getZ())); + drawLine(player, clipboard, new Vector(min.getX(), max.getY(), max.getZ()), new Vector(max.getX(), max.getY(), max.getZ())); + + drawLine(player, clipboard, new Vector(min.getX(), min.getY(), min.getZ()), new Vector(min.getX(), max.getY(), min.getZ())); + drawLine(player, clipboard, new Vector(max.getX(), min.getY(), min.getZ()), new Vector(max.getX(), max.getY(), min.getZ())); + drawLine(player, clipboard, new Vector(min.getX(), min.getY(), max.getZ()), new Vector(min.getX(), max.getY(), max.getZ())); + drawLine(player, clipboard, new Vector(max.getX(), min.getY(), max.getZ()), new Vector(max.getX(), max.getY(), max.getZ())); + + drawLine(player, clipboard, new Vector(min.getX(), min.getY(), min.getZ()), new Vector(min.getX(), min.getY(), max.getZ())); + drawLine(player, clipboard, new Vector(max.getX(), min.getY(), min.getZ()), new Vector(max.getX(), min.getY(), max.getZ())); + drawLine(player, clipboard, new Vector(min.getX(), max.getY(), min.getZ()), new Vector(min.getX(), max.getY(), max.getZ())); + drawLine(player, clipboard, new Vector(max.getX(), max.getY(), min.getZ()), new Vector(max.getX(), max.getY(), max.getZ())); + } + + private void drawLine(Player player, boolean clipboard, Vector min, Vector max) { + Particle particle; + if (clipboard) { + particle = TrickyParticleWrapper.impl.getVillagerHappy(); + } else { + particle = Particle.DRAGON_BREATH; + } + + Vector stepSize = max.clone().subtract(min).normalize().multiply(STEPS); + while (min.getX() <= max.getX() && min.getY() <= max.getY() && min.getZ() <= max.getZ()) { + Location location = player.getLocation(); + double dx = min.getX() - location.getX(); + double dy = min.getY() - location.getY(); + double dz = min.getZ() - location.getZ(); + if (dx * dx + dy * dy + dz * dz > SQ_VIEW_DISTANCE) { + min.add(stepSize); + continue; + } + + player.spawnParticle(particle, min.getX(), min.getY(), min.getZ(), 1, 0.0, 0.0, 0.0, 0.0); + min.add(stepSize); + } + } + + @Override + public void tick(Player player) { + } + + @Override + public void hide(Player player, boolean clipboard, boolean hide) { + } + + @Override + public void remove(Player player) { + } +} diff --git a/SpigotCore/SpigotCore_Main/src/SpigotCore.properties b/SpigotCore/SpigotCore_Main/src/SpigotCore.properties index 10c64603..94e57d6c 100644 --- a/SpigotCore/SpigotCore_Main/src/SpigotCore.properties +++ b/SpigotCore/SpigotCore_Main/src/SpigotCore.properties @@ -105,3 +105,22 @@ NOSCHEMSUBMITTING_PERMA=§7You are §epermanently§7 excluded from submitting § NOSCHEMSUBMITTING_UNTIL=§7You are excluded from submitting §e§lschematics §euntil {0}§8: §e{1} UNNOSCHEMSUBMITTING_ERROR=§cThe player is not excluded from submitting schematics. UNNOSCHEMSUBMITTING=§e{0} §7may now submit §e§lschematics§7 again§8. + +WORLDEDIT_CUI_TITLE = WorldEdit CUI +WORLDEDIT_CUI_TITLE_SUBMENU = WorldEdit CUI - {0} +WORLDEDIT_CUI_SELECTION = Own Selection +WORLDEDIT_CUI_CLIPBOARD = Own Clipboard +WORLDEDIT_CUI_SELECTION_OTHER = Other Selection +WORLDEDIT_CUI_CLIPBOARD_OTHER = Other Clipboard + +WORLDEDIT_CUI_MATERIAL_NAME = §eWorldEdit {0} +WORLDEDIT_CUI_MATERIAL_CLICK = §7Click to edit + +WORLDEDIT_CUI_WIDTH_NAME = §eWidth {0} +WORLDEDIT_CUI_WIDTH_LORE = §8> §7{0} +WORLDEDIT_CUI_WIDTH_LORE_SELECTED = §8> §e{0} +WORLDEDIT_CUI_WIDTH_CLICK = §7Click to change +WORLDEDIT_CUI_WIDTH_HUGE = 1/ 8 Block +WORLDEDIT_CUI_WIDTH_LARGE = 1/16 Block +WORLDEDIT_CUI_WIDTH_MEDIUM = 1/32 Block +WORLDEDIT_CUI_WIDTH_SLIM = 1/64 Block \ No newline at end of file diff --git a/SpigotCore/SpigotCore_Main/src/SpigotCore_de.properties b/SpigotCore/SpigotCore_Main/src/SpigotCore_de.properties index 83fa39f5..1f573eff 100644 --- a/SpigotCore/SpigotCore_Main/src/SpigotCore_de.properties +++ b/SpigotCore/SpigotCore_Main/src/SpigotCore_de.properties @@ -99,4 +99,15 @@ NOSCHEMSUBMITTING_TEAM={0} §e{1} §7wurde von §e{2} {3} §7vom §e§lSchematic NOSCHEMSUBMITTING_PERMA=§7Du bist §epermanent §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{0} NOSCHEMSUBMITTING_UNTIL=§7Du bist §ebis zum {0} §7vom §e§lEinsenden von Schematics§7 ausgeschlossen§8: §e{1} UNNOSCHEMSUBMITTING_ERROR=§cDer Spieler ist nicht vom Einsenden von Schematics ausgeschlossen. -UNNOSCHEMSUBMITTING=§e{0} §7darf nun wieder §e§lSchematis§7 einsenden§8. \ No newline at end of file +UNNOSCHEMSUBMITTING=§e{0} §7darf nun wieder §e§lSchematis§7 einsenden§8. + +WORLDEDIT_CUI_SELECTION = Eigene Auswahl +WORLDEDIT_CUI_CLIPBOARD = Eigene Kopie +WORLDEDIT_CUI_SELECTION_OTHER = Auswahl Anderer +WORLDEDIT_CUI_CLIPBOARD_OTHER = Kopie Anderer + +WORLDEDIT_CUI_MATERIAL_NAME = §eWorldEdit {0} +WORLDEDIT_CUI_MATERIAL_CLICK = §7Klicke zum Editieren + +WORLDEDIT_CUI_WIDTH_NAME = §eDicke - {0} +WORLDEDIT_CUI_WIDTH_CLICK = §7Klicke zum ändern \ No newline at end of file diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/Reflection.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/Reflection.java index 92e3d3fd..86dca0bf 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/Reflection.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/Reflection.java @@ -94,6 +94,7 @@ public final class Reflection { spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundContainerClickPacket", "net.minecraft.network.protocol.game.PacketPlayInWindowClick"); spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundInteractPacket", "net.minecraft.network.protocol.game.PacketPlayInUseEntity"); spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundInteractPacket$Action", "net.minecraft.network.protocol.game.PacketPlayInUseEntity$EnumEntityUseAction"); + spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundInteractPacket$ActionType", "net.minecraft.network.protocol.game.PacketPlayInUseEntity$b"); spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Pos", "net.minecraft.network.protocol.game.PacketPlayInFlying$PacketPlayInPosition"); spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$PosRot", "net.minecraft.network.protocol.game.PacketPlayInFlying$PacketPlayInPositionLook"); spigotClassnames.put("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Rot", "net.minecraft.network.protocol.game.PacketPlayInFlying$PacketPlayInLook"); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/command/CaseInsensitiveCommandsListener.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/command/CaseInsensitiveCommandsListener.java index a829308a..05eafdbb 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/command/CaseInsensitiveCommandsListener.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/command/CaseInsensitiveCommandsListener.java @@ -19,6 +19,10 @@ package de.steamwar.command; +import de.steamwar.core.Core; +import de.steamwar.providers.BauServerInfo; +import de.steamwar.sql.AuditLog; +import de.steamwar.sql.SteamwarUser; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -31,5 +35,6 @@ public class CaseInsensitiveCommandsListener implements Listener { String[] strings = event.getMessage().split(" "); strings[0] = strings[0].toLowerCase(); event.setMessage(String.join(" ", strings)); + AuditLog.createCommand(Core.getServerName(), BauServerInfo.getOwnerUser(), SteamwarUser.get(event.getPlayer().getUniqueId()), event.getMessage()); } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java index e5edcfae..d5919783 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java @@ -94,6 +94,7 @@ class CheckpointUtilsJ9 { private static final Reflection.Method bind = Reflection.getMethod(TinyProtocol.serverConnection, null, InetAddress.class, int.class); private static void freezeInternal(Path path) throws Exception { Bukkit.getPluginManager().callEvent(new CRIUSleepEvent()); + Bukkit.getWorlds().forEach(FlatteningWrapper.impl::syncSave); Statement.closeAll(); @@ -119,8 +120,9 @@ class CheckpointUtilsJ9 { criu.checkpointJVM(); } catch (JVMCRIUException e) { Path logfile = path.resolve("criu.log"); - if(logfile.toFile().exists()) + if(logfile.toFile().exists()) { throw new IllegalStateException("Could not create checkpoint, criu log:\n" + new String(Files.readAllBytes(logfile)), e); + } throw e; } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java index 4e7b7576..91c05851 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java @@ -23,13 +23,18 @@ import com.comphenix.tinyprotocol.TinyProtocol; import de.steamwar.Reflection; import de.steamwar.command.*; import de.steamwar.core.authlib.AuthlibInjector; -import de.steamwar.core.events.*; +import de.steamwar.core.events.AntiNocom; +import de.steamwar.core.events.ChattingEvent; +import de.steamwar.core.events.PlayerJoinedEvent; +import de.steamwar.core.events.WorldLoadEvent; import de.steamwar.message.Message; import de.steamwar.network.NetworkReceiver; import de.steamwar.network.handlers.ServerDataHandler; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.internal.Statement; +import lombok.Getter; +import lombok.Setter; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.event.Listener; @@ -41,7 +46,7 @@ import java.io.InputStreamReader; import java.util.Collection; import java.util.logging.Level; -public class Core extends JavaPlugin{ +public class Core extends JavaPlugin { public static final Message MESSAGE = new Message("SpigotCore", Core.class.getClassLoader()); @@ -49,12 +54,17 @@ public class Core extends JavaPlugin{ return Reflection.MAJOR_VERSION; } + @Getter + @Setter private static JavaPlugin instance; - public static JavaPlugin getInstance() { - return instance; - } - public static void setInstance(JavaPlugin instance) { - Core.instance = instance; + + @Getter + private static String serverName = ""; + + public static void setServerName(String serverName) { + if (serverName.isEmpty()) { + Core.serverName = serverName; + } } private ErrorHandler errorHandler; @@ -63,10 +73,13 @@ public class Core extends JavaPlugin{ @Override public void onLoad() { setInstance(this); + serverName = System.getProperty("serverName", ""); } @Override public void onEnable() { + new PlayerVersion(); + errorHandler = new ErrorHandler(); crashDetector = new CrashDetector(); @@ -102,7 +115,7 @@ public class Core extends JavaPlugin{ if(Core.getVersion() >= 19) new ServerDataHandler(); - if(Core.getVersion() > 8 && Bukkit.getPluginManager().getPlugin("WorldEdit") != null) + if(Bukkit.getPluginManager().getPlugin("WorldEdit") != null) new WorldEditRenderer(); Bukkit.getScheduler().runTaskTimer(this, TabCompletionCache::invalidateOldEntries, 20, 20); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/PlayerVersion.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/PlayerVersion.java new file mode 100644 index 00000000..512df0d3 --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/PlayerVersion.java @@ -0,0 +1,61 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.core; + +import de.steamwar.network.packets.PacketHandler; +import de.steamwar.network.packets.server.ClientVersionPacket; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class PlayerVersion extends PacketHandler implements Listener { + + private static final Map playerVersions = new HashMap<>(); + + public static int getVersion(Player player) { + return playerVersions.getOrDefault(player.getUniqueId(), -1); + } + + public static boolean isBedrock(Player player) { + return player.getName().startsWith("."); + } + + public PlayerVersion() { + Bukkit.getPluginManager().registerEvents(this, Core.getInstance()); + register(); + } + + @Handler + public void handlePacket(ClientVersionPacket clientVersionPacket) { + playerVersions.put(clientVersionPacket.getPlayer(), clientVersionPacket.getVersion()); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerQuit(PlayerQuitEvent event) { + playerVersions.remove(event.getPlayer().getUniqueId()); + } +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/VersionDependent.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/VersionDependent.java index 5e8ec241..2fe94ce5 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/VersionDependent.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/VersionDependent.java @@ -31,8 +31,16 @@ public class VersionDependent { } public static T getVersionImpl(Plugin plugin, String className){ + return getVersionImpl(plugin, Core.getVersion(), className); + } + + public static T getVersionImpl(Plugin plugin, int fromVersion){ + return getVersionImpl(plugin, fromVersion, (new Exception()).getStackTrace()[1].getClassName()); + } + + public static T getVersionImpl(Plugin plugin, int fromVersion, String className){ ClassLoader loader = plugin.getClass().getClassLoader(); - for(int version = Core.getVersion(); version >= 8; version--) { + for(int version = fromVersion; version >= 8; version--) { try { return ((Class) Class.forName(className + version, true, loader)).getDeclaredConstructor().newInstance(); } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java index 377efe13..225053a2 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRenderer.java @@ -29,20 +29,15 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.world.World; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.Particle; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.player.*; import org.bukkit.util.Vector; -public class WorldEditRenderer { - - private static final int VIEW_DISTANCE = 64; - private static final int SQ_VIEW_DISTANCE = VIEW_DISTANCE * VIEW_DISTANCE; - - private static final double STEP_SIZE = 0.5; - - private static final Vector ONES = new Vector(1, 1, 1); +public class WorldEditRenderer implements Listener { private static final Material WAND = FlatteningWrapper.impl.getMaterial("WOOD_AXE"); @@ -50,77 +45,116 @@ public class WorldEditRenderer { public WorldEditRenderer() { we = WorldEditWrapper.getWorldEditPlugin(); + Bukkit.getPluginManager().registerEvents(this, Core.getInstance()); - Bukkit.getScheduler().runTaskTimer(Core.getInstance(), this::render, 20, 20); + Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> { + for (Player player : Bukkit.getOnlinePlayers()) { + renderPlayer(player, true); + } + }, 20, 20); } - private void render() { - for(Player player : Bukkit.getOnlinePlayers()) { - //noinspection deprecation - if(player.getItemInHand().getType() != WAND) - continue; + private void renderPlayer(Player player, boolean scheduled) { + LocalSession session = we.getSession(player); + renderClipboard(player, session, scheduled); + renderRegion(player, session, scheduled); + } - LocalSession session = we.getSession(player); + private void renderClipboard(Player player, LocalSession session, boolean scheduled) { + try { + Clipboard clipboard = session.getClipboard().getClipboard(); + Vector pos = player.getLocation().toVector(); + Region region = clipboard.getRegion(); + Transform transform = session.getClipboard().getTransform(); + Vector a = WorldEditWrapper.impl.applyTransform(WorldEditWrapper.impl.getMinimum(region).subtract(WorldEditWrapper.impl.getOrigin(clipboard)), transform).add(pos); + Vector b = WorldEditWrapper.impl.applyTransform(WorldEditWrapper.impl.getMaximum(region).subtract(WorldEditWrapper.impl.getOrigin(clipboard)), transform).add(pos); + a = new Vector(a.getBlockX(), a.getBlockY(), a.getBlockZ()); + b = new Vector(b.getBlockX(), b.getBlockY(), b.getBlockZ()); + drawCuboid(Vector.getMinimum(a, b), Vector.getMaximum(a, b), scheduled, true, player); + } catch (EmptyClipboardException e) { + WorldEditRendererWrapper.impl.hide(player, true, true); + } + } + + private void renderRegion(Player player, LocalSession session, boolean scheduled) { + World world = session.getSelectionWorld(); + if(world != null) { + RegionSelector regionSelector = session.getRegionSelector(world); try { - Clipboard clipboard = session.getClipboard().getClipboard(); - Vector pos = player.getLocation().toVector(); - Region region = clipboard.getRegion(); - Transform transform = session.getClipboard().getTransform(); - Vector a = WorldEditWrapper.impl.applyTransform(WorldEditWrapper.impl.getMinimum(region).subtract(WorldEditWrapper.impl.getOrigin(clipboard)), transform).add(pos); - Vector b = WorldEditWrapper.impl.applyTransform(WorldEditWrapper.impl.getMaximum(region).subtract(WorldEditWrapper.impl.getOrigin(clipboard)), transform).add(pos); - drawCuboid(Vector.getMinimum(a, b), Vector.getMaximum(a, b), TrickyParticleWrapper.impl.getVillagerHappy(), player); - } catch (EmptyClipboardException e) { - //ignore - } - - World world = session.getSelectionWorld(); - if(world != null) { - RegionSelector regionSelector = session.getRegionSelector(world); - try { - Region region = regionSelector.getRegion(); - drawCuboid(WorldEditWrapper.impl.getMinimum(region), WorldEditWrapper.impl.getMaximum(region), Particle.DRAGON_BREATH, player); - } catch (IncompleteRegionException e) { - //ignore - } + Region region = regionSelector.getRegion(); + drawCuboid(WorldEditWrapper.impl.getMinimum(region), WorldEditWrapper.impl.getMaximum(region), scheduled, false, player); + } catch (IncompleteRegionException e) { + WorldEditRendererWrapper.impl.hide(player, false, true); } } } - private void drawCuboid(Vector min, Vector max, Particle particle, Player owner) { - max.add(ONES); - - for(double x = min.getBlockX(); x <= max.getBlockX(); x += STEP_SIZE) { - draw(x, min.getBlockY(), min.getBlockZ(), particle, owner); - draw(x, min.getBlockY(), max.getBlockZ(), particle, owner); - draw(x, max.getBlockY(), min.getBlockZ(), particle, owner); - draw(x, max.getBlockY(), max.getBlockZ(), particle, owner); - } - - for(double y = min.getBlockY() + STEP_SIZE; y <= max.getBlockY() - STEP_SIZE; y += STEP_SIZE) { - draw(min.getBlockX(), y, min.getBlockZ(), particle, owner); - draw(min.getBlockX(), y, max.getBlockZ(), particle, owner); - draw(max.getBlockX(), y, min.getBlockZ(), particle, owner); - draw(max.getBlockX(), y, max.getBlockZ(), particle, owner); - } - - for(double z = min.getBlockZ() + STEP_SIZE; z <= max.getBlockZ() - STEP_SIZE; z += STEP_SIZE) { - draw(min.getBlockX(), min.getBlockY(), z, particle, owner); - draw(min.getBlockX(), max.getBlockY(), z, particle, owner); - draw(max.getBlockX(), min.getBlockY(), z, particle, owner); - draw(max.getBlockX(), max.getBlockY(), z, particle, owner); + private void drawCuboid(Vector min, Vector max, boolean scheduled, boolean clipboard, Player owner) { + //noinspection deprecation + if(owner.getItemInHand().getType() != WAND) { + WorldEditRendererWrapper.impl.hide(owner, true, true); + WorldEditRendererWrapper.impl.hide(owner, false, true); + } else { + WorldEditRendererWrapper.impl.hide(owner, true, WorldEditRendererCUIEditor.Type.CLIPBOARD.getMaterial(owner) == Material.BARRIER); + WorldEditRendererWrapper.impl.hide(owner, false, WorldEditRendererCUIEditor.Type.SELECTION.getMaterial(owner) == Material.BARRIER); + WorldEditRendererWrapper.safeDraw(owner, scheduled, clipboard, min, max); } } - private void draw(double x, double y, double z, Particle particle, Player owner) { - for(Player player : Bukkit.getOnlinePlayers()) { - Location location = player.getLocation(); - double dx = x - location.getX(); - double dy = y - location.getY(); - double dz = z - location.getZ(); - if(dx*dx + dy*dy + dz*dz > SQ_VIEW_DISTANCE) - continue; - - player.spawnParticle(player == owner ? particle : Particle.TOWN_AURA, x, y, z, 1, 0.0, 0.0, 0.0, 0.0); + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + if(event.getPlayer().getItemInHand().getType() == WAND) { + WorldEditRendererWrapper.impl.tick(event.getPlayer()); } + renderClipboard(event.getPlayer(), we.getSession(event.getPlayer()), false); + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { + renderRegion(event.getPlayer(), we.getSession(event.getPlayer()), false); + }, 0); + } + + @EventHandler + public void onBlockBreak(BlockBreakEvent event) { + Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { + renderRegion(event.getPlayer(), we.getSession(event.getPlayer()), false); + }, 0); + } + + @EventHandler + public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { + if (event.getMessage().startsWith("//")) { + Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { + LocalSession session = we.getSession(event.getPlayer()); + renderRegion(event.getPlayer(), session, false); + renderClipboard(event.getPlayer(), session, false); + }, 5); + } + } + + @EventHandler + public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) { + Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { + renderPlayer(event.getPlayer(), false); + }, 1); + } + + @EventHandler + public void onPlayerDropItem(PlayerDropItemEvent event) { + renderPlayer(event.getPlayer(), false); + } + + @EventHandler + public void onPlayerItemHeld(PlayerItemHeldEvent event) { + Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { + renderPlayer(event.getPlayer(), false); + }, 1); + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + WorldEditRendererWrapper.impl.remove(event.getPlayer()); } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererCUIEditor.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererCUIEditor.java new file mode 100644 index 00000000..e50eac9d --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererCUIEditor.java @@ -0,0 +1,155 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.core; + +import de.steamwar.command.SWCommand; +import de.steamwar.inventory.SWInventory; +import de.steamwar.inventory.SWItem; +import de.steamwar.sql.UserConfig; +import lombok.AllArgsConstructor; +import org.bukkit.Material; +import org.bukkit.block.data.type.Light; +import org.bukkit.entity.Player; +import org.bukkit.inventory.meta.BlockDataMeta; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class WorldEditRendererCUIEditor { + + @AllArgsConstructor + public enum Type { + SELECTION("cui_selection_material", "cui_selection_width", Material.PURPLE_CONCRETE, Width.MEDIUM), + CLIPBOARD("cui_clipboard_material", "cui_clipboard_width", Material.LIME_CONCRETE, Width.SLIM), + ; + + private final String configMaterial; + private final String configWidth; + private final Material defaultMaterial; + private final Width defaultWidth; + + public Material getMaterial(Player player) { + String material = UserConfig.getConfig(player.getUniqueId(), configMaterial); + if (material == null) { + return defaultMaterial; + } else { + return Material.valueOf(material); + } + } + + public void setMaterial(Player player, Material material) { + UserConfig.updatePlayerConfig(player.getUniqueId(), configMaterial, material.name()); + } + + public Width getWidth(Player player) { + String width = UserConfig.getConfig(player.getUniqueId(), configWidth); + if (width == null) { + return defaultWidth; + } else { + return Width.valueOf(width); + } + } + + public void setWidth(Player player, Width width) { + UserConfig.updatePlayerConfig(player.getUniqueId(), configWidth, width.name()); + } + } + + @AllArgsConstructor + public enum Width { + HUGE(15, "WORLDEDIT_CUI_WIDTH_HUGE", 2/16f), + LARGE(8, "WORLDEDIT_CUI_WIDTH_LARGE", 1/16f), + MEDIUM(4, "WORLDEDIT_CUI_WIDTH_MEDIUM", 1/32f), + SLIM(0, "WORLDEDIT_CUI_WIDTH_SLIM", 1/64f); + + public final int lightLevel; + public final String name; + public final float value; + } + + public WorldEditRendererCUIEditor() { + if (Core.getVersion() >= 20) { + new Command(); + } + } + + private static class Command extends SWCommand { + + public Command() { + super("cui"); + } + + @Register + public void cuiEditor(Player player) { + SWInventory inv = new SWInventory(player, 9 * 2, Core.MESSAGE.parse("WORLDEDIT_CUI_TITLE", player)); + setElement(inv, player, 3, "WORLDEDIT_CUI_SELECTION", Type.SELECTION); + setElement(inv, player, 5, "WORLDEDIT_CUI_CLIPBOARD", Type.CLIPBOARD); + inv.open(); + } + + private void setElement(SWInventory inv, Player player, int index, String uiName, Type type) { + Material material = type.getMaterial(player); + Width width = type.getWidth(player); + + inv.setItem(index, new SWItem(material, Core.MESSAGE.parse("WORLDEDIT_CUI_MATERIAL_NAME", player, Core.MESSAGE.parse(uiName, player)), Arrays.asList(Core.MESSAGE.parse("WORLDEDIT_CUI_MATERIAL_CLICK", player)), false, click -> { + cuiMaterial(player, uiName, type, material); + })); + + List lore = new ArrayList<>(); + lore.add(Core.MESSAGE.parse("WORLDEDIT_CUI_WIDTH_CLICK", player)); + lore.add(""); + for (Width value : Width.values()) { + if (value == width) { + lore.add(Core.MESSAGE.parse("WORLDEDIT_CUI_WIDTH_LORE_SELECTED", player, Core.MESSAGE.parse(value.name, player))); + } else { + lore.add(Core.MESSAGE.parse("WORLDEDIT_CUI_WIDTH_LORE", player, Core.MESSAGE.parse(value.name, player))); + } + } + SWItem lightItem = new SWItem(Material.LIGHT, Core.MESSAGE.parse("WORLDEDIT_CUI_WIDTH_NAME", player, Core.MESSAGE.parse(uiName, player)), lore, false, click -> { + type.setWidth(player, Width.values()[(width.ordinal() + 1) % Width.values().length]); + setElement(inv, player, index, uiName, type); + }); + ItemMeta itemMeta = lightItem.getItemMeta(); + Light light = (Light) Material.LIGHT.createBlockData(); + light.setLevel(width.lightLevel); + ((BlockDataMeta) itemMeta).setBlockData(light); + lightItem.setItemMeta(itemMeta); + inv.setItem(index + 9, lightItem); + } + + private final Material[] materials = {Material.WHITE_CONCRETE, Material.LIGHT_GRAY_CONCRETE, Material.GRAY_CONCRETE, Material.BLACK_CONCRETE, Material.BROWN_CONCRETE, Material.RED_CONCRETE, Material.ORANGE_CONCRETE, Material.YELLOW_CONCRETE, Material.LIME_CONCRETE, Material.GREEN_CONCRETE, Material.CYAN_CONCRETE, Material.LIGHT_BLUE_CONCRETE, Material.BLUE_CONCRETE, Material.PURPLE_CONCRETE, Material.MAGENTA_CONCRETE, Material.PINK_CONCRETE, null, Material.BARRIER}; + + private void cuiMaterial(Player player, String subMenu, Type type, Material currentSelection) { + SWInventory inv = new SWInventory(player, 9 * 2, Core.MESSAGE.parse("WORLDEDIT_CUI_TITLE_SUBMENU", player, Core.MESSAGE.parse(subMenu, player))); + for (int i = 0; i < materials.length; i++) { + Material material = materials[i]; + if (material == null) continue; + inv.setItem(i, new SWItem(material, "", Collections.emptyList(), material == currentSelection, click -> { + type.setMaterial(player, material); + cuiEditor(player); + })); + } + inv.open(); + } + } +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererWrapper.java new file mode 100644 index 00000000..2439d40d --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditRendererWrapper.java @@ -0,0 +1,44 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.core; + +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +public interface WorldEditRendererWrapper { + WorldEditRendererWrapper fallback = VersionDependent.getVersionImpl(Core.getInstance(), 9); + WorldEditRendererWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); + + static void safeDraw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2) { + if (PlayerVersion.isBedrock(player) || PlayerVersion.getVersion(player) < 20) { + fallback.draw(player, scheduled, clipboard, pos1, pos2); + } else { + impl.draw(player, scheduled, clipboard, pos1, pos2); + } + } + + void draw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2); + + void tick(Player player); + + void hide(Player player, boolean clipboard, boolean hide); + + void remove(Player player); +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/events/PlayerJoinedEvent.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/events/PlayerJoinedEvent.java index 29b0ffd8..d3fd33a0 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/events/PlayerJoinedEvent.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/events/PlayerJoinedEvent.java @@ -19,6 +19,9 @@ package de.steamwar.core.events; +import de.steamwar.core.Core; +import de.steamwar.providers.BauServerInfo; +import de.steamwar.sql.AuditLog; import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.UserPerm; import de.steamwar.sql.internal.Statement; @@ -44,12 +47,14 @@ public class PlayerJoinedEvent implements Listener{ player.setDisplayName(prefix.getColorCode() + player.getName() + "§r"); event.setJoinMessage("§a§l» §r" + player.getDisplayName()); + AuditLog.createJoin(Core.getServerName(), BauServerInfo.getOwnerUser(), user); } - @EventHandler + @EventHandler(priority = EventPriority.LOWEST) private void onQuit(PlayerQuitEvent event) { Player player = event.getPlayer(); event.setQuitMessage("§c§l« §r" + player.getDisplayName()); + AuditLog.createLeave(Core.getServerName(), BauServerInfo.getOwnerUser(), SteamwarUser.get(player.getUniqueId())); } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CEntity.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CEntity.java new file mode 100644 index 00000000..373a2acf --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CEntity.java @@ -0,0 +1,67 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.entity; + +import org.bukkit.Location; +import org.bukkit.entity.EntityType; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * CEntities are Entities that are a compound of other Entities. + */ +public class CEntity extends REntity { + + protected List entities = new ArrayList<>(); + + public CEntity(REntityServer server) { + super(server, EntityType.MARKER, new Location(null, 0, 0, 0)); + } + + public List getEntities() { + return new ArrayList<>(entities); + } + + public List getEntitiesByType(Class clazz) { + return entities.stream().filter(clazz::isInstance).map(clazz::cast).collect(Collectors.toList()); + } + + @Override + void tick() { + entities.forEach(REntity::tick); + } + + @Override + public void hide(boolean hide) { + super.hide(hide); + entities.forEach(rEntity -> { + rEntity.hide(hide); + }); + } + + @Override + public void die() { + super.die(); + entities.forEach(REntity::die); + entities.clear(); + } +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CLine.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CLine.java new file mode 100644 index 00000000..f3b02deb --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CLine.java @@ -0,0 +1,243 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.entity; + +import org.bukkit.Location; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Display; +import org.bukkit.entity.Player; +import org.bukkit.util.Consumer; +import org.bukkit.util.Transformation; +import org.bukkit.util.Vector; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +import java.util.Objects; + +public class CLine extends CEntity { + + public static final float DEFAULT_WIDTH = 1 / 16f; + private static final float offset = 1 / 1024f; + private static final Vector offsetVec = new Vector(offset, offset, offset); + + private Location from; + private Location to; + private float width = DEFAULT_WIDTH; + private BlockData blockData = RBlockDisplay.DEFAULT_BLOCK; + private boolean hide = false; + + public CLine(REntityServer server) { + super(server); + } + + private CLine checkAndSet(T currentValue, T newValue, Consumer setter) { + if (Objects.equals(currentValue, newValue)) return this; + setter.accept(newValue); + tick(); + return this; + } + + public CLine setFrom(Location from) { + return checkAndSet(this.from, from, location -> this.from = location); + } + + public CLine setTo(Location to) { + return checkAndSet(this.to, to, location -> this.to = location); + } + + public CLine setWidth(float width) { + return checkAndSet(this.width, width, w -> this.width = w); + } + + public CLine setBlock(BlockData blockData) { + if (this.blockData.equals(blockData)) return this; + if (blockData == null) { + this.blockData = RBlockDisplay.DEFAULT_BLOCK; + } else { + this.blockData = blockData; + } + getEntitiesByType(RBlockDisplay.class).forEach(display -> { + display.setBlock(blockData); + }); + return this; + } + + @Override + public void hide(boolean hide) { + if (hide == this.hide) return; + this.hide = hide; + if (hide) { + if (startLine != null) startLine.hide(true); + if (middleLine != null) middleLine.hide(true); + if (endLine != null) endLine.hide(true); + } else { + tick(); + } + } + + @Override + void tick() { + if (from == null || to == null) return; + if (hide) return; + updateStart(); + updateMiddle(); + updateEnd(); + } + + private RBlockDisplay startLine; + private void updateStart() { + Vector vec = to.clone().subtract(from).toVector(); + if (vec.length() > 35) vec.normalize().multiply(35); + + if (startLine == null) { + startLine = new RBlockDisplay(server, new Location(null, 0, 0, 0)); + startLine.setBrightness(new Display.Brightness(15, 15)); + startLine.setViewRange(560); + startLine.setBlock(blockData); + entities.add(startLine); + } else { + startLine.hide(false); + } + + startLine.move(from.clone().subtract(offsetVec)); + startLine.setTransform(new Transformation(new Vector3f(0, 0, 0), new Quaternionf(0, 0, 0, 1), addWidth(vec).toVector3f(), new Quaternionf(0, 0, 0, 1))); + } + + private RBlockDisplay middleLine; + private void updateMiddle() { + Vector vec = to.clone().subtract(from).toVector(); + if (vec.length() <= 70) { + if (middleLine != null) middleLine.hide(true); + return; + } + if (vec.length() > 280) vec.normalize().multiply(280); + else vec = vec.clone().normalize().multiply(vec.length() - 60); + + if (middleLine == null) { + middleLine = new RBlockDisplay(server, new Location(null, 0, 0, 0)); + middleLine.setBrightness(new Display.Brightness(15, 15)); + middleLine.setViewRange(560); + middleLine.setBlock(blockData); + entities.add(middleLine); + } else { + middleLine.hide(false); + } + + Player player = server.getPlayers().stream().findFirst().orElse(null); + if (player == null) return; + + Vector tempVector = vec.clone().normalize().multiply(30); + Location from = this.from.clone().add(tempVector); + Location to = this.to.clone().subtract(tempVector); + + Vector lineVec = to.clone().subtract(from).toVector(); + Vector playerVec = player.getLocation().toVector().subtract(from.toVector()); + double lineVecDotItself = lineVec.dot(lineVec); + Vector projectionVec = lineVec.clone().multiply(lineVec.dot(playerVec)).divide(new Vector(lineVecDotItself, lineVecDotItself, lineVecDotItself)); + + Vector moveVec = from.toVector().add(projectionVec); + if (moveVec.getX() < from.getX()) { + moveVec.setX(from.getX()); + } + if (moveVec.getX() > to.getX()) { + moveVec.setX(to.getX()); + } + if (moveVec.getY() < from.getY()) { + moveVec.setY(from.getY()); + } + if (moveVec.getY() > to.getY()) { + moveVec.setY(to.getY()); + } + if (moveVec.getZ() < from.getZ()) { + moveVec.setZ(from.getZ()); + } + if (moveVec.getZ() > to.getZ()) { + moveVec.setZ(to.getZ()); + } + + Vector translation = vec.clone().divide(new Vector(2, 2, 2)); + translation.setX(-translation.getX()); + translation.setY(-translation.getY()); + translation.setZ(-translation.getZ()); + + Vector first = moveVec.clone().add(translation).subtract(from.toVector()); + if (first.getX() < 0) { + translation.setX(translation.getX() - first.getX()); + } + if (first.getY() < 0) { + translation.setY(translation.getY() - first.getY()); + } + if (first.getZ() < 0) { + translation.setZ(translation.getZ() - first.getZ()); + } + + Vector second = to.toVector().subtract(moveVec.clone().subtract(translation)); + if (second.getX() < 0) { + translation.setX(translation.getX() + second.getX()); + } + if (second.getY() < 0) { + translation.setY(translation.getY() + second.getY()); + } + if (second.getZ() < 0) { + translation.setZ(translation.getZ() + second.getZ()); + } + + middleLine.move(moveVec.toLocation(player.getWorld()).subtract(offsetVec)); + middleLine.setTransform(new Transformation(translation.toVector3f(), new Quaternionf(0, 0, 0, 1), addWidth(vec).toVector3f(), new Quaternionf(0, 0, 0, 1))); + } + + private RBlockDisplay endLine; + private void updateEnd() { + Vector vec = to.clone().subtract(from).toVector(); + if (vec.length() <= 35) { + if (endLine != null) endLine.hide(true); + return; + } + if (vec.length() > 35) vec.normalize().multiply(35); + + if (endLine == null) { + endLine = new RBlockDisplay(server, new Location(null, 0, 0, 0)); + endLine.setBrightness(new Display.Brightness(15, 15)); + endLine.setViewRange(560); + endLine.setBlock(blockData); + entities.add(endLine); + } else { + endLine.hide(false); + } + + endLine.move(to.clone().subtract(offsetVec)); + endLine.setTransform(new Transformation(vec.toVector3f().negate(), new Quaternionf(0, 0, 0, 1), addWidth(vec).toVector3f(), new Quaternionf(0, 0, 0, 1))); + } + + private Vector addWidth(Vector vector) { + vector = vector.clone(); + if (vector.getX() == 0) { + vector.setX(vector.getX() + width); + } + if (vector.getY() == 0) { + vector.setY(vector.getY() + width); + } + if (vector.getZ() == 0) { + vector.setZ(vector.getZ() + width); + } + vector.add(offsetVec).add(offsetVec); + return vector; + } +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CWireframe.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CWireframe.java new file mode 100644 index 00000000..cf15912d --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/CWireframe.java @@ -0,0 +1,103 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.entity; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.data.BlockData; +import org.bukkit.util.Consumer; +import org.bukkit.util.Vector; + +import java.util.List; +import java.util.Objects; + +/** + * Compound Box (12 CLine) + */ +public class CWireframe extends CEntity { + + public static final float DEFAULT_WIDTH = 1 / 16f; + private float width = DEFAULT_WIDTH; + + private Location pos1; + private Location pos2; + + public CWireframe(REntityServer server) { + super(server); + for (int i = 0; i < 12; i++) { + entities.add(new CLine(server)); + } + } + + public CWireframe setPos1(Location pos1) { + this.pos1 = pos1; + updateAndSpawnLines(); + return this; + } + + public CWireframe setPos2(Location pos2) { + this.pos2 = pos2; + updateAndSpawnLines(); + return this; + } + + public CWireframe setWidth(float width) { + this.width = width; + updateAndSpawnLines(); + getEntitiesByType(CLine.class).forEach(haaLine -> { + haaLine.setWidth(width); + }); + return this; + } + + public CWireframe setBlock(BlockData blockData) { + getEntitiesByType(CLine.class).forEach(haaLine -> { + haaLine.setBlock(blockData); + }); + return this; + } + + private void updateAndSpawnLines() { + if (pos1 == null || pos2 == null) return; + + World world = pos1.getWorld(); + Vector min = Vector.getMinimum(pos1.toVector(), pos2.toVector()); + Vector max = Vector.getMaximum(pos1.toVector(), pos2.toVector()) + .add(new Vector(1 - width, 1 - width, 1 - width)); + + List lines = getEntitiesByType(CLine.class); + lines.forEach(line -> line.setFrom(null).setTo(null)); + + lines.get(0).setFrom(new Vector(min.getX(), min.getY(), min.getZ()).toLocation(world)).setTo(new Vector(max.getX() + width, min.getY(), min.getZ()).toLocation(world)); + lines.get(1).setFrom(new Vector(min.getX(), max.getY(), min.getZ()).toLocation(world)).setTo(new Vector(max.getX() + width, max.getY(), min.getZ()).toLocation(world)); + lines.get(2).setFrom(new Vector(min.getX(), min.getY(), max.getZ()).toLocation(world)).setTo(new Vector(max.getX() + width, min.getY(), max.getZ()).toLocation(world)); + lines.get(3).setFrom(new Vector(min.getX(), max.getY(), max.getZ()).toLocation(world)).setTo(new Vector(max.getX() + width, max.getY(), max.getZ()).toLocation(world)); + + lines.get(4).setFrom(new Vector(min.getX(), min.getY(), min.getZ()).toLocation(world)).setTo(new Vector(min.getX(), max.getY() + width, min.getZ()).toLocation(world)); + lines.get(5).setFrom(new Vector(max.getX(), min.getY(), min.getZ()).toLocation(world)).setTo(new Vector(max.getX(), max.getY() + width, min.getZ()).toLocation(world)); + lines.get(6).setFrom(new Vector(min.getX(), min.getY(), max.getZ()).toLocation(world)).setTo(new Vector(min.getX(), max.getY() + width, max.getZ()).toLocation(world)); + lines.get(7).setFrom(new Vector(max.getX(), min.getY(), max.getZ()).toLocation(world)).setTo(new Vector(max.getX(), max.getY() + width, max.getZ()).toLocation(world)); + + lines.get(8).setFrom(new Vector(min.getX(), min.getY(), min.getZ()).toLocation(world)).setTo(new Vector(min.getX(), min.getY(), max.getZ() + width).toLocation(world)); + lines.get(9).setFrom(new Vector(max.getX(), min.getY(), min.getZ()).toLocation(world)).setTo(new Vector(max.getX(), min.getY(), max.getZ() + width).toLocation(world)); + lines.get(10).setFrom(new Vector(min.getX(), max.getY(), min.getZ()).toLocation(world)).setTo(new Vector(min.getX(), max.getY(), max.getZ() + width).toLocation(world)); + lines.get(11).setFrom(new Vector(max.getX(), max.getY(), min.getZ()).toLocation(world)).setTo(new Vector(max.getX(), max.getY(), max.getZ() + width).toLocation(world)); + } +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/PacketConstructor.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/PacketConstructor.java new file mode 100644 index 00000000..6fe49aa8 --- /dev/null +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/PacketConstructor.java @@ -0,0 +1,29 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2025 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.entity; + +import de.steamwar.core.Core; +import de.steamwar.core.VersionDependent; + +public interface PacketConstructor { + public static final PacketConstructor impl = VersionDependent.getVersionImpl(Core.getInstance()); + + Object teleportPacket(int entityId, double x, double y, double z, float yaw, float pitch); +} diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RBlockDisplay.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RBlockDisplay.java index 5f4c4d50..3a00ae9c 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RBlockDisplay.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RBlockDisplay.java @@ -21,6 +21,7 @@ package de.steamwar.entity; import de.steamwar.Reflection; import de.steamwar.core.BountifulWrapper; +import de.steamwar.core.Core; import lombok.Getter; import org.bukkit.Location; import org.bukkit.Material; @@ -59,7 +60,7 @@ public class RBlockDisplay extends RDisplay { private static final Class iBlockDataClass = Reflection.getClass("net.minecraft.world.level.block.state.BlockState"); private static final Reflection.Method getState = Reflection.getTypedMethod(Reflection.getClass("org.bukkit.craftbukkit.block.data.CraftBlockData"), "getState", iBlockDataClass); - private static final Object blockWatcher = BountifulWrapper.impl.getDataWatcherObject(22, iBlockDataClass); + private static final Object blockWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 23 : 22, iBlockDataClass); private void getBlock(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || !block.getAsString(true).equals(DEFAULT_BLOCK.getAsString(true))) { packetSink.accept(blockWatcher, getState.invoke(block)); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RDisplay.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RDisplay.java index 863dc658..d176054d 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RDisplay.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RDisplay.java @@ -20,6 +20,7 @@ package de.steamwar.entity; import de.steamwar.core.BountifulWrapper; +import de.steamwar.core.Core; import lombok.Getter; import lombok.NonNull; import org.bukkit.Color; @@ -110,10 +111,10 @@ public abstract class RDisplay extends REntity { sendPacket(updatePacketSink, this::getTransformData); } - private static final Object translationWatcher = BountifulWrapper.impl.getDataWatcherObject(10, Vector3f.class); - private static final Object leftRotationWatcher = BountifulWrapper.impl.getDataWatcherObject(12, Quaternionf.class); - private static final Object scaleWatcher = BountifulWrapper.impl.getDataWatcherObject(11, Vector3f.class); - private static final Object rightRotationWatcher = BountifulWrapper.impl.getDataWatcherObject(13, Quaternionf.class); + private static final Object translationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 11 : 10, Vector3f.class); + private static final Object leftRotationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 13 : 12, Quaternionf.class); + private static final Object scaleWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 12 : 11, Vector3f.class); + private static final Object rightRotationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 14 : 13, Quaternionf.class); private void getTransformData(boolean ignoreDefault, BiConsumer dataSink) { if (ignoreDefault || !transform.equals(DEFAULT_TRANSFORM)) { @@ -129,8 +130,8 @@ public abstract class RDisplay extends REntity { sendPacket(updatePacketSink, this::getInterpolationDuration); } - private static final Object transformationInterpolationDurationWatcher = BountifulWrapper.impl.getDataWatcherObject(8, Integer.class); - private static final Object positionOrRotationInterpolationDurationWatcher = BountifulWrapper.impl.getDataWatcherObject(9, Integer.class); + private static final Object transformationInterpolationDurationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 9 : 8, Integer.class); + private static final Object positionOrRotationInterpolationDurationWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 10 : 9, Integer.class); private void getInterpolationDuration(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || interpolationDelay != 0) { @@ -144,7 +145,7 @@ public abstract class RDisplay extends REntity { sendPacket(updatePacketSink, this::getViewRange); } - private static final Object viewRangeWatcher = BountifulWrapper.impl.getDataWatcherObject(16, Float.class); + private static final Object viewRangeWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 17 : 16, Float.class); private void getViewRange(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || viewRange != 1.0F) { @@ -157,7 +158,7 @@ public abstract class RDisplay extends REntity { sendPacket(updatePacketSink, this::getShadowRadius); } - private static final Object shadowRadiusWatcher = BountifulWrapper.impl.getDataWatcherObject(17, Float.class); + private static final Object shadowRadiusWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 18 : 17, Float.class); private void getShadowRadius(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || shadowRadius != 0.0F) { @@ -170,7 +171,7 @@ public abstract class RDisplay extends REntity { sendPacket(updatePacketSink, this::getShadowStrength); } - private static final Object shadowStrengthWatcher = BountifulWrapper.impl.getDataWatcherObject(18, Float.class); + private static final Object shadowStrengthWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 19 : 18, Float.class); private void getShadowStrength(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || shadowStrength != 1.0F) { @@ -183,7 +184,7 @@ public abstract class RDisplay extends REntity { sendPacket(updatePacketSink, this::getDisplayWidth); } - private static final Object displayWidthWatcher = BountifulWrapper.impl.getDataWatcherObject(19, Float.class); + private static final Object displayWidthWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 20 : 19, Float.class); private void getDisplayWidth(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || displayWidth != 0.0F) { @@ -196,7 +197,7 @@ public abstract class RDisplay extends REntity { sendPacket(updatePacketSink, this::getDisplayHeight); } - private static final Object displayHeightWatcher = BountifulWrapper.impl.getDataWatcherObject(20, Float.class); + private static final Object displayHeightWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 21 : 20, Float.class); private void getDisplayHeight(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || displayHeight != 0.0F) { @@ -209,7 +210,7 @@ public abstract class RDisplay extends REntity { sendPacket(updatePacketSink, this::getInterpolationDelay); } - private static final Object interpolationDelayWatcher = BountifulWrapper.impl.getDataWatcherObject(7, Integer.class); + private static final Object interpolationDelayWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 8 : 7, Integer.class); private void getInterpolationDelay(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || interpolationDelay != 0) { @@ -222,7 +223,7 @@ public abstract class RDisplay extends REntity { sendPacket(updatePacketSink, this::getBillboard); } - private static final Object billboardWatcher = BountifulWrapper.impl.getDataWatcherObject(14, Byte.class); + private static final Object billboardWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 15 : 14, Byte.class); private void getBillboard(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || billboard != Display.Billboard.FIXED) { @@ -235,7 +236,7 @@ public abstract class RDisplay extends REntity { sendPacket(updatePacketSink, this::getGlowColorOverride); } - private static final Object glowColorOverrideWatcher = BountifulWrapper.impl.getDataWatcherObject(21, Integer.class); + private static final Object glowColorOverrideWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 22 : 21, Integer.class); private void getGlowColorOverride(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || glowColorOverride != null) { @@ -248,7 +249,7 @@ public abstract class RDisplay extends REntity { sendPacket(updatePacketSink, this::getBrightness); } - private static final Object brightnessWatcher = BountifulWrapper.impl.getDataWatcherObject(15, Integer.class); + private static final Object brightnessWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 16 : 15, Integer.class); private void getBrightness(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || brightness != null) { diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/REntity.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/REntity.java index 0c02a889..a27e6f5e 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/REntity.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/REntity.java @@ -397,6 +397,10 @@ public class REntity { public static final Reflection.Field teleportEntity = Reflection.getField(teleportPacket, int.class, 0); public static final BountifulWrapper.PositionSetter teleportPosition = BountifulWrapper.impl.getPositionSetter(teleportPacket, Core.getVersion() == 8 ? 1 : 0); private Object getTeleportPacket(){ + if (Core.getVersion() >= 21) { + return PacketConstructor.impl.teleportPacket(entityId, x, y, z, pitch, yaw); + } + Object packet = Reflection.newInstance(teleportPacket); teleportEntity.set(packet, entityId); teleportPosition.set(packet, x, y, z, pitch, yaw); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/REntityServer.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/REntityServer.java index d5ced550..2a9a2a13 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/REntityServer.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/REntityServer.java @@ -54,7 +54,8 @@ public class REntityServer implements Listener { private static final Function getEntityAction; static { if(Core.getVersion() > 15) { - Reflection.Method useEntityGetAction = Reflection.getMethod(useEntityEnumAction, "a"); + Class useEntityEnumActionType = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundInteractPacket$ActionType"); + Reflection.Method useEntityGetAction = Reflection.getTypedMethod(useEntityEnumAction, null, useEntityEnumActionType); getEntityAction = value -> ((Enum) useEntityGetAction.invoke(value)).ordinal(); } else { getEntityAction = value -> ((Enum) value).ordinal(); @@ -291,10 +292,8 @@ public class REntityServer implements Listener { } public void tick() { - for(HashSet entitiesInChunk : entities.values()) { - for(REntity entity : entitiesInChunk) { - entity.tick(); - } + for (REntity entity : entityMap.values()) { + entity.tick(); } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RItemDisplay.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RItemDisplay.java index 52cbfc31..45889637 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RItemDisplay.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RItemDisplay.java @@ -20,6 +20,7 @@ package de.steamwar.entity; import de.steamwar.core.BountifulWrapper; +import de.steamwar.core.Core; import de.steamwar.core.ProtocolWrapper; import lombok.Getter; import org.bukkit.Location; @@ -60,14 +61,14 @@ public class RItemDisplay extends RDisplay { sendPacket(updatePacketSink, this::getItemStack); } - private static final Object itemStackWatcher = BountifulWrapper.impl.getDataWatcherObject(22, ProtocolWrapper.itemStack); + private static final Object itemStackWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 23 : 22, ProtocolWrapper.itemStack); private void getItemStack(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || !itemStack.equals(DEFAULT_ITEM_STACK)) { packetSink.accept(itemStackWatcher, asNMSCopy.invoke(null, itemStack)); } } - private static final Object itemDisplayTransformWatcher = BountifulWrapper.impl.getDataWatcherObject(23, Byte.class); + private static final Object itemDisplayTransformWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 24 : 23, Byte.class); public void setItemDisplayTransform(ItemDisplay.ItemDisplayTransform itemDisplayTransform) { this.itemDisplayTransform = itemDisplayTransform; sendPacket(updatePacketSink, this::getItemDisplayTransform); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RPlayer.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RPlayer.java index b4aaa3ee..0c383bfd 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RPlayer.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RPlayer.java @@ -19,12 +19,16 @@ package de.steamwar.entity; -import de.steamwar.Reflection; import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import de.steamwar.Reflection; import de.steamwar.core.BountifulWrapper; import de.steamwar.core.Core; import de.steamwar.core.FlatteningWrapper; import de.steamwar.core.ProtocolWrapper; +import de.steamwar.network.CoreNetworkHandler; +import de.steamwar.network.NetworkSender; +import de.steamwar.network.packets.common.PlayerSkinRequestPacket; import lombok.Getter; import org.bukkit.GameMode; import org.bukkit.Location; @@ -36,7 +40,6 @@ import java.util.UUID; import java.util.function.Consumer; import java.util.function.Function; -@Getter public class RPlayer extends REntity { private static int skinPartsIndex() { @@ -61,17 +64,38 @@ public class RPlayer extends REntity { private static final Object skinPartsDataWatcher = BountifulWrapper.impl.getDataWatcherObject(skinPartsIndex(), Byte.class); + @Getter + private final UUID actualUUID; + @Getter private final String name; public RPlayer(REntityServer server, UUID uuid, String name, Location location) { - super(server, EntityType.PLAYER, uuid, location,0); + super(server, EntityType.PLAYER, UUID.randomUUID(), location,0); + this.actualUUID = uuid; this.name = name; server.addEntity(this); } + private GameProfile getGameProfile() { + Property skinData = CoreNetworkHandler.SKIN_DATA_PROMISES.computeIfAbsent(actualUUID, __ -> { + NetworkSender.sendOrQueue(new PlayerSkinRequestPacket(actualUUID)); + return new Property("textures", null, null); + }); + if (skinData.getValue() != null) { + GameProfile gameProfile = new GameProfile(uuid, name); + gameProfile.getProperties().put("textures", skinData); + return gameProfile; + } else { + return new GameProfile(actualUUID, name); + } + } + + private GameProfile saved; + @Override void list(Consumer packetSink) { - packetSink.accept(ProtocolWrapper.impl.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.ADD, new GameProfile(uuid, name), GameMode.CREATIVE)); + saved = getGameProfile(); + packetSink.accept(ProtocolWrapper.impl.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.ADD, saved, GameMode.CREATIVE)); } @Override @@ -88,7 +112,8 @@ public class RPlayer extends REntity { @Override void delist(Consumer packetSink) { - packetSink.accept(ProtocolWrapper.impl.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.REMOVE, new GameProfile(uuid, name), GameMode.CREATIVE)); + if (saved == null) saved = getGameProfile(); + packetSink.accept(ProtocolWrapper.impl.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.REMOVE, saved, GameMode.CREATIVE)); } private static final Class namedSpawnPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundAddPlayerPacket"); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RTextDisplay.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RTextDisplay.java index 605b6770..38a10bd6 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RTextDisplay.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/entity/RTextDisplay.java @@ -22,6 +22,7 @@ package de.steamwar.entity; import de.steamwar.Reflection; import de.steamwar.core.BountifulWrapper; import de.steamwar.core.ChatWrapper; +import de.steamwar.core.Core; import lombok.Getter; import org.bukkit.Location; import org.bukkit.entity.EntityType; @@ -74,7 +75,7 @@ public class RTextDisplay extends RDisplay { } private static final Class iChatBaseComponent = Reflection.getClass("net.minecraft.network.chat.Component"); - private static final Object textWatcher = BountifulWrapper.impl.getDataWatcherObject(22, iChatBaseComponent); + private static final Object textWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 23 : 22, iChatBaseComponent); private void getText(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || !text.isEmpty()) { packetSink.accept(textWatcher, ChatWrapper.impl.stringToChatComponent(text)); @@ -86,7 +87,7 @@ public class RTextDisplay extends RDisplay { sendPacket(updatePacketSink, this::getLineWidth); } - private static final Object lineWidthWatcher = BountifulWrapper.impl.getDataWatcherObject(23, Integer.class); + private static final Object lineWidthWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 24 : 23, Integer.class); private void getLineWidth(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || lineWidth != 200) { packetSink.accept(lineWidthWatcher, lineWidth); @@ -98,7 +99,7 @@ public class RTextDisplay extends RDisplay { sendPacket(updatePacketSink, this::getTextOpacity); } - private static final Object textOpacityWatcher = BountifulWrapper.impl.getDataWatcherObject(25, Byte.class); + private static final Object textOpacityWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 26 : 25, Byte.class); private void getTextOpacity(boolean ignoreDefault, BiConsumer packetSink) { if (ignoreDefault || textOpacity != (byte) -1) { packetSink.accept(textOpacityWatcher, textOpacity); @@ -125,7 +126,7 @@ public class RTextDisplay extends RDisplay { sendPacket(updatePacketSink, this::getTextStatus); } - private static final Object textStatusWatcher = BountifulWrapper.impl.getDataWatcherObject(26, Byte.class); + private static final Object textStatusWatcher = BountifulWrapper.impl.getDataWatcherObject(Core.getVersion() >= 21 ? 27 : 26, Byte.class); private void getTextStatus(boolean ignoreDefault, BiConsumer packetSink) { byte status = 0; diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWInventory.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWInventory.java index 001fae9f..1b4529d3 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWInventory.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWInventory.java @@ -20,7 +20,9 @@ package de.steamwar.inventory; import de.steamwar.core.Core; -import de.steamwar.core.TrickyTrialsWrapper; +import de.steamwar.providers.BauServerInfo; +import de.steamwar.sql.AuditLog; +import de.steamwar.sql.SteamwarUser; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -145,6 +147,7 @@ public class SWInventory implements Listener { Bukkit.getPluginManager().registerEvents(this, Core.getInstance()); open = true; } + AuditLog.createGuiOpen(Core.getServerName(), BauServerInfo.getOwnerUser(), SteamwarUser.get(player.getUniqueId()), title); } @EventHandler @@ -156,6 +159,7 @@ public class SWInventory implements Listener { e.setCancelled(true); Core.getInstance().getLogger().info("[SWINV] " + e.getWhoClicked().getName() + " " + e.getClick().name() + " clicked " + e.getRawSlot() + " on " + (e.getCurrentItem() != null ? e.getCurrentItem().getItemMeta().getDisplayName() : "[EMPTY]") + " in " + e.getView().getTitle()); callbacks.get(e.getRawSlot()).accept(e); + AuditLog.createGuiClick(Core.getServerName(), BauServerInfo.getOwnerUser(), SteamwarUser.get(player.getUniqueId()), e.getView().getTitle(), e.getClick().name(), e.getRawSlot(), (e.getCurrentItem() != null ? e.getCurrentItem().getItemMeta().getDisplayName() : "[EMPTY]")); } } @@ -167,8 +171,10 @@ public class SWInventory implements Listener { InventoryClickEvent.getHandlerList().unregister(this); InventoryCloseEvent.getHandlerList().unregister(this); Core.getInstance().getLogger().info("[SWINV] " + player.getName() + " closed " + title); - if(callbacks.containsKey(-1)) + if(callbacks.containsKey(-1)) { callbacks.get(-1).accept(null); + } open = false; + AuditLog.createGuiClose(Core.getServerName(), BauServerInfo.getOwnerUser(), SteamwarUser.get(player.getUniqueId()), title); } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java index 1f9c9813..b368332d 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java @@ -142,65 +142,82 @@ public class SWItem { loreArray.forEach(jsonElement -> lore.add(jsonElement.getAsString())); item.setLore(lore); } + + if (itemJson.has("customModelData")) + item.setCustomModelData(itemJson.get("customModelData").getAsInt()); return item; } - private void hideAttributes() { - if (itemMeta == null) return; + private SWItem hideAttributes() { + if (itemMeta == null) return this; for (ItemFlag flag : EnumSet.allOf(ItemFlag.class)) { itemMeta.addItemFlags(flag); } + return this; } public ItemStack getItemStack() { return itemStack; } - public void setItemStack(ItemStack itemStack) { + public SWItem setItemStack(ItemStack itemStack) { this.itemStack = itemStack; itemMeta = itemStack.getItemMeta(); hideAttributes(); + return this; } public ItemMeta getItemMeta() { return itemMeta; } - public void setItemMeta(ItemMeta itemMeta) { + public SWItem setItemMeta(ItemMeta itemMeta) { this.itemMeta = itemMeta; itemStack.setItemMeta(itemMeta); hideAttributes(); + return this; } public InvCallback getCallback() { return callback; } - public void setCallback(InvCallback callback) { + public SWItem setCallback(InvCallback callback) { this.callback = callback; + return this; } - public void setName(String name) { + public SWItem setName(String name) { itemMeta.setDisplayName(name); itemStack.setItemMeta(itemMeta); + return this; } - public void setLore(List lore) { + public SWItem setLore(List lore) { itemMeta.setLore(lore); itemStack.setItemMeta(itemMeta); + return this; } - public void setLore(String... lore) { + public SWItem setLore(String... lore) { itemMeta.setLore(Arrays.stream(lore).collect(Collectors.toList())); itemStack.setItemMeta(itemMeta); + return this; } - public void setEnchanted(boolean enchanted) { + public SWItem setEnchanted(boolean enchanted) { if (enchanted){ itemMeta.addEnchant(TrickyTrialsWrapper.impl.getUnbreakingEnchantment() , 10, true); } else { itemMeta.removeEnchant(TrickyTrialsWrapper.impl.getUnbreakingEnchantment()); } itemStack.setItemMeta(itemMeta); + return this; + } + + public SWItem setCustomModelData(int customModelData) { + itemMeta.setCustomModelData(customModelData); + itemStack.setItemMeta(itemMeta); + return this; } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWListInv.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWListInv.java index 8851081f..181d8414 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWListInv.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWListInv.java @@ -20,6 +20,7 @@ package de.steamwar.inventory; import de.steamwar.core.Core; +import de.steamwar.data.CMDs; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SchematicType; import org.bukkit.Bukkit; @@ -63,28 +64,28 @@ public class SWListInv extends SWInventory { if (sizeBiggerMax()) { if (page != 0) { - setItem(45, SWItem.getDye(10), (byte) 10, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_ACTIVE", player), (ClickType click) -> { + setItem(45, new SWItem(SWItem.getDye(10), (byte) 10, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_ACTIVE", player), (ClickType click) -> { page--; open(); - }); + }).setCustomModelData(CMDs.PREVIOUS_PAGE)); } else { - setItem(45, SWItem.getDye(8), (byte) 8, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_INACTIVE", player), (ClickType click) -> { - }); + setItem(45, new SWItem(SWItem.getDye(8), (byte) 8, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_INACTIVE", player), (ClickType click) -> { + }).setCustomModelData(CMDs.PREVIOUS_PAGE)); } if (page < elements.size() / 45 - (elements.size() % 45 == 0 ? 1 : 0)) { - setItem(53, SWItem.getDye(10), (byte) 10, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_ACTIVE", player), (ClickType click) -> { + setItem(53, new SWItem(SWItem.getDye(10), (byte) 10, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_ACTIVE", player), (ClickType click) -> { page++; open(); - }); + }).setCustomModelData(CMDs.NEXT_PAGE)); } else { - setItem(53, SWItem.getDye(8), (byte) 8, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_INACTIVE", player), (ClickType click) -> { - }); + setItem(53, new SWItem(SWItem.getDye(8), (byte) 8, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_INACTIVE", player), (ClickType click) -> { + }).setCustomModelData(CMDs.NEXT_PAGE)); } } else if (!dynamicSize) { - setItem(45, SWItem.getDye(8), (byte) 8, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_INACTIVE", player), (ClickType click) -> { - }); - setItem(53, SWItem.getDye(8), (byte) 8, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_INACTIVE", player), (ClickType click) -> { - }); + setItem(45, new SWItem(SWItem.getDye(8), (byte) 8, Core.MESSAGE.parse("SWLISINV_PREVIOUS_PAGE_INACTIVE", player), (ClickType click) -> { + }).setCustomModelData(CMDs.PREVIOUS_PAGE)); + setItem(53, new SWItem(SWItem.getDye(8), (byte) 8, Core.MESSAGE.parse("SWLISINV_NEXT_PAGE_INACTIVE", player), (ClickType click) -> { + }).setCustomModelData(CMDs.NEXT_PAGE)); } int ipageLimit = elements.size() - page * 45; diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SchematicSelector.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SchematicSelector.java index 648247bb..6d7a6201 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SchematicSelector.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SchematicSelector.java @@ -24,6 +24,7 @@ import com.google.gson.JsonObject; import com.google.gson.internal.Streams; import com.google.gson.stream.JsonReader; import de.steamwar.core.Core; +import de.steamwar.data.CMDs; import de.steamwar.sql.*; import lombok.*; import org.bukkit.Bukkit; @@ -113,7 +114,7 @@ public class SchematicSelector { List> list = new ArrayList<>(); if(depth != 0) { - list.add(new SWListInv.SWListEntry<>(new SWItem(Material.ARROW, Core.MESSAGE.parse("SCHEM_SELECTOR_BACK", player), clickType -> {}), null)); + list.add(new SWListInv.SWListEntry<>(new SWItem(Material.ARROW, Core.MESSAGE.parse("SCHEM_SELECTOR_BACK", player), clickType -> {}).setCustomModelData(CMDs.BACK), null)); } for (SchematicNode node : nodes) { @@ -124,15 +125,15 @@ public class SchematicSelector { SWListInv inv = new SWListInv<>(player, MessageFormat.format(injectable.createTitle(player), target.target.getName(player), (filter == null || filter.getName() == null)?(parent == null?"/":parent.generateBreadcrumbs()):filter.getName()), false, list, (clickType, node) -> handleClick(node, parent)); if(publicMode == PublicMode.ALL) { if(user.getId() == 0) { - inv.setItem(48, Material.BUCKET, Core.MESSAGE.parse("SCHEM_SELECTOR_OWN", player), clickType -> { + inv.setItem(48, new SWItem(Material.BUCKET, Core.MESSAGE.parse("SCHEM_SELECTOR_OWN", player), clickType -> { this.user = SteamwarUser.get(player.getUniqueId()); openList(null); - }); + }).setCustomModelData(CMDs.Schematic.OWN_SCHEMS)); } else { - inv.setItem(48, Material.GLASS, Core.MESSAGE.parse("SCHEM_SELECTOR_PUB", player), clickType -> { + inv.setItem(48, new SWItem(Material.GLASS, Core.MESSAGE.parse("SCHEM_SELECTOR_PUB", player), clickType -> { this.user = SteamwarUser.get(0); openList(null); - }); + }).setCustomModelData(CMDs.Schematic.PUBLIC_SCHEMS)); } } if(target.target.dirs) { @@ -142,10 +143,10 @@ public class SchematicSelector { }); } if(user.getId() != 0) { - inv.setItem(50, Material.CHEST, Core.MESSAGE.parse("SCHEM_SELECTOR_NEW_DIR", player), clickType -> createFolderIn(parent)); + inv.setItem(50, new SWItem(Material.CHEST, Core.MESSAGE.parse("SCHEM_SELECTOR_NEW_DIR", player), clickType -> createFolderIn(parent)).setCustomModelData(CMDs.Schematic.NEW_DIR)); } - inv.setItem(51, Material.NAME_TAG, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER", player), clickType -> openFilter()); - inv.setItem(47, sorting.mat, Core.MESSAGE.parse("SCHEM_SELECTOR_SORTING", player), Arrays.asList( + inv.setItem(51, new SWItem(Material.NAME_TAG, Core.MESSAGE.parse("SCHEM_SELECTOR_FILTER", player), clickType -> openFilter()).setCustomModelData(CMDs.Schematic.FILTER)); + inv.setItem(47, new SWItem(sorting.mat, Core.MESSAGE.parse("SCHEM_SELECTOR_SORTING", player), Arrays.asList( Core.MESSAGE.parse("SCHEM_SELECTOR_SORTING_CURRENT", player, sorting.parseName(player)), Core.MESSAGE.parse("SCHEM_SELECTOR_SORTING_DIRECTION", player, Core.MESSAGE.parse(invertSorting?"SCHEM_SELECTOR_SORTING_DSC":"SCHEM_SELECTOR_SORTING_ASC", player)) ), invertSorting, click -> { @@ -155,7 +156,7 @@ public class SchematicSelector { invertSorting = !invertSorting; } openList(parent); - }); + }).setCustomModelData(invertSorting ? CMDs.Schematic.SORT_DESCENDING : CMDs.Schematic.SORT_ASCENDING)); injectable.onListRender(this, inv, parent); inv.open(); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/network/CoreNetworkHandler.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/network/CoreNetworkHandler.java index bf74682a..d2b9016d 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/network/CoreNetworkHandler.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/network/CoreNetworkHandler.java @@ -19,15 +19,19 @@ package de.steamwar.network; +import com.mojang.authlib.properties.Property; import de.steamwar.core.BountifulWrapper; import de.steamwar.network.handlers.InventoryHandler; import de.steamwar.network.packets.PacketHandler; +import de.steamwar.network.packets.common.PlayerSkinResponsePacket; import de.steamwar.network.packets.server.*; import de.steamwar.sql.BauweltMember; import de.steamwar.sql.SteamwarUser; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.UUID; public class CoreNetworkHandler extends PacketHandler { @@ -68,4 +72,17 @@ public class CoreNetworkHandler extends PacketHandler { public void handleLocaleChange(LocaleInvalidationPacket packet) { SteamwarUser.invalidate(packet.getPlayerId()); } + + public static final Map SKIN_DATA_PROMISES = new LinkedHashMap() { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > 100; + } + }; + + @Handler + public void handlePlayerSkinResponse(PlayerSkinResponsePacket packet) { + if (!SKIN_DATA_PROMISES.containsKey(packet.getUuid())) return; + SKIN_DATA_PROMISES.put(packet.getUuid(), new Property("textures", packet.getSkin(), packet.getSignature())); + } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/network/NetworkSender.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/network/NetworkSender.java index 10a387d8..197efd64 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/network/NetworkSender.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/network/NetworkSender.java @@ -24,8 +24,42 @@ import de.steamwar.network.packets.NetworkPacket; import lombok.SneakyThrows; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; -public class NetworkSender { +import java.util.ArrayList; +import java.util.List; + +public class NetworkSender implements Listener { + + private static List queued = new ArrayList<>(); + + static { + Bukkit.getPluginManager().registerEvents(new NetworkSender(), Core.getInstance()); + } + + private NetworkSender() { + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + if (Bukkit.getOnlinePlayers().size() > 1) { + return; + } + Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> { + queued.forEach(NetworkSender::send); + queued.clear(); + }, 1); + } + + public static void sendOrQueue(NetworkPacket packet) { + if (!Bukkit.getOnlinePlayers().isEmpty()) { + send(packet); + } else { + queued.add(packet); + } + } public static void send(NetworkPacket packet) { Bukkit.getOnlinePlayers().stream().findAny().ifPresent(player -> send(packet, player)); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/providers/BauServerInfo.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/providers/BauServerInfo.java index ddc7839e..309db835 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/providers/BauServerInfo.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/providers/BauServerInfo.java @@ -19,6 +19,7 @@ package de.steamwar.providers; +import de.steamwar.sql.SteamwarUser; import org.bukkit.Bukkit; public class BauServerInfo { @@ -37,4 +38,9 @@ public class BauServerInfo { public static boolean isBauServer() { return bauOwner != null; } + + public static SteamwarUser getOwnerUser() { + if (bauOwner == null) return null; + return SteamwarUser.get(bauOwner); + } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java index 5ab944dc..53cb261d 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java @@ -47,11 +47,25 @@ public class SchematicData { private final NodeData data; public SchematicData(SchematicNode node) { - this.data = NodeData.get(node); + this.data = NodeData.getLatest(node); if(node.isDir()) throw new SecurityException("Node is Directory"); } + public SchematicData(SchematicNode node, int revision) { + if(node.isDir()) + throw new SecurityException("Node is Directory"); + + if (revision < 1) { + this.data = NodeData.getLatest(node); + } else { + if (NodeData.getRevisions(node) < revision) { + throw new IllegalArgumentException("Revision " + revision + " does not exist"); + } + this.data = NodeData.get(node, revision); + } + } + public Clipboard load() throws IOException, NoClipboardException { return WorldEditWrapper.impl.getClipboard(data.schemData(), data.getNodeFormat()); } @@ -60,12 +74,12 @@ public class SchematicData { WorldEditWrapper.impl.setPlayerClipboard(player, data.schemData(), data.getNodeFormat()); } - public void saveFromPlayer(Player player) throws IOException, NoClipboardException { - data.saveFromStream(WorldEditWrapper.impl.getPlayerClipboard(player), WorldEditWrapper.impl.getNativeFormat()); + public static void saveFromPlayer(Player player, SchematicNode node) throws IOException, NoClipboardException { + NodeData.saveFromStream(node, WorldEditWrapper.impl.getPlayerClipboard(player), WorldEditWrapper.impl.getNativeFormat()); } @Deprecated - public void saveFromBytes(byte[] bytes, NodeData.SchematicFormat newFormat) { - data.saveFromStream(new ByteArrayInputStream(bytes), newFormat); + public static void saveFromBytes(SchematicNode node, byte[] bytes, NodeData.SchematicFormat newFormat) { + NodeData.saveFromStream(node, new ByteArrayInputStream(bytes), newFormat); } } diff --git a/TNTLeague/src/de/steamwar/tntleague/config/TNTLeagueConfig.kt b/TNTLeague/src/de/steamwar/tntleague/config/TNTLeagueConfig.kt index a44fe7d5..861eff6c 100644 --- a/TNTLeague/src/de/steamwar/tntleague/config/TNTLeagueConfig.kt +++ b/TNTLeague/src/de/steamwar/tntleague/config/TNTLeagueConfig.kt @@ -63,7 +63,7 @@ data class TNTLeagueConfig( blueTeam = TeamConfig(TNTLeagueWorldConfig.blueTeam, SubMessage("PLAIN_STRING", "§${eventTeamBlue.teamColor}${eventTeamBlue.teamName}"), eventTeamBlue.teamColor[0]) redTeam = TeamConfig(TNTLeagueWorldConfig.redTeam, SubMessage("PLAIN_STRING", "§${eventTeamRed.teamColor}${eventTeamRed.teamName}"), eventTeamRed.teamColor[0]) } else { - blueTeam = TeamConfig(TNTLeagueWorldConfig.blueTeam, SubMessage("BLUE"), '3') + blueTeam = TeamConfig(TNTLeagueWorldConfig.blueTeam, SubMessage("BLUE"), '9') redTeam = TeamConfig(TNTLeagueWorldConfig.redTeam, SubMessage("RED"), 'c') } } diff --git a/Teamserver/src/de/steamwar/teamserver/Builder.java b/Teamserver/src/de/steamwar/teamserver/Builder.java index 137906ad..55aeed2d 100644 --- a/Teamserver/src/de/steamwar/teamserver/Builder.java +++ b/Teamserver/src/de/steamwar/teamserver/Builder.java @@ -19,6 +19,7 @@ package de.steamwar.teamserver; +import de.steamwar.core.WorldEditRendererCUIEditor; import de.steamwar.message.Message; import de.steamwar.teamserver.command.*; import de.steamwar.teamserver.listener.AxiomHandshakeListener; @@ -58,6 +59,7 @@ public final class Builder extends JavaPlugin { Bukkit.getPluginManager().registerEvents(materialCommand, this); Bukkit.getWorlds().get(0).setGameRule(GameRule.REDUCED_DEBUG_INFO, false); + new WorldEditRendererCUIEditor(); } @Override diff --git a/Teamserver/src/de/steamwar/teamserver/command/MaterialCommand.java b/Teamserver/src/de/steamwar/teamserver/command/MaterialCommand.java index d5883062..808a5469 100644 --- a/Teamserver/src/de/steamwar/teamserver/command/MaterialCommand.java +++ b/Teamserver/src/de/steamwar/teamserver/command/MaterialCommand.java @@ -20,6 +20,7 @@ package de.steamwar.teamserver.command; import de.steamwar.command.SWCommand; +import de.steamwar.data.CMDs; import de.steamwar.inventory.SWAnvilInv; import de.steamwar.inventory.SWInventory; import de.steamwar.inventory.SWItem; @@ -206,9 +207,9 @@ public class MaterialCommand extends SWCommand implements Listener { private void searchGUI(Player p) { SWInventory swInventory = new SWInventory(p, 54, Builder.MESSAGE.parse("MATERIAL_SEARCH", p)); Search search = searchMap.get(p); - swInventory.setItem(45, new SWItem(Material.ARROW, Builder.MESSAGE.parse("MATERIAL_BACK", p), clickType -> { + swInventory.setItem(0, new SWItem(Material.ARROW, Builder.MESSAGE.parse("MATERIAL_BACK", p), clickType -> { materialGUI(p); - })); + }).setCustomModelData(CMDs.BACK)); swInventory.setItem(10, new SWItem(Material.NAME_TAG, Builder.MESSAGE.parse("MATERIAL_SEARCH_NAME", p) + Builder.MESSAGE.parse("MATERIAL_SEARCH_VALUE", p, search.name), clickType -> { SWAnvilInv swAnvilInv = new SWAnvilInv(p, Builder.MESSAGE.parse("MATERIAL_SEARCH_NAME", p), search.name); swAnvilInv.setCallback(s -> { diff --git a/TutorialSystem/src/de/steamwar/tutorial/TutorialSystem.java b/TutorialSystem/src/de/steamwar/tutorial/TutorialSystem.java deleted file mode 100644 index a261375f..00000000 --- a/TutorialSystem/src/de/steamwar/tutorial/TutorialSystem.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2021 SteamWar.de-Serverteam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 . - */ - -package de.steamwar.tutorial; - -import de.steamwar.tutorial.commands.BookReplaceCommand; -import de.steamwar.tutorial.commands.TutorialCommand; -import de.steamwar.tutorial.commands.UnsignCommand; -import de.steamwar.tutorial.listener.Joining; -import de.steamwar.tutorial.listener.RateSign; -import org.bukkit.plugin.java.JavaPlugin; - -public class TutorialSystem extends JavaPlugin { - - private static TutorialSystem plugin; - - @Override - public void onLoad() { - plugin = this; - } - - @Override - public void onEnable() { - new RateSign(); - new Joining(); - - new BookReplaceCommand(); - new TutorialCommand(); - new UnsignCommand(); - } - - public static TutorialSystem getPlugin() { - return plugin; - } -} diff --git a/TutorialSystem/src/de/steamwar/tutorial/commands/BookReplaceCommand.java b/TutorialSystem/src/de/steamwar/tutorial/commands/BookReplaceCommand.java deleted file mode 100644 index 46f6008f..00000000 --- a/TutorialSystem/src/de/steamwar/tutorial/commands/BookReplaceCommand.java +++ /dev/null @@ -1,48 +0,0 @@ -package de.steamwar.tutorial.commands; - -import de.steamwar.command.SWCommand; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.BookMeta; -import org.bukkit.inventory.meta.ItemMeta; - -import java.util.List; - -public class BookReplaceCommand extends SWCommand { - - public BookReplaceCommand() { - super("bookreplace"); - } - - @Register("color") - public void color(Player player) { - ItemStack itemStack = player.getInventory().getItemInMainHand(); - ItemMeta itemMeta = itemStack.getItemMeta(); - if (itemMeta instanceof BookMeta) { - BookMeta bookMeta = (BookMeta) itemMeta; - replace(bookMeta, '&', '§'); - itemStack.setItemMeta(bookMeta); - player.getInventory().setItemInMainHand(itemStack); - } - } - - @Register("uncolor") - public void uncolor(Player player) { - ItemStack itemStack = player.getInventory().getItemInMainHand(); - ItemMeta itemMeta = itemStack.getItemMeta(); - if (itemMeta instanceof BookMeta) { - BookMeta bookMeta = (BookMeta) itemMeta; - replace(bookMeta, '§', '&'); - itemStack.setItemMeta(bookMeta); - player.getInventory().setItemInMainHand(itemStack); - } - } - - private void replace(BookMeta bookMeta, char oldChar, char newChar) { - List stringList = bookMeta.getPages(); - for (int i = 0; i < stringList.size(); i++) { - String string = stringList.get(i); - bookMeta.setPage(i + 1, string.replace(oldChar, newChar)); - } - } -} diff --git a/TutorialSystem/src/de/steamwar/tutorial/commands/TutorialCommand.java b/TutorialSystem/src/de/steamwar/tutorial/commands/TutorialCommand.java deleted file mode 100644 index f3824d96..00000000 --- a/TutorialSystem/src/de/steamwar/tutorial/commands/TutorialCommand.java +++ /dev/null @@ -1,23 +0,0 @@ -package de.steamwar.tutorial.commands; - -import de.steamwar.command.SWCommand; -import de.steamwar.network.NetworkSender; -import de.steamwar.network.packets.client.ExecuteCommandPacket; -import de.steamwar.sql.SteamwarUser; -import org.bukkit.entity.Player; - -public class TutorialCommand extends SWCommand { - - public TutorialCommand() { - super("tutorial"); - } - - @Register("rate") - public void rateCommand(Player player) { - rate(player); - } - - public static void rate(Player player) { - NetworkSender.send(new ExecuteCommandPacket(SteamwarUser.get(player.getUniqueId()).getId(), "tutorial rate " + System.getProperty("tutorial"))); - } -} diff --git a/TutorialSystem/src/de/steamwar/tutorial/commands/UnsignCommand.java b/TutorialSystem/src/de/steamwar/tutorial/commands/UnsignCommand.java deleted file mode 100644 index 847db16f..00000000 --- a/TutorialSystem/src/de/steamwar/tutorial/commands/UnsignCommand.java +++ /dev/null @@ -1,21 +0,0 @@ -package de.steamwar.tutorial.commands; - -import de.steamwar.command.SWCommand; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - -public class UnsignCommand extends SWCommand { - - public UnsignCommand() { - super("unsign"); - } - - @Register - public void unsignCommand(Player p) { - ItemStack itemStack = p.getInventory().getItemInMainHand(); - if (itemStack.getType() != Material.WRITTEN_BOOK) return; - itemStack.setType(Material.WRITABLE_BOOK); - p.getInventory().setItemInMainHand(itemStack); - } -} diff --git a/TutorialSystem/src/de/steamwar/tutorial/listener/RateSign.java b/TutorialSystem/src/de/steamwar/tutorial/listener/RateSign.java deleted file mode 100644 index 01d87505..00000000 --- a/TutorialSystem/src/de/steamwar/tutorial/listener/RateSign.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2021 SteamWar.de-Serverteam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * 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 . - */ - -package de.steamwar.tutorial.listener; - -import de.steamwar.tutorial.commands.TutorialCommand; -import org.bukkit.block.BlockState; -import org.bukkit.block.Sign; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerInteractEvent; - -public class RateSign extends BasicListener { - - @EventHandler - public void onInteract(PlayerInteractEvent event) { - if(!event.hasBlock() || event.getAction() != Action.RIGHT_CLICK_BLOCK) - return; - - BlockState state = event.getClickedBlock().getState(); - if (!(state instanceof Sign)) - return; - - Sign sign = (Sign) state; - if(!"[rate]".equals(sign.getLine(0))) - return; - - Player player = event.getPlayer(); - TutorialCommand.rate(player); - } -} diff --git a/TutorialSystem/src/plugin.yml b/TutorialSystem/src/plugin.yml deleted file mode 100644 index 8534f043..00000000 --- a/TutorialSystem/src/plugin.yml +++ /dev/null @@ -1,7 +0,0 @@ -name: TutorialSystem -version: "1.0" -authors: - - Lixfel -main: de.steamwar.tutorial.TutorialSystem -depend: [SpigotCore] -api-version: "1.13" diff --git a/VelocityCore/Dependencies/build.gradle.kts b/VelocityCore/Dependencies/build.gradle.kts new file mode 100644 index 00000000..fab7a7f0 --- /dev/null +++ b/VelocityCore/Dependencies/build.gradle.kts @@ -0,0 +1,58 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2024 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +plugins { + steamwar.java + alias(libs.plugins.shadow) +} + +tasks.shadowJar { + exclude("META-INF/*") + exclude("org/sqlite/native/FreeBSD/**', 'org/sqlite/native/Mac/**', 'org/sqlite/native/Windows/**', 'org/sqlite/native/Linux-Android/**', 'org/sqlite/native/Linux-Musl/**") + exclude("org/sqlite/native/Linux/aarch64/**', 'org/sqlite/native/Linux/arm/**', 'org/sqlite/native/Linux/armv6/**', 'org/sqlite/native/Linux/armv7/**', 'org/sqlite/native/Linux/ppc64/**', 'org/sqlite/native/Linux/x86/**") + exclude("org/slf4j/**") + //https://imperceptiblethoughts.com/shadow/configuration/minimizing/ + duplicatesStrategy = DuplicatesStrategy.INCLUDE +} + +tasks.build { + finalizedBy(tasks.shadowJar) +} + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +dependencies { + compileOnly(libs.velocity) + annotationProcessor(libs.velocityapi) + + implementation(libs.jda) { + exclude(module = "opus-java") + } + + implementation(libs.sqlite) + implementation(libs.mysql) + + implementation(libs.msgpack) + implementation(libs.apolloprotos) + + implementation(libs.nbt) +} \ No newline at end of file diff --git a/VelocityCore/Dependencies/src/de/steamwar/discord/Dependencies.java b/VelocityCore/Dependencies/src/de/steamwar/discord/Dependencies.java new file mode 100644 index 00000000..f3b2a243 --- /dev/null +++ b/VelocityCore/Dependencies/src/de/steamwar/discord/Dependencies.java @@ -0,0 +1,29 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.discord; + +import com.velocitypowered.api.plugin.Plugin; + +@Plugin( + id = "depencendiesvelocitycore", + name = "DepencendiesVelocityCore" +) +public class Dependencies { +} diff --git a/VelocityCore/Persistent/src/de/steamwar/persistent/Persistent.java b/VelocityCore/Persistent/src/de/steamwar/persistent/Persistent.java index bc5fd1ed..52f764f2 100644 --- a/VelocityCore/Persistent/src/de/steamwar/persistent/Persistent.java +++ b/VelocityCore/Persistent/src/de/steamwar/persistent/Persistent.java @@ -24,9 +24,11 @@ import com.google.inject.Inject; import com.google.inject.Module; import com.google.inject.name.Names; import com.mojang.brigadier.Command; +import com.mojang.brigadier.context.CommandContext; import com.velocitypowered.api.command.BrigadierCommand; import com.velocitypowered.api.command.CommandManager; import com.velocitypowered.api.command.CommandMeta; +import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.event.EventManager; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; @@ -71,6 +73,8 @@ public class Persistent { private final Logger logger; private final Path directory; + private boolean restartQueued = false; + @Inject public Persistent(ProxyServer proxy, Logger logger, @DataDirectory Path dataDirectory) { instance = this; @@ -81,6 +85,12 @@ public class Persistent { @Subscribe public void onEnable(ProxyInitializeEvent event) { + proxy.getScheduler().buildTask(instance, () -> { + if (!restartQueued) return; + if (!proxy.getAllPlayers().isEmpty()) return; + proxy.shutdown(); + }).repeat(10, TimeUnit.SECONDS).schedule(); + proxy.getCommandManager().register( new BrigadierCommand( BrigadierCommand.literalArgumentBuilder("softreload") @@ -89,6 +99,14 @@ public class Persistent { .build() ) ); + proxy.getCommandManager().register( + new BrigadierCommand( + BrigadierCommand.literalArgumentBuilder("queuerestart") + .requires(commandSource -> commandSource.hasPermission("bungeecore.softreload")) + .executes(this::queueRestart) + .build() + ) + ); } @Subscribe @@ -97,6 +115,7 @@ public class Persistent { } public int softreload() { + restartQueued = false; PluginContainer container = null; ReloadablePlugin plugin = null; try { @@ -200,4 +219,15 @@ public class Persistent { ResourceBundle.clearCache(classLoader); classLoader.close(); } + + public int queueRestart(CommandContext context) { + if (restartQueued) { + restartQueued = false; + context.getSource().sendPlainMessage("§eRestart dequeued§8."); + } else { + restartQueued = true; + context.getSource().sendPlainMessage("§eRestart queued§8."); + } + return Command.SINGLE_SUCCESS; + } } diff --git a/VelocityCore/Persistent/src/de/steamwar/persistent/Subserver.java b/VelocityCore/Persistent/src/de/steamwar/persistent/Subserver.java index 9050255e..22d15f25 100644 --- a/VelocityCore/Persistent/src/de/steamwar/persistent/Subserver.java +++ b/VelocityCore/Persistent/src/de/steamwar/persistent/Subserver.java @@ -220,7 +220,7 @@ public class Subserver { try { if (checkpoint) { start(process.getErrorStream(), line -> line.contains("Restore finished successfully.")); - Thread.sleep(300); //Wait for port to be reopened + Thread.sleep(300); } else { start(process.getInputStream(), line -> { if (line.contains("Loading libraries, please wait")) diff --git a/VelocityCore/build.gradle.kts b/VelocityCore/build.gradle.kts index f81416a3..f290ed22 100644 --- a/VelocityCore/build.gradle.kts +++ b/VelocityCore/build.gradle.kts @@ -22,19 +22,6 @@ plugins { alias(libs.plugins.shadow) } -tasks.shadowJar { - exclude("META-INF/*") - exclude("org/sqlite/native/FreeBSD/**', 'org/sqlite/native/Mac/**', 'org/sqlite/native/Windows/**', 'org/sqlite/native/Linux-Android/**', 'org/sqlite/native/Linux-Musl/**") - exclude("org/sqlite/native/Linux/aarch64/**', 'org/sqlite/native/Linux/arm/**', 'org/sqlite/native/Linux/armv6/**', 'org/sqlite/native/Linux/armv7/**', 'org/sqlite/native/Linux/ppc64/**', 'org/sqlite/native/Linux/x86/**") - exclude("org/slf4j/**") - //https://imperceptiblethoughts.com/shadow/configuration/minimizing/ - minimize { - exclude(project(":VelocityCore")) - exclude(dependency("mysql:mysql-connector-java:.*")) - } - duplicatesStrategy = DuplicatesStrategy.INCLUDE -} - tasks.build { finalizedBy(tasks.shadowJar) } @@ -51,21 +38,10 @@ dependencies { compileOnly(libs.viavelocity) compileOnly(project(":VelocityCore:Persistent", "default")) + compileOnly(project(":VelocityCore:Dependencies", "default")) implementation(project(":CommonCore")) implementation(project(":CommandFramework")) - - implementation(libs.sqlite) - implementation(libs.mysql) - - implementation(libs.jda) { - exclude(module = "opus-java") - } - - implementation(libs.msgpack) - implementation(libs.apolloprotos) - - implementation(libs.nbt) } tasks.register("DevVelocity") { @@ -73,5 +49,6 @@ tasks.register("DevVelocity") { description = "Run a Dev Velocity" dependsOn(":VelocityCore:shadowJar") dependsOn(":VelocityCore:Persistent:jar") + dependsOn(":VelocityCore:Dependencies:shadowJar") template = "DevVelocity" } diff --git a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties index e9652e2c..71a1ac24 100644 --- a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties +++ b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties @@ -326,12 +326,15 @@ CHECK_ABORT=§aThe test operation was canceled! CHECK_NEXT=Next question CHECK_ACCEPT=Accept CHECK_DECLINE=Decline +CHECK_MARK_DECLINE=Mark Decline CHECK_RANK=§aRank {0}: {1} CHECK_RANK_HOVER=§aAccept with given rank CHECK_ACCEPTED=§aYour §e{0} {1} §ewas accepted§8! CHECK_ACCEPTED_TEAM=§7The schematic §e{0} §7from §e{1} §7is now approved! CHECK_DECLINED=§cYour §e{0} {1} §cwas declined§8: §c{2} CHECK_DECLINED_TEAM=§7The schematic §e{0} §7from §e{1} §7is now declined because §e{2}§7! +CHECK_DECLINED_QUESTIONS=§fQuestions answered declined: +CHECK_DECLINED_QUESTION_FORMAT=§c{0}: {1} #HistoricCommand HISTORIC_BROADCAST=§7Historic §e{0} §7fight by §e{1}§8! @@ -603,7 +606,7 @@ TABLIST_PHASE_WEBSITE=§8Website: https://§eSteam§8War.de TABLIST_PHASE_DISCORD=§8Discord: https://§eSteam§8War.de/discord TABLIST_FOOTER=§e{0} {1}§8ms §ePlayers§8: §7{2} TABLIST_BAU=§7§lBuild -LIST_COMMAND=§e{0}§8: §7{1} +LIST_COMMAND=§e{0}§8 [{1}]: §7{2} #EventStarter EVENT_FIGHT_BROADCAST=§eClick here §7for the fight §{0}{1} §8vs §{2}{3} diff --git a/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties b/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties index d43bd695..a25f2a0c 100644 --- a/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties +++ b/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties @@ -308,12 +308,14 @@ CHECK_ABORT=§aDer Prüfvorgang wurde abgebrochen! CHECK_NEXT=Nächste Frage CHECK_ACCEPT=Annehmen CHECK_DECLINE=Ablehnen +CHECK_MARK_DECLINE=Ablehnen Markieren CHECK_RANK=§aRang {0}: {1} CHECK_RANK_HOVER=§aMit diesem Rang freigeben CHECK_ACCEPTED=§aDein §e{0} {1} §ewurde freigegeben§8! CHECK_ACCEPTED_TEAM=§7Die Schematic §e{0} §7von §e{1} §7ist nun freigegeben! CHECK_DECLINED=§cDein §e{0} {1} §cwurde abgelehnt§8: §c{2} CHECK_DECLINED_TEAM=§7Die Schematic §e{0} §7von §e{1} §7wurde aufgrund von §e{2} §7abgelehnt! +CHECK_DECLINED_QUESTIONS=§fAls abgelehnt markierte Fragen: #HistoricCommand HISTORIC_BROADCAST=§7Historischer §e{0}§8-§7Kampf von §e{1}§8! @@ -574,11 +576,8 @@ POLL_ANSWER=§7{0} POLL_ANSWER_HOVER=§e{0} §ewählen #TablistManager -TABLIST_PHASE_WEBSITE=§8Website: https://§eSteam§8War.de -TABLIST_PHASE_DISCORD=§8Discord: https://§eSteam§8War.de/discord TABLIST_FOOTER=§e{0} {1}§8ms §eSpieler§8: §7{2} TABLIST_BAU=§7§lBau -LIST_COMMAND=§e{0}§8: §7{1} #EventStarter EVENT_FIGHT_BROADCAST=§7Hier §eklicken §7für den Kampf §{0}{1} §8vs §{2}{3} diff --git a/VelocityCore/src/de/steamwar/messages/Chatter.java b/VelocityCore/src/de/steamwar/messages/Chatter.java index 607b4fd2..5de34d0c 100644 --- a/VelocityCore/src/de/steamwar/messages/Chatter.java +++ b/VelocityCore/src/de/steamwar/messages/Chatter.java @@ -87,10 +87,11 @@ public interface Chatter { } default void withPlayerOrOffline(Consumer withPlayer, Runnable withOffline) { Player player = getPlayer(); - if(player == null) + if(player == null) { withOffline.run(); - else + } else { withPlayer.accept(player); + } } default void withPlayer(Consumer function) { withPlayerOrOffline(function, () -> {}); diff --git a/VelocityCore/src/de/steamwar/velocitycore/EventStarter.java b/VelocityCore/src/de/steamwar/velocitycore/EventStarter.java index 15c16b64..0b21cef1 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/EventStarter.java +++ b/VelocityCore/src/de/steamwar/velocitycore/EventStarter.java @@ -23,7 +23,9 @@ import de.steamwar.messages.Chatter; import de.steamwar.messages.Message; import de.steamwar.persistent.Subserver; import de.steamwar.sql.EventFight; +import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.Team; +import lombok.Getter; import net.kyori.adventure.text.event.ClickEvent; import java.sql.Timestamp; @@ -36,6 +38,7 @@ import static de.steamwar.persistent.Storage.eventServer; public class EventStarter { + @Getter private static final Map spectatePorts = new HashMap<>(); public static void addSpectateServer(int port, String command) { @@ -68,6 +71,15 @@ public class EventStarter { starter.callback(subserver -> { eventServer.put(blue.getTeamId(), subserver); eventServer.put(red.getTeamId(), subserver); + + if (VelocityCore.get().getConfig().isEventmode()) { + VelocityCore.getProxy().getAllPlayers().forEach(player -> { + SteamwarUser user = SteamwarUser.get(player.getUniqueId()); + if (user.getTeam() == blue.getTeamId() || user.getTeam() == red.getTeamId()) { + subserver.sendPlayer(player); + } + }); + } }).start(); command = "/event " + blue.getTeamKuerzel(); @@ -76,6 +88,7 @@ public class EventStarter { } Chatter.broadcast().system("EVENT_FIGHT_BROADCAST", new Message("EVENT_FIGHT_BROADCAST_HOVER"), ClickEvent.runCommand(command), blue.getTeamColor(), blue.getTeamName(), red.getTeamColor(), red.getTeamName()); } + EventFight.clearActiveFightsCache(); } private EventFight nextFight(Queue fights){ diff --git a/VelocityCore/src/de/steamwar/velocitycore/ServerStarter.java b/VelocityCore/src/de/steamwar/velocitycore/ServerStarter.java index 56620468..058771e7 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/ServerStarter.java +++ b/VelocityCore/src/de/steamwar/velocitycore/ServerStarter.java @@ -52,7 +52,6 @@ public class ServerStarter { public static final String TEMP_WORLD_PATH = TMP_DATA + "arenaserver/"; private static final String WORLDS_FOLDER = "/worlds"; - public static final String TUTORIAL_PATH = WORLDS_FOLDER + "/tutorials/"; public static final String WORLDS_BASE_PATH = WORLDS_FOLDER + "/userworlds"; public static final String BUILDER_BASE_PATH = WORLDS_FOLDER + "/builder"; @@ -194,15 +193,6 @@ public class ServerStarter { return this; } - public ServerStarter tutorial(Player owner, Tutorial tutorial) { - version = ServerVersion.SPIGOT_15; - directory = new File(SERVER_PATH, "Tutorial"); - buildWithTemp(owner); - tempWorld(TUTORIAL_PATH + tutorial.getTutorialId()); - arguments.put("tutorial", String.valueOf(tutorial.getTutorialId())); - return send(owner); - } - private void tempWorld(String template) { worldDir = TEMP_WORLD_PATH; worldSetup = () -> copyWorld(node, template, worldDir + worldName); @@ -286,6 +276,7 @@ public class ServerStarter { int port = portrange.freePort(); String serverName = serverNameProvider.apply(port); + arguments.put("serverName", serverName); if(node == null) { node = Node.getNode(); diff --git a/VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java b/VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java index d8952118..42c02fe5 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java +++ b/VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java @@ -44,15 +44,14 @@ public enum ServerVersion { PAPER_18("paper-1.18.2.jar", 15, ProtocolVersion.MINECRAFT_1_18_2), PAPER_19("paper-1.19.3.jar", 19, ProtocolVersion.MINECRAFT_1_19_3), PAPER_20("paper-1.20.1.jar", 20, ProtocolVersion.MINECRAFT_1_20), - DEVEL_21("paper-1.21.5.jar", 21, ProtocolVersion.MINECRAFT_1_21_5), - PAPER_21("paper-1.21.3.jar", 21, ProtocolVersion.MINECRAFT_1_21_2); + PAPER_21("paper-1.21.6.jar", 21, ProtocolVersion.MINECRAFT_1_21_6); private static final Map chatMap = new HashMap<>(); static { chatMap.put("21", ServerVersion.PAPER_21); chatMap.put("1.21", ServerVersion.PAPER_21); - chatMap.put("1.21.3", ServerVersion.PAPER_21); + chatMap.put("1.21.6", ServerVersion.PAPER_21); chatMap.put("20", ServerVersion.PAPER_20); chatMap.put("1.20", ServerVersion.PAPER_20); @@ -95,10 +94,6 @@ public enum ServerVersion { } public static ServerVersion get(int version) { - if (version == 21) { - return DEVEL_21; - } - return versionMap.get(version); } diff --git a/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java b/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java index 3cec098b..aa98a034 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java +++ b/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java @@ -60,7 +60,7 @@ import java.util.logging.Logger; @Plugin( id = "velocitycore", name = "VelocityCore", - dependencies = { @Dependency(id = "persistentvelocitycore") } + dependencies = { @Dependency(id = "persistentvelocitycore"), @Dependency(id = "depencendiesvelocitycore") } ) public class VelocityCore implements ReloadablePlugin { @@ -153,6 +153,7 @@ public class VelocityCore implements ReloadablePlugin { new CheckListener(); new IPSanitizer(); new VersionAnnouncer(); + new TexturePackSystem(); local = new Node.LocalNode(); if(MAIN_SERVER) { @@ -214,16 +215,16 @@ public class VelocityCore implements ReloadablePlugin { new ChallengeCommand(); new HistoricCommand(); new ReplayCommand(); - new TutorialCommand(); new Broadcaster(); + new CookieEvents(); }else{ new EventModeListener(); } for(PacketHandler handler : new PacketHandler[] { new EloPlayerHandler(), new EloSchemHandler(), new ExecuteCommandHandler(), new FightInfoHandler(), - new ImALobbyHandler(), new InventoryCallbackHandler(), new PrepareSchemHandler() + new ImALobbyHandler(), new InventoryCallbackHandler(), new PrepareSchemHandler(), new PlayerSkinHandler() }) handler.register(); @@ -288,7 +289,7 @@ public class VelocityCore implements ReloadablePlugin { if(server.getSpectatePort() != 0) EventStarter.addSpectateServer(server.getSpectatePort(), cmd); - new ServerSwitchCommand(cmd, entry.getKey(), cmds.toArray(new String[0])); + new ServerSwitchCommand(cmd, entry.getKey(), server.getSpectatePort() != 0, cmds.toArray(new String[0])); } } } diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/CheckCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/CheckCommand.java index 189d3075..8d618600 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/commands/CheckCommand.java +++ b/VelocityCore/src/de/steamwar/velocitycore/commands/CheckCommand.java @@ -41,6 +41,7 @@ import java.time.Instant; import java.util.List; import java.util.*; import java.util.concurrent.TimeUnit; +import java.util.function.BooleanSupplier; import java.util.logging.Level; public class CheckCommand extends SWCommand { @@ -98,12 +99,11 @@ public class CheckCommand extends SWCommand { for (SchematicNode schematic : schematicList) { CheckSession current = currentSchems.get(schematic.getId()); if (current == null) { - Optional lastCheck = CheckedSchematic.getLastCheck(schematic.getId()); sender.prefixless("CHECK_LIST_TO_CHECK", - lastCheck.map(CheckedSchematic::isInvestigationPending).orElse(false) ? new Message("PLAIN_STRING", lastCheck.map(CheckedSchematic::getInvestigationPendingReason).orElseThrow()) : new Message("CHECK_LIST_TO_CHECK_HOVER"), - !lastCheck.map(CheckedSchematic::isInvestigationPending).orElse(false) || sender.user().hasPerm(UserPerm.MODERATION) ? ClickEvent.runCommand("/check schematic " + schematic.getId()) : ClickEvent.suggestCommand(""), + new Message("CHECK_LIST_TO_CHECK_HOVER"), + ClickEvent.runCommand("/check schematic " + schematic.getId()), getWaitTime(schematic), - schematic.getSchemtype().getKuerzel(), SteamwarUser.get(schematic.getOwner()).getUserName(), (lastCheck.map(CheckedSchematic::isInvestigationPending).orElse(false) ? "§c" : "") + schematic.getName()); + schematic.getSchemtype().getKuerzel(), SteamwarUser.get(schematic.getOwner()).getUserName(), schematic.getName()); } else { sender.prefixless("CHECK_LIST_CHECKING", new Message("CHECK_LIST_CHECKING_HOVER"), @@ -129,10 +129,6 @@ public class CheckCommand extends SWCommand { sender.system("CHECK_SCHEMATIC_OWN"); return; } - Optional lastCheck = CheckedSchematic.getLastCheck(schem.getId()); - if(!lastCheck.map(CheckedSchematic::isInvestigationPending).orElse(false) || sender.user().hasPerm(UserPerm.MODERATION)) { - sender.system("CHECK_SCHEMATIC_INVESTIGATION_PENDING"); - } int playerTeam = sender.user().hasPerm(UserPerm.MODERATION) ? 0 : sender.user().getTeam(); if (playerTeam != 0 && SteamwarUser.get(schem.getOwner()).getTeam() == playerTeam) { @@ -169,6 +165,14 @@ public class CheckCommand extends SWCommand { next(sender); } + @Register(value = "decline", description = "CHECK_HELP_DECLINE") + public void decline(PlayerChatter sender) { + if(notChecking(sender.getPlayer())) + return; + + currentCheckers.get(sender.getPlayer().getUniqueId()).markDeclined(); + } + @Register(value = "decline", description = "CHECK_HELP_DECLINE") public void decline(PlayerChatter sender, String... message) { if(notChecking(sender.getPlayer())) @@ -177,14 +181,6 @@ public class CheckCommand extends SWCommand { currentCheckers.get(sender.getPlayer().getUniqueId()).decline(String.join(" ", message)); } - @Register(value = "block") - public void block(PlayerChatter sender, String... message) { - if(notChecking(sender.getPlayer())) - return; - - currentCheckers.get(sender.getPlayer().getUniqueId()).block(String.join(" ", message)); - } - public static List getSchemsToCheck(){ List schematicList = new ArrayList<>(); @@ -213,6 +209,8 @@ public class CheckCommand extends SWCommand { private final SchematicNode schematic; private final Timestamp startTime; private final ListIterator checkList; + private String currentQuestion; + private final List declinedQuestions = new ArrayList<>(); private CheckSession(PlayerChatter checker, SchematicNode schematic){ this.checker = checker; @@ -225,7 +223,7 @@ public class CheckCommand extends SWCommand { currentCheckers.put(checker.user().getUUID(), this); currentSchems.put(schematic.getId(), this); - for(CheckedSchematic previous : CheckedSchematic.getLastDeclinedOfNode(schematic.getId())) + for(CheckedSchematic previous : CheckedSchematic.previousChecks(schematic)) checker.prefixless("CHECK_SCHEMATIC_PREVIOUS", previous.getEndTime(), SteamwarUser.get(previous.getValidator()).getUserName(), previous.getDeclineReason()); next(); }).start(); @@ -233,42 +231,70 @@ public class CheckCommand extends SWCommand { private void next() { if(!checkList.hasNext()){ - accept(); + if (declinedQuestions.isEmpty()) { + accept(); + } else { + checker.system("CHECK_DECLINED_QUESTIONS"); + int i = 1; + for (String s : declinedQuestions) { + checker.prefixless("CHECK_DECLINED_QUESTION_FORMAT", i++, s); + } + declinedQuestions.clear(); + checker.sendMessage(Component + .text(checker.parseToPlain("CHECK_ACCEPT")) + .color(NamedTextColor.GREEN) + .clickEvent(ClickEvent.suggestCommand("/check accept")) + .append(Component + .text(" " + checker.parseToPlain("CHECK_DECLINE")) + .color(NamedTextColor.RED) + .clickEvent(ClickEvent.suggestCommand("/check decline ")))); + } return; } - checker.prefixless("PLAIN_STRING", checkList.next()); + currentQuestion = checkList.next(); + + checker.prefixless("PLAIN_STRING", currentQuestion); checker.sendMessage(Component .text(checker.parseToPlain(checkList.hasNext() ? "CHECK_NEXT" : "CHECK_ACCEPT")) .color(NamedTextColor.GREEN) .clickEvent(ClickEvent.runCommand("/check next")) .append(Component - .text(" " + checker.parseToPlain("CHECK_DECLINE")) + .text(" " + checker.parseToPlain("CHECK_MARK_DECLINE")) .color(NamedTextColor.RED) - .clickEvent(ClickEvent.suggestCommand("/check decline ")))); + .clickEvent(ClickEvent.runCommand("/check decline")))); + } + + private void markDeclined() { + declinedQuestions.add(currentQuestion); + next(); } private void accept(){ - if(concludeCheckSession("freigegeben", fightTypes.get(schematic.getSchemtype()), false)) { + concludeCheckSession("freigegeben", fightTypes.get(schematic.getSchemtype()), () -> { Chatter owner = Chatter.of(SteamwarUser.get(schematic.getOwner()).getUUID()); owner.withPlayerOrOffline( player -> owner.system("CHECK_ACCEPTED", schematic.getSchemtype().name(), schematic.getName()), () -> DiscordAlert.send(owner, Color.GREEN, new Message("DC_TITLE_SCHEMINFO"), new Message("DC_SCHEM_ACCEPT", schematic.getName()), true) ); notifyTeam(new Message("CHECK_ACCEPTED_TEAM", schematic.getName(), owner.user().getUserName())); - } + + return owner.getPlayer() != null; + }); } private void decline(String reason){ - if(concludeCheckSession(reason, SchematicType.Normal, false)) { + concludeCheckSession(reason, SchematicType.Normal, () -> { Chatter owner = Chatter.of(SteamwarUser.get(schematic.getOwner()).getUUID()); owner.withPlayerOrOffline( player -> owner.system("CHECK_DECLINED", schematic.getSchemtype().name(), schematic.getName(), reason), () -> DiscordAlert.send(owner, Color.RED, new Message("DC_TITLE_SCHEMINFO"), new Message("DC_SCHEM_DECLINE", schematic.getName(), reason), false) ); notifyTeam(new Message("CHECK_DECLINED_TEAM", schematic.getName(), owner.user().getUserName(), reason)); - } + + return owner.getPlayer() != null; + }); } private void notifyTeam(Message message) { @@ -277,20 +303,18 @@ public class CheckCommand extends SWCommand { } private void abort(){ - concludeCheckSession("Prüfvorgang abgebrochen", null, false); + concludeCheckSession("Prüfvorgang abgebrochen", null, () -> true); } - private boolean concludeCheckSession(String reason, SchematicType type, boolean investigation) { - boolean exists = SchematicNode.getSchematicNode(schematic.getId()) != null; - - if(exists) { - if (investigation) { - CheckedSchematic.createInvestigationPending(schematic, startTime, Timestamp.from(Instant.now()), checker.user().getId(), reason); - } else { - CheckedSchematic.create(schematic, checker.user().getId(), startTime, Timestamp.from(Instant.now()), reason); - } - if(type != null) + private void concludeCheckSession(String reason, SchematicType type, BooleanSupplier sendMessageIsOnline) { + if(SchematicNode.getSchematicNode(schematic.getId()) != null) { + CheckedSchematic.create(schematic, checker.user().getId(), startTime, Timestamp.from(Instant.now()), reason, sendMessageIsOnline.getAsBoolean()); + if(type != null) { schematic.setSchemtype(type); + if (type == SchematicType.Normal) { + schematic.setPrepared(false); + } + } } remove(); @@ -299,16 +323,11 @@ public class CheckCommand extends SWCommand { if(subserver != null) subserver.stop(); }).schedule(); - return exists; } private void remove() { currentCheckers.remove(checker.user().getUUID()); currentSchems.remove(schematic.getId()); } - - public void block(String reason) { - concludeCheckSession(reason, null, true); - } } } diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/ListCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/ListCommand.java index 1505b438..dab59005 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/commands/ListCommand.java +++ b/VelocityCore/src/de/steamwar/velocitycore/commands/ListCommand.java @@ -63,7 +63,7 @@ public class ListCommand extends SWCommand { if (server.equals("Bau")) { serverName = sender.parseToLegacy("TABLIST_BAU"); } - sender.prefixless("LIST_COMMAND", serverName, playerMap.get(server).stream().map(Player::getUsername).collect(Collectors.joining(", "))); + sender.prefixless("LIST_COMMAND", serverName, playerMap.get(server).size(), playerMap.get(server).stream().map(Player::getUsername).collect(Collectors.joining(", "))); } } } diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/ServerSwitchCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/ServerSwitchCommand.java index 142c5f56..3586f150 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/commands/ServerSwitchCommand.java +++ b/VelocityCore/src/de/steamwar/velocitycore/commands/ServerSwitchCommand.java @@ -19,22 +19,41 @@ package de.steamwar.velocitycore.commands; +import java.net.InetSocketAddress; +import java.util.List; + +import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.proxy.server.RegisteredServer; import de.steamwar.velocitycore.VelocityCore; import de.steamwar.command.SWCommand; import de.steamwar.messages.PlayerChatter; +import de.steamwar.sql.EventFight; +import de.steamwar.sql.SteamwarUser; public class ServerSwitchCommand extends SWCommand { private final RegisteredServer server; + private final boolean isSpectateServer; - public ServerSwitchCommand(String cmd, String name, String... aliases) { + public ServerSwitchCommand(String cmd, String name, boolean isSpectateServer, String... aliases) { super(cmd, null, aliases); server = VelocityCore.getProxy().getServer(name).orElseThrow(); + this.isSpectateServer = isSpectateServer; } @Register public void genericCommand(PlayerChatter sender) { + if (isSpectateServer && sender.getPlayer().getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) { + SteamwarUser user = SteamwarUser.get(sender.getPlayer().getUniqueId()); + List activeFights = EventFight.getActiveFights(); + + if (activeFights.stream() + .anyMatch(fight -> fight.getTeamRed() == user.getTeam() || fight.getTeamBlue() == user.getTeam())) { + sender.getPlayer().transferToHost(new InetSocketAddress("steamwar.de", 25566)); + return; + } + } + sender.getPlayer().createConnectionRequest(server).fireAndForget(); } } diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/TutorialCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/TutorialCommand.java deleted file mode 100644 index 877b7479..00000000 --- a/VelocityCore/src/de/steamwar/velocitycore/commands/TutorialCommand.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2022 SteamWar.de-Serverteam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package de.steamwar.velocitycore.commands; - -import de.steamwar.command.SWCommand; -import de.steamwar.command.TypeValidator; -import de.steamwar.messages.Chatter; -import de.steamwar.messages.Message; -import de.steamwar.messages.PlayerChatter; -import de.steamwar.persistent.Subserver; -import de.steamwar.sql.SteamwarUser; -import de.steamwar.sql.Tutorial; -import de.steamwar.sql.UserPerm; -import de.steamwar.velocitycore.ServerStarter; -import de.steamwar.velocitycore.SubserverSystem; -import de.steamwar.velocitycore.VelocityCore; -import de.steamwar.velocitycore.inventory.SWInventory; -import de.steamwar.velocitycore.inventory.SWItem; -import de.steamwar.velocitycore.inventory.SWListInv; -import de.steamwar.velocitycore.inventory.SWStreamInv; - -import java.io.File; -import java.util.Arrays; -import java.util.concurrent.TimeUnit; - -public class TutorialCommand extends SWCommand { - - public TutorialCommand() { - super("tutorial"); - } - - @Register - public void genericCommand(PlayerChatter sender) { - openInventory(sender, true, false); - } - - @Register("rate") - public void rate(PlayerChatter sender) { - sender.getPlayer().spoofChatInput("/tutorial rate"); - } - - @Register("rate") - public void rate(PlayerChatter sender, int id) { - Tutorial tutorial = Tutorial.get(id); - if(tutorial == null) { - sender.getPlayer().spoofChatInput("/tutorial rate"); // Catch players manually entering numbers - return; - } - - rate(sender, tutorial); - } - - @Register(value = "create", description = "TUTORIAL_CREATE_HELP") - public void create(PlayerChatter sender, String material, String... name) { - create(sender, String.join(" ", name), material.toUpperCase()); - } - - @Register("own") - public void own(PlayerChatter sender) { - openInventory(sender, false, true); - } - - @Register("unreleased") - public void unreleased(@Validator("unreleased") PlayerChatter sender) { - openInventory(sender, false, false); - } - - @Validator("unreleased") - public TypeValidator unreleasedChecker() { - return (sender, value, messageSender) -> sender.user().hasPerm(UserPerm.TEAM); - } - - private void openInventory(PlayerChatter sender, boolean released, boolean own) { - SteamwarUser user = sender.user(); - - new SWStreamInv<>( - sender, - new Message("TUTORIAL_TITLE"), - (click, tutorial) -> { - if(!released && click.isShiftClick() && user.hasPerm(UserPerm.TEAM) && user.getId() != tutorial.getCreator()) { - tutorial.release(); - openInventory(sender, released, own); - return; - } else if(own && click.isShiftClick() && click.isRightClick()) { - tutorial.delete(); - SubserverSystem.deleteFolder(VelocityCore.local, world(tutorial).getPath()); - openInventory(sender, released, own); - return; - } - - new ServerStarter().tutorial(sender.getPlayer(), tutorial).start(); - }, - page -> (own ? Tutorial.getOwn(user.getId(), page, 45) : Tutorial.getPage(page, 45, released)).stream().map(tutorial -> new SWListInv.SWListEntry<>(getTutorialItem(tutorial, own), tutorial)).toList() - ).open(); - } - - private SWItem getTutorialItem(Tutorial tutorial, boolean personalHighlights) { - SWItem item = new SWItem(tutorial.getItem(), new Message("TUTORIAL_NAME", tutorial.getName())); - item.setHideAttributes(true); - - item.addLore(new Message("TUTORIAL_BY", SteamwarUser.get(tutorial.getCreator()).getUserName())); - item.addLore(new Message("TUTORIAL_STARS", String.format("%.1f", tutorial.getStars()))); - - if (personalHighlights) - item.addLore(new Message("TUTORIAL_DELETE")); - - if (personalHighlights && tutorial.isReleased()) - item.setEnchanted(true); - - return item; - } - - private void rate(PlayerChatter sender, Tutorial tutorial) { - int[] rates = new int[]{1, 2, 3, 4, 5}; - - new SWListInv<>(sender, new Message("TUTORIAL_RATE_TITLE"), Arrays.stream(rates).mapToObj(rate -> new SWListInv.SWListEntry<>(new SWItem("NETHER_STAR", new Message("TUTORIAL_RATE", rate)), rate)).toList(), (click, rate) -> { - tutorial.rate(sender.user().getId(), rate); - SWInventory.close(sender); - }).open(); - } - - private void create(PlayerChatter sender, String name, String item) { - Subserver subserver = Subserver.getSubserver(sender.getPlayer()); - SteamwarUser user = sender.user(); - File tempWorld = new File(ServerStarter.TEMP_WORLD_PATH, ServerStarter.serverToWorldName(ServerStarter.bauServerName(user))); - - if(!Subserver.isBuild(subserver) || !subserver.isStarted() || !tempWorld.exists()) { - sender.system("TUTORIAL_CREATE_MISSING"); - return; - } - - subserver.execute("save-all"); - VelocityCore.schedule(() -> { - Tutorial tutorial = Tutorial.create(user.getId(), name, item); - File tutorialWorld = world(tutorial); - - if (tutorialWorld.exists()) - SubserverSystem.deleteFolder(VelocityCore.local, tutorialWorld.getPath()); - ServerStarter.copyWorld(VelocityCore.local, tempWorld.getPath(), tutorialWorld.getPath()); - sender.system("TUTORIAL_CREATED"); - }).delay(1, TimeUnit.SECONDS).schedule(); - } - - private File world(Tutorial tutorial) { - return new File(ServerStarter.TUTORIAL_PATH, String.valueOf(tutorial.getTutorialId())); - } -} diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java index 5fcbcf6a..49b5d4f2 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/channels/DiscordChannel.java @@ -85,9 +85,9 @@ public class DiscordChannel extends Chatter.PlayerlessChatter { public void send(String message) { message = message .replace("&", "") - .replace("@everyone", "`@everyone`") - .replace("@here", "`@here`") - .replaceAll("<[@#]!?\\d+>", "`$0`"); + .replace("@everyone", "@\u200Beveryone") + .replace("@here", "@\u200Bhere") + .replaceAll("<([@#])(!?\\d+)>", "<$1\u200B$2>"); if (maxNumberOfWebhooks > 0 && getChannel() instanceof TextChannel && message.contains("»")) { String[] strings = message.split("»", 2); diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java index 4a202368..f798d3ce 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java @@ -94,7 +94,7 @@ public class DiscordSchemUpload extends ListenerAdapter { version = NodeData.SchematicFormat.MCEDIT; } - NodeData.get(node).saveFromStream(new ByteArrayInputStream(bytes), version); + NodeData.saveFromStream(node, new ByteArrayInputStream(bytes), version); sender.system("DC_SCHEMUPLOAD_SUCCESS", name); } catch (InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/VelocityCore/src/de/steamwar/velocitycore/inventory/SWItem.java b/VelocityCore/src/de/steamwar/velocitycore/inventory/SWItem.java index c2db126f..ec3b6f40 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/inventory/SWItem.java +++ b/VelocityCore/src/de/steamwar/velocitycore/inventory/SWItem.java @@ -42,6 +42,7 @@ public class SWItem { @Getter private InvCallback callback; private int color = 0; + private int customModelData = 0; public SWItem(String material, Message title) { this.material = material.toUpperCase(); @@ -64,6 +65,11 @@ public class SWItem { return this; } + public SWItem setCustomModelData(int customModelData) { + this.customModelData = customModelData; + return this; + } + public JsonObject writeToString(Chatter player, int position) { JsonObject object = new JsonObject(); object.addProperty("material", material); @@ -84,6 +90,9 @@ public class SWItem { } object.add("lore", array); } + if (customModelData > 0) { + object.addProperty("customModelData", customModelData); + } return object; } diff --git a/VelocityCore/src/de/steamwar/velocitycore/listeners/ChatListener.java b/VelocityCore/src/de/steamwar/velocitycore/listeners/ChatListener.java index 17137bf5..dfdf5c7f 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/listeners/ChatListener.java +++ b/VelocityCore/src/de/steamwar/velocitycore/listeners/ChatListener.java @@ -27,6 +27,8 @@ import com.velocitypowered.api.event.player.PlayerChatEvent; import com.velocitypowered.api.event.player.TabCompleteEvent; import com.velocitypowered.api.proxy.ConsoleCommandSource; import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.ServerConnection; +import com.velocitypowered.api.proxy.server.ServerInfo; import de.steamwar.messages.Chatter; import de.steamwar.messages.ChatterGroup; import de.steamwar.messages.Message; @@ -80,17 +82,32 @@ public class ChatListener extends BasicListener { if(VelocityCore.getProxy().getCommandManager().hasCommand(cmd)) { CommandSource source = e.getCommandSource(); String name; - if(source instanceof Player player) + SteamwarUser user = null; + if (source instanceof Player player) { + user = SteamwarUser.get(player.getUniqueId()); name = player.getUsername(); - else if(source instanceof ConsoleCommandSource) + } else if (source instanceof ConsoleCommandSource) { + user = SteamwarUser.get(-1); name = "«CONSOLE»"; - else + } else { name = source.toString(); + } if (noLogCommands.contains(cmd)) { return; } + switch (cmd) { + case "msg": + case "r": + case "tc": + AuditLog.createSensitiveCommand(AuditLog.SERVER_NAME_VELOCITY, null, user, "/" + command); + break; + default: + AuditLog.createCommand(AuditLog.SERVER_NAME_VELOCITY, null, user, "/" + command); + break; + } + cmdLogger.log(Level.INFO, "%s -> executed command /%s".formatted(name, command)); } else if (e.getCommandSource() instanceof Player player) { // System.out.println("spoofChatInput " + e); @@ -106,8 +123,8 @@ public class ChatListener extends BasicListener { e.setResult(PlayerChatEvent.ChatResult.denied()); + SteamwarUser user = SteamwarUser.get(player.getUniqueId()); if (message.contains("jndi:ldap")) { - SteamwarUser user = SteamwarUser.get(player.getUniqueId()); PunishmentCommand.ban(user, Punishment.PERMA_TIME, "Versuchte Exploit-Ausnutzung", SteamwarUser.get(-1), true); VelocityCore.getLogger().log(Level.SEVERE, "%s %s wurde automatisch wegen jndi:ldap gebannt.".formatted(user.getUserName(), user.getId())); return; @@ -117,13 +134,20 @@ public class ChatListener extends BasicListener { return; Subserver subserver = Subserver.getSubserver(player); + String serverName = AuditLog.SERVER_NAME_VELOCITY; if(Subserver.isArena(subserver) && subserver.getServer() == player.getCurrentServer().orElseThrow().getServerInfo()) { + serverName = subserver.getServer().getName(); localChat(Chatter.of(player), message); } else if (message.startsWith("+")) { + serverName = player.getCurrentServer() + .map(ServerConnection::getServerInfo) + .map(ServerInfo::getName) + .orElse(serverName); localChat(Chatter.of(player), message.substring(1)); } else { sendChat(Chatter.of(player), Chatter.globalChat(), "CHAT_GLOBAL", null, message); } + AuditLog.createChat(serverName, null, user, message); } private static boolean isMistypedCommand(Player player, String message) { diff --git a/VelocityCore/src/de/steamwar/velocitycore/listeners/ConnectionListener.java b/VelocityCore/src/de/steamwar/velocitycore/listeners/ConnectionListener.java index 95edeabb..d534b29a 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/listeners/ConnectionListener.java +++ b/VelocityCore/src/de/steamwar/velocitycore/listeners/ConnectionListener.java @@ -23,17 +23,23 @@ import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.event.connection.PostLoginEvent; import com.velocitypowered.api.event.permission.PermissionsSetupEvent; +import com.velocitypowered.api.event.player.KickedFromServerEvent; +import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.permission.Tristate; import com.velocitypowered.api.proxy.Player; import de.steamwar.messages.Chatter; import de.steamwar.messages.Message; import de.steamwar.persistent.Subserver; +import de.steamwar.sql.CheckedSchematic; +import de.steamwar.sql.SchematicType; import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.UserPerm; +import de.steamwar.velocitycore.EventStarter; import de.steamwar.velocitycore.commands.*; import de.steamwar.velocitycore.discord.DiscordBot; import de.steamwar.velocitycore.discord.util.DiscordRanks; import de.steamwar.velocitycore.mods.ModUtils; +import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import java.util.HashSet; @@ -82,12 +88,35 @@ public class ConnectionListener extends BasicListener { } } + for (CheckedSchematic checkedSchematic : CheckedSchematic.getUnseen(user)) { + SchematicType type = SchematicType.fromDB(checkedSchematic.getNodeType()); + if(type == null) continue; + if (checkedSchematic.getDeclineReason().equals("freigegeben")) { + chatter.system("CHECK_ACCEPTED", type.name(), checkedSchematic.getSchemName()); + } else { + chatter.system("CHECK_DECLINED", type.name(), checkedSchematic.getSchemName(), checkedSchematic.getDeclineReason()); + } + + checkedSchematic.setSeen(true); + } + if(newPlayers.contains(player.getUniqueId())){ Chatter.broadcast().system("JOIN_FIRST", player); newPlayers.remove(player.getUniqueId()); } DiscordBot.withBot(bot -> DiscordRanks.update(user)); + + if (player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_5)) { + player.requestCookie(EventModeListener.EVENT_TO_SPECTATE_KEY); + } + } + + @Subscribe + public void kickEvent(KickedFromServerEvent event) { + if (event.getResult() instanceof KickedFromServerEvent.RedirectPlayer red) { + event.setResult(KickedFromServerEvent.RedirectPlayer.create(red.getServer(), Component.empty())); + } } @Subscribe diff --git a/VelocityCore/src/de/steamwar/velocitycore/listeners/CookieEvents.java b/VelocityCore/src/de/steamwar/velocitycore/listeners/CookieEvents.java new file mode 100644 index 00000000..4fb59b62 --- /dev/null +++ b/VelocityCore/src/de/steamwar/velocitycore/listeners/CookieEvents.java @@ -0,0 +1,47 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2025 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.velocitycore.listeners; + +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.player.CookieReceiveEvent; +import com.velocitypowered.api.proxy.Player; +import de.steamwar.sql.EventFight; +import de.steamwar.sql.SteamwarUser; +import de.steamwar.velocitycore.EventStarter; +import de.steamwar.velocitycore.VelocityCore; + +public class CookieEvents extends BasicListener { + + @Subscribe + public void handleCookies(CookieReceiveEvent e) { + if (e.getOriginalKey().equals(EventModeListener.EVENT_TO_SPECTATE_KEY)) { + Player player = e.getPlayer(); + SteamwarUser user = SteamwarUser.get(player.getUniqueId()); + + EventFight.getActiveFights().stream() + .filter(fight -> fight.getTeamRed() == user.getTeam() || fight.getTeamBlue() == user.getTeam()) + .filter(fight -> fight.getSpectatePort() != null) + .filter(fight -> fight.getSpectatePort() != 0) + .findFirst() + .flatMap(fight -> VelocityCore.getProxy().getServer(EventStarter.getSpectatePorts().get(fight.getSpectatePort()))) + .ifPresent(registeredServer -> player.createConnectionRequest(registeredServer).fireAndForget()); + } + } +} diff --git a/VelocityCore/src/de/steamwar/velocitycore/listeners/EventModeListener.java b/VelocityCore/src/de/steamwar/velocitycore/listeners/EventModeListener.java index 5cc55757..cdc76b1e 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/listeners/EventModeListener.java +++ b/VelocityCore/src/de/steamwar/velocitycore/listeners/EventModeListener.java @@ -19,31 +19,88 @@ package de.steamwar.velocitycore.listeners; +import java.net.InetSocketAddress; +import java.nio.charset.Charset; +import java.util.List; + import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.PostLoginEvent; +import com.velocitypowered.api.event.player.ServerConnectedEvent; +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.api.proxy.Player; + import de.steamwar.messages.Chatter; +import de.steamwar.persistent.Subserver; import de.steamwar.sql.Event; +import de.steamwar.sql.EventFight; import de.steamwar.sql.Referee; +import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.TeamTeilnahme; +import de.steamwar.velocitycore.EventStarter; +import de.steamwar.velocitycore.VelocityCore; +import net.kyori.adventure.key.Key; public class EventModeListener extends BasicListener { + public static final Key EVENT_TO_SPECTATE_KEY = Key.key("sw", "event_to_spectate"); + @Subscribe public void onPostLogin(PostLoginEvent e) { - Chatter sender = Chatter.disconnect(e.getPlayer()); + Player player = e.getPlayer(); + SteamwarUser user = SteamwarUser.get(player.getUniqueId()); + Chatter sender = Chatter.disconnect(player); Event event = Event.get(); - if(event == null) { - sender.system("EVENTMODE_KICK"); + if (event == null) { + if (player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_5)) { + sender.system("EVENTMODE_KICK"); + } else { + player.transferToHost(new InetSocketAddress("steamwar.de", 25565)); + } return; } - if(TeamTeilnahme.nimmtTeil(sender.user().getTeam(), event.getEventID())) + if (TeamTeilnahme.nimmtTeil(user.getTeam(), event.getEventID())) { + if (player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_5) && VelocityCore.getProxy().getAllPlayers().stream().map(p -> SteamwarUser.get(p.getUniqueId())).filter(u -> u.getTeam() == user.getTeam()).count() > event.getMaximumTeamMembers()) { + player.storeCookie(EVENT_TO_SPECTATE_KEY, "TRUE".getBytes()); + player.transferToHost(new InetSocketAddress("steamwar.de", 25565)); + return; + } + + Subserver server = EventStarter.getEventServer().get(user.getTeam()); + + if (server != null) { + server.sendPlayer(player); + } + + return; + } + + if (Referee.get(event.getEventID()).contains(user.getId())) return; - if(Referee.get(event.getEventID()).contains(sender.user().getId())) - return; + if (player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_5)) { + sender.system("EVENTMODE_KICK"); + } else { + player.transferToHost(new InetSocketAddress("steamwar.de", 25565)); + } + } - sender.system("EVENTMODE_KICK"); + @Subscribe + public void onLobby(ServerConnectedEvent e) { + Player player = e.getPlayer(); + + if (player.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_5)) { + return; + } + + SteamwarUser user = SteamwarUser.get(player.getUniqueId()); + + List activeFights = EventFight.getActiveFights(); + + if (activeFights.stream() + .noneMatch(fight -> fight.getTeamRed() == user.getTeam() || fight.getTeamBlue() == user.getTeam())) { + player.transferToHost(new InetSocketAddress("steamwar.de", 25565)); + } } } diff --git a/VelocityCore/src/de/steamwar/velocitycore/listeners/SessionManager.java b/VelocityCore/src/de/steamwar/velocitycore/listeners/SessionManager.java index 7caeac14..248fd606 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/listeners/SessionManager.java +++ b/VelocityCore/src/de/steamwar/velocitycore/listeners/SessionManager.java @@ -22,6 +22,7 @@ package de.steamwar.velocitycore.listeners; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.DisconnectEvent; import com.velocitypowered.api.event.connection.PostLoginEvent; +import de.steamwar.sql.AuditLog; import de.steamwar.velocitycore.VelocityCore; import de.steamwar.sql.Session; import de.steamwar.sql.SteamwarUser; @@ -36,10 +37,12 @@ public class SessionManager extends BasicListener { @Subscribe public void onPostLogin(PostLoginEvent event){ sessions.put(event.getPlayer(), Timestamp.from(Instant.now())); + AuditLog.createJoin(AuditLog.SERVER_NAME_VELOCITY, null, SteamwarUser.get(event.getPlayer().getUniqueId())); } @Subscribe public void onDisconnect(DisconnectEvent e){ + AuditLog.createLeave(AuditLog.SERVER_NAME_VELOCITY, null, SteamwarUser.get(e.getPlayer().getUniqueId())); Timestamp timestamp = sessions.remove(e.getPlayer()); if(timestamp != null) { VelocityCore.schedule(() -> Session.insertSession(SteamwarUser.get(e.getPlayer().getUniqueId()).getId(), timestamp)).schedule(); diff --git a/VelocityCore/src/de/steamwar/velocitycore/listeners/TexturePackSystem.java b/VelocityCore/src/de/steamwar/velocitycore/listeners/TexturePackSystem.java new file mode 100644 index 00000000..8d07e0c7 --- /dev/null +++ b/VelocityCore/src/de/steamwar/velocitycore/listeners/TexturePackSystem.java @@ -0,0 +1,106 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.velocitycore.listeners; + +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.player.ServerPostConnectEvent; +import com.velocitypowered.api.proxy.player.ResourcePackInfo; +import de.steamwar.velocitycore.VelocityCore; +import net.kyori.adventure.text.Component; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.TreeMap; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +// https://jd.papermc.io/velocity/3.4.0/com/velocitypowered/api/proxy/player/ResourcePackInfo.Builder.html#setHash(byte%5B%5D) +public class TexturePackSystem extends BasicListener { + + private static final File PACKS_DIR = new File("/var/www/packs"); + private static final String BASE_ULR = "https://packs.steamwar.de/"; + private TreeMap protocolVersionToPackVersion = new TreeMap<>(); + + public TexturePackSystem() { + // https://minecraft.wiki/w/Pack_format#List_of_resource_pack_formats + // https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol_version_numbers + protocolVersionToPackVersion.put(759, 9); + protocolVersionToPackVersion.put(761, 12); + protocolVersionToPackVersion.put(762, 13); + protocolVersionToPackVersion.put(763, 15); + protocolVersionToPackVersion.put(764, 18); + protocolVersionToPackVersion.put(765, 22); + protocolVersionToPackVersion.put(766, 32); + protocolVersionToPackVersion.put(767, 34); + protocolVersionToPackVersion.put(768, 42); + protocolVersionToPackVersion.put(769, 46); + protocolVersionToPackVersion.put(770, 55); + } + + @Subscribe + public void onLogin(ServerPostConnectEvent event) { + if (event.getPreviousServer() != null) { + return; + } + VelocityCore.schedule(() -> { + TreeMap fileTreeMap = new TreeMap<>(); + for (File fileEntry : PACKS_DIR.listFiles()) { + try { + int packVersion = Integer.parseInt(fileEntry.getName().split("_")[0]); + fileTreeMap.put(packVersion, fileEntry); + } catch (NumberFormatException e) { + // Ignore + } + } + + int playerVersion = event.getPlayer().getProtocolVersion().getProtocol(); + Map.Entry packVersionEntry = protocolVersionToPackVersion.floorEntry(playerVersion); + if (packVersionEntry == null) return; + Map.Entry selectedPackEntry = fileTreeMap.floorEntry(packVersionEntry.getValue()); + if (selectedPackEntry == null) return; + File selectedPack = selectedPackEntry.getValue(); + + String fileName = selectedPack.getName(); + fileName = fileName.substring(fileName.indexOf('_') + 1, fileName.lastIndexOf('.')); + byte[] hash = hexStringToByteArray(fileName); + + ResourcePackInfo resourcePackInfo = VelocityCore.getProxy().createResourcePackBuilder(BASE_ULR + selectedPack.getName()) + .setId(UUID.nameUUIDFromBytes(fileName.getBytes(StandardCharsets.UTF_8))) + .setHash(hash) + .setShouldForce(false) + .setPrompt(Component.text("The SteamWar TexturePack improves GUIs!")) + .build(); + event.getPlayer().sendResourcePacks(resourcePackInfo); + }).delay(500, TimeUnit.MILLISECONDS).schedule(); + } + + public static byte[] hexStringToByteArray(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i+1), 16)); + } + + return data; + } +} diff --git a/VelocityCore/src/de/steamwar/velocitycore/listeners/VersionAnnouncer.java b/VelocityCore/src/de/steamwar/velocitycore/listeners/VersionAnnouncer.java index c28a8fee..5204d258 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/listeners/VersionAnnouncer.java +++ b/VelocityCore/src/de/steamwar/velocitycore/listeners/VersionAnnouncer.java @@ -27,19 +27,36 @@ import com.velocitypowered.api.proxy.server.ServerInfo; import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.velocity.platform.VelocityViaConfig; import de.steamwar.messages.Chatter; +import de.steamwar.network.packets.server.ClientVersionPacket; import de.steamwar.persistent.Subserver; +import de.steamwar.velocitycore.VelocityCore; +import de.steamwar.velocitycore.network.NetworkSender; + +import java.time.Duration; +import java.time.temporal.ChronoUnit; public class VersionAnnouncer extends BasicListener { @Subscribe public void postConnect(ServerConnectedEvent e) { ServerInfo server = e.getServer().getServerInfo(); - if(!Subserver.isBuild(Subserver.getSubserver(server))) - return; - Player player = e.getPlayer(); int serverVersion = ((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols().get(server.getName()); - if(Via.getAPI().getPlayerVersion(player) == serverVersion) + + int playerVersion = Via.getAPI().getPlayerVersion(player); + ProtocolVersion protocolVersion = ProtocolVersion.getProtocolVersion(serverVersion); + if (protocolVersion.isSupported()) { + // PluginChannel 'vv:proxy_details' from ViaVersion apparently does not work any longer! + VelocityCore.schedule(() -> { + String[] strings = protocolVersion.getVersionIntroducedIn().split("\\."); + NetworkSender.send(player, new ClientVersionPacket(player.getUniqueId(), Integer.parseInt(strings[1]))); + }).delay(Duration.of(100, ChronoUnit.MILLIS)).schedule(); + } + + if(playerVersion == serverVersion) + return; + + if(!Subserver.isBuild(Subserver.getSubserver(server))) return; player.sendActionBar(Chatter.of(player).parse("SERVER_VERSION", ProtocolVersion.getProtocolVersion(serverVersion).getMostRecentSupportedVersion())); diff --git a/VelocityCore/src/de/steamwar/velocitycore/network/handlers/PlayerSkinHandler.java b/VelocityCore/src/de/steamwar/velocitycore/network/handlers/PlayerSkinHandler.java new file mode 100644 index 00000000..0515212e --- /dev/null +++ b/VelocityCore/src/de/steamwar/velocitycore/network/handlers/PlayerSkinHandler.java @@ -0,0 +1,121 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.velocitycore.network.handlers; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.connection.PostLoginEvent; +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.util.GameProfile; +import de.steamwar.network.packets.PacketHandler; +import de.steamwar.network.packets.common.PlayerSkinRequestPacket; +import de.steamwar.network.packets.common.PlayerSkinResponsePacket; +import de.steamwar.velocitycore.VelocityCore; +import de.steamwar.velocitycore.network.NetworkSender; +import de.steamwar.velocitycore.network.ServerMetaInfo; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.SneakyThrows; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +public class PlayerSkinHandler extends PacketHandler { + + private final int maxCacheSize = 1000; + + public PlayerSkinHandler() { + VelocityCore.getProxy().getEventManager().register(VelocityCore.get(), this); + } + + private Map skins = new LinkedHashMap<>() { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > maxCacheSize; + } + }; + + @Handler + @SneakyThrows + public void handle(PlayerSkinRequestPacket packet) { + if (skins.containsKey(packet.getUuid())) { + SkinData skinData = skins.get(packet.getUuid()); + NetworkSender.send(((ServerMetaInfo) packet.getMetaInfos()).sender().getServer(), new PlayerSkinResponsePacket(packet.getUuid(), skinData.skin, skinData.signature)); + return; + } + + String url = "https://sessionserver.mojang.com/session/minecraft/profile/" + packet.getUuid().toString().replace("-", "") + "?unsigned=false"; + + HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); + connection.setReadTimeout(5000); + connection.setConnectTimeout(5000); + connection.setRequestProperty("User-Agent", "SkinFetcher"); + + if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { + return; + } + + InputStream is = connection.getInputStream(); + String json = new BufferedReader(new InputStreamReader(is)) + .lines().collect(Collectors.joining("\n")); + + JsonObject obj = JsonParser.parseString(json).getAsJsonObject(); + JsonArray properties = obj.getAsJsonArray("properties"); + for (JsonElement propElement : properties) { + JsonObject prop = propElement.getAsJsonObject(); + if (prop.get("name").getAsString().equals("textures")) { + String skin = prop.get("value").getAsString(); + String signature = prop.get("signature").getAsString(); + skins.put(packet.getUuid(), new SkinData(skin, signature)); + NetworkSender.send(((ServerMetaInfo) packet.getMetaInfos()).sender().getServer(), new PlayerSkinResponsePacket(packet.getUuid(), skin, signature)); + return; + } + } + } + + @Subscribe + public void onPostLogin(PostLoginEvent event) { + Player player = event.getPlayer(); + GameProfile gameProfile = player.getGameProfile(); + GameProfile.Property property = gameProfile.getProperties().stream().filter(p -> p.getName().equals("textures")).findFirst().orElse(null); + if (property == null) return; + skins.put(player.getUniqueId(), new SkinData(property.getValue(), property.getSignature())); + + Set uuidSet = skins.keySet(); + VelocityCore.getProxy().getAllServers().forEach(server -> { + for (UUID uuid : uuidSet) { + NetworkSender.send(server, new PlayerSkinResponsePacket(uuid, property.getValue(), property.getSignature())); + } + }); + } + + public record SkinData(String skin, String signature) {} +} diff --git a/VelocityCore/src/de/steamwar/velocitycore/tablist/Tablist.java b/VelocityCore/src/de/steamwar/velocitycore/tablist/Tablist.java index 6195bd73..6afb69c7 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/tablist/Tablist.java +++ b/VelocityCore/src/de/steamwar/velocitycore/tablist/Tablist.java @@ -51,7 +51,7 @@ public class Tablist extends ChannelInboundHandlerAdapter { private static final UUID[] swUuids = IntStream.range(0, 80).mapToObj(i -> UUID.randomUUID()).toArray(UUID[]::new); private static final String[] swNames = IntStream.range(0, 80).mapToObj(i -> " »SW« " + String.format("%02d", i)).toArray(String[]::new); - public static final UpdateTeamsPacket createTeamPacket = new UpdateTeamsPacket("zzzzzsw-tab", UpdateTeamsPacket.Mode.CREATE, Component.empty(), Component.empty(), Component.empty(), UpdateTeamsPacket.NameTagVisibility.NEVER, UpdateTeamsPacket.CollisionRule.ALWAYS, 21, (byte)0x00, Arrays.stream(Tablist.swNames).toList()); + public static final UpdateTeamsPacket createTeamPacket = new UpdateTeamsPacket21("zzzzzsw-tab", UpdateTeamsPacket.Mode.CREATE, Component.empty(), Component.empty(), Component.empty(), UpdateTeamsPacket.NameTagVisibility.NEVER, UpdateTeamsPacket.CollisionRule.ALWAYS, 21, (byte)0x00, Arrays.stream(Tablist.swNames).toList()); private final Map directTabItems; private final List current = new ArrayList<>(); @@ -75,26 +75,12 @@ public class Tablist extends ChannelInboundHandlerAdapter { List tablist = new ArrayList<>(); List direct = new ArrayList<>(); global.print(viewer, player, tablist, direct); - - // NPC handling - List update = new ArrayList<>(); - synchronized (directTabItems) { - for (TablistPart.Item item : direct) { - UpsertPlayerInfoPacket.Entry tabItem = directTabItems.get(item.getUuid()); - - if(tabItem == null) { - tablist.add(0, item); - } else if(!item.getDisplayName().equals(getDisplayName(tabItem))) { - tabItem.setDisplayName(new ComponentHolder(player.getProtocolVersion(), item.getDisplayName())); - tabItem.setListed(true); - update.add(tabItem); - } - } - } + tablist.addAll(0, direct); // Main list handling int i = 0; List add = new ArrayList<>(); + List update = new ArrayList<>(); List remove = new ArrayList<>(); for (; i < tablist.size() && i < 80; i++) { TablistPart.Item item = tablist.get(i); @@ -171,6 +157,8 @@ public class Tablist extends ChannelInboundHandlerAdapter { } public void disable() { + sendTabPacket(new ArrayList<>(directTabItems.values()), null); + directTabItems.clear(); sendTabPacket(current, null); current.clear(); diff --git a/VelocityCore/src/de/steamwar/velocitycore/tablist/UpdateTeamsPacket21.java b/VelocityCore/src/de/steamwar/velocitycore/tablist/UpdateTeamsPacket21.java new file mode 100644 index 00000000..3feab317 --- /dev/null +++ b/VelocityCore/src/de/steamwar/velocitycore/tablist/UpdateTeamsPacket21.java @@ -0,0 +1,103 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.velocitycore.tablist; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import com.velocitypowered.proxy.protocol.packet.UpdateTeamsPacket; +import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; +import io.netty.buffer.ByteBuf; +import net.kyori.adventure.text.Component; + +import java.util.List; + +public class UpdateTeamsPacket21 extends UpdateTeamsPacket { + + private String name; + private Mode mode; + private Component displayName; + private Component prefix; + private Component suffix; + private NameTagVisibility nameTagVisibility; + private CollisionRule collisionRule; + private int color; + private byte friendlyFlags; + private List players; + + public UpdateTeamsPacket21(String name, Mode mode, Component displayName, Component prefix, Component suffix, NameTagVisibility nameTagVisibility, CollisionRule collisionRule, int color, byte friendlyFlags, List players) { + super(name, mode, displayName, prefix, suffix, nameTagVisibility, collisionRule, color, friendlyFlags, players); + this.name = name; + this.mode = mode; + this.displayName = displayName; + this.prefix = prefix; + this.suffix = suffix; + this.nameTagVisibility = nameTagVisibility; + this.collisionRule = collisionRule; + this.color = color; + this.friendlyFlags = friendlyFlags; + this.players = players; + } + + @Override + public void encode(ByteBuf byteBuf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ProtocolUtils.writeString(byteBuf, this.name); + byteBuf.writeByte(this.mode.ordinal()); + switch (this.mode) { + case CREATE: + case UPDATE: + (new ComponentHolder(protocolVersion, this.displayName)).write(byteBuf); + if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_13)) { + (new ComponentHolder(protocolVersion, this.prefix)).write(byteBuf); + (new ComponentHolder(protocolVersion, this.suffix)).write(byteBuf); + } + + byteBuf.writeByte(this.friendlyFlags); + if (protocolVersion.noLessThan(ProtocolVersion.MINECRAFT_1_21_5)) { + ProtocolUtils.writeVarInt(byteBuf, this.nameTagVisibility.ordinal()); + ProtocolUtils.writeVarInt(byteBuf, this.collisionRule.ordinal()); + } else { + ProtocolUtils.writeString(byteBuf, this.nameTagVisibility.getValue()); + ProtocolUtils.writeString(byteBuf, this.collisionRule.getValue()); + } + if (protocolVersion.greaterThan(ProtocolVersion.MINECRAFT_1_12_2)) { + ProtocolUtils.writeVarInt(byteBuf, this.color); + (new ComponentHolder(protocolVersion, this.prefix)).write(byteBuf); + (new ComponentHolder(protocolVersion, this.suffix)).write(byteBuf); + } else { + byteBuf.writeByte((byte)this.color); + } + + ProtocolUtils.writeVarInt(byteBuf, this.players.size()); + + for(String player : this.players) { + ProtocolUtils.writeString(byteBuf, player); + } + break; + case ADD_PLAYER: + case REMOVE_PLAYER: + ProtocolUtils.writeVarInt(byteBuf, this.players.size()); + + for(String player : this.players) { + ProtocolUtils.writeString(byteBuf, player); + } + case REMOVE: + } + } +} diff --git a/VelocityCore/src/de/steamwar/velocitycore/util/BauLock.java b/VelocityCore/src/de/steamwar/velocitycore/util/BauLock.java index 03bc4315..7f95599b 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/util/BauLock.java +++ b/VelocityCore/src/de/steamwar/velocitycore/util/BauLock.java @@ -20,6 +20,7 @@ package de.steamwar.velocitycore.util; import de.steamwar.messages.Chatter; +import de.steamwar.sql.BauweltMember; import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.UserConfig; import de.steamwar.sql.UserPerm; @@ -44,6 +45,10 @@ public class BauLock { case NOBODY: locked = true; break; + case SUPERVISOR: + BauweltMember member = BauweltMember.getBauMember(owner.getId(), target.getId()); + locked = !member.isSupervisor(); + break; case SERVERTEAM: locked = !target.hasPerm(UserPerm.TEAM); break; diff --git a/VelocityCore/src/de/steamwar/velocitycore/util/BauLockState.java b/VelocityCore/src/de/steamwar/velocitycore/util/BauLockState.java index 8fe89bf9..c6b8af4f 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/util/BauLockState.java +++ b/VelocityCore/src/de/steamwar/velocitycore/util/BauLockState.java @@ -22,6 +22,7 @@ package de.steamwar.velocitycore.util; public enum BauLockState { NOBODY, // Locks the build server for all users + SUPERVISOR, // Locks the build server for supervisors SERVERTEAM, // opens the build server only for every added user which is a server team member TEAM_AND_SERVERTEAM, //opens the build server only for every added user which is in the same team as the buildOwner and every server team member TEAM, //opens the build server only for every added user which is in the same team as the buildOwner diff --git a/WebsiteBackend/src/de/steamwar/data/Groups.kt b/WebsiteBackend/src/de/steamwar/data/Groups.kt deleted file mode 100644 index 2ecff054..00000000 --- a/WebsiteBackend/src/de/steamwar/data/Groups.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2024 SteamWar.de-Serverteam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package de.steamwar.data - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable -import kotlinx.serialization.cbor.Cbor -import kotlinx.serialization.decodeFromByteArray -import kotlinx.serialization.encodeToByteArray - -@Serializable -data class GroupsData(val groups: MutableList) - -@Serializable -data class GroupData(val name: String, val fights: MutableList) - -@OptIn(ExperimentalSerializationApi::class) -class Groups { - companion object { - private var groups: GroupsData = if (kGroupsFile.exists()) { - Cbor.decodeFromByteArray(kGroupsFile.readBytes()) - } else { - if (!kGroupsFile.parentFile.exists()) { - kGroupsFile.parentFile.mkdirs() - } - kGroupsFile.createNewFile() - kGroupsFile.writeBytes(Cbor.encodeToByteArray(GroupsData(mutableListOf()))) - - GroupsData(mutableListOf()) - } - - fun getGroup(name: String): GroupData? { - return groups.groups.find { it.name == name } - } - - fun getGroup(fight: Int): GroupData? { - return groups.groups.find { it.fights.contains(fight) } - } - - fun getOrCreateGroup(name: String): GroupData { - val group = getGroup(name) - if (group != null) { - return group - } - val newGroup = GroupData(name, mutableListOf()) - groups.groups.add(newGroup) - return newGroup - } - - fun resetGroup(fight: Int, save: Boolean = false) { - val oldGroup = getGroup(fight) - oldGroup?.fights?.remove(fight) - if(oldGroup?.fights?.isEmpty() == true) { - groups.groups.remove(oldGroup) - } - if(save) { - kGroupsFile.writeBytes(Cbor.encodeToByteArray(groups)) - } - } - - fun setGroup(fight: Int, group: String) { - resetGroup(fight) - val newGroup = getOrCreateGroup(group) - newGroup.fights.add(fight) - kGroupsFile.writeBytes(Cbor.encodeToByteArray(groups)) - } - - fun getAllGroups(): List { - return groups.groups.map { it.name } - } - } -} \ No newline at end of file diff --git a/WebsiteBackend/src/de/steamwar/routes/Data.kt b/WebsiteBackend/src/de/steamwar/routes/Data.kt index 0a2dd3ae..a7672063 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Data.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Data.kt @@ -20,12 +20,12 @@ package de.steamwar.routes import de.steamwar.ResponseError -import de.steamwar.data.Groups import de.steamwar.data.getCachedSkin import de.steamwar.plugins.SWAuthPrincipal import de.steamwar.plugins.SWPermissionCheck import de.steamwar.sql.SchematicType import de.steamwar.sql.SteamwarUser +import de.steamwar.sql.Team import de.steamwar.sql.UserPerm import de.steamwar.sql.loadSchematicTypes import de.steamwar.util.fetchData @@ -78,6 +78,9 @@ fun Route.configureDataRoutes() { get("/users") { call.respond(SteamwarUser.getAll().map { ResponseUser(it) }) } + get("/teams") { + call.respond(Team.getAll().map { ResponseTeam(it) }) + } get("/schematicTypes") { val types = mutableListOf() loadSchematicTypes(types, mutableMapOf()) @@ -102,9 +105,6 @@ fun Route.configureDataRoutes() { } call.respond(YamlConfiguration.loadConfiguration(file).getStringList("Server.Maps")) } - get("/groups") { - call.respond(Groups.getAllGroups()) - } } get("/server") { try { diff --git a/WebsiteBackend/src/de/steamwar/routes/EventFights.kt b/WebsiteBackend/src/de/steamwar/routes/EventFights.kt index e95ea89d..2f27b7e4 100644 --- a/WebsiteBackend/src/de/steamwar/routes/EventFights.kt +++ b/WebsiteBackend/src/de/steamwar/routes/EventFights.kt @@ -20,12 +20,7 @@ package de.steamwar.routes import de.steamwar.ResponseError -import de.steamwar.data.Groups -import de.steamwar.plugins.SWPermissionCheck -import de.steamwar.sql.EventFight -import de.steamwar.sql.SteamwarUser -import de.steamwar.sql.Team -import de.steamwar.sql.UserPerm +import de.steamwar.sql.* import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.request.* @@ -45,7 +40,8 @@ data class ResponseEventFight( val start: Long, val ergebnis: Int, val spectatePort: Int?, - val group: String? + val group: ResponseGroups?, + val hasFinished: Boolean ) { constructor(eventFight: EventFight) : this( eventFight.fightID, @@ -56,7 +52,8 @@ data class ResponseEventFight( eventFight.startTime.time, eventFight.ergebnis, eventFight.spectatePort, - Groups.getGroup(eventFight.fightID)?.name + eventFight.group.orElse(null)?.let { ResponseGroups(it, short = true) }, + eventFight.hasFinished() ) } @@ -72,36 +69,39 @@ data class UpdateEventFight( val start: Long? = null, val spielmodus: String? = null, val map: String? = null, - val group: String? = null, - val spectatePort: Int? = null + val group: Int? = null, + val spectatePort: Int? = null, + val ergebnis: Int? = null, ) @Serializable data class CreateEventFight( - val event: Int, val spielmodus: String, val map: String, val blueTeam: Int, val redTeam: Int, val start: Long, val spectatePort: Int? = null, - val group: String? = null + val group: Int? = null ) fun Route.configureEventFightRoutes() { route("/fights") { - install(SWPermissionCheck) { - allowMethod(HttpMethod.Get) - permission = UserPerm.MODERATION + get { + val event = call.receiveEvent() ?: return@get + call.respond(EventFight.getEvent(event.eventID).map { ResponseEventFight(it) }) } post { + val event = call.receiveEvent() ?: return@post + val fight = call.receiveNullable() if (fight == null) { call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid body")) return@post } + val eventFight = EventFight.create( - fight.event, + event.eventID, Timestamp.from(Instant.ofEpochMilli(fight.start)), fight.spielmodus, fight.map, @@ -110,9 +110,7 @@ fun Route.configureEventFightRoutes() { fight.spectatePort ) if (fight.group != null) { - if (fight.group != "null") { - Groups.setGroup(eventFight.fightID, fight.group) - } + eventFight.setGroup(fight.group) } call.respond(HttpStatusCode.Created, ResponseEventFight(eventFight)) } @@ -133,12 +131,17 @@ fun Route.configureEventFightRoutes() { val spectatePort = updateFight.spectatePort ?: fight.spectatePort if (updateFight.group != null) { - if (updateFight.group == "null") { - Groups.resetGroup(fight.fightID, true) + if (updateFight.group == -1) { + fight.setGroup(null) } else { - Groups.setGroup(fight.fightID, updateFight.group) + fight.setGroup(updateFight.group) } } + + if (updateFight.ergebnis != null) { + fight.ergebnis = updateFight.ergebnis + } + fight.update(start, spielmodus, map, teamBlue, teamRed, spectatePort) call.respond(HttpStatusCode.OK, ResponseEventFight(fight)) } diff --git a/WebsiteBackend/src/de/steamwar/routes/EventGroups.kt b/WebsiteBackend/src/de/steamwar/routes/EventGroups.kt new file mode 100644 index 00000000..38260e74 --- /dev/null +++ b/WebsiteBackend/src/de/steamwar/routes/EventGroups.kt @@ -0,0 +1,94 @@ +/* + * 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 . + */ + +package de.steamwar.routes + +import de.steamwar.sql.EventGroup +import de.steamwar.sql.EventGroup.EventGroupType +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import kotlinx.serialization.Serializable + +@Serializable +data class CreateEventGroup(val name: String, val type: EventGroupType) + +@Serializable +data class UpdateEventGroup( + val name: String? = null, + val type: EventGroupType? = null, + val pointsPerWin: Int? = null, + val pointsPerLoss: Int? = null, + val pointsPerDraw: Int? = null, +) + +fun Route.configureEventGroups() { + route("/groups") { + get { + val event = call.receiveEvent() ?: return@get + call.respond(EventGroup.get(event).map { ResponseGroups(it) }) + } + post { + val event = call.receiveEvent() ?: return@post + val createEventGroup = call.receive() + val group = EventGroup.create(event, createEventGroup.name, createEventGroup.type) + call.respond(ResponseGroups(group)) + } + route("/{group}") { + get { + val group = call.receiveEventGroup() ?: return@get + call.respond(ResponseGroups(group)) + } + put { + val group = call.receiveEventGroup() ?: return@put + val updateEventGroup = call.receive() + val name = updateEventGroup.name ?: group.name + val type = updateEventGroup.type ?: group.type + val pointsPerWin = updateEventGroup.pointsPerWin ?: group.pointsPerWin + val pointsPerLoss = updateEventGroup.pointsPerLoss ?: group.pointsPerLoss + val pointsPerDraw = updateEventGroup.pointsPerDraw ?: group.pointsPerDraw + group.update(name, type, pointsPerWin, pointsPerLoss, pointsPerDraw) + call.respond(ResponseGroups(EventGroup.get(group.id).orElse(null) ?: return@put)) + } + delete { + val group = call.receiveEventGroup() ?: return@delete + group.delete() + call.respond(HttpStatusCode.NoContent) + } + } + } +} + +suspend fun ApplicationCall.receiveEventGroup(): EventGroup? { + val groupId = parameters["group"]?.toIntOrNull() + if (groupId == null) { + respond(HttpStatusCode.BadRequest) + return null + } + + val group = EventGroup.get(groupId).orElse(null) + if (group == null) { + respond(HttpStatusCode.NotFound) + return null + } + + return group +} \ No newline at end of file diff --git a/WebsiteBackend/src/de/steamwar/routes/EventReferees.kt b/WebsiteBackend/src/de/steamwar/routes/EventReferees.kt new file mode 100644 index 00000000..051c31cd --- /dev/null +++ b/WebsiteBackend/src/de/steamwar/routes/EventReferees.kt @@ -0,0 +1,54 @@ +/* + * 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 . + */ + +package de.steamwar.routes + +import de.steamwar.sql.Referee +import de.steamwar.sql.SteamwarUser +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import java.util.* + +fun Route.configureEventRefereesRouting() { + route("/referees") { + get { + val event = call.receiveEvent() ?: return@get + call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.get(it)) }) + } + put { + val event = call.receiveEvent() ?: return@put + val referees = call.receive>() + referees.forEach { + Referee.add(event.eventID, SteamwarUser.get(UUID.fromString(it)).id) + } + call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.get(it)) }) + } + delete { + val event = call.receiveEvent() ?: return@delete + val referees = call.receive>() + referees.forEach { + Referee.remove(event.eventID, SteamwarUser.get(UUID.fromString(it)).id) + } + call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.get(it)) }) + } + } +} \ No newline at end of file diff --git a/WebsiteBackend/src/de/steamwar/routes/EventRelations.kt b/WebsiteBackend/src/de/steamwar/routes/EventRelations.kt new file mode 100644 index 00000000..c8af5866 --- /dev/null +++ b/WebsiteBackend/src/de/steamwar/routes/EventRelations.kt @@ -0,0 +1,109 @@ +/* + * 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 . + */ + +package de.steamwar.routes + +import de.steamwar.sql.EventFight +import de.steamwar.sql.EventGroup +import de.steamwar.sql.EventRelation +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import kotlinx.serialization.Serializable + +@Serializable +data class CreateEventRelation(val fightId: Int, val team: EventRelation.FightTeam, val fromType: EventRelation.FromType, val fromId: Int, val fromPlace: Int) + +@Serializable +data class UpdateEventRelation(val team: EventRelation.FightTeam? = null, val from: UpdateFromRelation? = null) + +@Serializable +data class UpdateFromRelation(val fromType: EventRelation.FromType, val fromId: Int, val fromPlace: Int) + +fun Route.configureEventRelations() { + route("/relations") { + get { + val event = call.receiveEvent() ?: return@get + + call.respond(EventRelation.get(event).map { ResponseRelation(it) }) + } + post { + val create = call.receive() + + val fight = EventFight.get(create.fightId) ?: return@post call.respond(HttpStatusCode.NotFound) + + when (create.fromType) { + EventRelation.FromType.FIGHT -> EventFight.get(create.fromId) ?: return@post call.respond(HttpStatusCode.BadRequest) + EventRelation.FromType.GROUP -> EventGroup.get(create.fromId) ?: return@post call.respond(HttpStatusCode.BadRequest) + } + + val relation = EventRelation.create(fight, create.team, create.fromType, create.fromId, create.fromPlace) + + call.respond(ResponseRelation(relation)) + } + route("/{relation}") { + get { + val relation = call.receiveEventRelation() ?: return@get + call.respond(ResponseRelation(relation)) + } + put { + val relation = call.receiveEventRelation() ?: return@put + val update = call.receive() + + update.from?.let { + when(it.fromType) { + EventRelation.FromType.FIGHT -> relation.setFromFight(EventFight.get(it.fromId) ?: return@put call.respond(HttpStatusCode.BadRequest), + it.fromPlace + ) + EventRelation.FromType.GROUP -> relation.setFromGroup(EventGroup.get(it.fromId).orElse(null) ?: return@put call.respond(HttpStatusCode.BadRequest), + it.fromPlace + ) + } + } + + update.team?.let { relation.setUpdateTeam(it) } + + call.respond(ResponseRelation(EventRelation.get(relation.id))) + } + delete { + val relation = call.receiveEventRelation() ?: return@delete + relation.delete() + call.respond(HttpStatusCode.NoContent) + } + } + } +} + +suspend fun ApplicationCall.receiveEventRelation(): EventRelation? { + val relationId = parameters["relation"]?.toIntOrNull() + if (relationId == null) { + respond(HttpStatusCode.BadRequest) + return null + } + + val relation = EventRelation.get(relationId) + if (relation == null) { + respond(HttpStatusCode.NotFound) + return null + } + + return relation +} \ No newline at end of file diff --git a/WebsiteBackend/src/de/steamwar/routes/EventTeams.kt b/WebsiteBackend/src/de/steamwar/routes/EventTeams.kt new file mode 100644 index 00000000..caacc0a9 --- /dev/null +++ b/WebsiteBackend/src/de/steamwar/routes/EventTeams.kt @@ -0,0 +1,52 @@ +/* + * 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 . + */ + +package de.steamwar.routes + +import de.steamwar.sql.TeamTeilnahme +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* + +fun Route.configureEventTeams() { + route("/teams") { + get { + val event = call.receiveEvent() ?: return@get + call.respond(TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) }) + } + put { + val event = call.receiveEvent() ?: return@put + val team = call.receive>() + team.forEach { + TeamTeilnahme.teilnehmen(it, event.eventID) + } + call.respond(HttpStatusCode.NoContent) + } + delete { + val event = call.receiveEvent() ?: return@delete + val team = call.receive>() + team.forEach { + TeamTeilnahme.notTeilnehmen(it, event.eventID) + } + call.respond(HttpStatusCode.NoContent) + } + } +} \ No newline at end of file diff --git a/WebsiteBackend/src/de/steamwar/routes/Events.kt b/WebsiteBackend/src/de/steamwar/routes/Events.kt index d40cdd3b..8dbb3993 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Events.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Events.kt @@ -20,9 +20,10 @@ package de.steamwar.routes import de.steamwar.ResponseError -import de.steamwar.data.Groups import de.steamwar.plugins.SWPermissionCheck import de.steamwar.sql.* +import de.steamwar.sql.EventGroup.EventGroupType +import de.steamwar.sql.EventRelation.FromType import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.request.* @@ -39,6 +40,45 @@ data class ShortEvent(val id: Int, val name: String, val start: Long, val end: L constructor(event: Event) : this(event.eventID, event.eventName, event.start.time, event.end.time) } +@Serializable +data class ResponseGroups( + val id: Int, + val name: String, + val pointsPerWin: Int, + val pointsPerLoss: Int, + val pointsPerDraw: Int, + val type: EventGroupType, + val points: Map +) { + constructor(group: EventGroup, short: Boolean = false) : this( + group.id, + group.name, + group.pointsPerWin, + group.pointsPerLoss, + group.pointsPerDraw, + group.type, + if (short) mapOf() else group.calculatePoints().mapKeys { it.key.teamId }) +} + +@Serializable +data class ResponseRelation( + val id: Int, + val fight: ResponseEventFight, + val type: FromType, + val fromFight: ResponseEventFight? = null, + val fromGroup: ResponseGroups? = null, + val fromPlace: Int +) { + constructor(relation: EventRelation) : this( + relation.id, + ResponseEventFight(relation.fight), + relation.fromType, + relation.fromFight.map { ResponseEventFight(it) }.orElse(null), + relation.fromGroup.map { ResponseGroups(it) }.orElse(null), + relation.fromPlace + ) +} + @Serializable data class ResponseEvent( val id: Int, @@ -49,7 +89,6 @@ data class ResponseEvent( val maxTeamMembers: Int, val schemType: String?, val publicSchemsOnly: Boolean, - val referees: List, ) { constructor(event: Event) : this( event.eventID, @@ -60,7 +99,6 @@ data class ResponseEvent( event.maximumTeamMembers, event.schematicType?.toDB(), event.publicSchemsOnly(), - Referee.get(event.eventID).map { ResponseUser(SteamwarUser.get(it)) } ) } @@ -68,8 +106,20 @@ data class ResponseEvent( data class ExtendedResponseEvent( val event: ResponseEvent, val teams: List, - val fights: List -) + val groups: List, + val fights: List, + val referees: List, + val relations: List +) { + constructor(event: Event) : this( + ResponseEvent(event), + TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) }, + EventGroup.get(event).map { ResponseGroups(it) }, + EventFight.getEvent(event.eventID).map { ResponseEventFight(it) }, + Referee.get(event.eventID).map { ResponseUser(SteamwarUser.get(it)) }, + EventRelation.get(event).map { ResponseRelation(it) } + ) +} @Serializable data class CreateEvent(val name: String, val start: Long, val end: Long) @@ -111,49 +161,11 @@ fun Route.configureEventsRoute() { } route("/{id}") { get { - val id = call.parameters["id"]?.toIntOrNull() - if (id == null) { - call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid ID")) - return@get - } - val event = Event.get(id) - if (event == null) { - call.respond(HttpStatusCode.NotFound, ResponseError("Event not found")) - return@get - } + val event = call.receiveEvent() ?: return@get call.respond( - ExtendedResponseEvent( - ResponseEvent(event), - TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) }, - EventFight.getEvent(event.eventID).map { ResponseEventFight(it) }) + ExtendedResponseEvent(event) ) } - get("/teams") { - val id = call.parameters["id"]?.toIntOrNull() - if (id == null) { - call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid ID")) - return@get - } - val event = Event.get(id) - if (event == null) { - call.respond(HttpStatusCode.NotFound, ResponseError("Event not found")) - return@get - } - call.respond(TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) }) - } - get("/fights") { - val id = call.parameters["id"]?.toIntOrNull() - if (id == null) { - call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid ID")) - return@get - } - val event = Event.get(id) - if (event == null) { - call.respond(HttpStatusCode.NotFound, ResponseError("Event not found")) - return@get - } - call.respond(EventFight.getEvent(event.eventID).map { ResponseEventFight(it) }) - } get("/csv") { val event = call.receiveEvent() ?: return@get @@ -164,7 +176,7 @@ fun Route.configureEventsRoute() { csv.appendLine() val blue = Team.get(it.teamBlue) val red = Team.get(it.teamRed) - val winner = when(it.ergebnis) { + val winner = when (it.ergebnis) { 1 -> blue.teamName 2 -> red.teamName 3 -> "Tie" @@ -176,7 +188,7 @@ fun Route.configureEventsRoute() { Team.get(it.teamBlue).teamName, Team.get(it.teamRed).teamName, winner, - Groups.getGroup(it.fightID)?.name ?: "Ungrouped" + it.group.map { it.name }.orElse("Ungrouped") ).joinToString(",") ) } @@ -200,7 +212,9 @@ fun Route.configureEventsRoute() { val end = updateEvent.end?.let { Timestamp.from(Instant.ofEpochMilli(it)) } ?: event.end val maxTeamMembers = updateEvent.maxTeamMembers ?: event.maximumTeamMembers - val schemType = if (updateEvent.schemType == "null") null else updateEvent.schemType?.let { SchematicType.fromDB(it) } ?: event.schematicType + val schemType = + if (updateEvent.schemType == "null") null else updateEvent.schemType?.let { SchematicType.fromDB(it) } + ?: event.schematicType val publicSchemsOnly = updateEvent.publicSchemsOnly ?: event.publicSchemsOnly() if (updateEvent.addReferee != null) { @@ -231,6 +245,11 @@ fun Route.configureEventsRoute() { event.delete() call.respond(HttpStatusCode.NoContent) } + configureEventFightRoutes() + configureEventTeams() + configureEventGroups() + configureEventRelations() + configureEventRefereesRouting() } } } diff --git a/WebsiteBackend/src/de/steamwar/routes/Page.kt b/WebsiteBackend/src/de/steamwar/routes/Page.kt index 6f9a9fc4..2f8de4ee 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Page.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Page.kt @@ -24,7 +24,6 @@ import de.steamwar.plugins.SWAuthPrincipal import de.steamwar.plugins.SWPermissionCheck import de.steamwar.sql.UserPerm import io.ktor.client.* -import io.ktor.client.call.* import io.ktor.client.engine.java.* import io.ktor.client.plugins.* import io.ktor.client.plugins.contentnegotiation.* @@ -37,11 +36,13 @@ import io.ktor.server.auth.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -import io.ktor.util.reflect.* import kotlinx.serialization.Serializable -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.* +import java.time.Instant +import java.time.LocalDate +import java.time.format.DateTimeFormatter import java.util.Base64 +import java.util.Date val pathPageIdMap = mutableMapOf() var pageId = 1 @@ -90,6 +91,9 @@ data class PageResponse( @Serializable data class CreatePageRequest(val path: String, val slug: String?, val title: String?) +@Serializable +data class AddImageRequest(val name: String, val data: String) + @Serializable data class CreateBranchRequest(val branch: String) @@ -102,6 +106,9 @@ data class MergeBranchRequest(val branch: String, val message: String) @Serializable data class DeletePageRequest(val sha: String, val message: String) +@Serializable +data class CreateGiteaPageRequest(val message: String, val content: String, val branch: String, val author: Identity) + fun Route.configurePage() { val client = HttpClient(Java) { install(ContentNegotiation) { @@ -113,70 +120,44 @@ fun Route.configurePage() { } } + suspend fun filesInDirectory(path: String, branch: String = "master", fileFilter: (name: String) -> Boolean = { true }): List { + val filesToCheck = mutableListOf(path) + val files = mutableListOf() + + while (filesToCheck.isNotEmpty()) { + val path = filesToCheck.removeAt(0) + val res = client.get("repos/SteamWar/Website/contents/$path?ref=$branch") + val fileJson = Json.parseToJsonElement(res.bodyAsText()) + + if (fileJson is JsonArray) { + fileJson.forEach { + val obj = it.jsonObject + if (obj["type"]?.jsonPrimitive?.content == "dir") { + filesToCheck.add(obj["path"]?.jsonPrimitive?.content!!) + } else if (obj["type"]?.jsonPrimitive?.content == "file" && fileFilter(obj["name"]!!.jsonPrimitive.content)) { + files.add(PageResponseList(obj, pathPageIdMap.computeIfAbsent(obj["path"]?.jsonPrimitive?.content!!) { pageId++ })) + } + } + } else { + files.add(PageResponseList(fileJson.jsonObject, pathPageIdMap.computeIfAbsent(fileJson.jsonObject["path"]?.jsonPrimitive?.content!!) { pageId++ })) + } + } + + return files + } + route("page") { install(SWPermissionCheck) { permission = UserPerm.MODERATION } get { val branch = call.request.queryParameters["branch"] ?: "master" - val filesToCheck = mutableListOf("src/content") - val files = mutableListOf() - while (filesToCheck.isNotEmpty()) { - val path = filesToCheck.removeAt(0) - val res = client.get("repos/SteamWar/Website/contents/$path?ref=$branch") - val fileJson = Json.parseToJsonElement(res.bodyAsText()) - - if (fileJson is JsonArray) { - fileJson.forEach { - val obj = it.jsonObject - if (obj["type"]?.jsonPrimitive?.content == "dir") { - filesToCheck.add(obj["path"]?.jsonPrimitive?.content!!) - } else if (obj["type"]?.jsonPrimitive?.content == "file" && (obj["name"]?.jsonPrimitive?.content?.endsWith(".md") == true || obj["name"]?.jsonPrimitive?.content?.endsWith(".json") == true)) { - files.add(PageResponseList(obj, pathPageIdMap.computeIfAbsent(obj["path"]?.jsonPrimitive?.content!!) { pageId++ })) - } - } - } else { - files.add(PageResponseList(fileJson.jsonObject, pathPageIdMap.computeIfAbsent(fileJson.jsonObject["path"]?.jsonPrimitive?.content!!) { pageId++ })) - } - } - - call.respond(files) - } - get("branch") { - val res = client.get("repos/SteamWar/Website/branches") - call.respond(res.status, Json.parseToJsonElement(res.bodyAsText()).jsonArray.map { it.jsonObject["name"]?.jsonPrimitive?.content!! }) - } - post("branch") { - @Serializable - data class CreateGiteaBranchRequest(val new_branch_name: String, val old_branch_name: String) - - val branch = call.receive().branch - val res = client.post("repos/SteamWar/Website/branches") { - contentType(ContentType.Application.Json) - setBody(CreateGiteaBranchRequest(branch, "master")) - } - - - @Serializable - data class CreateGiteaMergeRequest(val base: String, val head: String, val title: String) - - client.post("repos/SteamWar/Website/pulls") { - contentType(ContentType.Application.Json) - setBody(CreateGiteaMergeRequest("master", branch, "Merge branch $branch")) - } - - call.respond(res.status) - } - delete("branch") { - val branch = call.receive().branch - val res = client.delete("repos/SteamWar/Website/branches/$branch") - call.respond(res.status) + call.respond(filesInDirectory("/src/content", branch) { + it.endsWith(".md") || it.endsWith(".json") + }) } post { - @Serializable - data class CreateGiteaPageRequest(val message: String, val content: String, val branch: String, val author: Identity) - val req = call.receive() if(req.path.startsWith("src/content/")) { call.respond(HttpStatusCode.BadRequest, "Invalid path") @@ -186,66 +167,125 @@ fun Route.configurePage() { contentType(ContentType.Application.Json) setBody(CreateGiteaPageRequest( "Create page ${req.path}", - Base64.getEncoder().encodeToString(""" + Base64.getEncoder().encodeToString(( + if (req.path.endsWith(".md")) """ --- - title: ${req.title ?: "[Enter Title]"} - description: [Enter Description] - slug: ${req.slug ?: "[Enter Slug]"} + title: ${req.title?.removeSuffix(".md") ?: "Enter Title"} + description: Enter Description + key: ${req.slug?.lowercase()?.removeSuffix(".md") ?: "Enter Slug"} + created: ${LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE)} + tags: + - test --- # ${req.path} - """.trimIndent().toByteArray()), + """ else "{}" + ).trimIndent().toByteArray()), call.request.queryParameters["branch"] ?: "master", Identity(call.principal()!!.user.userName, "admin-tool@steamwar.de" - ))) + ))) } call.respond(res.status) } - get("{id}") { - val id = call.parameters["id"]?.toIntOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest, "Invalid id") - val path = pathPageIdMap.entries.find { it.value == id }?.key ?: return@get call.respond(HttpStatusCode.NotFound, "Page not found") - - val branch = call.request.queryParameters["branch"] ?: "master" - val res = client.get("repos/SteamWar/Website/contents/$path?ref=$branch") - val fileJson = Json.parseToJsonElement(res.bodyAsText()) - if (fileJson is JsonArray) { - return@get call.respond(HttpStatusCode.BadRequest, "Invalid id") + route("branch") { + get { + val res = client.get("repos/SteamWar/Website/branches") + call.respond(res.status, Json.parseToJsonElement(res.bodyAsText()).jsonArray.map { it.jsonObject["name"]?.jsonPrimitive?.content!! }) } + post { + @Serializable + data class CreateGiteaBranchRequest(val new_branch_name: String, val old_branch_name: String) - val file = PageResponse(fileJson.jsonObject, id) - call.respond(file) + val branch = call.receive().branch + val res = client.post("repos/SteamWar/Website/branches") { + contentType(ContentType.Application.Json) + setBody(CreateGiteaBranchRequest(branch, "master")) + } + + + @Serializable + data class CreateGiteaMergeRequest(val base: String, val head: String, val title: String) + + client.post("repos/SteamWar/Website/pulls") { + contentType(ContentType.Application.Json) + setBody(CreateGiteaMergeRequest("master", branch, "Merge branch $branch")) + } + + call.respond(res.status) + } + delete { + val branch = call.receive().branch + val res = client.delete("repos/SteamWar/Website/branches/$branch") + call.respond(res.status) + } } + route("{id}") { + get { + val id = call.parameters["id"]?.toIntOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest, "Invalid id") + val path = pathPageIdMap.entries.find { it.value == id }?.key ?: return@get call.respond(HttpStatusCode.NotFound, "Page not found") - delete("{id}") { - val data = call.receive() + val branch = call.request.queryParameters["branch"] ?: "master" + val res = client.get("repos/SteamWar/Website/contents/$path?ref=$branch") + val fileJson = Json.parseToJsonElement(res.bodyAsText()) + if (fileJson is JsonArray) { + return@get call.respond(HttpStatusCode.BadRequest, "Invalid id") + } - val path = pathPageIdMap.entries.find { it.value == call.parameters["id"]?.toIntOrNull() }?.key ?: return@delete call.respond(HttpStatusCode.NotFound, "Page not found") - val branch = call.request.queryParameters["branch"] ?: "master" - - @Serializable - data class DeleteGiteaPageRequest(val sha: String, val message: String, val branch: String, val author: Identity) - - val res = client.delete("repos/SteamWar/Website/contents/$path") { - contentType(ContentType.Application.Json) - setBody(DeleteGiteaPageRequest(data.sha, data.message, branch, Identity(call.principal()!!.user.userName, "admin-tool@steamwar.de"))) + val file = PageResponse(fileJson.jsonObject, id) + call.respond(file) } + delete { + val data = call.receive() - call.respond(res.status) + val path = pathPageIdMap.entries.find { it.value == call.parameters["id"]?.toIntOrNull() }?.key ?: return@delete call.respond(HttpStatusCode.NotFound, "Page not found") + val branch = call.request.queryParameters["branch"] ?: "master" + + @Serializable + data class DeleteGiteaPageRequest(val sha: String, val message: String, val branch: String, val author: Identity) + + val res = client.delete("repos/SteamWar/Website/contents/$path") { + contentType(ContentType.Application.Json) + setBody(DeleteGiteaPageRequest(data.sha, data.message, branch, Identity(call.principal()!!.user.userName, "admin-tool@steamwar.de"))) + } + + call.respond(res.status) + } + put { + @Serializable + data class UpdateGiteaPageRequest(val content: String, val sha: String, val message: String, val branch: String, val author: Identity) + + val data = call.receive() + val path = pathPageIdMap.entries.find { it.value == call.parameters["id"]?.toIntOrNull() }?.key ?: return@put call.respond(HttpStatusCode.NotFound, "Page not found") + + val res = client.put("repos/SteamWar/Website/contents/$path") { + contentType(ContentType.Application.Json) + setBody(UpdateGiteaPageRequest(data.content, data.sha, data.message, (call.request.queryParameters["branch"] ?: "master"), Identity(call.principal()!!.user.userName, "admin-tool@steamwar.de"))) + } + + call.respond(res.status) + } } + route("images") { + get { + val branch = call.request.queryParameters["branch"] ?: "master" - put("{id}") { - @Serializable - data class UpdateGiteaPageRequest(val content: String, val sha: String, val message: String, val branch: String, val author: Identity) - - val data = call.receive() - val path = pathPageIdMap.entries.find { it.value == call.parameters["id"]?.toIntOrNull() }?.key ?: return@put call.respond(HttpStatusCode.NotFound, "Page not found") - - val res = client.put("repos/SteamWar/Website/contents/$path") { - contentType(ContentType.Application.Json) - setBody(UpdateGiteaPageRequest(data.content, data.sha, data.message, (call.request.queryParameters["branch"] ?: "master"), Identity(call.principal()!!.user.userName, "admin-tool@steamwar.de"))) + call.respond(filesInDirectory("/src/images", branch)) } + post { + val req = call.receive() - call.respond(res.status) + client.post("repos/SteamWar/Website/contents/src/images/${req.name}") { + contentType(ContentType.Application.Json) + setBody(CreateGiteaPageRequest( + "Add Image ${req.name}", + req.data, + call.request.queryParameters["branch"] ?: "master", + Identity(call.principal()!!.user.userName, "admin-tool@steamwar.de" + ))) + } + + call.respond(HttpStatusCode.Created) + } } } } \ No newline at end of file diff --git a/WebsiteBackend/src/de/steamwar/routes/Routes.kt b/WebsiteBackend/src/de/steamwar/routes/Routes.kt index 388f8055..f4e883ee 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Routes.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Routes.kt @@ -28,7 +28,6 @@ fun Application.configureRoutes() { authenticate("sw-auth", optional = true) { configureEventsRoute() configureDataRoutes() - configureEventFightRoutes() configureUserPerms() configureStats() configurePage() diff --git a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt index ec3b54fb..7024a657 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt @@ -89,7 +89,7 @@ fun Route.configureSchematic() { return@get } - val data = NodeData.get(node) ?: run { + val data = NodeData.getLatest(node) ?: run { call.respond(HttpStatusCode.InternalServerError) return@get } @@ -166,8 +166,7 @@ fun Route.configureSchematic() { } catch (_: Exception) {} } - val data = NodeData(node.id, version) - data.saveFromStream(content.inputStream(), version) + NodeData.saveFromStream(node, content.inputStream(), version) call.respond(ResponseSchematic(node)) } catch (e: Exception) { diff --git a/buildSrc/src/steamwar.devserver.gradle b/buildSrc/src/steamwar.devserver.gradle index 53f8be3d..3c5cf882 100644 --- a/buildSrc/src/steamwar.devserver.gradle +++ b/buildSrc/src/steamwar.devserver.gradle @@ -1,3 +1,5 @@ +import java.security.MessageDigest + /* * This file is a part of the SteamWar software. * @@ -121,6 +123,22 @@ class DevServer extends DefaultTask { } def archive = archiveTask.archiveFile.get().asFile + + Process process = new ProcessBuilder("ssh", host, "-T", "sha1sum $base/${archive.name.replace("-all", "")}").start(); + byte[] bytes = MessageDigest.getInstance("sha1").digest(archive.bytes) + StringBuilder sb = new StringBuilder() + for (byte b : bytes) { + sb.append(String.format("%02X", b)) + } + boolean same = false + process.inputStream.readLines().forEach { + same |= it.startsWith(sb.toString().toLowerCase()) + } + if (same) { + println("Skipping $archive") + return + } + println("Uploading $archive") new ProcessBuilder("ssh", host, "-T", "rm $base/${archive.name.replace("-all", "")}").start().waitFor() new ProcessBuilder("scp", archive.absolutePath, "$host:~/$base/${archive.name.replace("-all", "")}").start().waitFor() diff --git a/settings.gradle.kts b/settings.gradle.kts index 9a649445..8ab618ff 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -111,11 +111,11 @@ dependencyResolutionManagement { library("spigotapi", "org.spigotmc:spigot-api:1.20-R0.1-SNAPSHOT") library("spigotannotations", "org.spigotmc:plugin-annotations:1.2.3-SNAPSHOT") library("paperapi", "io.papermc.paper:paper-api:1.19.2-R0.1-SNAPSHOT") - library("paperapi21", "io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT") + library("paperapi21", "io.papermc.paper:paper-api:1.21.6-R0.1-SNAPSHOT") library("authlib", "com.mojang:authlib:1.5.25") library("datafixer", "com.mojang:datafixerupper:4.0.26") library("brigadier", "com.mojang:brigadier:1.0.18") - library("anvilgui", "net.wesjd:anvilgui:1.10.3-SNAPSHOT") + library("anvilgui", "net.wesjd:anvilgui:1.10.6-SNAPSHOT") library("nms8", "de.steamwar:spigot:1.8") library("nms9", "de.steamwar:spigot:1.9") @@ -126,7 +126,7 @@ dependencyResolutionManagement { library("nms18", "de.steamwar:spigot:1.18") library("nms19", "de.steamwar:spigot:1.19") library("nms20", "de.steamwar:spigot:1.20") - library("nms21", "de.steamwar:spigot:1.21") + library("nms21", "de.steamwar:spigot:1.21.5") library("axiom", "de.steamwar:axiompaper:RELEASE") library("worldedit12", "de.steamwar:worldedit:1.12") @@ -184,6 +184,7 @@ include("CommandFramework") include( "CommonCore", + "CommonCore:Data", "CommonCore:SQL", "CommonCore:Network" ) @@ -246,6 +247,7 @@ include("TutorialSystem") include( "VelocityCore", + "VelocityCore:Dependencies", "VelocityCore:Persistent" ) diff --git a/steamwarci.yml b/steamwarci.yml index 3e3660b1..5548033a 100644 --- a/steamwarci.yml +++ b/steamwarci.yml @@ -29,6 +29,7 @@ artifacts: "/jars/TutorialSystem.jar": "TutorialSystem/build/libs/TutorialSystem.jar" "/jars/PersistentVelocityCore.jar": "VelocityCore/Persistent/build/libs/Persistent.jar" + "/jars/DependenciesVelocityCore.jar": "VelocityCore/Dependencies/build/libs/Dependencies-all.jar" "/jars/VelocityCore.jar": "VelocityCore/build/libs/VelocityCore-all.jar" "/usr/local/bin/deployarena.py": "VelocityCore/deployarena.py"