Skip to content

Commit a2a7454

Browse files
committed
Upstream
2 parents 1486be1 + 3d3124d commit a2a7454

18 files changed

Lines changed: 251 additions & 17 deletions

File tree

.github/workflows/build-pr.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ jobs:
99
os: [ubuntu-latest, windows-latest, macos-latest]
1010
steps:
1111
- name: Checkout Repository
12-
uses: actions/checkout@v4
12+
uses: actions/checkout@v5
1313
- name: Validate Gradle Wrapper
1414
uses: gradle/actions/wrapper-validation@v4
1515
- name: Setup Java
16-
uses: actions/setup-java@v4
16+
uses: actions/setup-java@v5
1717
with:
1818
distribution: temurin
1919
cache: gradle

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ jobs:
99
runs-on: ubuntu-latest
1010
steps:
1111
- name: Checkout Repository
12-
uses: actions/checkout@v4
12+
uses: actions/checkout@v5
1313
- name: Validate Gradle Wrapper
1414
uses: gradle/actions/wrapper-validation@v4
1515
- name: Setup Java
16-
uses: actions/setup-java@v4
16+
uses: actions/setup-java@v5
1717
with:
1818
distribution: temurin
1919
cache: gradle

.github/workflows/codeql.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ jobs:
1919
language: ['java']
2020
steps:
2121
- name: Checkout repository
22-
uses: actions/checkout@v4
22+
uses: actions/checkout@v5
2323
- name: Setup Java
24-
uses: actions/setup-java@v4
24+
uses: actions/setup-java@v5
2525
with:
2626
distribution: temurin
2727
cache: gradle

.github/workflows/upload-release-assets.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ jobs:
77
runs-on: ubuntu-latest
88
steps:
99
- name: Checkout Repository
10-
uses: actions/checkout@v4
10+
uses: actions/checkout@v5
1111
- name: Validate Gradle Wrapper
1212
uses: gradle/actions/wrapper-validation@v4
1313
- name: Setup Java
14-
uses: actions/setup-java@v4
14+
uses: actions/setup-java@v5
1515
with:
1616
distribution: temurin
1717
cache: gradle

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import java.time.format.DateTimeFormatter
55
import xyz.jpenilla.runpaper.task.RunServer
66

77
plugins {
8-
id("com.gradleup.nmcp.aggregation") version "1.0.2"
8+
id("com.gradleup.nmcp.aggregation") version "1.1.0"
99
id("xyz.jpenilla.run-paper") version "2.3.1"
1010
}
1111

