From 3e270643e8e985f94e0d10f43a579c5dd0d8e85a Mon Sep 17 00:00:00 2001 From: TheBreadBeard Date: Wed, 27 Nov 2024 19:18:41 +0100 Subject: [PATCH 01/22] Add private ticket log --- .../discord/listeners/DiscordTicketHandler.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java index a9592c6c..27a20fb6 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java @@ -126,6 +126,14 @@ public class DiscordTicketHandler extends ListenerAdapter { SplitUtil.Strategy.ANYWHERE ).stream().map(message -> new MessageCreateBuilder().setEmbeds(embedBuilder.setDescription(message).build())).forEach(builder -> logChannel.sendMessage(builder.build()).queue()); + SplitUtil.split( + messages.stream() + .map(StringBuilder::toString).collect(Collectors.joining()), + 2000, + SplitUtil.Strategy.NEWLINE, + SplitUtil.Strategy.ANYWHERE + ).stream().map(message -> new MessageCreateBuilder().setEmbeds(embedBuilder.setDescription(message).build())).forEach(builder -> logChannel.sendMessage(builder.build()).queue()); + Chatter.serverteam().prefixless("DISCORD_TICKET_CLOSED", channel.getName()); channel.delete().reason("Closed").queue(); } From b3cd8d843f5da01c75161966473521b8a27df1f3 Mon Sep 17 00:00:00 2001 From: TheBreadBeard Date: Wed, 27 Nov 2024 19:34:19 +0100 Subject: [PATCH 02/22] Add private ticket log --- .../velocitycore/discord/listeners/DiscordTicketHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java index 27a20fb6..d797a6f3 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java @@ -132,7 +132,7 @@ public class DiscordTicketHandler extends ListenerAdapter { 2000, SplitUtil.Strategy.NEWLINE, SplitUtil.Strategy.ANYWHERE - ).stream().map(message -> new MessageCreateBuilder().setEmbeds(embedBuilder.setDescription(message).build())).forEach(builder -> logChannel.sendMessage(builder.build()).queue()); + ).stream().map(message -> new MessageCreateBuilder().setEmbeds(embedBuilder.setDescription(message).build())).forEach(builder -> user.openPrivateChannel().queue(privateChannel -> privateChannel.sendMessage(builder.build()).queue())); Chatter.serverteam().prefixless("DISCORD_TICKET_CLOSED", channel.getName()); channel.delete().reason("Closed").queue(); From 0134ef1f6181369137666f615968839f0dbc2eb9 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Tue, 3 Dec 2024 22:43:14 +0100 Subject: [PATCH 03/22] Maybe, Fix Schematics Readers --- .../SQL/src/de/steamwar/sql/NodeData.java | 26 +- .../src/de/steamwar/sql/SchematicNode.java | 5 +- .../fightsystem/utils/WorldeditWrapper14.java | 3 +- .../fightsystem/utils/WorldeditWrapper8.java | 3 +- .../fightsystem/record/PacketProcessor.java | 3 +- .../SchematicCommandUtils.java | 2 +- .../de/steamwar/core/WorldEditWrapper14.java | 57 +- .../de/steamwar/core/WorldEditWrapper18.java | 13 +- SpigotCore/SpigotCore_21/build.gradle.kts | 20 +- .../steamwar/core/FaWeSchematicReaderV3.java | 857 ++++++++++++++++++ .../de/steamwar/core/WorldEditWrapper21.java | 49 +- .../de/steamwar/core/WorldEditWrapper8.java | 46 +- .../src/de/steamwar/core/ErrorHandler.java | 2 +- .../de/steamwar/core/WorldEditWrapper.java | 24 +- .../src/de/steamwar/sql/SchematicData.java | 10 +- SpigotCore/build.gradle.kts | 7 +- .../discord/listeners/DiscordSchemUpload.java | 2 +- .../src/de/steamwar/routes/Schematic.kt | 6 +- 18 files changed, 1010 insertions(+), 125 deletions(-) create mode 100644 SpigotCore/SpigotCore_21/src/de/steamwar/core/FaWeSchematicReaderV3.java diff --git a/CommonCore/SQL/src/de/steamwar/sql/NodeData.java b/CommonCore/SQL/src/de/steamwar/sql/NodeData.java index 52743811..c580dc3f 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/NodeData.java +++ b/CommonCore/SQL/src/de/steamwar/sql/NodeData.java @@ -28,12 +28,15 @@ import java.sql.PreparedStatement; import java.util.zip.GZIPInputStream; @AllArgsConstructor +@Getter public class NodeData { static { new SqlTypeMapper<>(PipedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("PipedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream); new SqlTypeMapper<>(ByteArrayInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("ByteArrayInputStream is write only datatype"); }, PreparedStatement::setBinaryStream); new SqlTypeMapper<>(BufferedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("BufferedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream); + + SqlTypeMapper.ordinalEnumMapper(SchematicFormat.class); } private static final Table table = new Table<>(NodeData.class); @@ -48,21 +51,24 @@ public class NodeData { throw new IllegalArgumentException("Node is a directory"); return get.select(rs -> { if(rs.next()) { - return new NodeData(node.getId(), rs.getBoolean("NodeFormat")); + return new NodeData(node.getId(), SchematicFormat.values()[rs.getInt("NodeFormat")]); } else { - return new NodeData(node.getId(), false); + return new NodeData(node.getId(), SchematicFormat.MCEDIT); } }, node); } - @Getter @Field(keys = {Table.PRIMARY}) private final int nodeId; @Field - private boolean nodeFormat; + private SchematicFormat nodeFormat; public InputStream schemData() throws IOException { + return new GZIPInputStream(schemDataRaw()); + } + + public InputStream schemDataRaw() throws IOException { try { return selSchemData.select(rs -> { rs.next(); @@ -81,12 +87,18 @@ public class NodeData { } } - public void saveFromStream(InputStream blob, boolean newFormat) { + public void saveFromStream(InputStream blob, SchematicFormat newFormat) { updateDatabase.update(nodeId, newFormat, blob); nodeFormat = newFormat; } - public boolean getNodeFormat() { - return nodeFormat; + @AllArgsConstructor + @Getter + public enum SchematicFormat { + MCEDIT(".schematic"), + V2(".schem"), + V3(".schem"); + + private final String fileEnding; } } diff --git a/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java b/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java index 3df740da..bece8549 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java +++ b/CommonCore/SQL/src/de/steamwar/sql/SchematicNode.java @@ -375,11 +375,10 @@ public class SchematicNode { return nodeType == null; } - @Deprecated - public boolean getSchemFormat() { + public String getFileEnding() { if(isDir()) throw new SecurityException("Node is Directory"); - return NodeData.get(this).getNodeFormat(); + return NodeData.get(this).getNodeFormat().getFileEnding(); } public int getRank() { 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 288b89e8..df366205 100644 --- a/FightSystem/FightSystem_14/src/de/steamwar/fightsystem/utils/WorldeditWrapper14.java +++ b/FightSystem/FightSystem_14/src/de/steamwar/fightsystem/utils/WorldeditWrapper14.java @@ -42,6 +42,7 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; +import de.steamwar.sql.NodeData; import de.steamwar.sql.SchematicData; import de.steamwar.sql.SchematicNode; import org.bukkit.DyeColor; @@ -144,6 +145,6 @@ public class WorldeditWrapper14 implements WorldeditWrapper { throw new SecurityException(e); } - new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), true); + new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), NodeData.SchematicFormat.V2); } } 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 19854db8..018552f2 100644 --- a/FightSystem/FightSystem_8/src/de/steamwar/fightsystem/utils/WorldeditWrapper8.java +++ b/FightSystem/FightSystem_8/src/de/steamwar/fightsystem/utils/WorldeditWrapper8.java @@ -39,6 +39,7 @@ import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.world.World; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; +import de.steamwar.sql.NodeData; import de.steamwar.sql.SchematicData; import de.steamwar.sql.SchematicNode; import org.bukkit.DyeColor; @@ -142,6 +143,6 @@ public class WorldeditWrapper8 implements WorldeditWrapper { throw new SecurityException(e); } - new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), false); + new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), NodeData.SchematicFormat.MCEDIT); } } 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 ee0c1af1..e6ed1d3a 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java @@ -22,6 +22,7 @@ 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; import de.steamwar.entity.REntityServer; import de.steamwar.entity.RPlayer; @@ -519,7 +520,7 @@ public class PacketProcessor implements Listener { public void close() { // FAWE 1.12 calls close... } - }, Core.getVersion() > 12); + }, WorldEditWrapper.getNativeFormat()); execSync(() -> team.pasteSchem(schemId, clipboard)); } 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 753cd3b9..14ecdabb 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 @@ -245,7 +245,7 @@ public class SchematicCommandUtils { SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_ELO", player, node.getElo(Season.getSeason())); } - SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_FORMAT", player, node.getSchemFormat() ? ".schem" : ".schematic"); + SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_FORMAT", player, node.getFileEnding()); CheckedSchematic.getLastDeclinedOfNode(node.getId()).stream().findFirst().ifPresent(checkedSchematic -> SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_STATUS", player, checkedSchematic.getEndTime(), checkedSchematic.getDeclineReason())); } else { SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_TYPE", player, SchematicSystem.MESSAGE.parse("UTIL_INFO_TYPE_DIR", player)); diff --git a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java index cd116bac..cba992f5 100644 --- a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java +++ b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java @@ -45,6 +45,7 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; import de.steamwar.sql.NoClipboardException; +import de.steamwar.sql.NodeData; import org.bukkit.entity.Player; import org.bukkit.util.Vector; @@ -57,24 +58,17 @@ import static com.google.common.base.Preconditions.checkNotNull; public class WorldEditWrapper14 implements WorldEditWrapper { - private static final ClipboardFormat SCHEMATIC = BuiltInClipboardFormat.MCEDIT_SCHEMATIC; - private static final ClipboardFormat SCHEM = BuiltInClipboardFormat.SPONGE_SCHEMATIC; - @Override - public InputStream getPlayerClipboard(Player player, boolean schemFormat) { - return WorldEditWrapper.getPlayerClipboard(player, schemFormat, (outputStream, clipboard, clipboardHolder) -> { - if(schemFormat){ - ClipboardWriter writer = SCHEM.getWriter(outputStream); - writer.write(clipboard); - writer.close(); - }else{ - SCHEMATIC.getWriter(outputStream).write(clipboard); - } + public InputStream getPlayerClipboard(Player player) { + return WorldEditWrapper.getPlayerClipboard(player, (outputStream, clipboard, clipboardHolder) -> { + ClipboardWriter writer = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(outputStream); + writer.write(clipboard); + writer.close(); }); } @Override - public void setPlayerClipboard(Player player, InputStream is, boolean schemFormat) { + public void setPlayerClipboard(Player player, InputStream is, NodeData.SchematicFormat schemFormat) { Clipboard clipboard = null; try { clipboard = getClipboard(is, schemFormat); @@ -90,12 +84,16 @@ public class WorldEditWrapper14 implements WorldEditWrapper { } @Override - public Clipboard getClipboard(InputStream is, boolean schemFormat) throws IOException { + public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException { try { - if(schemFormat){ - return new SpongeSchematicReader(new NBTInputStream(is)).read(); - }else{ - return new MCEditSchematicReader(new NBTInputStream(is)).read(); + + switch (schemFormat) { + case V2: + return new SpongeSchematicReader(new NBTInputStream(is)).read(); + case MCEDIT: + return new MCEditSchematicReader(new NBTInputStream(is)).read(); + default: + throw new IOException("This schematic format is currently not supported"); } } catch (NullPointerException e) { throw new NoClipboardException(); @@ -455,6 +453,11 @@ public class WorldEditWrapper14 implements WorldEditWrapper { // Check Map schematic = schematicTag.getValue(); + if (schematic.size() == 1) { + schematicTag = requireTag(schematic, "Schematic", CompoundTag.class); + schematic = schematicTag.getValue(); + } + schematicVersion = requireTag(schematic, "Version", IntTag.class).getValue(); return schematicTag; } @@ -499,12 +502,16 @@ public class WorldEditWrapper14 implements WorldEditWrapper { region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE)); } - IntTag paletteMaxTag = getTag(schematic, "PaletteMax", IntTag.class); - Map paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue(); - if (paletteMaxTag != null && paletteObject.size() != paletteMaxTag.getValue()) { - throw new IOException("Block palette size does not match expected size."); + Map blockContainer = null; + boolean v3Mode = false; + + if (schematicVersion == 3) { + blockContainer = requireTag(schematic, "Blocks", CompoundTag.class).getValue(); + v3Mode = true; } + Map paletteObject = requireTag(v3Mode ? blockContainer: schematic, "Palette", CompoundTag.class).getValue(); + Map palette = new HashMap<>(); ParserContext parserContext = new ParserContext(); @@ -526,12 +533,12 @@ public class WorldEditWrapper14 implements WorldEditWrapper { palette.put(id, state); } - byte[] blocks = requireTag(schematic, "BlockData", ByteArrayTag.class).getValue(); + byte[] blocks = requireTag(v3Mode ? blockContainer: schematic, v3Mode ? "Data" : "BlockData", ByteArrayTag.class).getValue(); Map> tileEntitiesMap = new HashMap<>(); - ListTag tileEntities = getTag(schematic, "BlockEntities", ListTag.class); + ListTag tileEntities = getTag(v3Mode ? blockContainer: schematic, "BlockEntities", ListTag.class); if (tileEntities == null) { - tileEntities = getTag(schematic, "TileEntities", ListTag.class); + tileEntities = getTag(v3Mode ? blockContainer: schematic, "TileEntities", ListTag.class); } if (tileEntities != null) { List> tileEntityTags = tileEntities.getValue().stream() diff --git a/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java b/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java index 903113c4..23590848 100644 --- a/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java +++ b/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java @@ -19,10 +19,12 @@ package de.steamwar.core; +import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReader; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.*; import de.steamwar.sql.NoClipboardException; +import de.steamwar.sql.NodeData; import java.io.IOException; import java.io.InputStream; @@ -31,11 +33,18 @@ public class WorldEditWrapper18 extends WorldEditWrapper14 { @Override @SuppressWarnings("removal") - public Clipboard getClipboard(InputStream is, boolean schemFormat) throws IOException { + public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException { NBTInputStream nbtStream = new NBTInputStream(is); //Use FAWE reader due to FAWE capability of reading corrupt FAWE schems try { - return (schemFormat ? new SpongeSchematicReader(nbtStream) : new MCEditSchematicReader(nbtStream)).read(); + switch (schemFormat) { + case MCEDIT: + return new MCEditSchematicReader(nbtStream).read(); + case V2: + return new SpongeSchematicReader(nbtStream).read(); + default: + throw new IllegalArgumentException("Unsupported schematic format"); + } } catch (NullPointerException e) { throw new NoClipboardException(); } diff --git a/SpigotCore/SpigotCore_21/build.gradle.kts b/SpigotCore/SpigotCore_21/build.gradle.kts index b9a7805e..8f2acba4 100644 --- a/SpigotCore/SpigotCore_21/build.gradle.kts +++ b/SpigotCore/SpigotCore_21/build.gradle.kts @@ -21,7 +21,13 @@ plugins { steamwar.java } +java { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} + dependencies { + compileOnly(project(":CommonCore", "default")) compileOnly(project(":SpigotCore:SpigotCore_Main", "default")) compileOnly(project(":SpigotCore:SpigotCore_18", "default")) compileOnly(project(":SpigotCore:SpigotCore_14", "default")) @@ -29,16 +35,6 @@ dependencies { compileOnly(libs.fawe21) - compileOnly(libs.paperapi21) { - attributes { - // Very Hacky, but it works - attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21) - } - } - compileOnly(libs.nms21) { - attributes { - // Very Hacky, but it works - attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21) - } - } + compileOnly(libs.paperapi21) + compileOnly(libs.nms21) } diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/FaWeSchematicReaderV3.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/FaWeSchematicReaderV3.java new file mode 100644 index 00000000..9a11dd2e --- /dev/null +++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/FaWeSchematicReaderV3.java @@ -0,0 +1,857 @@ +/* + * 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.core; + +import com.fastasyncworldedit.core.extent.clipboard.LinearClipboard; +import com.fastasyncworldedit.core.extent.clipboard.SimpleClipboard; +import com.fastasyncworldedit.core.internal.io.ResettableFileInputStream; +import com.fastasyncworldedit.core.internal.io.VarIntStreamIterator; +import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; +import com.fastasyncworldedit.core.util.IOUtil; +import com.fastasyncworldedit.core.util.MathMan; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.NBTConstants; +import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.extent.clipboard.io.sponge.ReaderUtil; +import com.sk89q.worldedit.extent.clipboard.io.sponge.VersionedDataFixer; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import com.sk89q.worldedit.world.entity.EntityType; +import it.unimi.dsi.fastutil.io.FastBufferedInputStream; +import it.unimi.dsi.fastutil.io.FastBufferedOutputStream; +import net.jpountz.lz4.LZ4BlockInputStream; +import net.jpountz.lz4.LZ4BlockOutputStream; +import org.apache.logging.log4j.Logger; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinTagType; +import org.jetbrains.annotations.ApiStatus; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalInt; +import java.util.Set; +import java.util.UUID; +import java.util.function.BooleanSupplier; +import java.util.function.Function; +import java.util.zip.GZIPInputStream; + +/** + * ClipboardReader for the Sponge Schematic Format v3. + * Not necessarily much faster than {@link com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader}, but uses a + * stream based approach to keep the memory overhead minimal (especially in larger schematics) + * + * @since 2.11.1 + */ +@SuppressWarnings("removal") // JNBT +public class FaWeSchematicReaderV3 implements ClipboardReader { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static final byte CACHE_IDENTIFIER_END = 0x00; + private static final byte CACHE_IDENTIFIER_BLOCK = 0x01; + private static final byte CACHE_IDENTIFIER_BIOMES = 0x02; + private static final byte CACHE_IDENTIFIER_ENTITIES = 0x03; + private static final byte CACHE_IDENTIFIER_BLOCK_TILE_ENTITIES = 0x04; + + private final InputStream parentStream; + private final MutableBlockVector3 dimensions = MutableBlockVector3.at(0, 0, 0); + private final Set remainingTags; + + private DataInputStream dataInputStream; + private NBTInputStream nbtInputStream; + + private VersionedDataFixer dataFixer; + private BlockVector3 offset; + private BlockVector3 origin = BlockVector3.ZERO; + private BlockState[] blockPalette; + private BiomeType[] biomePalette; + private int dataVersion = -1; + + // Only used if the InputStream is not file based (and therefor does not support resets based on FileChannels) + // and the file is unordered + // Data and Palette cache is separated, as the data requires a fully populated palette - and the order is not guaranteed + private byte[] dataCache; + private byte[] paletteCache; + private OutputStream dataCacheWriter; + private OutputStream paletteCacheWriter; + + + public FaWeSchematicReaderV3(@NonNull InputStream stream) { + Objects.requireNonNull(stream, "stream"); + if (stream instanceof ResettableFileInputStream) { + stream.mark(Integer.MAX_VALUE); + this.remainingTags = new HashSet<>(); + } else if (stream instanceof FileInputStream fileInputStream) { + stream = new ResettableFileInputStream(fileInputStream); + stream.mark(Integer.MAX_VALUE); + this.remainingTags = new HashSet<>(); + } else if (stream instanceof FastBufferedInputStream || stream instanceof BufferedInputStream) { + this.remainingTags = null; + } else { + stream = new FastBufferedInputStream(stream); + this.remainingTags = null; + } + this.parentStream = stream; + } + + @Override + public Clipboard read(final UUID uuid, final Function createOutput) throws IOException { + Clipboard clipboard = null; + + this.setSubStreams(); + skipHeader(this.dataInputStream); + + byte type; + String tag; + while ((type = dataInputStream.readByte()) != NBTConstants.TYPE_END) { + tag = this.dataInputStream.readUTF(); + switch (tag) { + case "DataVersion" -> { + final Platform platform = + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); + this.dataVersion = this.dataInputStream.readInt(); + this.dataFixer = ReaderUtil.getVersionedDataFixer(this.dataVersion, platform, platform.getDataVersion()); + } + case "Metadata" -> { + LinCompoundTag metadataCompoundTag = + (LinCompoundTag) this.nbtInputStream.readTagPayload(NBTConstants.TYPE_COMPOUND, 0).toLinTag(); + + LinCompoundTag worldEditTag = metadataCompoundTag.findTag("WorldEdit", LinTagType.compoundTag()); + if (worldEditTag != null) { // allowed to be optional + LinIntArrayTag originTag = worldEditTag.findTag("Origin", LinTagType.intArrayTag()); + if (originTag != null) { // allowed to be optional + int[] parts = originTag.value(); + + if (parts.length != 3) { + throw new IOException("`Metadata > WorldEdit > Origin` int array length is invalid."); + } + + this.origin = BlockVector3.at(parts[0], parts[1], parts[2]); + } + } + } + case "Offset" -> { + this.dataInputStream.skipNBytes(4); // Array Length field (4 byte int) + this.offset = BlockVector3.at( + this.dataInputStream.readInt(), + this.dataInputStream.readInt(), + this.dataInputStream.readInt() + ); + } + case "Width" -> this.dimensions.mutX(this.dataInputStream.readShort() & 0xFFFF); + case "Height" -> this.dimensions.mutY(this.dataInputStream.readShort() & 0xFFFF); + case "Length" -> this.dimensions.mutZ(this.dataInputStream.readShort() & 0xFFFF); + case "Blocks" -> readBlocks(clipboard); + case "Biomes" -> readBiomes(clipboard); + case "Entities" -> readEntities(clipboard); + default -> this.nbtInputStream.readTagPayloadLazy(type, 0); + } + if (clipboard == null && this.areDimensionsAvailable()) { + clipboard = createOutput.apply(this.dimensions); + } + } + + if (clipboard == null) { + throw new IOException("Invalid schematic - missing dimensions"); + } + if (dataFixer == null) { + throw new IOException("Invalid schematic - missing DataVersion"); + } + + if (this.supportsReset() && !remainingTags.isEmpty()) { + readRemainingDataReset(clipboard); + } else if (this.dataCacheWriter != null || this.paletteCacheWriter != null) { + readRemainingDataCache(clipboard); + } + + clipboard.setOrigin(this.offset.multiply(-1)); + if (clipboard instanceof SimpleClipboard simpleClipboard && !this.offset.equals(BlockVector3.ZERO)) { + clipboard = new BlockArrayClipboard(simpleClipboard, this.offset.add(this.origin)); + } + return clipboard; + } + + + /** + * Reads all locally cached data (due to reset not being available) and applies them to the clipboard. + *

+ * Firstly, closes all cache writers (which adds the END identifier to each and fills the cache byte arrays on this instance) + * If required, creates all missing palettes first (as needed by all remaining data). + * At last writes all missing data (block states, tile entities, biomes, entities). + * + * @param clipboard The clipboard to write into. + * @throws IOException on I/O error. + */ + private void readRemainingDataCache(Clipboard clipboard) throws IOException { + byte identifier; + if (this.paletteCacheWriter != null) { + this.paletteCacheWriter.close(); + } + if (this.dataCacheWriter != null) { + this.dataCacheWriter.close(); + } + if (this.paletteCache != null) { + try (final DataInputStream cacheStream = new DataInputStream(new FastBufferedInputStream( + new LZ4BlockInputStream(new FastBufferedInputStream(new ByteArrayInputStream(this.paletteCache)))))) { + while ((identifier = cacheStream.readByte()) != CACHE_IDENTIFIER_END) { + if (identifier == CACHE_IDENTIFIER_BLOCK) { + this.readPaletteMap(cacheStream, this.provideBlockPaletteInitializer()); + continue; + } + if (identifier == CACHE_IDENTIFIER_BIOMES) { + this.readPaletteMap(cacheStream, this.provideBiomePaletteInitializer()); + continue; + } + throw new IOException("invalid cache state - got identifier: 0x" + identifier); + } + } + } + try (final DataInputStream cacheStream = new DataInputStream(new FastBufferedInputStream( + new LZ4BlockInputStream(new FastBufferedInputStream(new ByteArrayInputStream(this.dataCache))))); + final NBTInputStream cacheNbtIn = new NBTInputStream(cacheStream)) { + while ((identifier = cacheStream.readByte()) != CACHE_IDENTIFIER_END) { + switch (identifier) { + case CACHE_IDENTIFIER_BLOCK -> this.readPaletteData(cacheStream, this.getBlockWriter(clipboard)); + case CACHE_IDENTIFIER_BIOMES -> this.readPaletteData(cacheStream, this.getBiomeWriter(clipboard)); + case CACHE_IDENTIFIER_ENTITIES -> { + cacheStream.skipNBytes(1); // list child type (TAG_Compound) + this.readEntityContainers( + cacheStream, + cacheNbtIn, + DataFixer.FixTypes.ENTITY, + this.provideEntityTransformer(clipboard) + ); + } + case CACHE_IDENTIFIER_BLOCK_TILE_ENTITIES -> { + cacheStream.skipNBytes(1); // list child type (TAG_Compound) + this.readEntityContainers( + cacheStream, + cacheNbtIn, + DataFixer.FixTypes.BLOCK_ENTITY, + this.provideTileEntityTransformer(clipboard) + ); + } + default -> throw new IOException("invalid cache state - got identifier: 0x" + identifier); + } + } + } + } + + /** + * Reset the main stream of this clipboard and reads all remaining data that could not be read or fixed yet. + * Might need two iterations if the DataVersion tag is after the Blocks tag while the Palette inside the Blocks tag is not + * at the first position. + * + * @param clipboard The clipboard to write into. + * @throws IOException on I/O error. + */ + private void readRemainingDataReset(Clipboard clipboard) throws IOException { + byte type; + String tag; + outer: + while (!this.remainingTags.isEmpty()) { + this.reset(); + skipHeader(this.dataInputStream); + while ((type = dataInputStream.readByte()) != NBTConstants.TYPE_END) { + tag = dataInputStream.readUTF(); + byte b = tag.equals("Blocks") ? CACHE_IDENTIFIER_BLOCK : + tag.equals("Biomes") ? CACHE_IDENTIFIER_BIOMES : + tag.equals("Entities") ? CACHE_IDENTIFIER_ENTITIES : + CACHE_IDENTIFIER_END; + if (!this.remainingTags.remove(b)) { + this.nbtInputStream.readTagPayloadLazy(type, 0); + continue; + } + switch (tag) { + case "Blocks" -> readBlocks(clipboard); + case "Biomes" -> readBiomes(clipboard); + case "Entities" -> readEntities(clipboard); + default -> this.nbtInputStream.readTagPayloadLazy(type, 0); // Should never happen, but just in case + } + if (this.remainingTags.isEmpty()) { + break outer; + } + } + } + } + + /** + * {@inheritDoc} + *

+ * Requires {@link #read()}, {@link #read(UUID)} or {@link #read(UUID, Function)} to be called before. + */ + @Override + public OptionalInt getDataVersion() { + return this.dataVersion > -1 ? OptionalInt.of(this.dataVersion) : OptionalInt.empty(); + } + + private void readBlocks(Clipboard target) throws IOException { + this.blockPalette = new BlockState[BlockTypesCache.states.length]; + readPalette( + target != null, + CACHE_IDENTIFIER_BLOCK, + () -> this.blockPalette[0] != null, + this.provideBlockPaletteInitializer(), + this.getBlockWriter(target), + (type, tag) -> { + if (!tag.equals("BlockEntities")) { + try { + this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_LIST, 0); + } catch (IOException e) { + LOGGER.error("Failed to skip additional tag", e); + } + return; + } + try { + this.readTileEntities(target); + } catch (IOException e) { + LOGGER.warn("Failed to read tile entities", e); + } + } + ); + } + + private void readBiomes(Clipboard target) throws IOException { + this.biomePalette = new BiomeType[BiomeType.REGISTRY.size()]; + readPalette( + target != null, + CACHE_IDENTIFIER_BIOMES, + () -> this.biomePalette[0] != null, + this.provideBiomePaletteInitializer(), + this.getBiomeWriter(target), + (type, tag) -> { + try { + this.nbtInputStream.readTagPayloadLazy(type, 0); + } catch (IOException e) { + LOGGER.error("Failed to skip additional tag in biome container: {}", tag, e); + } + } + ); + } + + private void readEntities(@Nullable Clipboard target) throws IOException { + if (target == null || this.dataFixer == null) { + if (supportsReset()) { + this.remainingTags.add(CACHE_IDENTIFIER_ENTITIES); + this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_LIST, 0); + return; + } + // Easier than streaming for now + final NBTOutputStream cacheStream = new NBTOutputStream(this.getDataCacheWriter()); + cacheStream.writeByte(CACHE_IDENTIFIER_ENTITIES); + cacheStream.writeTagPayload(this.nbtInputStream.readTagPayload(NBTConstants.TYPE_LIST, 0)); + return; + } + if (this.dataInputStream.read() != NBTConstants.TYPE_COMPOUND) { + throw new IOException("Expected a compound block for entity"); + } + this.readEntityContainers( + this.dataInputStream, this.nbtInputStream, DataFixer.FixTypes.ENTITY, this.provideEntityTransformer(target) + ); + } + + private void readTileEntities(Clipboard target) throws IOException { + if (target == null || this.dataFixer == null) { + if (supportsReset()) { + this.remainingTags.add(CACHE_IDENTIFIER_BLOCK); // use block identifier, as this method will be called by + // readBlocks again + this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_LIST, 0); + return; + } + // Easier than streaming for now + final NBTOutputStream cacheStream = new NBTOutputStream(this.getDataCacheWriter()); + cacheStream.writeByte(CACHE_IDENTIFIER_BLOCK_TILE_ENTITIES); + cacheStream.writeTagPayload(this.nbtInputStream.readTagPayload(NBTConstants.TYPE_LIST, 0)); + return; + } + if (this.dataInputStream.read() != NBTConstants.TYPE_COMPOUND) { + throw new IOException("Expected a compound block for tile entity"); + } + this.readEntityContainers( + this.dataInputStream, + this.nbtInputStream, + DataFixer.FixTypes.BLOCK_ENTITY, + this.provideTileEntityTransformer(target) + ); + } + + private void readEntityContainers( + DataInputStream stream, + NBTInputStream nbtStream, + DataFixer.FixType fixType, + EntityTransformer transformer + ) throws IOException { + double x, y, z; + LinCompoundTag tag; + String id; + byte type; + int count = stream.readInt(); + while (count-- > 0) { + x = -1; + y = -1; + z = -1; + tag = null; + id = null; + while ((type = stream.readByte()) != NBTConstants.TYPE_END) { + switch (type) { + // Depending on the type of entity container (tile vs "normal") the pos consists of either doubles or ints + case NBTConstants.TYPE_INT_ARRAY -> { + if (!stream.readUTF().equals("Pos")) { + throw new IOException("Expected INT_ARRAY tag to be Pos"); + } + stream.skipNBytes(4); // count of following ints - for pos = 3 + x = stream.readInt(); + y = stream.readInt(); + z = stream.readInt(); + } + case NBTConstants.TYPE_LIST -> { + if (!stream.readUTF().equals("Pos")) { + throw new IOException("Expected LIST tag to be Pos"); + } + if (stream.readByte() != NBTConstants.TYPE_DOUBLE) { + throw new IOException("Expected LIST Pos tag to contain DOUBLE"); + } + stream.skipNBytes(4); // count of following doubles - for pos = 3 + x = stream.readDouble(); + y = stream.readDouble(); + z = stream.readDouble(); + } + case NBTConstants.TYPE_STRING -> { + if (!stream.readUTF().equals("Id")) { + throw new IOException("Expected STRING tag to be Id"); + } + id = stream.readUTF(); + } + case NBTConstants.TYPE_COMPOUND -> { + if (!stream.readUTF().equals("Data")) { + throw new IOException("Expected COMPOUND tag to be Data"); + } + if (!(nbtStream.readTagPayload(NBTConstants.TYPE_COMPOUND, 0).toLinTag() instanceof LinCompoundTag lin)) { + throw new IOException("Data tag could not be read into LinCompoundTag"); + } + tag = lin; + } + default -> throw new IOException("Unexpected tag in compound: " + type); + } + } + if (id == null) { + throw new IOException("Missing Id tag in compound"); + } + if (x < 0 || y < 0 || z < 0) { + throw new IOException("Missing position for entity " + id); + } + if (tag == null) { + transformer.transform(x, y, z, id, LinCompoundTag.of(Map.of())); + continue; + } + tag = this.dataFixer.fixUp(fixType, tag); + if (tag == null) { + LOGGER.warn("Failed to fix-up entity for {} @ {},{},{} - skipping", id, x, y, z); + continue; + } + transformer.transform(x, y, z, id, tag); + } + } + + /** + * The `Palette` tag is required first, as that contains the information of the actual palette size. + * Keeping the whole Data block in memory - which *could* be compressed - is just not it + * + * @param paletteInitializer Invoked for each 'Palette' entry using the actual palette value (e.g. block state) + index + * @param paletteDataApplier Invoked for each 'Data' entry using the data index and the palette index at the data index + */ + private void readPalette( + boolean hasClipboard, + byte paletteType, + BooleanSupplier paletteAlreadyInitialized, + PaletteInitializer paletteInitializer, + PaletteDataApplier paletteDataApplier, + AdditionalTagConsumer additionalTag + ) throws IOException { + boolean hasPalette = paletteAlreadyInitialized.getAsBoolean(); + byte type; + String tag; + while ((type = this.dataInputStream.readByte()) != NBTConstants.TYPE_END) { + tag = this.dataInputStream.readUTF(); + if (tag.equals("Palette")) { + if (hasPalette) { + // Skip palette, as already exists + this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_COMPOUND, 0); + continue; + } + if (!this.readPaletteMap(this.dataInputStream, paletteInitializer)) { + if (this.supportsReset()) { + // Couldn't read - skip palette for now + this.remainingTags.add(paletteType); + this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_COMPOUND, 0); + continue; + } + // Reset not possible, write into cache + final NBTOutputStream cacheWriter = new NBTOutputStream(this.getPaletteCacheWriter()); + cacheWriter.write(paletteType); + cacheWriter.writeTagPayload(this.nbtInputStream.readTagPayload(NBTConstants.TYPE_COMPOUND, 0)); + continue; + } + hasPalette = true; + continue; + } + if (tag.equals("Data")) { + // No palette or dimensions are yet available + if (!hasPalette || this.dataFixer == null || !hasClipboard) { + if (this.supportsReset()) { + this.remainingTags.add(paletteType); + this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_BYTE_ARRAY, 0); + continue; + } + // Reset not possible, write into cache + int byteLen = this.dataInputStream.readInt(); + final DataOutputStream cacheWriter = new DataOutputStream(this.getDataCacheWriter()); + cacheWriter.write(paletteType); + cacheWriter.writeInt(byteLen); + IOUtil.copy(this.dataInputStream, cacheWriter, byteLen); + continue; + } + this.readPaletteData(this.dataInputStream, paletteDataApplier); + continue; + } + additionalTag.accept(type, tag); + } + } + + private void readPaletteData(DataInputStream stream, PaletteDataApplier applier) throws IOException { + int length = stream.readInt(); + // Write data into clipboard + int i = 0; + if (needsVarIntReading(length)) { + for (var iter = new VarIntStreamIterator(stream, length); iter.hasNext(); i++) { + applier.apply(i, (char) iter.nextInt()); + } + return; + } + while (i < length) { + applier.apply(i++, (char) stream.readUnsignedByte()); + } + } + + /** + * Reads the CompoundTag containing the palette mapping ({@code index: value}) and passes each entry to the + * {@link PaletteInitializer}. + *

+ * This method expects that the identifier ({@link NBTConstants#TYPE_COMPOUND}) is already consumed from the stream. + * + * @param stream The stream to read the data from. + * @param initializer The initializer called for each entry with its index and backed value. + * @return {@code true} if the mapping could be read, {@code false} otherwise (e.g. DataFixer is not yet available). + * @throws IOException on I/O error. + */ + private boolean readPaletteMap(DataInputStream stream, PaletteInitializer initializer) throws IOException { + if (this.dataFixer == null) { + return false; + } + while (stream.readByte() != NBTConstants.TYPE_END) { + String value = stream.readUTF(); + char index = (char) stream.readInt(); + initializer.initialize(index, value); + } + return true; + } + + private void indexToPosition(int index, PositionConsumer supplier) { + int y = index / (dimensions.x() * dimensions.z()); + int remainder = index - (y * dimensions.x() * dimensions.z()); + int z = remainder / dimensions.x(); + int x = remainder - z * dimensions.x(); + supplier.accept(x, y, z); + } + + private PaletteDataApplier getBlockWriter(Clipboard target) { + if (target instanceof LinearClipboard linearClipboard) { + return (index, ordinal) -> linearClipboard.setBlock(index, this.blockPalette[ordinal]); + } + return (index, ordinal) -> indexToPosition(index, (x, y, z) -> target.setBlock(x, y, z, this.blockPalette[ordinal])); + } + + private PaletteDataApplier getBiomeWriter(Clipboard target) { + return (index, ordinal) -> indexToPosition(index, (x, y, z) -> target.setBiome(x, y, z, this.biomePalette[ordinal])); + } + + private PaletteInitializer provideBlockPaletteInitializer() { + return (index, value) -> { + if (this.dataFixer == null) { + throw new IllegalStateException("Can't read block palette map if DataFixer is not yet available"); + } + value = dataFixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, value); + try { + this.blockPalette[index] = BlockState.get(value); + } catch (InputParseException e) { + LOGGER.warn("Invalid BlockState in palette: {}. Block will be replaced with air.", value); + this.blockPalette[index] = BlockTypes.AIR.getDefaultState(); + } + }; + } + + private PaletteInitializer provideBiomePaletteInitializer() { + return (index, value) -> { + if (this.dataFixer == null) { + throw new IllegalStateException("Can't read biome palette map if DataFixer is not yet available"); + } + value = dataFixer.fixUp(DataFixer.FixTypes.BIOME, value); + BiomeType biomeType = BiomeTypes.get(value); + if (biomeType == null) { + biomeType = BiomeTypes.PLAINS; + LOGGER.warn("Invalid biome type in palette: {}. Biome will be replaced with plains.", value); + } + this.biomePalette[index] = biomeType; + }; + } + + private EntityTransformer provideEntityTransformer(Clipboard clipboard) { + return (x, y, z, id, tag) -> { + EntityType type = EntityType.REGISTRY.get(id); + if (type == null) { + LOGGER.warn("Invalid entity id: {} - skipping", id); + return; + } + clipboard.createEntity( + new Location(clipboard, Location.at(x, y, z).add(clipboard.getMinimumPoint().toVector3())), + new BaseEntity(type, LazyReference.computed(tag)) + ); + }; + } + + private EntityTransformer provideTileEntityTransformer(Clipboard clipboard) { + return (x, y, z, id, tag) -> clipboard.tile( + MathMan.roundInt(x + clipboard.getMinimumPoint().x()), + MathMan.roundInt(y + clipboard.getMinimumPoint().y()), + MathMan.roundInt(z + clipboard.getMinimumPoint().z()), + FaweCompoundTag.of(tag) + ); + } + + /** + * @return {@code true} if {@code Width}, {@code Length} and {@code Height} are already read from the stream + */ + private boolean areDimensionsAvailable() { + return this.dimensions.x() != 0 && this.dimensions.y() != 0 && this.dimensions.z() != 0; + } + + /** + * Closes this reader instance and all underlying resources. + * + * @throws IOException on I/O error. + */ + @Override + public void close() throws IOException { + parentStream.close(); // closes all underlying resources implicitly + } + + /** + * Resets the main stream to the previously marked position ({@code 0}), if supported (see {@link #supportsReset()}). + * If the stream is reset, the sub streams (for DataInput and NBT) are re-created to respect the new position. + * + * @throws IOException on I/O error. + */ + private void reset() throws IOException { + if (this.supportsReset()) { + this.parentStream.reset(); + this.parentStream.mark(Integer.MAX_VALUE); + this.setSubStreams(); + } + } + + /** + * @return {@code true} if the stream used while instantiating the reader supports resets (without memory overhead). + */ + private boolean supportsReset() { + return this.remainingTags != null; + } + + /** + * Overwrites the DataInput- and NBT-InputStreams (e.g. when the marker of the backed stream updated). + * + * @throws IOException on I/O error. + */ + private void setSubStreams() throws IOException { + this.dataInputStream = new DataInputStream(this.parentStream); + this.nbtInputStream = new NBTInputStream(this.parentStream); + } + + /** + * Creates a new cache writer for non-palette data, if none exists yet. + * Returns either the already created or new one. + * + * @return the output stream for non-palette cache data. + */ + private OutputStream getDataCacheWriter() { + if (this.dataCacheWriter == null) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(512); + this.dataCacheWriter = new FastBufferedOutputStream(new LZ4BlockOutputStream(byteArrayOutputStream)) { + @Override + public void close() throws IOException { + this.write(CACHE_IDENTIFIER_END); + super.close(); + FaWeSchematicReaderV3.this.dataCache = byteArrayOutputStream.toByteArray(); + } + }; + } + return this.dataCacheWriter; + } + + /** + * Creates a new cache writer for palette data, if none exists yet. + * Returns either the already created or new one. + * + * @return the output stream for palette cache data. + */ + private OutputStream getPaletteCacheWriter() { + if (this.paletteCacheWriter == null) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(256); + this.paletteCacheWriter = new FastBufferedOutputStream(new LZ4BlockOutputStream(byteArrayOutputStream)) { + @Override + public void close() throws IOException { + this.write(CACHE_IDENTIFIER_END); + super.close(); + FaWeSchematicReaderV3.this.paletteCache = byteArrayOutputStream.toByteArray(); + } + }; + } + return this.paletteCacheWriter; + } + + private boolean needsVarIntReading(int byteArrayLength) { + return byteArrayLength > this.dimensions.x() * this.dimensions.y() * this.dimensions.z(); + } + + /** + * Skips the schematic header including the root compound (empty name) and the root's child compound ("Schematic") + * + * @param dataInputStream The stream containing the schematic data to skip + * @throws IOException on I/O error + */ + private static void skipHeader(DataInputStream dataInputStream) throws IOException { + dataInputStream.skipNBytes(1 + 2); // 1 Byte = TAG_Compound, 2 Bytes = Short (Length of tag name = "") + dataInputStream.skipNBytes(1 + 2 + 9); // as above + 9 bytes = "Schematic" + } + + @ApiStatus.Internal + @FunctionalInterface + private interface PositionConsumer { + + /** + * Called with block location coordinates. + * + * @param x the x coordinate. + * @param y the y coordinate. + * @param z the z coordinate. + */ + void accept(int x, int y, int z); + + } + + @ApiStatus.Internal + @FunctionalInterface + private interface EntityTransformer { + + /** + * Called for each entity from the Schematics {@code Entities} compound list. + * + * @param x the relative x coordinate of the entity. + * @param y the relative y coordinate of the entity. + * @param z the relative z coordinate of the entity. + * @param id the entity id as a resource location (e.g. {@code minecraft:sheep}). + * @param tag the - already fixed, if required - nbt data of the entity. + */ + void transform(double x, double y, double z, String id, LinCompoundTag tag); + + } + + @ApiStatus.Internal + @FunctionalInterface + private interface PaletteInitializer { + + /** + * Called for each palette entry (the mapping part, not data). + * + * @param index the index of the entry, as used in the Data byte array. + * @param value the value for this entry (either biome type as resource location or the block state as a string). + */ + void initialize(char index, String value); + + } + + @ApiStatus.Internal + @FunctionalInterface + private interface PaletteDataApplier { + + /** + * Called for each palette data entry (not the mapping part, but the var-int byte array). + * + * @param index The index of this data entry (due to var-int behaviour not necessarily the index in the data byte array). + * @param ordinal The ordinal of this entry as defined in the palette mapping. + */ + void apply(int index, char ordinal); + + } + + @ApiStatus.Internal + @FunctionalInterface + private interface AdditionalTagConsumer { + + /** + * Called for each unknown nbt tag. + * + * @param type The type of the tag (as defined by the constants in {@link NBTConstants}). + * @param name The name of the tag. + */ + void accept(byte type, String name); + + } + +} diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java index 4ae22cac..60dcce9e 100644 --- a/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java +++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java @@ -20,33 +20,27 @@ package de.steamwar.core; import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV2; -import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV3; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader; -import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV1Reader; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; +import de.steamwar.sql.NodeData; import org.bukkit.entity.Player; import org.bukkit.util.Vector; -import org.enginehub.linbus.stream.LinBinaryIO; -import org.enginehub.linbus.stream.LinStream; -import org.enginehub.linbus.tree.LinCompoundTag; -import org.enginehub.linbus.tree.LinRootEntry; -import org.enginehub.linbus.tree.LinTagType; import java.io.*; public class WorldEditWrapper21 implements WorldEditWrapper { @Override - public InputStream getPlayerClipboard(Player player, boolean schemFormat) { - return WorldEditWrapper.getPlayerClipboard(player, schemFormat, (outputStream, clipboard, clipboardHolder) -> { + public InputStream getPlayerClipboard(Player player) { + return WorldEditWrapper.getPlayerClipboard(player, (outputStream, clipboard, clipboardHolder) -> { ClipboardWriter writer = BuiltInClipboardFormat.FAST_V3.getWriter(outputStream); writer.write(clipboard); writer.close(); @@ -54,7 +48,7 @@ public class WorldEditWrapper21 implements WorldEditWrapper { } @Override - public void setPlayerClipboard(Player player, InputStream is, boolean schemFormat) { + public void setPlayerClipboard(Player player, InputStream is, NodeData.SchematicFormat schemFormat) { Clipboard clipboard = null; try { clipboard = getClipboard(is, schemFormat); @@ -70,35 +64,12 @@ public class WorldEditWrapper21 implements WorldEditWrapper { } @Override - public Clipboard getClipboard(InputStream is, boolean schemFormat) throws IOException { - if (!schemFormat) { - return new MCEditSchematicReader(new NBTInputStream(is)).read(); - } else { - BufferedInputStream bis = new BufferedInputStream(is); - - bis.mark(Integer.MAX_VALUE); - - LinStream linStream = LinBinaryIO.read(new DataInputStream(bis)); - - LinCompoundTag entry = LinRootEntry.readFrom(linStream).value(); - - if (entry.value().size() == 1) { - entry = entry.getTag("Schematic", LinTagType.compoundTag()); - } - - bis.reset(); - - switch (entry.getTag("Version", LinTagType.intTag()).valueAsInt()) { - case 1: - return new SpongeSchematicV1Reader(entry.linStream()).read(); - case 2: - return new FastSchematicReaderV2(new NBTInputStream(bis)).read(); - case 3: - return new FastSchematicReaderV3(bis).read(); - default: - throw new IOException("Unknown schematic version"); - } - } + public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException { + return switch (schemFormat) { + case MCEDIT -> new MCEditSchematicReader(new NBTInputStream(is)).read(); + case V2 -> new FastSchematicReaderV2(new NBTInputStream(is)).read(); + case V3 -> new FaWeSchematicReaderV3(is).read(); + }; } @Override diff --git a/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java index f3fc2800..b077a107 100644 --- a/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java +++ b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java @@ -37,6 +37,7 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.world.registry.WorldData; +import de.steamwar.sql.NodeData; import org.bukkit.entity.Player; import java.io.IOException; @@ -50,13 +51,13 @@ import java.util.stream.Collectors; public class WorldEditWrapper8 implements WorldEditWrapper { @Override - public InputStream getPlayerClipboard(Player player, boolean schemFormat) { - return WorldEditWrapper.getPlayerClipboard(player, schemFormat, (outputStream, clipboard, clipboardHolder) -> + public InputStream getPlayerClipboard(Player player) { + return WorldEditWrapper.getPlayerClipboard(player, (outputStream, clipboard, clipboardHolder) -> ClipboardFormat.SCHEMATIC.getWriter(outputStream).write(clipboard, clipboardHolder.getWorldData())); } @Override - public void setPlayerClipboard(Player player, InputStream is, boolean schemFormat) { + public void setPlayerClipboard(Player player, InputStream is, NodeData.SchematicFormat schemFormat) { WorldData world = new BukkitWorld(player.getWorld()).getWorldData(); Clipboard clipboard; try { @@ -70,11 +71,16 @@ public class WorldEditWrapper8 implements WorldEditWrapper { } @Override - public Clipboard getClipboard(InputStream is, boolean schemFormat) throws IOException { - if(schemFormat) - return new SpongeSchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData()); - else - return new SchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData()); + public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException { + switch (schemFormat) { + case MCEDIT: + return new SchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData()); + case V2: + case V3: + return new SpongeSchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData()); + default: + throw new IllegalArgumentException("Unsupported schematic format"); + } } @Override @@ -137,6 +143,13 @@ public class WorldEditWrapper8 implements WorldEditWrapper { IDConverter8 ids = new IDConverter8(); Map schematic = schematicTag.getValue(); + boolean v3Mode = false; + + if (schematic.size() == 1) { + schematic = (requireTag(schematic, "Schematic", CompoundTag.class)).getValue(); + v3Mode = true; + } + int width = (requireTag(schematic, "Width", ShortTag.class)).getValue(); int height = (requireTag(schematic, "Height", ShortTag.class)).getValue(); int length = (requireTag(schematic, "Length", ShortTag.class)).getValue(); @@ -167,10 +180,13 @@ public class WorldEditWrapper8 implements WorldEditWrapper { region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector.ONE)); } - IntTag paletteMaxTag = getTag(schematic, "PaletteMax", IntTag.class); - Map paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue(); - if (paletteMaxTag != null && paletteObject.size() != paletteMaxTag.getValue()) - throw new IOException("Block palette size does not match expected size."); + Map blockContainer = null; + + if (v3Mode) { + blockContainer = getTag(schematic, "Blocks", CompoundTag.class).getValue(); + } + + Map paletteObject = requireTag(v3Mode ? blockContainer : schematic, "Palette", CompoundTag.class).getValue(); Map palette = new HashMap<>(); ParserContext parserContext = new ParserContext(); @@ -182,11 +198,11 @@ public class WorldEditWrapper8 implements WorldEditWrapper { palette.put(requireTag(paletteObject, palettePart, IntTag.class).getValue(), new BaseBlock(blockID.getBlockId(), blockID.getDataId())); } - byte[] blocks = requireTag(schematic, "BlockData", ByteArrayTag.class).getValue(); + byte[] blocks = requireTag(v3Mode ? blockContainer : schematic, v3Mode ? "Data" : "BlockData", ByteArrayTag.class).getValue(); Map> tileEntitiesMap = new HashMap<>(); - ListTag tileEntities = getTag(schematic, "BlockEntities", ListTag.class); + ListTag tileEntities = getTag(v3Mode ? blockContainer : schematic, "BlockEntities", ListTag.class); if (tileEntities == null) { - tileEntities = getTag(schematic, "TileEntities", ListTag.class); + tileEntities = getTag(v3Mode ? blockContainer : schematic, "TileEntities", ListTag.class); } if (tileEntities != null) { diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/ErrorHandler.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/ErrorHandler.java index c9585847..62a7f2b7 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/ErrorHandler.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/ErrorHandler.java @@ -77,7 +77,7 @@ public class ErrorHandler extends Handler { return; try { - SWException.log(message, stacktrace); + //SWException.log(message, stacktrace); } catch (SecurityException e) { Core.getInstance().getLogger().log(Level.INFO, "Could not log error in database", e); } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java index 87906944..703fa9e3 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java @@ -26,19 +26,23 @@ import com.sk89q.worldedit.session.ClipboardHolder; import de.steamwar.sql.NoClipboardException; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.Region; +import de.steamwar.sql.NodeData; +import lombok.AllArgsConstructor; +import lombok.Data; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.util.Vector; import java.io.*; +import java.util.concurrent.CompletableFuture; import java.util.logging.Level; public interface WorldEditWrapper { WorldEditWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); - InputStream getPlayerClipboard(Player player, boolean schemFormat); - void setPlayerClipboard(Player player, InputStream is, boolean schemFormat); - Clipboard getClipboard(InputStream is, boolean schemFormat) throws IOException; + InputStream getPlayerClipboard(Player player); + void setPlayerClipboard(Player player, InputStream is, NodeData.SchematicFormat schemFormat); + Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException; Vector getOrigin(Clipboard clipboard); Vector getMinimum(Region region); @@ -49,7 +53,7 @@ public interface WorldEditWrapper { return (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit"); } - public static InputStream getPlayerClipboard(Player player, boolean schemFormat, SchematicWriter consumer) { + static InputStream getPlayerClipboard(Player player, SchematicWriter consumer) { ClipboardHolder clipboardHolder; try { clipboardHolder = WorldEditWrapper.getWorldEditPlugin().getSession(player).getClipboard(); @@ -85,7 +89,17 @@ public interface WorldEditWrapper { return inputStream; } - public static interface SchematicWriter { + static NodeData.SchematicFormat getNativeFormat() { + if (Core.getVersion() <= 12) { + return NodeData.SchematicFormat.MCEDIT; + } else if (Core.getVersion() <= 20) { + return NodeData.SchematicFormat.V2; + } else { + return NodeData.SchematicFormat.V3; + } + } + + interface SchematicWriter { void write(OutputStream outputStream, Clipboard clipboard, ClipboardHolder holder) throws IOException; } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java index ecbf86aa..0957bae0 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java @@ -36,7 +36,7 @@ import java.util.zip.GZIPInputStream; public class SchematicData { - public static Clipboard clipboardFromStream(InputStream is, boolean schemFormat) { + public static Clipboard clipboardFromStream(InputStream is, NodeData.SchematicFormat schemFormat) { try { return WorldEditWrapper.impl.getClipboard(is, schemFormat); } catch (IOException e) { @@ -61,15 +61,11 @@ public class SchematicData { } public void saveFromPlayer(Player player) throws IOException, NoClipboardException { - saveFromPlayer(player, Core.getVersion() > 12); - } - - public void saveFromPlayer(Player player, boolean newFormat) throws IOException, NoClipboardException { - data.saveFromStream(WorldEditWrapper.impl.getPlayerClipboard(player, newFormat), newFormat); + data.saveFromStream(WorldEditWrapper.impl.getPlayerClipboard(player), WorldEditWrapper.getNativeFormat()); } @Deprecated - public void saveFromBytes(byte[] bytes, boolean newFormat) { + public void saveFromBytes(byte[] bytes, NodeData.SchematicFormat newFormat) { data.saveFromStream(new ByteArrayInputStream(bytes), newFormat); } } diff --git a/SpigotCore/build.gradle.kts b/SpigotCore/build.gradle.kts index b7ff647e..d615cfc7 100644 --- a/SpigotCore/build.gradle.kts +++ b/SpigotCore/build.gradle.kts @@ -40,5 +40,10 @@ dependencies { implementation(project(":SpigotCore:SpigotCore_18")) implementation(project(":SpigotCore:SpigotCore_19")) implementation(project(":SpigotCore:SpigotCore_20")) - implementation(project(":SpigotCore:SpigotCore_21")) + implementation(project(":SpigotCore:SpigotCore_21")) { + attributes { + // Very Hacky, but it works + attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21) + } + } } diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java index 037eadcd..75892359 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java @@ -79,7 +79,7 @@ public class DiscordSchemUpload extends ListenerAdapter { node = SchematicNode.createSchematic(user.getId(), name, null); try (InputStream in = attachment.getProxy().download().get()) { - NodeData.get(node).saveFromStream(in, fileName.substring(dot).equalsIgnoreCase(".schem")); + NodeData.get(node).saveFromStream(in, fileName.substring(dot).equalsIgnoreCase(".schem") ? NodeData.SchematicFormat.V2 : NodeData.SchematicFormat.MCEDIT); sender.system("DC_SCHEMUPLOAD_SUCCESS", name); } catch (InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt index b873b97d..006b914e 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt @@ -88,7 +88,7 @@ fun Route.configureSchematic() { return@get } - call.response.header("Content-Disposition", "attachment; filename=\"${node.name}.${if (data.nodeFormat) "schem" else "schematic"}\"") + call.response.header("Content-Disposition", "attachment; filename=\"${node.name}${data.nodeFormat.fileEnding}\"") call.respondBytes(data.schemData().readAllBytes(), contentType = ContentType.Application.OctetStream, status = HttpStatusCode.OK) } get("/info") { @@ -118,8 +118,8 @@ fun Route.configureSchematic() { node = SchematicNode.createSchematic(user.id, schemName, 0) } - val data = NodeData(node.id, false) - data.saveFromStream(content.inputStream(), schemType == "schem") + val data = NodeData(node.id, NodeData.SchematicFormat.V2) + data.saveFromStream(content.inputStream(), NodeData.SchematicFormat.V2) call.respond(ResponseSchematic(node)) } From 06eec10660baa3b08b9b64d5eed169e0b12f96d0 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Sun, 8 Dec 2024 23:18:32 +0100 Subject: [PATCH 04/22] Fixes... --- CommonCore/SQL/src/de/steamwar/sql/NodeData.java | 8 ++------ .../de/steamwar/fightsystem/utils/WorldeditWrapper14.java | 2 +- .../src/de/steamwar/core/WorldEditWrapper14.java | 5 ++--- .../src/de/steamwar/core/WorldEditWrapper18.java | 3 +-- .../src/de/steamwar/core/WorldEditWrapper21.java | 4 ++-- .../src/de/steamwar/core/WorldEditWrapper8.java | 4 ++-- .../src/de/steamwar/core/WorldEditWrapper.java | 7 ++----- .../discord/listeners/DiscordSchemUpload.java | 2 +- 8 files changed, 13 insertions(+), 22 deletions(-) diff --git a/CommonCore/SQL/src/de/steamwar/sql/NodeData.java b/CommonCore/SQL/src/de/steamwar/sql/NodeData.java index c580dc3f..0de6c6c5 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/NodeData.java +++ b/CommonCore/SQL/src/de/steamwar/sql/NodeData.java @@ -65,10 +65,6 @@ public class NodeData { private SchematicFormat nodeFormat; public InputStream schemData() throws IOException { - return new GZIPInputStream(schemDataRaw()); - } - - public InputStream schemDataRaw() throws IOException { try { return selSchemData.select(rs -> { rs.next(); @@ -96,8 +92,8 @@ public class NodeData { @Getter public enum SchematicFormat { MCEDIT(".schematic"), - V2(".schem"), - V3(".schem"); + SPONGE_V2(".schem"), + SPONGE_V3(".schem"); private final String fileEnding; } 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 df366205..9a0ae4b5 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.V2); + new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), NodeData.SchematicFormat.SPONGE_V2); } } diff --git a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java index cba992f5..ec072aa4 100644 --- a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java +++ b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java @@ -22,7 +22,6 @@ package de.steamwar.core; import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; import com.sk89q.jnbt.*; -import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extension.input.InputParseException; @@ -51,7 +50,6 @@ import org.bukkit.util.Vector; import java.io.*; import java.util.*; -import java.util.logging.Level; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; @@ -88,7 +86,8 @@ public class WorldEditWrapper14 implements WorldEditWrapper { try { switch (schemFormat) { - case V2: + case SPONGE_V2: + case SPONGE_V3: return new SpongeSchematicReader(new NBTInputStream(is)).read(); case MCEDIT: return new MCEditSchematicReader(new NBTInputStream(is)).read(); diff --git a/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java b/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java index 23590848..b381ecf7 100644 --- a/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java +++ b/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java @@ -19,7 +19,6 @@ package de.steamwar.core; -import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReader; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.*; @@ -40,7 +39,7 @@ public class WorldEditWrapper18 extends WorldEditWrapper14 { switch (schemFormat) { case MCEDIT: return new MCEditSchematicReader(nbtStream).read(); - case V2: + case SPONGE_V2: return new SpongeSchematicReader(nbtStream).read(); default: throw new IllegalArgumentException("Unsupported schematic format"); diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java index 60dcce9e..52743f45 100644 --- a/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java +++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java @@ -67,8 +67,8 @@ public class WorldEditWrapper21 implements WorldEditWrapper { public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException { return switch (schemFormat) { case MCEDIT -> new MCEditSchematicReader(new NBTInputStream(is)).read(); - case V2 -> new FastSchematicReaderV2(new NBTInputStream(is)).read(); - case V3 -> new FaWeSchematicReaderV3(is).read(); + case SPONGE_V2 -> new FastSchematicReaderV2(new NBTInputStream(is)).read(); + case SPONGE_V3 -> new FaWeSchematicReaderV3(is).read(); }; } diff --git a/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java index b077a107..a6aad3b5 100644 --- a/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java +++ b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java @@ -75,8 +75,8 @@ public class WorldEditWrapper8 implements WorldEditWrapper { switch (schemFormat) { case MCEDIT: return new SchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData()); - case V2: - case V3: + case SPONGE_V2: + case SPONGE_V3: return new SpongeSchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData()); default: throw new IllegalArgumentException("Unsupported schematic format"); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java index 703fa9e3..d07bd155 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java @@ -27,14 +27,11 @@ import de.steamwar.sql.NoClipboardException; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.Region; import de.steamwar.sql.NodeData; -import lombok.AllArgsConstructor; -import lombok.Data; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.util.Vector; import java.io.*; -import java.util.concurrent.CompletableFuture; import java.util.logging.Level; public interface WorldEditWrapper { @@ -93,9 +90,9 @@ public interface WorldEditWrapper { if (Core.getVersion() <= 12) { return NodeData.SchematicFormat.MCEDIT; } else if (Core.getVersion() <= 20) { - return NodeData.SchematicFormat.V2; + return NodeData.SchematicFormat.SPONGE_V2; } else { - return NodeData.SchematicFormat.V3; + return NodeData.SchematicFormat.SPONGE_V3; } } diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java index 75892359..a39837f6 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java @@ -79,7 +79,7 @@ public class DiscordSchemUpload extends ListenerAdapter { node = SchematicNode.createSchematic(user.getId(), name, null); try (InputStream in = attachment.getProxy().download().get()) { - NodeData.get(node).saveFromStream(in, fileName.substring(dot).equalsIgnoreCase(".schem") ? NodeData.SchematicFormat.V2 : NodeData.SchematicFormat.MCEDIT); + NodeData.get(node).saveFromStream(in, fileName.substring(dot).equalsIgnoreCase(".schem") ? NodeData.SchematicFormat.SPONGE_V2 : NodeData.SchematicFormat.MCEDIT); sender.system("DC_SCHEMUPLOAD_SUCCESS", name); } catch (InterruptedException e) { Thread.currentThread().interrupt(); From 336915dd961169fbfd72e89497c1d1e7ebb1c6f5 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Sat, 21 Dec 2024 12:03:43 +0100 Subject: [PATCH 05/22] Fix Schem Upload --- WebsiteBackend/build.gradle.kts | 1 + .../src/de/steamwar/routes/Schematic.kt | 29 +++++++++++++++++-- settings.gradle.kts | 1 + 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/WebsiteBackend/build.gradle.kts b/WebsiteBackend/build.gradle.kts index 2cf527a7..f93dacde 100644 --- a/WebsiteBackend/build.gradle.kts +++ b/WebsiteBackend/build.gradle.kts @@ -53,4 +53,5 @@ dependencies { implementation(libs.yamlconfig) implementation(libs.kotlinxSerializationCbor) implementation(libs.ktorRateLimit) + implementation(libs.knbt) } \ No newline at end of file diff --git a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt index 006b914e..0dea01f7 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt @@ -22,6 +22,7 @@ package de.steamwar.routes import de.steamwar.plugins.SWAuthPrincipal import de.steamwar.plugins.SWPermissionCheck import de.steamwar.sql.NodeData +import de.steamwar.sql.NodeData.SchematicFormat import de.steamwar.sql.NodeDownload import de.steamwar.sql.NodeMember import de.steamwar.sql.SWException @@ -32,7 +33,10 @@ import io.ktor.server.auth.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* +import kotlinx.coroutines.launch import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromByteArray +import net.benwoodworth.knbt.* import java.security.MessageDigest import java.time.Duration import java.time.Instant @@ -71,6 +75,11 @@ data class SchematicCode(val id: Int, val code: String, val expires: Long) @Serializable data class UploadSchematic(val name: String, val content: String) +val nbt = Nbt { + variant = NbtVariant.Java + compression = NbtCompression.Gzip +} + fun Route.configureSchematic() { route("/download/{code}") { get { @@ -112,14 +121,28 @@ fun Route.configureSchematic() { val user = call.principal()!!.user - val content = Base64.getDecoder().decode(file.content) var node = SchematicNode.getSchematicNode(user.id, schemName, 0) if (node == null) { node = SchematicNode.createSchematic(user.id, schemName, 0) } - val data = NodeData(node.id, NodeData.SchematicFormat.V2) - data.saveFromStream(content.inputStream(), NodeData.SchematicFormat.V2) + val content = Base64.getDecoder().decode(file.content) + + var schem = nbt.decodeFromByteArray(content) + + if (schem.size == 1) schem = schem[schem.keys.first()] as NbtCompound + + val version = schem.let { + if (it.containsKey("Materials")) + return@let SchematicFormat.MCEDIT + else if (it.containsKey("Blocks")) + return@let SchematicFormat.SPONGE_V3 + else + return@let SchematicFormat.SPONGE_V2 + } + + val data = NodeData(node.id, version) + data.saveFromStream(content.inputStream(), version) call.respond(ResponseSchematic(node)) } diff --git a/settings.gradle.kts b/settings.gradle.kts index 69d5c67b..07242d37 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -165,6 +165,7 @@ dependencyResolutionManagement { library("yamlconfig", "org.bspfsystems:yamlconfiguration:1.3.0") library("kotlinxSerializationCbor", "org.jetbrains.kotlinx:kotlinx-serialization-cbor:1.4.1") library("ktorRateLimit", "io.ktor:ktor-server-rate-limit:$ktorVersion") + library("knbt", "net.benwoodworth.knbt:knbt:0.11.7") } } } From d08ccc3a98a00bb9f278be435c78861b4fc13987 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Sat, 21 Dec 2024 12:30:39 +0100 Subject: [PATCH 06/22] Fix Everything --- .../fightsystem/record/PacketProcessor.java | 2 +- .../de/steamwar/core/WorldEditWrapper14.java | 5 + .../steamwar/core/FaWeSchematicReaderV3.java | 857 ------------------ .../de/steamwar/core/WorldEditWrapper21.java | 12 +- .../de/steamwar/core/WorldEditWrapper8.java | 5 + .../src/de/steamwar/core/ErrorHandler.java | 2 +- .../de/steamwar/core/WorldEditWrapper.java | 12 +- .../src/de/steamwar/sql/SchematicData.java | 2 +- VelocityCore/build.gradle.kts | 2 + .../discord/listeners/DiscordSchemUpload.java | 17 +- .../src/de/steamwar/routes/Schematic.kt | 34 +- settings.gradle.kts | 2 + 12 files changed, 64 insertions(+), 888 deletions(-) delete mode 100644 SpigotCore/SpigotCore_21/src/de/steamwar/core/FaWeSchematicReaderV3.java 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 e6ed1d3a..eafe4377 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/record/PacketProcessor.java @@ -520,7 +520,7 @@ public class PacketProcessor implements Listener { public void close() { // FAWE 1.12 calls close... } - }, WorldEditWrapper.getNativeFormat()); + }, WorldEditWrapper.impl.getNativeFormat()); execSync(() -> team.pasteSchem(schemId, clipboard)); } diff --git a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java index ec072aa4..ca96d554 100644 --- a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java +++ b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java @@ -121,6 +121,11 @@ public class WorldEditWrapper14 implements WorldEditWrapper { return new org.bukkit.util.Vector(v.getX(), v.getY(), v.getZ()); } + @Override + public NodeData.SchematicFormat getNativeFormat() { + return NodeData.SchematicFormat.SPONGE_V2; + } + private static class MCEditSchematicReader extends NBTSchematicReader { private final NBTInputStream inputStream; diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/FaWeSchematicReaderV3.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/FaWeSchematicReaderV3.java deleted file mode 100644 index 9a11dd2e..00000000 --- a/SpigotCore/SpigotCore_21/src/de/steamwar/core/FaWeSchematicReaderV3.java +++ /dev/null @@ -1,857 +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.core; - -import com.fastasyncworldedit.core.extent.clipboard.LinearClipboard; -import com.fastasyncworldedit.core.extent.clipboard.SimpleClipboard; -import com.fastasyncworldedit.core.internal.io.ResettableFileInputStream; -import com.fastasyncworldedit.core.internal.io.VarIntStreamIterator; -import com.fastasyncworldedit.core.math.MutableBlockVector3; -import com.fastasyncworldedit.core.nbt.FaweCompoundTag; -import com.fastasyncworldedit.core.util.IOUtil; -import com.fastasyncworldedit.core.util.MathMan; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.NBTConstants; -import com.sk89q.jnbt.NBTInputStream; -import com.sk89q.jnbt.NBTOutputStream; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extension.input.InputParseException; -import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.extension.platform.Platform; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; -import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; -import com.sk89q.worldedit.extent.clipboard.io.sponge.ReaderUtil; -import com.sk89q.worldedit.extent.clipboard.io.sponge.VersionedDataFixer; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.world.DataFixer; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import com.sk89q.worldedit.world.entity.EntityType; -import it.unimi.dsi.fastutil.io.FastBufferedInputStream; -import it.unimi.dsi.fastutil.io.FastBufferedOutputStream; -import net.jpountz.lz4.LZ4BlockInputStream; -import net.jpountz.lz4.LZ4BlockOutputStream; -import org.apache.logging.log4j.Logger; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.enginehub.linbus.tree.LinCompoundTag; -import org.enginehub.linbus.tree.LinIntArrayTag; -import org.enginehub.linbus.tree.LinTagType; -import org.jetbrains.annotations.ApiStatus; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.OptionalInt; -import java.util.Set; -import java.util.UUID; -import java.util.function.BooleanSupplier; -import java.util.function.Function; -import java.util.zip.GZIPInputStream; - -/** - * ClipboardReader for the Sponge Schematic Format v3. - * Not necessarily much faster than {@link com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader}, but uses a - * stream based approach to keep the memory overhead minimal (especially in larger schematics) - * - * @since 2.11.1 - */ -@SuppressWarnings("removal") // JNBT -public class FaWeSchematicReaderV3 implements ClipboardReader { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - private static final byte CACHE_IDENTIFIER_END = 0x00; - private static final byte CACHE_IDENTIFIER_BLOCK = 0x01; - private static final byte CACHE_IDENTIFIER_BIOMES = 0x02; - private static final byte CACHE_IDENTIFIER_ENTITIES = 0x03; - private static final byte CACHE_IDENTIFIER_BLOCK_TILE_ENTITIES = 0x04; - - private final InputStream parentStream; - private final MutableBlockVector3 dimensions = MutableBlockVector3.at(0, 0, 0); - private final Set remainingTags; - - private DataInputStream dataInputStream; - private NBTInputStream nbtInputStream; - - private VersionedDataFixer dataFixer; - private BlockVector3 offset; - private BlockVector3 origin = BlockVector3.ZERO; - private BlockState[] blockPalette; - private BiomeType[] biomePalette; - private int dataVersion = -1; - - // Only used if the InputStream is not file based (and therefor does not support resets based on FileChannels) - // and the file is unordered - // Data and Palette cache is separated, as the data requires a fully populated palette - and the order is not guaranteed - private byte[] dataCache; - private byte[] paletteCache; - private OutputStream dataCacheWriter; - private OutputStream paletteCacheWriter; - - - public FaWeSchematicReaderV3(@NonNull InputStream stream) { - Objects.requireNonNull(stream, "stream"); - if (stream instanceof ResettableFileInputStream) { - stream.mark(Integer.MAX_VALUE); - this.remainingTags = new HashSet<>(); - } else if (stream instanceof FileInputStream fileInputStream) { - stream = new ResettableFileInputStream(fileInputStream); - stream.mark(Integer.MAX_VALUE); - this.remainingTags = new HashSet<>(); - } else if (stream instanceof FastBufferedInputStream || stream instanceof BufferedInputStream) { - this.remainingTags = null; - } else { - stream = new FastBufferedInputStream(stream); - this.remainingTags = null; - } - this.parentStream = stream; - } - - @Override - public Clipboard read(final UUID uuid, final Function createOutput) throws IOException { - Clipboard clipboard = null; - - this.setSubStreams(); - skipHeader(this.dataInputStream); - - byte type; - String tag; - while ((type = dataInputStream.readByte()) != NBTConstants.TYPE_END) { - tag = this.dataInputStream.readUTF(); - switch (tag) { - case "DataVersion" -> { - final Platform platform = - WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); - this.dataVersion = this.dataInputStream.readInt(); - this.dataFixer = ReaderUtil.getVersionedDataFixer(this.dataVersion, platform, platform.getDataVersion()); - } - case "Metadata" -> { - LinCompoundTag metadataCompoundTag = - (LinCompoundTag) this.nbtInputStream.readTagPayload(NBTConstants.TYPE_COMPOUND, 0).toLinTag(); - - LinCompoundTag worldEditTag = metadataCompoundTag.findTag("WorldEdit", LinTagType.compoundTag()); - if (worldEditTag != null) { // allowed to be optional - LinIntArrayTag originTag = worldEditTag.findTag("Origin", LinTagType.intArrayTag()); - if (originTag != null) { // allowed to be optional - int[] parts = originTag.value(); - - if (parts.length != 3) { - throw new IOException("`Metadata > WorldEdit > Origin` int array length is invalid."); - } - - this.origin = BlockVector3.at(parts[0], parts[1], parts[2]); - } - } - } - case "Offset" -> { - this.dataInputStream.skipNBytes(4); // Array Length field (4 byte int) - this.offset = BlockVector3.at( - this.dataInputStream.readInt(), - this.dataInputStream.readInt(), - this.dataInputStream.readInt() - ); - } - case "Width" -> this.dimensions.mutX(this.dataInputStream.readShort() & 0xFFFF); - case "Height" -> this.dimensions.mutY(this.dataInputStream.readShort() & 0xFFFF); - case "Length" -> this.dimensions.mutZ(this.dataInputStream.readShort() & 0xFFFF); - case "Blocks" -> readBlocks(clipboard); - case "Biomes" -> readBiomes(clipboard); - case "Entities" -> readEntities(clipboard); - default -> this.nbtInputStream.readTagPayloadLazy(type, 0); - } - if (clipboard == null && this.areDimensionsAvailable()) { - clipboard = createOutput.apply(this.dimensions); - } - } - - if (clipboard == null) { - throw new IOException("Invalid schematic - missing dimensions"); - } - if (dataFixer == null) { - throw new IOException("Invalid schematic - missing DataVersion"); - } - - if (this.supportsReset() && !remainingTags.isEmpty()) { - readRemainingDataReset(clipboard); - } else if (this.dataCacheWriter != null || this.paletteCacheWriter != null) { - readRemainingDataCache(clipboard); - } - - clipboard.setOrigin(this.offset.multiply(-1)); - if (clipboard instanceof SimpleClipboard simpleClipboard && !this.offset.equals(BlockVector3.ZERO)) { - clipboard = new BlockArrayClipboard(simpleClipboard, this.offset.add(this.origin)); - } - return clipboard; - } - - - /** - * Reads all locally cached data (due to reset not being available) and applies them to the clipboard. - *

- * Firstly, closes all cache writers (which adds the END identifier to each and fills the cache byte arrays on this instance) - * If required, creates all missing palettes first (as needed by all remaining data). - * At last writes all missing data (block states, tile entities, biomes, entities). - * - * @param clipboard The clipboard to write into. - * @throws IOException on I/O error. - */ - private void readRemainingDataCache(Clipboard clipboard) throws IOException { - byte identifier; - if (this.paletteCacheWriter != null) { - this.paletteCacheWriter.close(); - } - if (this.dataCacheWriter != null) { - this.dataCacheWriter.close(); - } - if (this.paletteCache != null) { - try (final DataInputStream cacheStream = new DataInputStream(new FastBufferedInputStream( - new LZ4BlockInputStream(new FastBufferedInputStream(new ByteArrayInputStream(this.paletteCache)))))) { - while ((identifier = cacheStream.readByte()) != CACHE_IDENTIFIER_END) { - if (identifier == CACHE_IDENTIFIER_BLOCK) { - this.readPaletteMap(cacheStream, this.provideBlockPaletteInitializer()); - continue; - } - if (identifier == CACHE_IDENTIFIER_BIOMES) { - this.readPaletteMap(cacheStream, this.provideBiomePaletteInitializer()); - continue; - } - throw new IOException("invalid cache state - got identifier: 0x" + identifier); - } - } - } - try (final DataInputStream cacheStream = new DataInputStream(new FastBufferedInputStream( - new LZ4BlockInputStream(new FastBufferedInputStream(new ByteArrayInputStream(this.dataCache))))); - final NBTInputStream cacheNbtIn = new NBTInputStream(cacheStream)) { - while ((identifier = cacheStream.readByte()) != CACHE_IDENTIFIER_END) { - switch (identifier) { - case CACHE_IDENTIFIER_BLOCK -> this.readPaletteData(cacheStream, this.getBlockWriter(clipboard)); - case CACHE_IDENTIFIER_BIOMES -> this.readPaletteData(cacheStream, this.getBiomeWriter(clipboard)); - case CACHE_IDENTIFIER_ENTITIES -> { - cacheStream.skipNBytes(1); // list child type (TAG_Compound) - this.readEntityContainers( - cacheStream, - cacheNbtIn, - DataFixer.FixTypes.ENTITY, - this.provideEntityTransformer(clipboard) - ); - } - case CACHE_IDENTIFIER_BLOCK_TILE_ENTITIES -> { - cacheStream.skipNBytes(1); // list child type (TAG_Compound) - this.readEntityContainers( - cacheStream, - cacheNbtIn, - DataFixer.FixTypes.BLOCK_ENTITY, - this.provideTileEntityTransformer(clipboard) - ); - } - default -> throw new IOException("invalid cache state - got identifier: 0x" + identifier); - } - } - } - } - - /** - * Reset the main stream of this clipboard and reads all remaining data that could not be read or fixed yet. - * Might need two iterations if the DataVersion tag is after the Blocks tag while the Palette inside the Blocks tag is not - * at the first position. - * - * @param clipboard The clipboard to write into. - * @throws IOException on I/O error. - */ - private void readRemainingDataReset(Clipboard clipboard) throws IOException { - byte type; - String tag; - outer: - while (!this.remainingTags.isEmpty()) { - this.reset(); - skipHeader(this.dataInputStream); - while ((type = dataInputStream.readByte()) != NBTConstants.TYPE_END) { - tag = dataInputStream.readUTF(); - byte b = tag.equals("Blocks") ? CACHE_IDENTIFIER_BLOCK : - tag.equals("Biomes") ? CACHE_IDENTIFIER_BIOMES : - tag.equals("Entities") ? CACHE_IDENTIFIER_ENTITIES : - CACHE_IDENTIFIER_END; - if (!this.remainingTags.remove(b)) { - this.nbtInputStream.readTagPayloadLazy(type, 0); - continue; - } - switch (tag) { - case "Blocks" -> readBlocks(clipboard); - case "Biomes" -> readBiomes(clipboard); - case "Entities" -> readEntities(clipboard); - default -> this.nbtInputStream.readTagPayloadLazy(type, 0); // Should never happen, but just in case - } - if (this.remainingTags.isEmpty()) { - break outer; - } - } - } - } - - /** - * {@inheritDoc} - *

- * Requires {@link #read()}, {@link #read(UUID)} or {@link #read(UUID, Function)} to be called before. - */ - @Override - public OptionalInt getDataVersion() { - return this.dataVersion > -1 ? OptionalInt.of(this.dataVersion) : OptionalInt.empty(); - } - - private void readBlocks(Clipboard target) throws IOException { - this.blockPalette = new BlockState[BlockTypesCache.states.length]; - readPalette( - target != null, - CACHE_IDENTIFIER_BLOCK, - () -> this.blockPalette[0] != null, - this.provideBlockPaletteInitializer(), - this.getBlockWriter(target), - (type, tag) -> { - if (!tag.equals("BlockEntities")) { - try { - this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_LIST, 0); - } catch (IOException e) { - LOGGER.error("Failed to skip additional tag", e); - } - return; - } - try { - this.readTileEntities(target); - } catch (IOException e) { - LOGGER.warn("Failed to read tile entities", e); - } - } - ); - } - - private void readBiomes(Clipboard target) throws IOException { - this.biomePalette = new BiomeType[BiomeType.REGISTRY.size()]; - readPalette( - target != null, - CACHE_IDENTIFIER_BIOMES, - () -> this.biomePalette[0] != null, - this.provideBiomePaletteInitializer(), - this.getBiomeWriter(target), - (type, tag) -> { - try { - this.nbtInputStream.readTagPayloadLazy(type, 0); - } catch (IOException e) { - LOGGER.error("Failed to skip additional tag in biome container: {}", tag, e); - } - } - ); - } - - private void readEntities(@Nullable Clipboard target) throws IOException { - if (target == null || this.dataFixer == null) { - if (supportsReset()) { - this.remainingTags.add(CACHE_IDENTIFIER_ENTITIES); - this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_LIST, 0); - return; - } - // Easier than streaming for now - final NBTOutputStream cacheStream = new NBTOutputStream(this.getDataCacheWriter()); - cacheStream.writeByte(CACHE_IDENTIFIER_ENTITIES); - cacheStream.writeTagPayload(this.nbtInputStream.readTagPayload(NBTConstants.TYPE_LIST, 0)); - return; - } - if (this.dataInputStream.read() != NBTConstants.TYPE_COMPOUND) { - throw new IOException("Expected a compound block for entity"); - } - this.readEntityContainers( - this.dataInputStream, this.nbtInputStream, DataFixer.FixTypes.ENTITY, this.provideEntityTransformer(target) - ); - } - - private void readTileEntities(Clipboard target) throws IOException { - if (target == null || this.dataFixer == null) { - if (supportsReset()) { - this.remainingTags.add(CACHE_IDENTIFIER_BLOCK); // use block identifier, as this method will be called by - // readBlocks again - this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_LIST, 0); - return; - } - // Easier than streaming for now - final NBTOutputStream cacheStream = new NBTOutputStream(this.getDataCacheWriter()); - cacheStream.writeByte(CACHE_IDENTIFIER_BLOCK_TILE_ENTITIES); - cacheStream.writeTagPayload(this.nbtInputStream.readTagPayload(NBTConstants.TYPE_LIST, 0)); - return; - } - if (this.dataInputStream.read() != NBTConstants.TYPE_COMPOUND) { - throw new IOException("Expected a compound block for tile entity"); - } - this.readEntityContainers( - this.dataInputStream, - this.nbtInputStream, - DataFixer.FixTypes.BLOCK_ENTITY, - this.provideTileEntityTransformer(target) - ); - } - - private void readEntityContainers( - DataInputStream stream, - NBTInputStream nbtStream, - DataFixer.FixType fixType, - EntityTransformer transformer - ) throws IOException { - double x, y, z; - LinCompoundTag tag; - String id; - byte type; - int count = stream.readInt(); - while (count-- > 0) { - x = -1; - y = -1; - z = -1; - tag = null; - id = null; - while ((type = stream.readByte()) != NBTConstants.TYPE_END) { - switch (type) { - // Depending on the type of entity container (tile vs "normal") the pos consists of either doubles or ints - case NBTConstants.TYPE_INT_ARRAY -> { - if (!stream.readUTF().equals("Pos")) { - throw new IOException("Expected INT_ARRAY tag to be Pos"); - } - stream.skipNBytes(4); // count of following ints - for pos = 3 - x = stream.readInt(); - y = stream.readInt(); - z = stream.readInt(); - } - case NBTConstants.TYPE_LIST -> { - if (!stream.readUTF().equals("Pos")) { - throw new IOException("Expected LIST tag to be Pos"); - } - if (stream.readByte() != NBTConstants.TYPE_DOUBLE) { - throw new IOException("Expected LIST Pos tag to contain DOUBLE"); - } - stream.skipNBytes(4); // count of following doubles - for pos = 3 - x = stream.readDouble(); - y = stream.readDouble(); - z = stream.readDouble(); - } - case NBTConstants.TYPE_STRING -> { - if (!stream.readUTF().equals("Id")) { - throw new IOException("Expected STRING tag to be Id"); - } - id = stream.readUTF(); - } - case NBTConstants.TYPE_COMPOUND -> { - if (!stream.readUTF().equals("Data")) { - throw new IOException("Expected COMPOUND tag to be Data"); - } - if (!(nbtStream.readTagPayload(NBTConstants.TYPE_COMPOUND, 0).toLinTag() instanceof LinCompoundTag lin)) { - throw new IOException("Data tag could not be read into LinCompoundTag"); - } - tag = lin; - } - default -> throw new IOException("Unexpected tag in compound: " + type); - } - } - if (id == null) { - throw new IOException("Missing Id tag in compound"); - } - if (x < 0 || y < 0 || z < 0) { - throw new IOException("Missing position for entity " + id); - } - if (tag == null) { - transformer.transform(x, y, z, id, LinCompoundTag.of(Map.of())); - continue; - } - tag = this.dataFixer.fixUp(fixType, tag); - if (tag == null) { - LOGGER.warn("Failed to fix-up entity for {} @ {},{},{} - skipping", id, x, y, z); - continue; - } - transformer.transform(x, y, z, id, tag); - } - } - - /** - * The `Palette` tag is required first, as that contains the information of the actual palette size. - * Keeping the whole Data block in memory - which *could* be compressed - is just not it - * - * @param paletteInitializer Invoked for each 'Palette' entry using the actual palette value (e.g. block state) + index - * @param paletteDataApplier Invoked for each 'Data' entry using the data index and the palette index at the data index - */ - private void readPalette( - boolean hasClipboard, - byte paletteType, - BooleanSupplier paletteAlreadyInitialized, - PaletteInitializer paletteInitializer, - PaletteDataApplier paletteDataApplier, - AdditionalTagConsumer additionalTag - ) throws IOException { - boolean hasPalette = paletteAlreadyInitialized.getAsBoolean(); - byte type; - String tag; - while ((type = this.dataInputStream.readByte()) != NBTConstants.TYPE_END) { - tag = this.dataInputStream.readUTF(); - if (tag.equals("Palette")) { - if (hasPalette) { - // Skip palette, as already exists - this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_COMPOUND, 0); - continue; - } - if (!this.readPaletteMap(this.dataInputStream, paletteInitializer)) { - if (this.supportsReset()) { - // Couldn't read - skip palette for now - this.remainingTags.add(paletteType); - this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_COMPOUND, 0); - continue; - } - // Reset not possible, write into cache - final NBTOutputStream cacheWriter = new NBTOutputStream(this.getPaletteCacheWriter()); - cacheWriter.write(paletteType); - cacheWriter.writeTagPayload(this.nbtInputStream.readTagPayload(NBTConstants.TYPE_COMPOUND, 0)); - continue; - } - hasPalette = true; - continue; - } - if (tag.equals("Data")) { - // No palette or dimensions are yet available - if (!hasPalette || this.dataFixer == null || !hasClipboard) { - if (this.supportsReset()) { - this.remainingTags.add(paletteType); - this.nbtInputStream.readTagPayloadLazy(NBTConstants.TYPE_BYTE_ARRAY, 0); - continue; - } - // Reset not possible, write into cache - int byteLen = this.dataInputStream.readInt(); - final DataOutputStream cacheWriter = new DataOutputStream(this.getDataCacheWriter()); - cacheWriter.write(paletteType); - cacheWriter.writeInt(byteLen); - IOUtil.copy(this.dataInputStream, cacheWriter, byteLen); - continue; - } - this.readPaletteData(this.dataInputStream, paletteDataApplier); - continue; - } - additionalTag.accept(type, tag); - } - } - - private void readPaletteData(DataInputStream stream, PaletteDataApplier applier) throws IOException { - int length = stream.readInt(); - // Write data into clipboard - int i = 0; - if (needsVarIntReading(length)) { - for (var iter = new VarIntStreamIterator(stream, length); iter.hasNext(); i++) { - applier.apply(i, (char) iter.nextInt()); - } - return; - } - while (i < length) { - applier.apply(i++, (char) stream.readUnsignedByte()); - } - } - - /** - * Reads the CompoundTag containing the palette mapping ({@code index: value}) and passes each entry to the - * {@link PaletteInitializer}. - *

- * This method expects that the identifier ({@link NBTConstants#TYPE_COMPOUND}) is already consumed from the stream. - * - * @param stream The stream to read the data from. - * @param initializer The initializer called for each entry with its index and backed value. - * @return {@code true} if the mapping could be read, {@code false} otherwise (e.g. DataFixer is not yet available). - * @throws IOException on I/O error. - */ - private boolean readPaletteMap(DataInputStream stream, PaletteInitializer initializer) throws IOException { - if (this.dataFixer == null) { - return false; - } - while (stream.readByte() != NBTConstants.TYPE_END) { - String value = stream.readUTF(); - char index = (char) stream.readInt(); - initializer.initialize(index, value); - } - return true; - } - - private void indexToPosition(int index, PositionConsumer supplier) { - int y = index / (dimensions.x() * dimensions.z()); - int remainder = index - (y * dimensions.x() * dimensions.z()); - int z = remainder / dimensions.x(); - int x = remainder - z * dimensions.x(); - supplier.accept(x, y, z); - } - - private PaletteDataApplier getBlockWriter(Clipboard target) { - if (target instanceof LinearClipboard linearClipboard) { - return (index, ordinal) -> linearClipboard.setBlock(index, this.blockPalette[ordinal]); - } - return (index, ordinal) -> indexToPosition(index, (x, y, z) -> target.setBlock(x, y, z, this.blockPalette[ordinal])); - } - - private PaletteDataApplier getBiomeWriter(Clipboard target) { - return (index, ordinal) -> indexToPosition(index, (x, y, z) -> target.setBiome(x, y, z, this.biomePalette[ordinal])); - } - - private PaletteInitializer provideBlockPaletteInitializer() { - return (index, value) -> { - if (this.dataFixer == null) { - throw new IllegalStateException("Can't read block palette map if DataFixer is not yet available"); - } - value = dataFixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, value); - try { - this.blockPalette[index] = BlockState.get(value); - } catch (InputParseException e) { - LOGGER.warn("Invalid BlockState in palette: {}. Block will be replaced with air.", value); - this.blockPalette[index] = BlockTypes.AIR.getDefaultState(); - } - }; - } - - private PaletteInitializer provideBiomePaletteInitializer() { - return (index, value) -> { - if (this.dataFixer == null) { - throw new IllegalStateException("Can't read biome palette map if DataFixer is not yet available"); - } - value = dataFixer.fixUp(DataFixer.FixTypes.BIOME, value); - BiomeType biomeType = BiomeTypes.get(value); - if (biomeType == null) { - biomeType = BiomeTypes.PLAINS; - LOGGER.warn("Invalid biome type in palette: {}. Biome will be replaced with plains.", value); - } - this.biomePalette[index] = biomeType; - }; - } - - private EntityTransformer provideEntityTransformer(Clipboard clipboard) { - return (x, y, z, id, tag) -> { - EntityType type = EntityType.REGISTRY.get(id); - if (type == null) { - LOGGER.warn("Invalid entity id: {} - skipping", id); - return; - } - clipboard.createEntity( - new Location(clipboard, Location.at(x, y, z).add(clipboard.getMinimumPoint().toVector3())), - new BaseEntity(type, LazyReference.computed(tag)) - ); - }; - } - - private EntityTransformer provideTileEntityTransformer(Clipboard clipboard) { - return (x, y, z, id, tag) -> clipboard.tile( - MathMan.roundInt(x + clipboard.getMinimumPoint().x()), - MathMan.roundInt(y + clipboard.getMinimumPoint().y()), - MathMan.roundInt(z + clipboard.getMinimumPoint().z()), - FaweCompoundTag.of(tag) - ); - } - - /** - * @return {@code true} if {@code Width}, {@code Length} and {@code Height} are already read from the stream - */ - private boolean areDimensionsAvailable() { - return this.dimensions.x() != 0 && this.dimensions.y() != 0 && this.dimensions.z() != 0; - } - - /** - * Closes this reader instance and all underlying resources. - * - * @throws IOException on I/O error. - */ - @Override - public void close() throws IOException { - parentStream.close(); // closes all underlying resources implicitly - } - - /** - * Resets the main stream to the previously marked position ({@code 0}), if supported (see {@link #supportsReset()}). - * If the stream is reset, the sub streams (for DataInput and NBT) are re-created to respect the new position. - * - * @throws IOException on I/O error. - */ - private void reset() throws IOException { - if (this.supportsReset()) { - this.parentStream.reset(); - this.parentStream.mark(Integer.MAX_VALUE); - this.setSubStreams(); - } - } - - /** - * @return {@code true} if the stream used while instantiating the reader supports resets (without memory overhead). - */ - private boolean supportsReset() { - return this.remainingTags != null; - } - - /** - * Overwrites the DataInput- and NBT-InputStreams (e.g. when the marker of the backed stream updated). - * - * @throws IOException on I/O error. - */ - private void setSubStreams() throws IOException { - this.dataInputStream = new DataInputStream(this.parentStream); - this.nbtInputStream = new NBTInputStream(this.parentStream); - } - - /** - * Creates a new cache writer for non-palette data, if none exists yet. - * Returns either the already created or new one. - * - * @return the output stream for non-palette cache data. - */ - private OutputStream getDataCacheWriter() { - if (this.dataCacheWriter == null) { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(512); - this.dataCacheWriter = new FastBufferedOutputStream(new LZ4BlockOutputStream(byteArrayOutputStream)) { - @Override - public void close() throws IOException { - this.write(CACHE_IDENTIFIER_END); - super.close(); - FaWeSchematicReaderV3.this.dataCache = byteArrayOutputStream.toByteArray(); - } - }; - } - return this.dataCacheWriter; - } - - /** - * Creates a new cache writer for palette data, if none exists yet. - * Returns either the already created or new one. - * - * @return the output stream for palette cache data. - */ - private OutputStream getPaletteCacheWriter() { - if (this.paletteCacheWriter == null) { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(256); - this.paletteCacheWriter = new FastBufferedOutputStream(new LZ4BlockOutputStream(byteArrayOutputStream)) { - @Override - public void close() throws IOException { - this.write(CACHE_IDENTIFIER_END); - super.close(); - FaWeSchematicReaderV3.this.paletteCache = byteArrayOutputStream.toByteArray(); - } - }; - } - return this.paletteCacheWriter; - } - - private boolean needsVarIntReading(int byteArrayLength) { - return byteArrayLength > this.dimensions.x() * this.dimensions.y() * this.dimensions.z(); - } - - /** - * Skips the schematic header including the root compound (empty name) and the root's child compound ("Schematic") - * - * @param dataInputStream The stream containing the schematic data to skip - * @throws IOException on I/O error - */ - private static void skipHeader(DataInputStream dataInputStream) throws IOException { - dataInputStream.skipNBytes(1 + 2); // 1 Byte = TAG_Compound, 2 Bytes = Short (Length of tag name = "") - dataInputStream.skipNBytes(1 + 2 + 9); // as above + 9 bytes = "Schematic" - } - - @ApiStatus.Internal - @FunctionalInterface - private interface PositionConsumer { - - /** - * Called with block location coordinates. - * - * @param x the x coordinate. - * @param y the y coordinate. - * @param z the z coordinate. - */ - void accept(int x, int y, int z); - - } - - @ApiStatus.Internal - @FunctionalInterface - private interface EntityTransformer { - - /** - * Called for each entity from the Schematics {@code Entities} compound list. - * - * @param x the relative x coordinate of the entity. - * @param y the relative y coordinate of the entity. - * @param z the relative z coordinate of the entity. - * @param id the entity id as a resource location (e.g. {@code minecraft:sheep}). - * @param tag the - already fixed, if required - nbt data of the entity. - */ - void transform(double x, double y, double z, String id, LinCompoundTag tag); - - } - - @ApiStatus.Internal - @FunctionalInterface - private interface PaletteInitializer { - - /** - * Called for each palette entry (the mapping part, not data). - * - * @param index the index of the entry, as used in the Data byte array. - * @param value the value for this entry (either biome type as resource location or the block state as a string). - */ - void initialize(char index, String value); - - } - - @ApiStatus.Internal - @FunctionalInterface - private interface PaletteDataApplier { - - /** - * Called for each palette data entry (not the mapping part, but the var-int byte array). - * - * @param index The index of this data entry (due to var-int behaviour not necessarily the index in the data byte array). - * @param ordinal The ordinal of this entry as defined in the palette mapping. - */ - void apply(int index, char ordinal); - - } - - @ApiStatus.Internal - @FunctionalInterface - private interface AdditionalTagConsumer { - - /** - * Called for each unknown nbt tag. - * - * @param type The type of the tag (as defined by the constants in {@link NBTConstants}). - * @param name The name of the tag. - */ - void accept(byte type, String name); - - } - -} diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java index 52743f45..d93c095d 100644 --- a/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java +++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java @@ -26,6 +26,8 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader; +import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV2Reader; +import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.Region; @@ -33,6 +35,7 @@ import com.sk89q.worldedit.session.ClipboardHolder; import de.steamwar.sql.NodeData; import org.bukkit.entity.Player; import org.bukkit.util.Vector; +import org.enginehub.linbus.stream.LinBinaryIO; import java.io.*; @@ -67,8 +70,8 @@ public class WorldEditWrapper21 implements WorldEditWrapper { public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException { return switch (schemFormat) { case MCEDIT -> new MCEditSchematicReader(new NBTInputStream(is)).read(); - case SPONGE_V2 -> new FastSchematicReaderV2(new NBTInputStream(is)).read(); - case SPONGE_V3 -> new FaWeSchematicReaderV3(is).read(); + case SPONGE_V2 -> new SpongeSchematicV2Reader(LinBinaryIO.read(new DataInputStream(is))).read(); + case SPONGE_V3 -> new SpongeSchematicV3Reader(LinBinaryIO.read(new DataInputStream(is))).read(); }; } @@ -93,4 +96,9 @@ public class WorldEditWrapper21 implements WorldEditWrapper { v = transform.apply(v); return new org.bukkit.util.Vector(v.x(), v.y(), v.z()); } + + @Override + public NodeData.SchematicFormat getNativeFormat() { + return NodeData.SchematicFormat.SPONGE_V3; + } } diff --git a/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java index a6aad3b5..75957933 100644 --- a/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java +++ b/SpigotCore/SpigotCore_8/src/de/steamwar/core/WorldEditWrapper8.java @@ -105,6 +105,11 @@ public class WorldEditWrapper8 implements WorldEditWrapper { return new org.bukkit.util.Vector(v.getX(), v.getY(), v.getZ()); } + @Override + public NodeData.SchematicFormat getNativeFormat() { + return NodeData.SchematicFormat.MCEDIT; + } + private static class SpongeSchematicReader implements ClipboardReader { private final NBTInputStream inputStream; diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/ErrorHandler.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/ErrorHandler.java index 62a7f2b7..c9585847 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/ErrorHandler.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/ErrorHandler.java @@ -77,7 +77,7 @@ public class ErrorHandler extends Handler { return; try { - //SWException.log(message, stacktrace); + SWException.log(message, stacktrace); } catch (SecurityException e) { Core.getInstance().getLogger().log(Level.INFO, "Could not log error in database", e); } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java index d07bd155..9928b947 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/WorldEditWrapper.java @@ -46,6 +46,8 @@ public interface WorldEditWrapper { Vector getMaximum(Region region); Vector applyTransform(Vector vector, Transform transform); + NodeData.SchematicFormat getNativeFormat(); + static WorldEditPlugin getWorldEditPlugin() { return (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit"); } @@ -86,16 +88,6 @@ public interface WorldEditWrapper { return inputStream; } - static NodeData.SchematicFormat getNativeFormat() { - if (Core.getVersion() <= 12) { - return NodeData.SchematicFormat.MCEDIT; - } else if (Core.getVersion() <= 20) { - return NodeData.SchematicFormat.SPONGE_V2; - } else { - return NodeData.SchematicFormat.SPONGE_V3; - } - } - interface SchematicWriter { void write(OutputStream outputStream, Clipboard clipboard, ClipboardHolder holder) throws IOException; } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java index 0957bae0..62f00369 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java @@ -61,7 +61,7 @@ public class SchematicData { } public void saveFromPlayer(Player player) throws IOException, NoClipboardException { - data.saveFromStream(WorldEditWrapper.impl.getPlayerClipboard(player), WorldEditWrapper.getNativeFormat()); + data.saveFromStream(WorldEditWrapper.impl.getPlayerClipboard(player), WorldEditWrapper.impl.getNativeFormat()); } @Deprecated diff --git a/VelocityCore/build.gradle.kts b/VelocityCore/build.gradle.kts index e9d6386e..166df4c4 100644 --- a/VelocityCore/build.gradle.kts +++ b/VelocityCore/build.gradle.kts @@ -64,4 +64,6 @@ dependencies { implementation(libs.apolloapi) implementation(libs.apollocommon) + + implementation(libs.nbt) } \ No newline at end of file diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java index a39837f6..68b8d360 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordSchemUpload.java @@ -25,10 +25,13 @@ import de.steamwar.sql.NodeData; import de.steamwar.sql.Punishment; import de.steamwar.sql.SchematicNode; import de.steamwar.sql.SteamwarUser; +import dev.dewy.nbt.Nbt; +import dev.dewy.nbt.tags.collection.CompoundTag; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; @@ -38,6 +41,8 @@ import java.util.logging.Level; public class DiscordSchemUpload extends ListenerAdapter { + private static final Nbt NBT = new Nbt(); + private static final List SCHEM_FILE_ENDINGS = Arrays.asList(".schem", ".schematic"); @Override @@ -79,7 +84,17 @@ public class DiscordSchemUpload extends ListenerAdapter { node = SchematicNode.createSchematic(user.getId(), name, null); try (InputStream in = attachment.getProxy().download().get()) { - NodeData.get(node).saveFromStream(in, fileName.substring(dot).equalsIgnoreCase(".schem") ? NodeData.SchematicFormat.SPONGE_V2 : NodeData.SchematicFormat.MCEDIT); + CompoundTag tags = NBT.fromStream(new DataInputStream(in)); + + NodeData.SchematicFormat version = NodeData.SchematicFormat.SPONGE_V2; + + if (tags.size() == 1) { + version = NodeData.SchematicFormat.SPONGE_V3; + } else if (tags.contains("Materials")) { + version = NodeData.SchematicFormat.MCEDIT; + } + + NodeData.get(node).saveFromStream(in, version); sender.system("DC_SCHEMUPLOAD_SUCCESS", name); } catch (InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt index 0dea01f7..e40b5287 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt @@ -126,25 +126,29 @@ fun Route.configureSchematic() { node = SchematicNode.createSchematic(user.id, schemName, 0) } - val content = Base64.getDecoder().decode(file.content) + try { + val content = Base64.getDecoder().decode(file.content) - var schem = nbt.decodeFromByteArray(content) + var schem = nbt.decodeFromByteArray(content) - if (schem.size == 1) schem = schem[schem.keys.first()] as NbtCompound + if (schem.size == 1) schem = schem[schem.keys.first()] as NbtCompound - val version = schem.let { - if (it.containsKey("Materials")) - return@let SchematicFormat.MCEDIT - else if (it.containsKey("Blocks")) - return@let SchematicFormat.SPONGE_V3 - else - return@let SchematicFormat.SPONGE_V2 + val version = schem.let { + if (it.containsKey("Materials")) + return@let SchematicFormat.MCEDIT + else if (it.containsKey("Blocks")) + return@let SchematicFormat.SPONGE_V3 + else + return@let SchematicFormat.SPONGE_V2 + } + + val data = NodeData(node.id, version) + data.saveFromStream(content.inputStream(), version) + + call.respond(ResponseSchematic(node)) + } catch (e: Exception) { + call.respond(HttpStatusCode.BadRequest) } - - val data = NodeData(node.id, version) - data.saveFromStream(content.inputStream(), version) - - call.respond(ResponseSchematic(node)) } } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 07242d37..670bea38 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -165,7 +165,9 @@ dependencyResolutionManagement { library("yamlconfig", "org.bspfsystems:yamlconfiguration:1.3.0") library("kotlinxSerializationCbor", "org.jetbrains.kotlinx:kotlinx-serialization-cbor:1.4.1") library("ktorRateLimit", "io.ktor:ktor-server-rate-limit:$ktorVersion") + library("knbt", "net.benwoodworth.knbt:knbt:0.11.7") + library("nbt", "dev.dewy:nbt:1.5.1") } } } From ec5382316ad4732f33133f6ec3876d313dfe3a92 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Sat, 21 Dec 2024 19:33:23 +0100 Subject: [PATCH 07/22] Fixes --- WebsiteBackend/build.gradle.kts | 2 +- .../src/de/steamwar/routes/Schematic.kt | 17 +++++++---------- settings.gradle.kts | 1 - 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/WebsiteBackend/build.gradle.kts b/WebsiteBackend/build.gradle.kts index f93dacde..d58a5142 100644 --- a/WebsiteBackend/build.gradle.kts +++ b/WebsiteBackend/build.gradle.kts @@ -53,5 +53,5 @@ dependencies { implementation(libs.yamlconfig) implementation(libs.kotlinxSerializationCbor) implementation(libs.ktorRateLimit) - implementation(libs.knbt) + implementation(libs.nbt) } \ No newline at end of file diff --git a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt index e40b5287..c4d76f80 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Schematic.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Schematic.kt @@ -27,16 +27,16 @@ import de.steamwar.sql.NodeDownload import de.steamwar.sql.NodeMember import de.steamwar.sql.SWException import de.steamwar.sql.SchematicNode +import dev.dewy.nbt.Nbt +import dev.dewy.nbt.tags.collection.CompoundTag import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.auth.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -import kotlinx.coroutines.launch import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromByteArray -import net.benwoodworth.knbt.* import java.security.MessageDigest import java.time.Duration import java.time.Instant @@ -75,10 +75,7 @@ data class SchematicCode(val id: Int, val code: String, val expires: Long) @Serializable data class UploadSchematic(val name: String, val content: String) -val nbt = Nbt { - variant = NbtVariant.Java - compression = NbtCompression.Gzip -} +val nbt = Nbt() fun Route.configureSchematic() { route("/download/{code}") { @@ -129,14 +126,14 @@ fun Route.configureSchematic() { try { val content = Base64.getDecoder().decode(file.content) - var schem = nbt.decodeFromByteArray(content) + var schem = nbt.fromByteArray(content) - if (schem.size == 1) schem = schem[schem.keys.first()] as NbtCompound + if (schem.size() == 1) schem = schem.first() as CompoundTag val version = schem.let { - if (it.containsKey("Materials")) + if (it.contains("Materials")) return@let SchematicFormat.MCEDIT - else if (it.containsKey("Blocks")) + else if (it.contains("Blocks")) return@let SchematicFormat.SPONGE_V3 else return@let SchematicFormat.SPONGE_V2 diff --git a/settings.gradle.kts b/settings.gradle.kts index 423e814e..8f3fcdcb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -165,7 +165,6 @@ dependencyResolutionManagement { library("kotlinxSerializationCbor", "org.jetbrains.kotlinx:kotlinx-serialization-cbor:1.4.1") library("ktorRateLimit", "io.ktor:ktor-server-rate-limit:$ktorVersion") - library("knbt", "net.benwoodworth.knbt:knbt:0.11.7") library("nbt", "dev.dewy:nbt:1.5.1") } } From fb0a653b0e2eddb342f695c0a23869511c857e80 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Mon, 23 Dec 2024 13:05:00 +0100 Subject: [PATCH 08/22] Remove /leader command, allow for Leader promotion --- .../de/steamwar/fightsystem/FightSystem.java | 1 - .../fightsystem/FightSystem.properties | 10 ++-- .../fightsystem/FightSystem_de.properties | 10 ++-- .../de/steamwar/fightsystem/commands/GUI.java | 22 +++++-- .../fightsystem/commands/LeaderCommand.java | 60 ------------------- .../steamwar/fightsystem/fight/FightTeam.java | 7 ++- .../fightsystem/listener/TestJoin.java | 7 --- .../fightsystem/utils/BungeeFightInfo.java | 4 -- FightSystem/FightSystem_Core/src/plugin.yml | 1 - .../src/de/steamwar/inventory/SWItem.java | 11 ++-- 10 files changed, 37 insertions(+), 96 deletions(-) delete mode 100644 FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/LeaderCommand.java diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java index 6e6b1c40..57400063 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.java @@ -153,7 +153,6 @@ public class FightSystem extends JavaPlugin { new GamemodeCommand(); new ReadyCommand(); new AkCommand(); - new LeaderCommand(); new LockschemCommand(); new StateCommand(); new SkipCommand(); diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties index 9f80ab7e..3d9a9218 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem.properties @@ -34,9 +34,6 @@ GAMEMODE_NOT_ALLOWED=§cChanging gamemode is not permitted GAMEMODE_UNKNOWN=§cUnknown gamemode {0} GAMEMODE_HELP=§8/§7gm §8[§egamemode§8] -LEADER_FULL=§cAll teams already have a leader -ALREADY_IN_TEAM=§cYou are already in a team - LOCKSCHEM_HELP=§8/§7lockschem §8[§eteam§8] UNKNOWN_TEAM=§cThis team does not exist LOCKSCHEM_LOCKED=§7Schematic locked @@ -65,7 +62,9 @@ STATE_RUNNING=§eFighting phase STATE_SPECTATE_WIN=§7Victory {0} STATE_SPECTATE_TIE=§7Draw -REMOVE_TITLE=Kick player +MANAGE_TITLE=Manage players +MANAGE_LORE1=§eLeft §7click§8: §ekick +MANAGE_LORE2=§eRight §7click§8: §epromote KIT_SELECTION_TITLE=Kit selection KIT_NO_KITS=§cNo kits found @@ -113,7 +112,7 @@ SKIP_NOT_READY=§c§mSkipping to next event TEAM_CHAT={0}{1}§8» {0}{2} CHOOSE_KIT=§eChoose kit RESPAWN=§eRespawn -REMOVE_PLAYERS=§cKick player +MANAGE_PLAYERS=§cManage players CHOOSE_SCHEMATIC=§eChoose {0} SCHEMATIC_REQUIRED=§cChoose a schematic first ADD_AI=§eAdd AI @@ -141,7 +140,6 @@ NO_TELEPORT=§cYou are not allowed to use this teleport function OPEN_INVENTORY_TO_CUSTOMIZE=§eOpen inventory to customize your kit NO_ENTERN=§cYou may not board NO_TEAMAREA=§cYou are not allowed in the team area -TEST_BECOME_LEADER=§7Become a team leader with §8/§eleader PREPARE_SCHEM_DELETED=§cApparently the schematic to be submitted was deleted. submission aborted. PREPARE_SCHEM_EXISTS=§cThere is already a schematic with the suffix -prepared, please rename or delete it, submission aborted. PREPARE_ACTIVE_PISTON=§cMoving pistons were found in the team area, submission aborted. diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem_de.properties b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem_de.properties index 6723bcfb..d45cdfd0 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem_de.properties +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/FightSystem_de.properties @@ -32,9 +32,6 @@ GAMEMODE_NOT_ALLOWED=§cSpielmodusänderung verboten GAMEMODE_UNKNOWN=§cUnbekannter Spielmodus {0} GAMEMODE_HELP=§8/§7gm §8[§eSpielmodus§8] -LEADER_FULL=§cAlle Teams haben bereits einen Leader -ALREADY_IN_TEAM=§cDu bist bereits in einem Team - LOCKSCHEM_HELP=§8/§7lockschem §8[§eTeam§8] UNKNOWN_TEAM=§cDieses Team existiert nicht LOCKSCHEM_LOCKED=§7Schematic gesperrt @@ -59,7 +56,9 @@ STATE_RUNNING=§eKampfphase STATE_SPECTATE_WIN=§7Sieg {0} STATE_SPECTATE_TIE=§7Unentschieden -REMOVE_TITLE=Spieler rauswerfen +MANAGE_TITLE=Mitspieler verwalten +MANAGE_LORE1=§eLinksklick§8: §eRauswurf +MANAGE_LORE2=§eRechtsklick§8: §eBefördern KIT_SELECTION_TITLE=Kitauswahl KIT_NO_KITS=§cKeine Kits gefunden @@ -106,7 +105,7 @@ SKIP_READY=§aBeschleunigung zum nächsten Event SKIP_NOT_READY=§c§mBeschleunigung zum nächsten Event CHOOSE_KIT=§eKit wählen RESPAWN=§eRespawn -REMOVE_PLAYERS=§cSpieler rauswerfen +MANAGE_PLAYERS=§cMitspieler verwalten CHOOSE_SCHEMATIC=§e{0} wählen SCHEMATIC_REQUIRED=§cZuerst muss eine Schematic gewählt sein ADD_AI=§eKI hinzufügen @@ -134,7 +133,6 @@ NO_TELEPORT=§cDu darfst diese Teleportfunktion nicht benutzen OPEN_INVENTORY_TO_CUSTOMIZE=§eInventar zum Anpassen des Kits öffnen NO_ENTERN=§cDu darfst nicht entern NO_TEAMAREA=§cDu darfst nicht zu den Teams -TEST_BECOME_LEADER=§7Werde zum Teamleader mit §8/§eleader PREPARE_SCHEM_DELETED=§cAnscheinend wurde die auszufahrende Schematic gelöscht, Einsenden wird abgebrochen. PREPARE_SCHEM_EXISTS=§cEs existiert bereits eine Schem mit Namenszusatz -prepared, diese bitte umbenennen oder löschen, Einsenden wird abgebrochen. PREPARE_ACTIVE_PISTON=§cIm Teambereich wurden sich noch bewegende Pistons gefunden, Einsenden wird abgebrochen. diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java index 4834bb0a..2ca6849c 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/GUI.java @@ -36,6 +36,7 @@ import de.steamwar.sql.SteamwarUser; import net.md_5.bungee.api.ChatMessageType; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; @@ -53,7 +54,11 @@ public class GUI { String name = team.getLeader() != null ? team.getLeader().getEntity().getName() : team.getName(); inv.setItem(pos, SWItem.getDye(colorCode), colorCode, msg.parse("JOIN_REQUEST_TEAM", p, team.getColor() + name), click -> { p.closeInventory(); - JoinRequest.forPlayer(p, team); + + if(ArenaMode.ManualTeams.contains(Config.mode) && team.canbeLeader(p)) + team.addMember(p); + else + JoinRequest.forPlayer(p, team); }); } @@ -117,14 +122,21 @@ public class GUI { inv.open(); } - public static void chooseRemove(Player p){ + public static void managePlayers(Player p){ List> players = SWListInv.createPlayerList(p.getUniqueId()); FightTeam team = Fight.getPlayerTeam(p); if(team == null) return; - players.removeIf(swItemUUIDPair -> !team.equals(Fight.getPlayerTeam(Bukkit.getPlayer(swItemUUIDPair.getObject())))); - SWListInv inv = new SWListInv<>(p, msg.parse("REMOVE_TITLE", p), players, (ClickType click, UUID player) -> { - Commands.kick(p, SteamwarUser.get(player).getUserName()); + players.removeIf(listEntry -> !team.equals(Fight.getPlayerTeam(Bukkit.getPlayer(listEntry.getObject())))); + players.forEach(listEntry -> listEntry.getItem().setLore(msg.parse("MANAGE_LORE1", p), msg.parse("MANAGE_LORE2", p))); + SWListInv inv = new SWListInv<>(p, msg.parse("MANAGE_TITLE", p), players, (ClickType click, UUID player) -> { + if(click.isLeftClick()) { + Commands.kick(p, SteamwarUser.get(player).getUserName()); + } else if(click.isRightClick()) { + LivingEntity target = (LivingEntity) Bukkit.getEntity(player); + if(target != null) + team.setLeader(team.getFightPlayer(target), false); + } p.closeInventory(); }); inv.setCallback(-999, (ClickType click) -> p.closeInventory()); diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/LeaderCommand.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/LeaderCommand.java deleted file mode 100644 index e2151956..00000000 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/commands/LeaderCommand.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - This file is a part of the SteamWar software. - - Copyright (C) 2020 SteamWar.de-Serverteam - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -package de.steamwar.fightsystem.commands; - -import de.steamwar.fightsystem.ArenaMode; -import de.steamwar.fightsystem.FightSystem; -import de.steamwar.fightsystem.fight.Fight; -import de.steamwar.fightsystem.fight.FightTeam; -import de.steamwar.fightsystem.states.FightState; -import de.steamwar.fightsystem.states.StateDependentCommand; -import net.md_5.bungee.api.ChatMessageType; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -public class LeaderCommand implements CommandExecutor { - - public LeaderCommand() { - new StateDependentCommand(ArenaMode.ManualTeams, FightState.Setup, "leader", this); - } - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if(!(sender instanceof Player)) - return false; - Player player = (Player) sender; - - if(Fight.getFightPlayer(player) != null) { - FightSystem.getMessage().sendPrefixless("ALREADY_IN_TEAM", player, ChatMessageType.ACTION_BAR); - return false; - } - - for(FightTeam team : Fight.teams()) { - if(team.canbeLeader(player)) { - team.addMember(player); - return false; - } - } - FightSystem.getMessage().sendPrefixless("LEADER_FULL", player, ChatMessageType.ACTION_BAR); - return false; - } -} 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 334f3f83..3a6a12a2 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/fight/FightTeam.java @@ -73,7 +73,7 @@ public class FightTeam { if(ArenaMode.VariableTeams.contains(Config.mode)){ notReadyKit.setItem(2, "REQUESTS", new ItemBuilder(Material.PAPER).build(), GUI::chooseJoinRequests); - notReadyKit.setItem(3, "REMOVE_PLAYERS", new ItemBuilder(SWItem.getMaterial("FIREWORK_CHARGE")).build(), GUI::chooseRemove); + notReadyKit.setItem(3, "MANAGE_PLAYERS", SWItem.getPlayerSkull("AdmiralSeekrank").getItemStack(), GUI::managePlayers); if(!AIManager.availableAIs().isEmpty()) notReadyKit.setItem(6, "ADD_AI", new ItemBuilder(Material.REDSTONE).build(), GUI::addAI); } @@ -343,7 +343,10 @@ public class FightTeam { } } - private void setLeader(FightPlayer leader, boolean silent) { + public void setLeader(FightPlayer leader, boolean silent) { + if(this.leader != null) + this.leader.ifPlayer(memberKit::loadToPlayer); + leader.ifPlayer(PersonalKitCreator::closeIfInKitCreator); this.leader = leader; diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/TestJoin.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/TestJoin.java index 77240153..13a512a4 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/TestJoin.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/listener/TestJoin.java @@ -22,8 +22,6 @@ package de.steamwar.fightsystem.listener; import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; -import de.steamwar.fightsystem.fight.Fight; -import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.sql.SteamwarUser; @@ -42,7 +40,6 @@ public class TestJoin implements Listener { @EventHandler public void handlePlayerJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); - FightTeam fightTeam = Fight.getPlayerTeam(player); if(Config.ReplayID != 0 && !SteamwarUser.get(player.getUniqueId()).hasPerm(UserPerm.MODERATION)) { FightSystem.getMessage().send("CHECK_JOIN_DENIED", player); @@ -50,10 +47,6 @@ public class TestJoin implements Listener { return; } - if (fightTeam == null && Fight.teams().stream().anyMatch(team -> team.canbeLeader(player))) { - FightSystem.getMessage().send("TEST_BECOME_LEADER", player); - } - player.setOp(true); if(FightState.getFightState() == FightState.PRE_LEADER_SETUP){ diff --git a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/BungeeFightInfo.java b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/BungeeFightInfo.java index 6ffa0e98..783917bb 100644 --- a/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/BungeeFightInfo.java +++ b/FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/BungeeFightInfo.java @@ -40,10 +40,6 @@ public class BungeeFightInfo { } private void send() { - Player player = Bukkit.getOnlinePlayers().stream().findAny().orElse(null); - if(player == null) - return; - NetworkSender.send(new FightInfoPacket( Config.world.getName(), Config.SchematicType.toDB(), diff --git a/FightSystem/FightSystem_Core/src/plugin.yml b/FightSystem/FightSystem_Core/src/plugin.yml index d8763954..64ece716 100644 --- a/FightSystem/FightSystem_Core/src/plugin.yml +++ b/FightSystem/FightSystem_Core/src/plugin.yml @@ -19,7 +19,6 @@ commands: ready: kit: remove: - leader: lockschem: state: skip: diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java index bc401476..1f9c9813 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/inventory/SWItem.java @@ -21,21 +21,19 @@ package de.steamwar.inventory; import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import de.steamwar.core.Core; import de.steamwar.core.FlatteningWrapper; import de.steamwar.core.TrickyTrialsWrapper; -import de.steamwar.core.VersionDependent; import org.bukkit.Material; import org.bukkit.OfflinePlayer; -import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import java.util.ArrayList; -import java.util.Collection; +import java.util.Arrays; import java.util.EnumSet; import java.util.List; +import java.util.stream.Collectors; public class SWItem { @@ -192,6 +190,11 @@ public class SWItem { itemStack.setItemMeta(itemMeta); } + public void setLore(String... lore) { + itemMeta.setLore(Arrays.stream(lore).collect(Collectors.toList())); + itemStack.setItemMeta(itemMeta); + } + public void setEnchanted(boolean enchanted) { if (enchanted){ itemMeta.addEnchant(TrickyTrialsWrapper.impl.getUnbreakingEnchantment() , 10, true); From 22a8ca4aea23e9f51334e76c8c8bdb1d65090e19 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Tue, 24 Dec 2024 14:55:27 +0100 Subject: [PATCH 09/22] Move ViaVersion to Proxy --- BauSystem/BauSystem_Main/build.gradle.kts | 1 - .../BauSystem_Main/src/BauSystem.properties | 4 +- .../src/BauSystem_de.properties | 4 +- .../bausystem/utils/VersionAnnouncer.java | 49 ----------- BauSystem/BauSystem_Main/src/plugin.yml | 2 - SpigotCore/SpigotCore_9/build.gradle.kts | 2 - .../de/steamwar/core/BountifulWrapper9.java | 4 +- SpigotCore/SpigotCore_Main/build.gradle.kts | 1 - .../de/steamwar/core/CheckpointUtilsJ9.java | 3 - .../src/de/steamwar/core/Core.java | 3 - .../core/events/PartialChunkFixer.java | 84 ------------------- SpigotCore/SpigotCore_Main/src/plugin.yml | 1 - .../src/de/steamwar/persistent/Subserver.java | 10 +-- VelocityCore/build.gradle.kts | 3 +- .../steamwar/messages/BungeeCore.properties | 3 + .../messages/BungeeCore_de.properties | 3 + .../steamwar/velocitycore/GameModeConfig.java | 9 +- .../src/de/steamwar/velocitycore/Node.java | 14 ++-- .../steamwar/velocitycore/ServerStarter.java | 14 ++-- .../steamwar/velocitycore/ServerVersion.java | 29 ++++--- .../steamwar/velocitycore/VelocityCore.java | 1 + .../listeners/VersionAnnouncer.java | 47 +++++++++++ settings.gradle.kts | 3 +- 23 files changed, 104 insertions(+), 190 deletions(-) delete mode 100644 BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/VersionAnnouncer.java delete mode 100644 SpigotCore/SpigotCore_Main/src/de/steamwar/core/events/PartialChunkFixer.java create mode 100644 VelocityCore/src/de/steamwar/velocitycore/listeners/VersionAnnouncer.java diff --git a/BauSystem/BauSystem_Main/build.gradle.kts b/BauSystem/BauSystem_Main/build.gradle.kts index 8f46699d..5b8f0a89 100644 --- a/BauSystem/BauSystem_Main/build.gradle.kts +++ b/BauSystem/BauSystem_Main/build.gradle.kts @@ -38,7 +38,6 @@ dependencies { compileOnly(libs.spigotapi) compileOnly(libs.axiom) compileOnly(libs.authlib) - compileOnly(libs.viaapi) compileOnly(libs.fawe18) diff --git a/BauSystem/BauSystem_Main/src/BauSystem.properties b/BauSystem/BauSystem_Main/src/BauSystem.properties index c9116dce..929d0c67 100644 --- a/BauSystem/BauSystem_Main/src/BauSystem.properties +++ b/BauSystem/BauSystem_Main/src/BauSystem.properties @@ -1013,6 +1013,4 @@ XRAY_OFF=§cXray deactivated COLORREPLACE_HELP=§8//§ecolorreplace §8[§7color§8] §8[§7color§8] §8- §7Replace all blocks of one color with another TYPEREPLACE_HELP=§8//§etypereplace §8[§7type§8] §8[§7type§8] §8- §7Replace all blocks of one type with another # Schematic -SCHEMATIC_GUI_ITEM=§eSchematics -#VersionAnnouncer -SERVER_VERSION=§7This server runs on Minecraft version §e{0} \ No newline at end of file +SCHEMATIC_GUI_ITEM=§eSchematics \ No newline at end of file diff --git a/BauSystem/BauSystem_Main/src/BauSystem_de.properties b/BauSystem/BauSystem_Main/src/BauSystem_de.properties index 45e60f84..4cb20d95 100644 --- a/BauSystem/BauSystem_Main/src/BauSystem_de.properties +++ b/BauSystem/BauSystem_Main/src/BauSystem_de.properties @@ -954,6 +954,4 @@ XRAY_OFF=§cXray deaktiviert COLORREPLACE_HELP=§8//§ecolorreplace §8[§7color§8] §8[§7color§8] §8- §7Ersetzt eine Farbe mit einer anderen TYPEREPLACE_HELP=§8//§etyreplace §8[§7type§8] §8[§7type§8] §8- §7Ersetzt einen Blockgruppe mit einer anderen # Schematics -SCHEMATIC_GUI_ITEM=§eSchematics -#VersionAnnouncer -SERVER_VERSION=§7Dieser Server läuft auf Minecraft-Version §e{0} \ No newline at end of file +SCHEMATIC_GUI_ITEM=§eSchematics \ No newline at end of file diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/VersionAnnouncer.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/VersionAnnouncer.java deleted file mode 100644 index ee9e91be..00000000 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/VersionAnnouncer.java +++ /dev/null @@ -1,49 +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.bausystem.utils; - -import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.api.ViaAPI; -import de.steamwar.bausystem.BauSystem; -import de.steamwar.linkage.Linked; -import net.md_5.bungee.api.ChatMessageType; -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; - -@Linked -public class VersionAnnouncer implements Listener { - - private final String versionString = Bukkit.getBukkitVersion().split("-", 2)[0]; - - @SuppressWarnings("unchecked") - private final ViaAPI via = Via.getAPI(); - - @EventHandler - public void onJoin(PlayerJoinEvent event) { - Player player = event.getPlayer(); - if(via.getServerVersion().supportedVersions().contains(via.getPlayerVersion(player))) - return; - - BauSystem.MESSAGE.sendPrefixless("SERVER_VERSION", player, ChatMessageType.ACTION_BAR, versionString); - } -} diff --git a/BauSystem/BauSystem_Main/src/plugin.yml b/BauSystem/BauSystem_Main/src/plugin.yml index 53585eaa..71b08d95 100644 --- a/BauSystem/BauSystem_Main/src/plugin.yml +++ b/BauSystem/BauSystem_Main/src/plugin.yml @@ -2,8 +2,6 @@ name: BauSystem authors: [ Lixfel, YoyoNow, Chaoscaot, Zeanon, D4rkr34lm ] version: "2.0" depend: [ WorldEdit, SpigotCore ] -softdepend: - - ViaVersion load: POSTWORLD main: de.steamwar.bausystem.BauSystem api-version: "1.13" diff --git a/SpigotCore/SpigotCore_9/build.gradle.kts b/SpigotCore/SpigotCore_9/build.gradle.kts index 3463498a..a888faf1 100644 --- a/SpigotCore/SpigotCore_9/build.gradle.kts +++ b/SpigotCore/SpigotCore_9/build.gradle.kts @@ -26,6 +26,4 @@ dependencies { compileOnly(project(":SpigotCore:SpigotCore_8", "default")) compileOnly(libs.nms9) - - compileOnly(libs.viaapi) } diff --git a/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java b/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java index fa126698..d35e4239 100644 --- a/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java +++ b/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java @@ -20,10 +20,8 @@ package de.steamwar.core; import com.comphenix.tinyprotocol.Reflection; -import com.viaversion.viaversion.api.Via; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.BaseComponent; -import net.minecraft.server.v1_9_R2.PacketPlayOutEntity; import org.bukkit.Sound; import org.bukkit.entity.Player; @@ -38,7 +36,7 @@ public class BountifulWrapper9 implements BountifulWrapper.IBountifulWrapper { @Override public void sendMessage(Player player, ChatMessageType type, BaseComponent... msg) { - if(type == ChatMessageType.CHAT && Via.getAPI().getPlayerVersion(player.getUniqueId()) >= 759) + if(type == ChatMessageType.CHAT) type = ChatMessageType.SYSTEM; player.spigot().sendMessage(type, msg); diff --git a/SpigotCore/SpigotCore_Main/build.gradle.kts b/SpigotCore/SpigotCore_Main/build.gradle.kts index 88825bc9..cc941d8c 100644 --- a/SpigotCore/SpigotCore_Main/build.gradle.kts +++ b/SpigotCore/SpigotCore_Main/build.gradle.kts @@ -35,7 +35,6 @@ dependencies { compileOnly(libs.spigotapi) compileOnly(libs.netty) compileOnly(libs.authlib) - compileOnly(libs.viaapi) compileOnly(libs.fastutil) implementation(libs.anvilgui) diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java index cde82084..50658aea 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/CheckpointUtilsJ9.java @@ -21,7 +21,6 @@ package de.steamwar.core; import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.TinyProtocol; -import com.viaversion.viaversion.api.Via; import de.steamwar.sql.internal.Statement; import io.netty.channel.ChannelFuture; import org.bukkit.Bukkit; @@ -99,7 +98,6 @@ class CheckpointUtilsJ9 { Statement.closeAll(); // Close socket - Via.getManager().getInjector().uninject(); Object serverConnection = TinyProtocol.getServerConnection(Core.getInstance()); List channels = channelFutures.get(serverConnection); for(Object future : channels) { @@ -140,7 +138,6 @@ class CheckpointUtilsJ9 { ((ChannelFuture) future).channel().config().setAutoRead(true); } } - Via.getManager().getInjector().inject(); Bukkit.getPluginManager().callEvent(new CRIUWakeupEvent()); Core.getInstance().getLogger().log(Level.INFO, "Checkpoint restored"); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java index 9c1e51ef..f4a2b419 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/Core.java @@ -100,9 +100,6 @@ public class Core extends JavaPlugin{ CheckpointUtils.signalHandler(); new AntiNocom(); - if(Core.getVersion() < 17 && Bukkit.getPluginManager().getPlugin("ViaVersion") != null) - new PartialChunkFixer(); - if(Core.getVersion() >= 19) new ServerDataHandler(); diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/events/PartialChunkFixer.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/core/events/PartialChunkFixer.java deleted file mode 100644 index 6efab3c5..00000000 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/core/events/PartialChunkFixer.java +++ /dev/null @@ -1,84 +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.core.events; - -import com.comphenix.tinyprotocol.Reflection; -import com.comphenix.tinyprotocol.TinyProtocol; -import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.api.ViaAPI; -import de.steamwar.core.Core; -import de.steamwar.core.CraftbukkitWrapper; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.List; - -/** - * TinyProtocol can't translate BlockEntities during 1.16 to 1.17 conversions du to removed partial chunk update support. This class cancels PartialChunkUpdates for this players and sends them a complete chunk instead. - * This class can only be loaded on 1.9 to 1.15 with active ViaVersion. - **/ -public class PartialChunkFixer { - - private static final int PROTOCOL1_17 = 755; - private static final Class mapChunk = Reflection.getClass("{nms}.PacketPlayOutMapChunk"); - private static final Reflection.FieldAccessor fullChunkFlag = Reflection.getField(mapChunk, boolean.class, 0); - private static final Reflection.FieldAccessor chunkX = Reflection.getField(mapChunk, int.class, 0); - private static final Reflection.FieldAccessor chunkZ = Reflection.getField(mapChunk, int.class, 1); - - private final ViaAPI via = Via.getAPI(); - - private final List chunksToResend = new ArrayList<>(); - - public PartialChunkFixer() { - TinyProtocol.instance.addFilter(mapChunk, this::chunkFilter); - Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> { - synchronized (chunksToResend) { - for(ResendChunk chunk : chunksToResend) { - CraftbukkitWrapper.impl.sendChunk(chunk.player, chunk.x, chunk.z); - } - chunksToResend.clear(); - } - }, 1, 1); - } - - private Object chunkFilter(Player player, Object packet) { - if(via.getPlayerVersion(player) >= PROTOCOL1_17 && !fullChunkFlag.get(packet)) { - // partial chunk update - synchronized (chunksToResend) { - chunksToResend.add(new ResendChunk(player, chunkX.get(packet), chunkZ.get(packet))); - } - return null; - } - return packet; - } - - private static class ResendChunk { - private final Player player; - private final int x; - private final int z; - - private ResendChunk(Player player, int x, int z) { - this.player = player; - this.x = x; - this.z = z; - } - } -} diff --git a/SpigotCore/SpigotCore_Main/src/plugin.yml b/SpigotCore/SpigotCore_Main/src/plugin.yml index 75652668..a29249d2 100644 --- a/SpigotCore/SpigotCore_Main/src/plugin.yml +++ b/SpigotCore/SpigotCore_Main/src/plugin.yml @@ -4,7 +4,6 @@ author: Lixfel api-version: "1.13" load: STARTUP softdepend: - - ViaVersion - WorldEdit main: de.steamwar.core.Core diff --git a/VelocityCore/Persistent/src/de/steamwar/persistent/Subserver.java b/VelocityCore/Persistent/src/de/steamwar/persistent/Subserver.java index 072f1467..d4290814 100644 --- a/VelocityCore/Persistent/src/de/steamwar/persistent/Subserver.java +++ b/VelocityCore/Persistent/src/de/steamwar/persistent/Subserver.java @@ -225,20 +225,16 @@ public class Subserver { if (line.contains("Loading libraries, please wait")) sendProgress(2); else if (line.contains("Starting Minecraft server on")) - sendProgress(4); + sendProgress(5); else if (line.contains("Preparing start region")) - sendProgress(6); - return line.contains("Finished mapping loading"); + sendProgress(8); + return line.contains("Done ("); }); } if (!started) return; - sendProgress(8); - - Thread.sleep(300); - sendProgress(10); for (Player cachedPlayer : cachedPlayers) { sendPlayer(cachedPlayer); diff --git a/VelocityCore/build.gradle.kts b/VelocityCore/build.gradle.kts index 78603f8c..2029b3f4 100644 --- a/VelocityCore/build.gradle.kts +++ b/VelocityCore/build.gradle.kts @@ -47,6 +47,8 @@ java { dependencies { annotationProcessor(libs.velocityapi) compileOnly(libs.velocity) + compileOnly(libs.viaapi) + compileOnly(libs.viavelocity) compileOnly(project(":VelocityCore:Persistent", "default")) @@ -61,6 +63,5 @@ dependencies { } implementation(libs.msgpack) - implementation(libs.apolloprotos) } \ No newline at end of file diff --git a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties index b133d99b..c018323c 100644 --- a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties +++ b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties @@ -728,6 +728,9 @@ MOD_ITEM_BACK=§7Back INV_PAGE_BACK=§{0}Seite zurück INV_PAGE_NEXT=§{0}Seite vor +#VersionAnnouncer +SERVER_VERSION=§7This server runs on Minecraft version §e{0} + #Discord DC_UNLINKED=For this action your Discord account has to be linked to your Minecraft account. To link your accounts go onto the SteamWar Discord to the `regeln-infos` Channel and click on `Minecraft Verknüpfen`. DC_TITLE_SCHEMINFO=Schematic Info diff --git a/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties b/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties index 9299064f..26d52987 100644 --- a/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties +++ b/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties @@ -681,6 +681,9 @@ ADVENT_CALENDAR_OPEN=§7Du hast §e{0}§7 aus dem Adventskalender erhalten! INV_PAGE_BACK=§{0}Page back INV_PAGE_NEXT=§{0}Next page +#VersionAnnouncer +SERVER_VERSION=§7Dieser Server läuft auf Minecraft-Version §e{0} + #Discord DC_UNLINKED=Für diese Aktion muss dein Minecraftaccount mit deinem Discordaccount verknüpft sein, gehe dazu auf dem SteamWar-Discord in den `regeln-infos` Channel und Klicke auf `Minecraft Verknüpfen`. DC_TITLE_SCHEMINFO=Schematicinfo diff --git a/VelocityCore/src/de/steamwar/velocitycore/GameModeConfig.java b/VelocityCore/src/de/steamwar/velocitycore/GameModeConfig.java index 8dab4d8d..74fb19bf 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/GameModeConfig.java +++ b/VelocityCore/src/de/steamwar/velocitycore/GameModeConfig.java @@ -27,10 +27,13 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.BiConsumer; +import java.util.regex.Pattern; @Getter public class GameModeConfig { + private static final Pattern terminatingNumber = Pattern.compile("\\D+(\\d+)$"); + public static void loadAll(Class config, BiConsumer consumer) { File folder = new File(VelocityCore.get().getDataDirectory().getParent().toFile(), "FightSystem"); if(!folder.exists()) @@ -51,9 +54,9 @@ public class GameModeConfig { @Getter public static class Server { private String Folder; - private String ServerJar; private List ChatNames = Collections.emptyList(); private List Maps; + private boolean Spigot = false; private boolean Ranked = false; private boolean Historic = false; } @@ -66,8 +69,8 @@ public class GameModeConfig { private boolean ManualCheck = true; } - public String getServerJar() { - return getServer().getServerJar(); + public ServerVersion getVersion() { + return ServerVersion.valueOf((getServer().isSpigot() ? "SPIGOT_" : "PAPER_") + terminatingNumber.matcher(getServer().getFolder()).group(1)); } public String getFolder() { diff --git a/VelocityCore/src/de/steamwar/velocitycore/Node.java b/VelocityCore/src/de/steamwar/velocitycore/Node.java index b97ef0ba..23cf808a 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/Node.java +++ b/VelocityCore/src/de/steamwar/velocitycore/Node.java @@ -63,7 +63,7 @@ public abstract class Node { nodes.forEach(consumer); } - public abstract ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams); + public abstract ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String... dParams); protected abstract ProcessBuilder prepareExecution(String... command); protected abstract void calcLoadLimit(); @@ -95,7 +95,7 @@ public abstract class Node { return hostname; } - protected void constructServerstart(File directory, List cmd, String serverJar, String worldDir, String levelName, int port, String xmx, String... dParams) { + protected void constructServerstart(File directory, List cmd, String serverJar, String worldDir, String levelName, int port, String... dParams) { if (JAVA_8.contains(serverJar)) cmd.add("/usr/lib/jvm/java-8-openj9-amd64/bin/java"); else @@ -105,7 +105,7 @@ public abstract class Node { cmd.add("-D" + param); } cmd.add("-Xshareclasses:nonfatal,name=" + directory.getName()); - cmd.add("-Xmx" + xmx); + cmd.add("-Xmx768M"); cmd.addAll(OPENJ9_ARGS); if (!JAVA_8.contains(serverJar)) { cmd.add("--add-opens"); @@ -142,9 +142,9 @@ public abstract class Node { } @Override - public ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams) { + public ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String... dParams) { List cmd = new ArrayList<>(); - constructServerstart(directory, cmd, serverJar, worldDir, levelName, port, xmx, dParams); + constructServerstart(directory, cmd, serverJar, worldDir, levelName, port, dParams); ProcessBuilder builder = new ProcessBuilder(cmd); builder.directory(directory); return builder; @@ -174,7 +174,7 @@ public abstract class Node { } @Override - public ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams) { + public ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String... dParams) { List cmd = new ArrayList<>(); cmd.add("ssh"); cmd.add("-L"); @@ -183,7 +183,7 @@ public abstract class Node { cmd.add("cd"); cmd.add(directory.getPath()); cmd.add(";"); - constructServerstart(directory, cmd, serverJar, worldDir, levelName, port, xmx, dParams); + constructServerstart(directory, cmd, serverJar, worldDir, levelName, port, dParams); return new ProcessBuilder(cmd); } diff --git a/VelocityCore/src/de/steamwar/velocitycore/ServerStarter.java b/VelocityCore/src/de/steamwar/velocitycore/ServerStarter.java index 1b834390..0fbdf696 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/ServerStarter.java +++ b/VelocityCore/src/de/steamwar/velocitycore/ServerStarter.java @@ -20,6 +20,8 @@ package de.steamwar.velocitycore; import com.velocitypowered.api.proxy.Player; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.velocity.platform.VelocityViaConfig; import de.steamwar.messages.Chatter; import de.steamwar.persistent.Arenaserver; import de.steamwar.persistent.Bauserver; @@ -56,8 +58,7 @@ public class ServerStarter { private String worldDir = null; private Node node = null; - private String serverJar = "spigot-1.15.2.jar"; - private String xmx = "768M"; + private ServerVersion version = ServerVersion.PAPER_20; private Portrange portrange = BAU_PORTS; private Function serverNameProvider = port -> node.getName() + port; private BooleanSupplier startCondition = () -> true; @@ -78,7 +79,7 @@ public class ServerStarter { public ServerStarter arena(ArenaMode mode, String map) { portrange = ARENA_PORTS; serverNameProvider = port -> mode.getGameName() + (port - portrange.start); - serverJar = mode.getServerJar(); + version = mode.getVersion(); allowMerge = true; fightMap = map; gameMode = mode.getInternalName(); @@ -145,8 +146,8 @@ public class ServerStarter { } public ServerStarter build(ServerVersion version, UUID owner) { + this.version = version; directory = version.getServerDirectory("Bau"); - serverJar = version.getServerJar(); worldDir = version.getWorldFolder(WORLDS_BASE_PATH); worldName = version != ServerVersion.SPIGOT_12 ? String.valueOf(SteamwarUser.get(owner).getId()) : owner.toString(); checkpoint = true; @@ -219,7 +220,7 @@ public class ServerStarter { } public ServerStarter builder(ServerVersion version, String map, File generator) { - serverJar = version.getServerJar(); + this.version = version; directory = version.getServerDirectory("Builder"); worldDir = version.getWorldFolder(BUILDER_BASE_PATH); worldName = map; @@ -294,6 +295,7 @@ public class ServerStarter { if(checkpoint) arguments.put("checkpoint", checkpointDir.getPath()); + ((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols().put(serverName, version.getProtocolVersion().getProtocol()); if(checkpoint && checkpointDir.exists()) { try(DataOutputStream out = new DataOutputStream(Files.newOutputStream(new File(checkpointDir, "port").toPath()))) { out.writeInt(port); @@ -313,7 +315,7 @@ public class ServerStarter { private void regularStart(String serverName, int port) { postStart(constructor.construct(serverName, port, node.startServer( - serverJar, directory, worldDir, worldName, port, xmx, arguments.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).toArray(String[]::new) + version.getServerJar(), directory, worldDir, worldName, port, arguments.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).toArray(String[]::new) ), worldCleanup, null)); } diff --git a/VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java b/VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java index 31b8e39e..fd505e77 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java +++ b/VelocityCore/src/de/steamwar/velocitycore/ServerVersion.java @@ -19,6 +19,8 @@ package de.steamwar.velocitycore; +import com.velocitypowered.api.network.ProtocolVersion; +import lombok.AllArgsConstructor; import lombok.Getter; import java.io.File; @@ -27,12 +29,23 @@ import java.util.Map; import java.util.Set; @Getter +@AllArgsConstructor public enum ServerVersion { - SPIGOT_12("spigot-1.12.2.jar", 12), - SPIGOT_15("spigot-1.15.2.jar", 15), - PAPER_19("paper-1.19.3.jar", 19), - PAPER_20("paper-1.20.1.jar", 20), - PAPER_21("paper-1.21.jar", 21); + SPIGOT_8("spigot-1.8.8.jar", 8, ProtocolVersion.MINECRAFT_1_8), + SPIGOT_9("spigot-1.9.4.jar", 9, ProtocolVersion.MINECRAFT_1_9), + SPIGOT_10("spigot-1.10.2.jar", 10, ProtocolVersion.MINECRAFT_1_10), + SPIGOT_12("spigot-1.12.2.jar", 12, ProtocolVersion.MINECRAFT_1_12_2), + SPIGOT_14("spigot-1.14.4.jar", 14, ProtocolVersion.MINECRAFT_1_14_4), + SPIGOT_15("spigot-1.15.2.jar", 15, ProtocolVersion.MINECRAFT_1_15_2), + + PAPER_8("paper-1.8.8.jar", 8, ProtocolVersion.MINECRAFT_1_8), + PAPER_10("paper-1.10.2.jar", 10, ProtocolVersion.MINECRAFT_1_10), + PAPER_12("paper-1.12.2.jar", 12, ProtocolVersion.MINECRAFT_1_12_2), + PAPER_15("paper-1.15.2.jar", 15, ProtocolVersion.MINECRAFT_1_15_2), + 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), + PAPER_21("paper-1.21.jar", 21, ProtocolVersion.MINECRAFT_1_21_2); private static final Map chatMap = new HashMap<>(); @@ -76,11 +89,7 @@ public enum ServerVersion { private final String serverJar; private final int versionSuffix; - - ServerVersion(String serverJar, int versionSuffix) { - this.serverJar = serverJar; - this.versionSuffix = versionSuffix; - } + private final ProtocolVersion protocolVersion; public String getWorldFolder(String base) { return base + versionSuffix + "/"; diff --git a/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java b/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java index 6a5b3ade..5e6dca1d 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java +++ b/VelocityCore/src/de/steamwar/velocitycore/VelocityCore.java @@ -152,6 +152,7 @@ public class VelocityCore implements ReloadablePlugin { new BanListener(); new CheckListener(); new IPSanitizer(); + new VersionAnnouncer(); local = new Node.LocalNode(); if(MAIN_SERVER) { diff --git a/VelocityCore/src/de/steamwar/velocitycore/listeners/VersionAnnouncer.java b/VelocityCore/src/de/steamwar/velocitycore/listeners/VersionAnnouncer.java new file mode 100644 index 00000000..c28a8fee --- /dev/null +++ b/VelocityCore/src/de/steamwar/velocitycore/listeners/VersionAnnouncer.java @@ -0,0 +1,47 @@ +/* + * 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.velocitycore.listeners; + +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.player.ServerConnectedEvent; +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.api.proxy.Player; +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.persistent.Subserver; + +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) + return; + + player.sendActionBar(Chatter.of(player).parse("SERVER_VERSION", ProtocolVersion.getProtocolVersion(serverVersion).getMostRecentSupportedVersion())); + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index a29c0412..9389f289 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -116,7 +116,6 @@ dependencyResolutionManagement { 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("viaapi", "com.viaversion:viaversion-api:4.3.1") library("anvilgui", "net.wesjd:anvilgui:1.10.3-SNAPSHOT") library("nms8", "de.steamwar:spigot:1.8") @@ -138,6 +137,8 @@ dependencyResolutionManagement { library("velocity", "de.steamwar:velocity:RELEASE") library("velocityapi", "com.velocitypowered:velocity-api:3.3.0-SNAPSHOT") + library("viaapi", "com.viaversion:viaversion-api:4.3.1") + library("viavelocity", "com.viaversion:viaversion-velocity:4.3.1") library("jda", "net.dv8tion:JDA:5.2.0") library("msgpack", "org.msgpack:msgpack-core:0.9.8") library("apolloprotos", "com.lunarclient:apollo-protos:1.0-SNAPSHOT") From a16e1e8cee02d6acd858a0e0b0051e1318a852a2 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Thu, 26 Dec 2024 21:44:40 +0100 Subject: [PATCH 10/22] Add LastOnline to WhoisCommand --- CommonCore/SQL/src/de/steamwar/sql/SteamwarUser.java | 9 +++++++++ .../src/de/steamwar/messages/BungeeCore.properties | 1 + .../src/de/steamwar/messages/BungeeCore_de.properties | 1 + .../de/steamwar/velocitycore/commands/WhoisCommand.java | 9 ++++++--- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CommonCore/SQL/src/de/steamwar/sql/SteamwarUser.java b/CommonCore/SQL/src/de/steamwar/sql/SteamwarUser.java index 96974c61..d5b87b6e 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/SteamwarUser.java +++ b/CommonCore/SQL/src/de/steamwar/sql/SteamwarUser.java @@ -73,6 +73,7 @@ public class SteamwarUser { private static final Statement getPlaytime = new Statement("SELECT SUM(UNIX_TIMESTAMP(EndTime) - UNIX_TIMESTAMP(StartTime)) as Playtime FROM Session WHERE UserID = ?"); private static final Statement getFirstjoin = new Statement("SELECT MIN(StartTime) AS FirstJoin FROM Session WHERE UserID = ?"); + private static final Statement getLastonline = new Statement("SELECT MAX(EndTime) AS LastOnline FROM Session WHERE UserID = ?"); private static final Map usersById = new HashMap<>(); private static final Map usersByUUID = new HashMap<>(); @@ -276,6 +277,14 @@ public class SteamwarUser { }, id); } + public Timestamp getLastOnline() { + return getLastonline.select(rs -> { + if (rs.next()) + return rs.getTimestamp("LastOnline"); + return null; + }, id); + } + public void punish(Punishment.PunishmentType punishment, Timestamp time, String banReason, int from, boolean perma) { initPunishments(); punishments.remove(punishment); diff --git a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties index b133d99b..e8ca12bb 100644 --- a/VelocityCore/src/de/steamwar/messages/BungeeCore.properties +++ b/VelocityCore/src/de/steamwar/messages/BungeeCore.properties @@ -626,6 +626,7 @@ WHOIS_ID=§7ID§8: §e{0} WHOIS_PERMS=§7Perms§8: §7{0} WHOIS_DISCORD_ID=§7Discord-ID§8: §e{0} WHOIS_JOINED_FIRST=§7Joined on§8: §e{0} +WHOIS_LAST_ONLINE=§7Last on§8: §e{0} WHOIS_HOURS_PLAYED=§7Online Time§8: §e{0}h WHOIS_CURRENT_PLAYED=§7Current Online Time§8: §e{0}m WHOIS_CURRENT_SERVER=§7Current Server§8: §e{0} diff --git a/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties b/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties index 9299064f..db367a1f 100644 --- a/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties +++ b/VelocityCore/src/de/steamwar/messages/BungeeCore_de.properties @@ -602,6 +602,7 @@ WHOIS_UUID_HOVER=§eUUID Kopieren WHOIS_ID=§7ID§8: §e{0} WHOIS_DISCORD_ID=§7Discord-ID§8: §e{0} WHOIS_JOINED_FIRST=§7Beigetreten am§8: §e{0} +WHOIS_LAST_ONLINE=§7Zuletzt online§8: §e{0} WHOIS_HOURS_PLAYED=§7Spielzeit§8: §e{0}h WHOIS_CURRENT_PLAYED=§7Aktuell online§8: §e{0}m WHOIS_CURRENT_SERVER=§7Aktueller Server§8: §e{0} diff --git a/VelocityCore/src/de/steamwar/velocitycore/commands/WhoisCommand.java b/VelocityCore/src/de/steamwar/velocitycore/commands/WhoisCommand.java index 6512c9c0..4daa5b78 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/commands/WhoisCommand.java +++ b/VelocityCore/src/de/steamwar/velocitycore/commands/WhoisCommand.java @@ -20,15 +20,15 @@ package de.steamwar.velocitycore.commands; import com.velocitypowered.api.proxy.Player; -import de.steamwar.persistent.Storage; -import de.steamwar.velocitycore.VelocityCore; -import de.steamwar.velocitycore.mods.ModUtils; import de.steamwar.command.PreviousArguments; import de.steamwar.command.SWCommand; import de.steamwar.command.TypeMapper; import de.steamwar.messages.Chatter; import de.steamwar.messages.Message; +import de.steamwar.persistent.Storage; import de.steamwar.sql.*; +import de.steamwar.velocitycore.VelocityCore; +import de.steamwar.velocitycore.mods.ModUtils; import lombok.AllArgsConstructor; import lombok.Getter; import net.kyori.adventure.text.event.ClickEvent; @@ -86,9 +86,12 @@ public class WhoisCommand extends SWCommand { if(firstJoin == null && target != null) { firstJoin = Storage.sessions.get(target); } + Timestamp lastOnline = user.getLastOnline(); if(firstJoin != null) sender.system("WHOIS_JOINED_FIRST", firstJoin.toString()); + if (lastOnline != null) + sender.system("WHOIS_LAST_ONLINE", lastOnline.toString()); sender.system("WHOIS_HOURS_PLAYED", new DecimalFormat("###.##").format(onlineTime / 3600d)); if(target != null) { From e9ac198fcb995e48a7256e55227e8da38119296d Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Thu, 26 Dec 2024 22:41:46 +0100 Subject: [PATCH 11/22] Remove deop on TNTLeague join (mit Lixfel abgesprochen) --- TNTLeague/src/de/steamwar/tntleague/events/GlobalListener.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/TNTLeague/src/de/steamwar/tntleague/events/GlobalListener.kt b/TNTLeague/src/de/steamwar/tntleague/events/GlobalListener.kt index 1d9eb19d..b01dffd9 100644 --- a/TNTLeague/src/de/steamwar/tntleague/events/GlobalListener.kt +++ b/TNTLeague/src/de/steamwar/tntleague/events/GlobalListener.kt @@ -46,7 +46,6 @@ object GlobalListener: Listener { with(e.player) { teleport(TNTLeagueWorldConfig.lobby) inventory.clear() - isOp = false gameMode = GameMode.SPECTATOR respawnLocation = TNTLeagueWorldConfig.lobby } From 7eba9231d5eece2144af468b175df967a707c5b9 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sat, 28 Dec 2024 17:15:57 +0100 Subject: [PATCH 12/22] Fix build issues --- .../listeners/DiscordTicketHandler.java | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java index d797a6f3..f32b4767 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java +++ b/VelocityCore/src/de/steamwar/velocitycore/discord/listeners/DiscordTicketHandler.java @@ -41,12 +41,12 @@ import net.dv8tion.jda.api.interactions.components.ActionRow; import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.utils.SplitUtil; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; +import net.dv8tion.jda.api.utils.messages.MessageCreateData; import net.kyori.adventure.text.event.ClickEvent; import org.jetbrains.annotations.NotNull; import java.awt.*; import java.time.Instant; -import java.util.Collections; import java.util.LinkedList; import java.util.stream.Collectors; @@ -112,9 +112,12 @@ public class DiscordTicketHandler extends ListenerAdapter { .setTimestamp(Instant.now()) .setTitle(event.getChannel().getName()); + User user; if(channel.getTopic() != null && !channel.getTopic().isEmpty()) { - User user = event.getJDA().retrieveUserById(channel.getTopic()).complete(); + user = event.getJDA().retrieveUserById(channel.getTopic()).complete(); embedBuilder.setAuthor(user.getName(), null, user.getAvatarUrl()); + } else { + user = null; } TextChannel logChannel = event.getGuild().getTextChannelById(TICKET_LOG); @@ -124,15 +127,14 @@ public class DiscordTicketHandler extends ListenerAdapter { 2000, SplitUtil.Strategy.NEWLINE, SplitUtil.Strategy.ANYWHERE - ).stream().map(message -> new MessageCreateBuilder().setEmbeds(embedBuilder.setDescription(message).build())).forEach(builder -> logChannel.sendMessage(builder.build()).queue()); - - SplitUtil.split( - messages.stream() - .map(StringBuilder::toString).collect(Collectors.joining()), - 2000, - SplitUtil.Strategy.NEWLINE, - SplitUtil.Strategy.ANYWHERE - ).stream().map(message -> new MessageCreateBuilder().setEmbeds(embedBuilder.setDescription(message).build())).forEach(builder -> user.openPrivateChannel().queue(privateChannel -> privateChannel.sendMessage(builder.build()).queue())); + ).stream().map(message -> new MessageCreateBuilder().setEmbeds(embedBuilder.setDescription(message).build())) + .forEach(builder -> { + MessageCreateData createData = builder.build(); + logChannel.sendMessage(createData).queue(); + if (user != null) { + user.openPrivateChannel().queue(privateChannel -> privateChannel.sendMessage(createData).queue()); + } + }); Chatter.serverteam().prefixless("DISCORD_TICKET_CLOSED", channel.getName()); channel.delete().reason("Closed").queue(); From f111d552004e883874b39fbb4cf7bc3937aa713f Mon Sep 17 00:00:00 2001 From: TheBreadBeard Date: Sat, 28 Dec 2024 17:36:40 +0100 Subject: [PATCH 13/22] Add custom NPC Chats for specific players --- .../src/de/steamwar/lobby/LobbySystem.properties | 2 ++ .../src/de/steamwar/lobby/LobbySystem_de.properties | 2 ++ .../src/de/steamwar/lobby/team/TeamPlayer.java | 11 ++++++++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties b/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties index 2d3aa782..7469e86e 100644 --- a/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties +++ b/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties @@ -10,6 +10,8 @@ NPC_CHAT_2 = §eSteam§8War§f was established in 2019. NPC_CHAT_3 = §fBecome a part of our team by applying via our Discord server (https://steamwar.de/discord). NPC_CHAT_4 = §fYou can develop your own buildserver features with our Lua script system. NPC_CHAT_5 = §fThere are many secrets to discover in this lobby. +## TheBreadBeard +NPC_CHAT_3266_0 = §fI collect Alts like Infinity Stones. # Portal Command PORTAL_COMMAND_LIST_HELP = §8/§7portal §elist §8- §7Lists all portals diff --git a/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties b/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties index 73808174..f7422e89 100644 --- a/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties +++ b/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties @@ -10,6 +10,8 @@ NPC_CHAT_2 = §eSteam§8War§f gibt es seit 2019. NPC_CHAT_3 = §fBewerbe dich gerne für unser Team über unseren Discord-Server (https://steamwar.de/discord). NPC_CHAT_4 = §fDu kannst mit unserm Lua Script-System deine eigenen Bau Features programmieren. NPC_CHAT_5 = §fAuf dieser Lobby sind so einige secrets versteckt. +## TheBreadBeard +NPC_CHAT_3266_0 = §fIch sammle Alts wie Infinity Stones. # Portal Command PORTAL_COMMAND_LIST_HELP = §8/§7portal §elist §8- §7Listet alle Portale auf diff --git a/LobbySystem/src/de/steamwar/lobby/team/TeamPlayer.java b/LobbySystem/src/de/steamwar/lobby/team/TeamPlayer.java index 2829ec2f..a42d184a 100644 --- a/LobbySystem/src/de/steamwar/lobby/team/TeamPlayer.java +++ b/LobbySystem/src/de/steamwar/lobby/team/TeamPlayer.java @@ -144,11 +144,16 @@ public class TeamPlayer extends BasicListener { players.remove(event.getPlayer()); return; } - - String message = "NPC_CHAT_" + random.nextInt(6); SteamwarUser user = SteamwarUser.get(event.getRightClicked().getName()); UserPerm.Prefix prefix = user.prefix(); - LobbySystem.getMessage().send(message, event.getPlayer(), event.getRightClicked().getName(), prefix.getColorCode() + prefix.getChatPrefix()); + Object[] parameters = new Object[]{event.getRightClicked().getName(),prefix.getColorCode() + prefix.getChatPrefix()}; + String message; + try { + message = LobbySystem.getMessage().parsePrefixed("NPC_CHAT_" + user.getId() + "_" + random.nextInt(6), event.getPlayer(),parameters); + } catch (Exception e) { + message = LobbySystem.getMessage().parsePrefixed("NPC_CHAT_" + random.nextInt(6), event.getPlayer(),parameters); + } + event.getPlayer().sendMessage(message); } @EventHandler From ca0f82897ee14b9c84a7a82d069ae633438655d5 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Sat, 28 Dec 2024 18:26:04 +0100 Subject: [PATCH 14/22] Remove anti pickaxe drop code --- .../src/de/steamwar/tntleague/events/IngameListener.kt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/TNTLeague/src/de/steamwar/tntleague/events/IngameListener.kt b/TNTLeague/src/de/steamwar/tntleague/events/IngameListener.kt index e48ea7e6..ca379821 100644 --- a/TNTLeague/src/de/steamwar/tntleague/events/IngameListener.kt +++ b/TNTLeague/src/de/steamwar/tntleague/events/IngameListener.kt @@ -27,13 +27,11 @@ import de.steamwar.tntleague.inventory.DealerInventory import de.steamwar.tntleague.util.TNTLeagueScoreboard import org.bukkit.GameMode import org.bukkit.Location -import org.bukkit.Material import org.bukkit.entity.EntityType import org.bukkit.event.EventHandler import org.bukkit.event.Listener import org.bukkit.event.entity.EntityExplodeEvent import org.bukkit.event.player.PlayerAttemptPickupItemEvent -import org.bukkit.event.player.PlayerDropItemEvent import org.bukkit.event.player.PlayerInteractEntityEvent import org.bukkit.event.player.PlayerJoinEvent import org.bukkit.event.player.PlayerMoveEvent @@ -74,13 +72,6 @@ object IngameListener: Listener { } } - @EventHandler - fun onDropPickaxe(e: PlayerDropItemEvent) { - if (e.itemDrop.itemStack.type == Material.DIAMOND_PICKAXE) { - e.isCancelled = true - } - } - @EventHandler fun onPickupCoins(e: PlayerAttemptPickupItemEvent) { if (e.item.itemStack.isSimilar(DealerInventory.coins)) { From f52cec04484c91c5c4467f3ea1d6461a5374742c Mon Sep 17 00:00:00 2001 From: TheBreadBeard Date: Sat, 28 Dec 2024 22:58:35 +0100 Subject: [PATCH 15/22] Add custom NPC Chats for TheBreadBeard --- LobbySystem/src/de/steamwar/lobby/LobbySystem.properties | 5 +++++ .../src/de/steamwar/lobby/LobbySystem_de.properties | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties b/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties index 7469e86e..275a99a8 100644 --- a/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties +++ b/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties @@ -12,6 +12,11 @@ NPC_CHAT_4 = §fYou can develop your own buildserver features with our Lua scrip NPC_CHAT_5 = §fThere are many secrets to discover in this lobby. ## TheBreadBeard NPC_CHAT_3266_0 = §fI collect Alts like Infinity Stones. +NPC_CHAT_3266_1 = &fYou want my Bread? You can have it! Just look for it! I've hidden the best bakery in the world somewhere! +NPC_CHAT_3266_2 = &fHey, I am TheBreadBeard, ex- EuropSuchties Player, formerly (un)known as WarGear_Titan. +NPC_CHAT_3266_3 = &fInventor of Lactose Intolerance, the Placeholder and Infinity-Ring. All technical principles no one knows or needs. +NPC_CHAT_3266_4 = &fKnown for the Lobby-Banners, logos, spontaneous Arenas, as well as an Organizer and Moderator of many Events. +NPC_CHAT_3266_5 = &fFrom Supporter to Moderator to Builder ... Maybe the journey takes me to being a Developer next. # Portal Command PORTAL_COMMAND_LIST_HELP = §8/§7portal §elist §8- §7Lists all portals diff --git a/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties b/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties index f7422e89..bf382639 100644 --- a/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties +++ b/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties @@ -11,7 +11,12 @@ NPC_CHAT_3 = §fBewerbe dich gerne für unser Team über unseren Discord-Server NPC_CHAT_4 = §fDu kannst mit unserm Lua Script-System deine eigenen Bau Features programmieren. NPC_CHAT_5 = §fAuf dieser Lobby sind so einige secrets versteckt. ## TheBreadBeard -NPC_CHAT_3266_0 = §fIch sammle Alts wie Infinity Stones. +NPC_CHAT_3266_0 = §fIch sammel Alts wie Infinity Stones. +NPC_CHAT_3266_1 = &fIhr wollt meine Teigwaren? Die könnt ihr haben! Sucht sie doch! Irgendwo hab ich die beste Bäckerei der Welt versteckt! +NPC_CHAT_3266_2 = &fMoin, Ich bin TheBreadBeard, ehemaliger EuropSuchties Spieler, damals (un)bekannt als WarGear_Titan. +NPC_CHAT_3266_3 = &fErfinder der Laktoseintoleranz, des Platzhalters und des Infinity-Rings. Alles Prinzipien, die keiner kennt und keiner braucht. +NPC_CHAT_3266_4 = &fBekannt für die Lobbybanner, Logos, spontane Arenen, sowie als Leiter von so manchem Event. +NPC_CHAT_3266_5 = &fVon Supporter zu Moderator zu Builder ... Vielleicht führt mich die Reise als Nächstes zum Developer. # Portal Command PORTAL_COMMAND_LIST_HELP = §8/§7portal §elist §8- §7Listet alle Portale auf From 7dc56863891b577603612b41adffc02d3bbf81ba Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Tue, 31 Dec 2024 11:25:00 +0100 Subject: [PATCH 16/22] Fixes... --- .../src/de/steamwar/core/WorldEditWrapper14.java | 9 ++++----- .../src/de/steamwar/core/WorldEditWrapper18.java | 3 ++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java index ca96d554..6f5d0ffc 100644 --- a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java +++ b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java @@ -389,7 +389,7 @@ public class WorldEditWrapper14 implements WorldEditWrapper { inputStream.close(); } } - private static class SpongeSchematicReader extends NBTSchematicReader { + public static class SpongeSchematicReader extends NBTSchematicReader { private final NBTInputStream inputStream; private DataFixer fixer = null; @@ -420,7 +420,7 @@ public class WorldEditWrapper14 implements WorldEditWrapper { dataVersion = 1631; // this is a relatively safe assumption unless someone imports a schematic from 1.12, e.g. sponge 7.1- fixer = platform.getDataFixer(); return readVersion1(schematicTag); - } else if (schematicVersion == 2) { + } else if (schematicVersion == 2 || schematicVersion == 3) { dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); if (dataVersion < liveDataVersion) { fixer = platform.getDataFixer(); @@ -449,9 +449,6 @@ public class WorldEditWrapper14 implements WorldEditWrapper { private CompoundTag getBaseTag() throws IOException { NamedTag rootTag = inputStream.readNamedTag(); - if (!rootTag.getName().equals("Schematic")) { - throw new IOException("Tag 'Schematic' does not exist or is not first"); - } CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); // Check @@ -460,6 +457,8 @@ public class WorldEditWrapper14 implements WorldEditWrapper { if (schematic.size() == 1) { schematicTag = requireTag(schematic, "Schematic", CompoundTag.class); schematic = schematicTag.getValue(); + } else if (!rootTag.getName().equals("Schematic")) { + throw new IOException("Tag 'Schematic' does not exist or is not first"); } schematicVersion = requireTag(schematic, "Version", IntTag.class).getValue(); diff --git a/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java b/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java index b381ecf7..1c674150 100644 --- a/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java +++ b/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java @@ -40,7 +40,8 @@ public class WorldEditWrapper18 extends WorldEditWrapper14 { case MCEDIT: return new MCEditSchematicReader(nbtStream).read(); case SPONGE_V2: - return new SpongeSchematicReader(nbtStream).read(); + case SPONGE_V3: + return new WorldEditWrapper14.SpongeSchematicReader(nbtStream).read(); default: throw new IllegalArgumentException("Unsupported schematic format"); } From c1dbce464800c1aaf3d0972e45f87b5f1de68e71 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Tue, 31 Dec 2024 18:56:42 +0100 Subject: [PATCH 17/22] Fix EventListener.onPlayerQuit --- .../bausystem/features/script/event/EventListener.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/EventListener.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/EventListener.java index 3eb099aa..4c5feada 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/EventListener.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/script/event/EventListener.java @@ -24,7 +24,6 @@ import de.steamwar.bausystem.Permission; import de.steamwar.bausystem.features.script.ScriptRunner; import de.steamwar.bausystem.features.script.lua.SteamWarGlobalLuaPlugin; import de.steamwar.bausystem.features.script.lua.libs.StorageLib; -import de.steamwar.bausystem.features.tpslimit.TPSUtils; import de.steamwar.bausystem.region.Region; import de.steamwar.bausystem.region.utils.RegionExtensionType; import de.steamwar.bausystem.region.utils.RegionType; @@ -32,7 +31,6 @@ import de.steamwar.core.TrickyTrialsWrapper; import de.steamwar.linkage.Linked; import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -72,9 +70,10 @@ public class EventListener implements Listener { @EventHandler(priority = EventPriority.HIGH) public void onPlayerQuit(PlayerQuitEvent event) { + if(Permission.BUILD.hasPermission(event.getPlayer())) { + ScriptRunner.callEvent(event.getPlayer(), SteamWarGlobalLuaPlugin.EventType.SelfLeave, LuaValue.NIL, event); + } StorageLib.removePlayer(event.getPlayer()); - if(!Permission.BUILD.hasPermission(event.getPlayer())) return; - ScriptRunner.callEvent(event.getPlayer(), SteamWarGlobalLuaPlugin.EventType.SelfLeave, LuaValue.NIL, event); } @EventHandler(priority = EventPriority.HIGH) From d64e32eaa56317c7ad530a39f8bb21069652d201 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Wed, 1 Jan 2025 12:56:49 +0100 Subject: [PATCH 18/22] Cleanup code --- .../src/de/steamwar/lobby/team/TeamPlayer.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/LobbySystem/src/de/steamwar/lobby/team/TeamPlayer.java b/LobbySystem/src/de/steamwar/lobby/team/TeamPlayer.java index a42d184a..989fca7a 100644 --- a/LobbySystem/src/de/steamwar/lobby/team/TeamPlayer.java +++ b/LobbySystem/src/de/steamwar/lobby/team/TeamPlayer.java @@ -23,7 +23,6 @@ import de.steamwar.lobby.LobbySystem; import de.steamwar.lobby.display.NPC; import de.steamwar.lobby.listener.BasicListener; import de.steamwar.sql.SteamwarUser; -import de.steamwar.sql.UserPerm; import lombok.AllArgsConstructor; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -135,6 +134,10 @@ public class TeamPlayer extends BasicListener { return false; } + private String parseRandomMessage(Player player, SteamwarUser target, String message) throws MissingResourceException { + return LobbySystem.getMessage().parsePrefixed(message + random.nextInt(6), player, target.getUserName(), target.prefix().getColorCode() + target.prefix().getChatPrefix()); + } + @EventHandler public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { if (!(event.getRightClicked() instanceof Villager)) { @@ -144,14 +147,13 @@ public class TeamPlayer extends BasicListener { players.remove(event.getPlayer()); return; } - SteamwarUser user = SteamwarUser.get(event.getRightClicked().getName()); - UserPerm.Prefix prefix = user.prefix(); - Object[] parameters = new Object[]{event.getRightClicked().getName(),prefix.getColorCode() + prefix.getChatPrefix()}; + + SteamwarUser target = SteamwarUser.get(event.getRightClicked().getName()); String message; try { - message = LobbySystem.getMessage().parsePrefixed("NPC_CHAT_" + user.getId() + "_" + random.nextInt(6), event.getPlayer(),parameters); - } catch (Exception e) { - message = LobbySystem.getMessage().parsePrefixed("NPC_CHAT_" + random.nextInt(6), event.getPlayer(),parameters); + message = parseRandomMessage(event.getPlayer(), target, "NPC_CHAT_" + target.getId() + "_"); + } catch (MissingResourceException e) { + message = parseRandomMessage(event.getPlayer(), target, "NPC_CHAT_"); } event.getPlayer().sendMessage(message); } From 025ec2a850470e7b55d39a16c48655533ccb7b6b Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Wed, 1 Jan 2025 14:12:38 +0100 Subject: [PATCH 19/22] Hotfix: 1.20 Schematic Reader --- .../de/steamwar/core/WorldEditWrapper14.java | 13 ++++++-- .../de/steamwar/core/WorldEditWrapper18.java | 30 +++++-------------- .../de/steamwar/core/WorldEditWrapper21.java | 1 + 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java index 6f5d0ffc..3251e5bc 100644 --- a/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java +++ b/SpigotCore/SpigotCore_14/src/de/steamwar/core/WorldEditWrapper14.java @@ -54,6 +54,7 @@ import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; +@SuppressWarnings("removal") public class WorldEditWrapper14 implements WorldEditWrapper { @Override @@ -88,7 +89,7 @@ public class WorldEditWrapper14 implements WorldEditWrapper { switch (schemFormat) { case SPONGE_V2: case SPONGE_V3: - return new SpongeSchematicReader(new NBTInputStream(is)).read(); + return new SpongeSchematicReader(new NBTInputStream(is), this).read(); case MCEDIT: return new MCEditSchematicReader(new NBTInputStream(is)).read(); default: @@ -126,6 +127,10 @@ public class WorldEditWrapper14 implements WorldEditWrapper { return NodeData.SchematicFormat.SPONGE_V2; } + public Map applyDataFixer(DataFixer fixer, int dataVersion, Map values) { + return fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, new CompoundTag(values), dataVersion).getValue(); + } + private static class MCEditSchematicReader extends NBTSchematicReader { private final NBTInputStream inputStream; @@ -396,15 +401,17 @@ public class WorldEditWrapper14 implements WorldEditWrapper { private int schematicVersion = -1; private int dataVersion = -1; private boolean faweSchem = false; + private final WorldEditWrapper14 wrapper; /** * Create a new instance. * * @param inputStream the input stream to read from */ - public SpongeSchematicReader(NBTInputStream inputStream) { + public SpongeSchematicReader(NBTInputStream inputStream, WorldEditWrapper14 wrapper) { checkNotNull(inputStream); this.inputStream = inputStream; + this.wrapper = wrapper; } @Override @@ -572,7 +579,7 @@ public class WorldEditWrapper14 implements WorldEditWrapper { values.remove("Id"); values.remove("Pos"); if (fixer != null) { - tileEntity = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, new CompoundTag(values), dataVersion).getValue(); + tileEntity = wrapper.applyDataFixer(fixer, dataVersion, values); } else { tileEntity = values; } diff --git a/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java b/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java index 1c674150..1c216a1a 100644 --- a/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java +++ b/SpigotCore/SpigotCore_18/src/de/steamwar/core/WorldEditWrapper18.java @@ -19,34 +19,18 @@ package de.steamwar.core; -import com.sk89q.jnbt.NBTInputStream; -import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.extent.clipboard.io.*; -import de.steamwar.sql.NoClipboardException; -import de.steamwar.sql.NodeData; +import com.sk89q.jnbt.AdventureNBTConverter; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.world.DataFixer; -import java.io.IOException; -import java.io.InputStream; +import java.util.Map; public class WorldEditWrapper18 extends WorldEditWrapper14 { @Override @SuppressWarnings("removal") - public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException { - NBTInputStream nbtStream = new NBTInputStream(is); - //Use FAWE reader due to FAWE capability of reading corrupt FAWE schems - try { - switch (schemFormat) { - case MCEDIT: - return new MCEditSchematicReader(nbtStream).read(); - case SPONGE_V2: - case SPONGE_V3: - return new WorldEditWrapper14.SpongeSchematicReader(nbtStream).read(); - default: - throw new IllegalArgumentException("Unsupported schematic format"); - } - } catch (NullPointerException e) { - throw new NoClipboardException(); - } + public Map applyDataFixer(DataFixer fixer, int dataVersion, Map values) { + return ((CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, new CompoundTag(values).asBinaryTag(), dataVersion))).getValue(); } } diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java index d93c095d..52947f3a 100644 --- a/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java +++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java @@ -67,6 +67,7 @@ public class WorldEditWrapper21 implements WorldEditWrapper { } @Override + @SuppressWarnings("removal") public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException { return switch (schemFormat) { case MCEDIT -> new MCEditSchematicReader(new NBTInputStream(is)).read(); From 6b7825ead9965c2424b5bb02102a96dd82fc95fc Mon Sep 17 00:00:00 2001 From: Lixfel Date: Thu, 2 Jan 2025 11:05:07 +0100 Subject: [PATCH 20/22] Fix version matching --- .../src/de/steamwar/velocitycore/GameModeConfig.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/VelocityCore/src/de/steamwar/velocitycore/GameModeConfig.java b/VelocityCore/src/de/steamwar/velocitycore/GameModeConfig.java index 74fb19bf..208f6df3 100644 --- a/VelocityCore/src/de/steamwar/velocitycore/GameModeConfig.java +++ b/VelocityCore/src/de/steamwar/velocitycore/GameModeConfig.java @@ -27,12 +27,13 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.function.BiConsumer; +import java.util.regex.Matcher; import java.util.regex.Pattern; @Getter public class GameModeConfig { - private static final Pattern terminatingNumber = Pattern.compile("\\D+(\\d+)$"); + private static final Pattern terminatingNumber = Pattern.compile("(\\d+)$"); public static void loadAll(Class config, BiConsumer consumer) { File folder = new File(VelocityCore.get().getDataDirectory().getParent().toFile(), "FightSystem"); @@ -70,7 +71,9 @@ public class GameModeConfig { } public ServerVersion getVersion() { - return ServerVersion.valueOf((getServer().isSpigot() ? "SPIGOT_" : "PAPER_") + terminatingNumber.matcher(getServer().getFolder()).group(1)); + Matcher matcher = terminatingNumber.matcher(getServer().getFolder()); + matcher.find(); + return ServerVersion.valueOf((getServer().isSpigot() ? "SPIGOT_" : "PAPER_") + matcher.group(1)); } public String getFolder() { From 9f0f11adebf68c802c1a3a7348d4e8380dfbb840 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Thu, 2 Jan 2025 17:24:37 +0100 Subject: [PATCH 21/22] Fix entity orientation --- .../src/de/steamwar/core/BountifulWrapper21.java | 2 +- .../src/de/steamwar/core/BountifulWrapper8.java | 7 +++---- .../src/de/steamwar/core/BountifulWrapper9.java | 14 +++++++------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/BountifulWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/BountifulWrapper21.java index d144c9b6..f7ed9508 100644 --- a/SpigotCore/SpigotCore_21/src/de/steamwar/core/BountifulWrapper21.java +++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/BountifulWrapper21.java @@ -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(), pitch, yaw)); + field.set(packet, new PositionMoveRotation(new Vec3D(x, y, z), pos.b(), yaw, pitch)); }; } catch (IllegalArgumentException e) { return super.getPositionSetter(packetClass, fieldOffset); diff --git a/SpigotCore/SpigotCore_8/src/de/steamwar/core/BountifulWrapper8.java b/SpigotCore/SpigotCore_8/src/de/steamwar/core/BountifulWrapper8.java index 54ea45b3..2b7aeab7 100644 --- a/SpigotCore/SpigotCore_8/src/de/steamwar/core/BountifulWrapper8.java +++ b/SpigotCore/SpigotCore_8/src/de/steamwar/core/BountifulWrapper8.java @@ -25,7 +25,6 @@ import net.md_5.bungee.api.chat.BaseComponent; import net.minecraft.server.v1_8_R3.ChatComponentText; import net.minecraft.server.v1_8_R3.MathHelper; import net.minecraft.server.v1_8_R3.PacketPlayOutChat; -import net.minecraft.server.v1_8_R3.PacketPlayOutEntityTeleport; import org.bukkit.Sound; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.entity.Player; @@ -71,15 +70,15 @@ public class BountifulWrapper8 implements BountifulWrapper.IBountifulWrapper { Reflection.FieldAccessor posX = Reflection.getField(packetClass, int.class, fieldOffset); Reflection.FieldAccessor posY = Reflection.getField(packetClass, int.class, fieldOffset +1); Reflection.FieldAccessor posZ = Reflection.getField(packetClass, int.class, fieldOffset +2); - Reflection.FieldAccessor lookPitch = Reflection.getField(packetClass, byte.class, 0); - Reflection.FieldAccessor lookYaw = Reflection.getField(packetClass, byte.class, 1); + Reflection.FieldAccessor lookYaw = Reflection.getField(packetClass, byte.class, 0); + Reflection.FieldAccessor lookPitch = Reflection.getField(packetClass, byte.class, 1); return (packet, x, y, z, pitch, yaw) -> { posX.set(packet, MathHelper.floor(x * 32)); posY.set(packet, MathHelper.floor(y * 32)); posZ.set(packet, MathHelper.floor(z * 32)); - lookPitch.set(packet, (byte)(pitch * 256 / 360)); lookYaw.set(packet, (byte)(yaw * 256 / 360)); + lookPitch.set(packet, (byte)(pitch * 256 / 360)); }; } diff --git a/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java b/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java index fa126698..300d6c8d 100644 --- a/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java +++ b/SpigotCore/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java @@ -67,19 +67,19 @@ public class BountifulWrapper9 implements BountifulWrapper.IBountifulWrapper { Reflection.FieldAccessor posZ = Reflection.getField(packetClass, double.class, fieldOffset+2); boolean isByteClass = packetClass.getSimpleName().contains("PacketPlayOutEntityTeleport") || packetClass.getSimpleName().contains("PacketPlayOutNamedEntitySpawn"); Class pitchYawType = isByteClass ? byte.class : int.class; - Reflection.FieldAccessor lookPitch = Reflection.getField(packetClass, pitchYawType, isByteClass ? 0 : 1); - Reflection.FieldAccessor lookYaw = Reflection.getField(packetClass, pitchYawType, isByteClass ? 1 : 2); + Reflection.FieldAccessor lookYaw = Reflection.getField(packetClass, pitchYawType, isByteClass ? 0 : 1); + Reflection.FieldAccessor lookPitch = Reflection.getField(packetClass, pitchYawType, isByteClass ? 1 : 2); return (packet, x, y, z, pitch, yaw) -> { posX.set(packet, x); posY.set(packet, y); posZ.set(packet, z); if (isByteClass) { - lookPitch.set(packet, (byte) (pitch*256/360)); lookYaw.set(packet, (byte) (yaw*256/360)); + lookPitch.set(packet, (byte) (pitch*256/360)); } else { - lookPitch.set(packet, (int) (pitch*256/360)); lookYaw.set(packet, (int) (yaw*256/360)); + lookPitch.set(packet, (int) (pitch*256/360)); } }; } @@ -90,15 +90,15 @@ public class BountifulWrapper9 implements BountifulWrapper.IBountifulWrapper { Reflection.FieldAccessor moveX = Reflection.getField(packetClass, "b", type); Reflection.FieldAccessor moveY = Reflection.getField(packetClass, "c", type); Reflection.FieldAccessor moveZ = Reflection.getField(packetClass, "d", type); - Reflection.FieldAccessor movePitch = Reflection.getField(packetClass, "e", byte.class); - Reflection.FieldAccessor moveYaw = Reflection.getField(packetClass, "f", byte.class); + Reflection.FieldAccessor moveYaw = Reflection.getField(packetClass, "e", byte.class); + Reflection.FieldAccessor movePitch = Reflection.getField(packetClass, "f", byte.class); return (packet, x, y, z, pitch, yaw) -> { moveX.set(packet, (short)(x*4096)); moveY.set(packet, (short)(y*4096)); moveZ.set(packet, (short)(z*4096)); - movePitch.set(packet, (byte)(pitch*256/360)); moveYaw.set(packet, (byte)(yaw*256/360)); + movePitch.set(packet, (byte)(pitch*256/360)); }; } From a3490b801e0223ebcfa938953411d70fe4d4dd0c Mon Sep 17 00:00:00 2001 From: Lixfel Date: Fri, 3 Jan 2025 12:55:59 +0100 Subject: [PATCH 22/22] Fix server transfer failure after checkpoint restoration --- .../Persistent/src/de/steamwar/persistent/Subserver.java | 1 + 1 file changed, 1 insertion(+) diff --git a/VelocityCore/Persistent/src/de/steamwar/persistent/Subserver.java b/VelocityCore/Persistent/src/de/steamwar/persistent/Subserver.java index d4290814..9050255e 100644 --- a/VelocityCore/Persistent/src/de/steamwar/persistent/Subserver.java +++ b/VelocityCore/Persistent/src/de/steamwar/persistent/Subserver.java @@ -220,6 +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 } else { start(process.getInputStream(), line -> { if (line.contains("Loading libraries, please wait"))