buildSrc/src/main/kotlin/CommonConfig.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ fun Project.applyCommonConfiguration() {
1414
maven {
1515
name = "EngineHub"
1616
url = uri("https://maven.enginehub.org/repo/")
17+
content {
18+
excludeModule("io.papermc.paper", "dev-bundle")
19+
}
1720
}
1821
maven {
1922
name = "OSS Sonatype Snapshots"
@@ -23,6 +26,13 @@ fun Project.applyCommonConfiguration() {
2326
name = "Athion"
2427
url = uri("https://ci.athion.net/plugin/repository/tools/")
2528
}
29+
maven {
30+
name = "IntellectualSites"
31+
url = uri("https://repo.intellectualsites.dev/repository/paper-dev-bundles/")
32+
content {
33+
includeModule("io.papermc.paper", "dev-bundle")
34+
}
35+
}
2636
}
2737

2838
configurations.all {

gradle/libs.versions.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ worldguard-bukkit = "7.0.14"
1313
griefprevention = "17.0.0"
1414
griefdefender = "2.1.0-SNAPSHOT"
1515
residence = "4.5._13.1"
16-
towny = "0.101.2.1"
16+
towny = "0.101.2.3"
1717
plotsquared = "7.5.6"
1818

1919
# Third party
@@ -46,7 +46,7 @@ text = "3.0.4"
4646
piston = "0.5.10"
4747

4848
# Tests
49-
mockito = "5.18.0"
49+
mockito = "5.19.0"
5050

5151
# Gradle plugins
5252
pluginyml = "0.6.0"

worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import org.anarres.parallelgzip.ParallelGZIPOutputStream;
4141
import org.enginehub.linbus.stream.LinBinaryIO;
4242
import org.enginehub.linbus.stream.LinReadOptions;
43-
import org.enginehub.linbus.tree.LinCompoundTag;
4443
import org.enginehub.linbus.tree.LinRootEntry;
4544

4645
import java.io.BufferedInputStream;
@@ -261,7 +260,11 @@ public boolean isFormat(InputStream inputStream) {
261260

262261
@Override
263262
public boolean isFormat(File file) {
264-
return MCEDIT_SCHEMATIC.isFormat(file);
263+
String name = file.getName().toLowerCase(Locale.ROOT);
264+
if (name.endsWith(".mcedit") || name.endsWith(".mce")) {
265+
return false;
266+
}
267+
return super.isFormat(file);
265268
}
266269

267270
@Override
@@ -272,7 +275,7 @@ public Set<String> getExplicitFileExtensions() {
272275

273276
/**
274277
* @deprecated Slow, resource intensive, but sometimes safer than using the recommended
275-
* {@link BuiltInClipboardFormat#FAST}.
278+
* {@link BuiltInClipboardFormat#FAST_V2}.
276279
* Avoid using with any large schematics/clipboards for reading/writing.
277280
*/
278281
@Deprecated

worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,19 @@
3030
import com.google.common.collect.Multimaps;
3131
import com.google.common.io.ByteSource;
3232
import com.google.common.io.Files;
33+
import com.sk89q.jnbt.NBTConstants;
34+
import com.sk89q.jnbt.NBTInputStream;
3335
import com.sk89q.worldedit.LocalConfiguration;
3436
import com.sk89q.worldedit.WorldEdit;
3537
import com.sk89q.worldedit.extension.platform.Actor;
38+
import com.sk89q.worldedit.internal.util.LogManagerCompat;
3639
import com.sk89q.worldedit.util.formatting.text.TextComponent;
40+
import it.unimi.dsi.fastutil.io.FastBufferedInputStream;
41+
import org.apache.logging.log4j.Logger;
3742

3843
import javax.annotation.Nullable;
44+
import java.io.DataInputStream;
45+
import java.io.EOFException;
3946
import java.io.File;
4047
import java.io.IOException;
4148
import java.io.InputStream;
@@ -44,6 +51,7 @@
4451
import java.net.URL;
4552
import java.nio.channels.Channels;
4653
import java.nio.channels.ReadableByteChannel;
54+
import java.nio.charset.StandardCharsets;
4755
import java.util.ArrayList;
4856
import java.util.Arrays;
4957
import java.util.Collection;
@@ -55,8 +63,11 @@
5563
import java.util.Locale;
5664
import java.util.Map;
5765
import java.util.Map.Entry;
66+
import java.util.Set;
5867
import java.util.regex.Pattern;
68+
import java.util.zip.GZIPInputStream;
5969
import java.util.zip.ZipEntry;
70+
import java.util.zip.ZipException;
6071
import java.util.zip.ZipInputStream;
6172

6273
import static com.google.common.base.Preconditions.checkNotNull;
@@ -70,6 +81,22 @@ public class ClipboardFormats {
7081
// FAWE end
7182
private static final List<ClipboardFormat> registeredFormats = new ArrayList<>();
7283

84+
// FAWE start - provide logger instance + track fast-search formats
85+
private static final Logger LOGGER = LogManagerCompat.getLogger();
86+
// a list of all schematic formats which are handled by the faster detection algorithm.
87+
// contains all builtin formats as of the time of writing, but in case we forget updating the algorithm after introducing a
88+
// new format, we keep track manually to avoid breaking something.
89+
@SuppressWarnings("deprecation")
90+
private static final Set<ClipboardFormat> FAST_SEARCH_BUILTIN_FORMATS = Set.of(
91+
BuiltInClipboardFormat.PNG, BuiltInClipboardFormat.MCEDIT_SCHEMATIC, BuiltInClipboardFormat.MINECRAFT_STRUCTURE,
92+
BuiltInClipboardFormat.SPONGE_V1_SCHEMATIC, BuiltInClipboardFormat.FAST_V2, BuiltInClipboardFormat.FAST_V3,
93+
// the following formats are not explicitly supported, but either don't support reading or
94+
// are handled by previous formats (e.g. SPONGE_V2_SCHEMATIC -> FAST_V2)
95+
BuiltInClipboardFormat.SPONGE_V2_SCHEMATIC, BuiltInClipboardFormat.SPONGE_V3_SCHEMATIC,
96+
BuiltInClipboardFormat.BROKENENTITY
97+
);
98+
// FAWE end
99+
73100
public static void registerClipboardFormat(ClipboardFormat format) {
74101
checkNotNull(format);
75102

@@ -112,24 +139,118 @@ public static ClipboardFormat findByAlias(String alias) {
112139
return aliasMap.get(alias.toLowerCase(Locale.ROOT).trim());
113140
}
114141

142+
//FAWE start - optimize format detection for builtin / known formats
143+
115144
/**
116-
* Detect the format of given a file.
145+
* Detect the format of a given file.
117146
*
118147
* @param file the file
119148
* @return the format, otherwise null if one cannot be detected
120149
*/
150+
@SuppressWarnings("removal") // NBTInputStream + NBTConstants
121151
@Nullable
122152
public static ClipboardFormat findByFile(File file) {
123153
checkNotNull(file);
124154

155+
if (file.getName().toLowerCase().endsWith(".png")) {
156+
return BuiltInClipboardFormat.PNG;
157+
}
158+
159+
/* Conditions for known formats
160+
FAST_V3: Compound_Tag("") -> Compound_Tag("Schematic") -> Int_Tag("Version") == 3
161+
MINECRAFT_STRUCTURE: Compound_Tag("") -> exist(Nbt_List_Tag("size" || "palette" || "blocks" || "entities"))
162+
FAST_V2: Compound_Tag("Schematic") -> Int_Tag("Version") == 2
163+
SPONGE_V1: Compound_Tag("Schematic") -> Int_Tag("Version") == 1
164+
MC_EDIT: Compound_Tag("Schematic") -> exist(Byte_Array_Tag("Blocks") || String_Tag("Materials"))
165+
*/
166+
try (final DataInputStream inputStream = new DataInputStream(new GZIPInputStream(new FastBufferedInputStream(java.nio.file.Files.newInputStream(
167+
file.toPath()))));
168+
final NBTInputStream nbtInputStream = new NBTInputStream(inputStream)) {
169+
if (inputStream.readByte() != NBTConstants.TYPE_COMPOUND) {
170+
return findByFileInExternalFormats(file);
171+
}
172+
final int rootNameTagLength = inputStream.readShort() & 0xFFFF;
173+
if (rootNameTagLength != 0 && rootNameTagLength != 9) { // Only allow "" and "Schematic"
174+
return findByFileInExternalFormats(file);
175+
}
176+
final String rootName = new String(inputStream.readNBytes(rootNameTagLength), StandardCharsets.UTF_8);
177+
if (rootName.isEmpty()) {
178+
// Only FAST_V3 and MINECRAFT_STRUCTURE use empty named root compound tags
179+
// FAST_V3 only contains a single child component - if that's not present, only MINECRAFT_STRUCTURE is possible
180+
do {
181+
byte type = inputStream.readByte();
182+
if (type == NBTConstants.TYPE_END) {
183+
return findByFileInExternalFormats(file);
184+
}
185+
String name = nbtInputStream.readNamedTagName(type);
186+
if (type == NBTConstants.TYPE_COMPOUND && name.equals("Schematic")) {
187+
// unwrap inner schematic compound for general processing below
188+
break;
189+
}
190+
// search for almost all known compound children for a fast return path (lowercase is specific enough for now)
191+
if (type == NBTConstants.TYPE_LIST &&
192+
(name.equals("size") || name.equals("palette") || name.equals("blocks") || name.equals("entities"))) {
193+
return BuiltInClipboardFormat.MINECRAFT_STRUCTURE;
194+
}
195+
nbtInputStream.readTagPayloadLazy(type, 0); // skip unwanted tags and continue search
196+
} while (true);
197+
}
198+
199+
do {
200+
byte type = inputStream.readByte();
201+
if (type == NBTConstants.TYPE_END) {
202+
return findByFileInExternalFormats(file);
203+
}
204+
String name = nbtInputStream.readNamedTagName(type);
205+
if ((type == NBTConstants.TYPE_BYTE_ARRAY && name.equals("Blocks")) ||
206+
(type == NBTConstants.TYPE_STRING && name.equals("Materials"))) {
207+
return BuiltInClipboardFormat.MCEDIT_SCHEMATIC;
208+
}
209+
if (type == NBTConstants.TYPE_INT && name.equals("Version")) {
210+
int version = inputStream.readInt();
211+
return switch (version) {
212+
case 1 -> BuiltInClipboardFormat.SPONGE_V1_SCHEMATIC;
213+
case 2 -> BuiltInClipboardFormat.FAST_V2;
214+
case 3 -> BuiltInClipboardFormat.FAST_V3;
215+
default -> findByFileInExternalFormats(file);
216+
};
217+
}
218+
nbtInputStream.readTagPayloadLazy(type, 0); // skip unwanted tags and continue search
219+
} while (true);
220+
} catch (ZipException | EOFException ignored) {
221+
// ignore gzip errors and EOFs - the file format might not use gzip, or we expected more data from known formats
222+
// all other builtin formats use gzip compression
223+
} catch (IOException e) {
224+
// other IO errors (non gzip-related) should be logged
225+
LOGGER.error("Failed determining clipboard format for file {}", file.getAbsolutePath(), e);
226+
return null;
227+
}
228+
229+
// no builtin format seems to match - test the remaining registered formats (added by other plugins, for example)
230+
return findByFileInExternalFormats(file);
231+
}
232+
233+
/**
234+
* Detect the clipboard format for a specified file while skipping optimized builtin formats
235+
*
236+
* @param file the file
237+
* @return the format or {@code null}
238+
*/
239+
private static ClipboardFormat findByFileInExternalFormats(File file) {
240+
if (registeredFormats.size() == FAST_SEARCH_BUILTIN_FORMATS.size()) {
241+
return null;
242+
}
125243
for (ClipboardFormat format : registeredFormats) {
244+
if (FAST_SEARCH_BUILTIN_FORMATS.contains(format)) {
245+
continue;
246+
}
126247
if (format.isFormat(file)) {
127248
return format;
128249
}
129250
}
130-
131251
return null;
132252
}
253+
//FAWE end
133254

134255
/**
135256
* A mapping from extensions to formats.

0 commit comments

Comments
 (0)