Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-19 09:20:08 +01:00
Merge remote-tracking branch 'origin/main' into feat/spongeSchemV3
Dieser Commit ist enthalten in:
Commit
9d7446cec0
@ -511,7 +511,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes());
|
||||
PalettedContainer<Holder<Biome>> paletteBiomes = setBiomesToPalettedContainer(
|
||||
biomes,
|
||||
setSectionIndex,
|
||||
existingSection.getBiomes()
|
||||
);
|
||||
if (paletteBiomes != null) {
|
||||
PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -553,11 +560,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
if (existingSection == null) {
|
||||
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
|
||||
biomeHolderIdMap,
|
||||
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
|
||||
.getInstance()
|
||||
.getBukkitImplAdapter()
|
||||
.getInternalBiomeId(
|
||||
BiomeTypes.PLAINS)),
|
||||
biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
|
||||
PalettedContainer.Strategy.SECTION_BIOMES,
|
||||
null
|
||||
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
|
||||
@ -625,15 +628,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
existingSection.getBiomes()
|
||||
);
|
||||
|
||||
newSection =
|
||||
PaperweightPlatformAdapter.newChunkSection(
|
||||
layerNo,
|
||||
this::loadPrivately,
|
||||
setArr,
|
||||
adapter,
|
||||
biomeRegistry,
|
||||
biomeData
|
||||
);
|
||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||
layerNo,
|
||||
this::loadPrivately,
|
||||
setArr,
|
||||
adapter,
|
||||
biomeRegistry,
|
||||
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
||||
);
|
||||
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
||||
levelChunkSections,
|
||||
existingSection,
|
||||
@ -845,7 +847,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
queueHandler.async(finalizer, null);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
@ -1103,9 +1105,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
final int sectionIndex,
|
||||
final PalettedContainerRO<Holder<Biome>> data
|
||||
) {
|
||||
BiomeType[] sectionBiomes;
|
||||
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
|
||||
return null;
|
||||
}
|
||||
PalettedContainer<Holder<Biome>> biomeData;
|
||||
if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
||||
biomeData = palettedContainer;
|
||||
biomeData = palettedContainer.copy();
|
||||
} else {
|
||||
LOGGER.warn(
|
||||
"Cannot correctly set biomes to world, existing biomes may be lost. Expected class " +
|
||||
@ -1115,10 +1121,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
);
|
||||
biomeData = data.recreate();
|
||||
}
|
||||
BiomeType[] sectionBiomes;
|
||||
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
|
||||
return biomeData;
|
||||
}
|
||||
for (int y = 0, index = 0; y < 4; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, index++) {
|
||||
@ -1130,10 +1132,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
|
||||
.getInstance()
|
||||
.getBukkitImplAdapter()
|
||||
.getInternalBiomeId(biomeType))
|
||||
biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
private static final Field fieldTickingFluidCount;
|
||||
private static final Field fieldTickingBlockCount;
|
||||
private static final Field fieldNonEmptyBlockCount;
|
||||
private static final Field fieldBiomes;
|
||||
|
||||
private static final MethodHandle methodGetVisibleChunk;
|
||||
|
||||
@ -139,8 +139,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
fieldTickingFluidCount.setAccessible(true);
|
||||
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "g"));
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "f"));
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
Field tmpFieldBiomes;
|
||||
try {
|
||||
// It seems to actually be biomes, but is apparently obfuscated to "j"
|
||||
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes");
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("j");
|
||||
}
|
||||
fieldBiomes = tmpFieldBiomes;
|
||||
fieldBiomes.setAccessible(true);
|
||||
|
||||
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
|
||||
"getVisibleChunkIfPresent",
|
||||
@ -502,6 +509,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
return new LevelChunkSection(layer, dataPaletteBlocks, biomes);
|
||||
}
|
||||
|
||||
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
|
||||
try {
|
||||
fieldBiomes.set(section, biomes);
|
||||
} catch (IllegalAccessException e) {
|
||||
LOGGER.error("Could not set biomes to chunk section", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
|
||||
*/
|
||||
|
@ -510,7 +510,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes());
|
||||
PalettedContainer<Holder<Biome>> paletteBiomes = setBiomesToPalettedContainer(
|
||||
biomes,
|
||||
setSectionIndex,
|
||||
existingSection.getBiomes()
|
||||
);
|
||||
if (paletteBiomes != null) {
|
||||
PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -552,11 +559,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
if (existingSection == null) {
|
||||
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
|
||||
biomeHolderIdMap,
|
||||
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
|
||||
.getInstance()
|
||||
.getBukkitImplAdapter()
|
||||
.getInternalBiomeId(
|
||||
BiomeTypes.PLAINS)),
|
||||
biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
|
||||
PalettedContainer.Strategy.SECTION_BIOMES
|
||||
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
|
||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||
@ -623,15 +626,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
existingSection.getBiomes()
|
||||
);
|
||||
|
||||
newSection =
|
||||
PaperweightPlatformAdapter.newChunkSection(
|
||||
layerNo,
|
||||
this::loadPrivately,
|
||||
setArr,
|
||||
adapter,
|
||||
biomeRegistry,
|
||||
biomeData
|
||||
);
|
||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||
layerNo,
|
||||
this::loadPrivately,
|
||||
setArr,
|
||||
adapter,
|
||||
biomeRegistry,
|
||||
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
||||
);
|
||||
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
||||
levelChunkSections,
|
||||
existingSection,
|
||||
@ -843,7 +845,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
queueHandler.async(finalizer, null);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
@ -1100,9 +1102,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
final int sectionIndex,
|
||||
final PalettedContainerRO<Holder<Biome>> data
|
||||
) {
|
||||
BiomeType[] sectionBiomes;
|
||||
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
|
||||
return null;
|
||||
}
|
||||
PalettedContainer<Holder<Biome>> biomeData;
|
||||
if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
||||
biomeData = palettedContainer;
|
||||
biomeData = palettedContainer.copy();
|
||||
} else {
|
||||
LOGGER.warn(
|
||||
"Cannot correctly set biomes to world, existing biomes may be lost. Expected class " +
|
||||
@ -1112,10 +1118,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
);
|
||||
biomeData = data.recreate();
|
||||
}
|
||||
BiomeType[] sectionBiomes;
|
||||
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
|
||||
return biomeData;
|
||||
}
|
||||
for (int y = 0, index = 0; y < 4; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, index++) {
|
||||
@ -1127,10 +1129,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
|
||||
.getInstance()
|
||||
.getBukkitImplAdapter()
|
||||
.getInternalBiomeId(biomeType))
|
||||
biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,6 @@ import net.minecraft.world.level.entity.PersistentEntitySectionManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftChunk;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
@ -102,7 +101,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
private static final Field fieldTickingFluidCount;
|
||||
private static final Field fieldTickingBlockCount;
|
||||
private static final Field fieldNonEmptyBlockCount;
|
||||
|
||||
private static final MethodHandle methodGetVisibleChunk;
|
||||
|
||||
@ -111,6 +109,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
private static final MethodHandle methodRemoveGameEventListener;
|
||||
private static final MethodHandle methodremoveTickingBlockEntity;
|
||||
private static final Field fieldBiomes;
|
||||
|
||||
private static final Field fieldOffers;
|
||||
private static final MerchantOffers OFFERS = new MerchantOffers();
|
||||
@ -149,8 +148,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
fieldTickingFluidCount.setAccessible(true);
|
||||
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f"));
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e"));
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
Field tmpFieldBiomes;
|
||||
try {
|
||||
// It seems to actually be biomes, but is apparently obfuscated to "i"
|
||||
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes");
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i");
|
||||
}
|
||||
fieldBiomes = tmpFieldBiomes;
|
||||
fieldBiomes.setAccessible(true);
|
||||
|
||||
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
|
||||
"getVisibleChunkIfPresent",
|
||||
@ -417,7 +423,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
@Nullable PalettedContainer<Holder<Biome>> biomes
|
||||
) {
|
||||
if (set == null) {
|
||||
return newChunkSection(layer, biomeRegistry, biomes);
|
||||
return newChunkSection(biomeRegistry, biomes);
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
|
||||
@ -507,7 +513,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
@SuppressWarnings("deprecation") // Only deprecated in paper
|
||||
private static LevelChunkSection newChunkSection(
|
||||
int layer,
|
||||
Registry<Biome> biomeRegistry,
|
||||
@Nullable PalettedContainer<Holder<Biome>> biomes
|
||||
) {
|
||||
@ -522,6 +527,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
return new LevelChunkSection(dataPaletteBlocks, biomes);
|
||||
}
|
||||
|
||||
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
|
||||
try {
|
||||
fieldBiomes.set(section, biomes);
|
||||
} catch (IllegalAccessException e) {
|
||||
LOGGER.error("Could not set biomes to chunk section", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
|
||||
*/
|
||||
|
@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import io.papermc.paper.event.block.BeaconDeactivatedEvent;
|
||||
import net.minecraft.core.*;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.IdMap;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
@ -42,7 +46,14 @@ import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.entity.BeaconBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.*;
|
||||
import net.minecraft.world.level.chunk.DataLayer;
|
||||
import net.minecraft.world.level.chunk.HashMapPalette;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.LinearPalette;
|
||||
import net.minecraft.world.level.chunk.Palette;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import net.minecraft.world.level.chunk.PalettedContainerRO;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@ -52,7 +63,17 @@ import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.*;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
@ -497,7 +518,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes());
|
||||
PalettedContainer<Holder<Biome>> paletteBiomes = setBiomesToPalettedContainer(
|
||||
biomes,
|
||||
setSectionIndex,
|
||||
existingSection.getBiomes()
|
||||
);
|
||||
if (paletteBiomes != null) {
|
||||
PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -539,11 +567,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
if (existingSection == null) {
|
||||
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
|
||||
biomeHolderIdMap,
|
||||
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
|
||||
.getInstance()
|
||||
.getBukkitImplAdapter()
|
||||
.getInternalBiomeId(
|
||||
BiomeTypes.PLAINS)),
|
||||
biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
|
||||
PalettedContainer.Strategy.SECTION_BIOMES
|
||||
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
|
||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||
@ -610,15 +634,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
existingSection.getBiomes()
|
||||
);
|
||||
|
||||
newSection =
|
||||
PaperweightPlatformAdapter.newChunkSection(
|
||||
layerNo,
|
||||
this::loadPrivately,
|
||||
setArr,
|
||||
adapter,
|
||||
biomeRegistry,
|
||||
biomeData
|
||||
);
|
||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||
layerNo,
|
||||
this::loadPrivately,
|
||||
setArr,
|
||||
adapter,
|
||||
biomeRegistry,
|
||||
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
||||
);
|
||||
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
||||
levelChunkSections,
|
||||
existingSection,
|
||||
@ -830,7 +853,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
queueHandler.async(finalizer, null);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
@ -1087,9 +1110,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
final int sectionIndex,
|
||||
final PalettedContainerRO<Holder<Biome>> data
|
||||
) {
|
||||
BiomeType[] sectionBiomes;
|
||||
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
|
||||
return null;
|
||||
}
|
||||
PalettedContainer<Holder<Biome>> biomeData;
|
||||
if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
||||
biomeData = palettedContainer;
|
||||
biomeData = palettedContainer.copy();
|
||||
} else {
|
||||
LOGGER.warn(
|
||||
"Cannot correctly set biomes to world, existing biomes may be lost. Expected class " +
|
||||
@ -1099,10 +1126,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
);
|
||||
biomeData = data.recreate();
|
||||
}
|
||||
BiomeType[] sectionBiomes;
|
||||
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
|
||||
return biomeData;
|
||||
}
|
||||
for (int y = 0, index = 0; y < 4; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, index++) {
|
||||
@ -1114,10 +1137,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
|
||||
.getInstance()
|
||||
.getBukkitImplAdapter()
|
||||
.getInternalBiomeId(biomeType))
|
||||
biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,6 @@ import net.minecraft.world.level.entity.PersistentEntitySectionManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_20_R2.CraftChunk;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
@ -99,7 +98,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
private static final Field fieldTickingFluidCount;
|
||||
private static final Field fieldTickingBlockCount;
|
||||
private static final Field fieldNonEmptyBlockCount;
|
||||
|
||||
private static final MethodHandle methodGetVisibleChunk;
|
||||
|
||||
@ -108,6 +106,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
private static final MethodHandle methodRemoveGameEventListener;
|
||||
private static final MethodHandle methodremoveTickingBlockEntity;
|
||||
private static final Field fieldBiomes;
|
||||
|
||||
/*
|
||||
* This is a workaround for the changes from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1fddefce1cdce44010927b888432bf70c0e88cde#src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
@ -143,8 +142,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
fieldTickingFluidCount.setAccessible(true);
|
||||
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f"));
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e"));
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
Field tmpFieldBiomes;
|
||||
try {
|
||||
// It seems to actually be biomes, but is apparently obfuscated to "i"
|
||||
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes");
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i");
|
||||
}
|
||||
fieldBiomes = tmpFieldBiomes;
|
||||
fieldBiomes.setAccessible(true);
|
||||
|
||||
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
|
||||
"getVisibleChunkIfPresent",
|
||||
@ -408,7 +414,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
@Nullable PalettedContainer<Holder<Biome>> biomes
|
||||
) {
|
||||
if (set == null) {
|
||||
return newChunkSection(layer, biomeRegistry, biomes);
|
||||
return newChunkSection(biomeRegistry, biomes);
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
|
||||
@ -498,7 +504,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
@SuppressWarnings("deprecation") // Only deprecated in paper
|
||||
private static LevelChunkSection newChunkSection(
|
||||
int layer,
|
||||
Registry<Biome> biomeRegistry,
|
||||
@Nullable PalettedContainer<Holder<Biome>> biomes
|
||||
) {
|
||||
@ -513,6 +518,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
return new LevelChunkSection(dataPaletteBlocks, biomes);
|
||||
}
|
||||
|
||||
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
|
||||
try {
|
||||
fieldBiomes.set(section, biomes);
|
||||
} catch (IllegalAccessException e) {
|
||||
LOGGER.error("Could not set biomes to chunk section", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
|
||||
*/
|
||||
|
@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import io.papermc.paper.event.block.BeaconDeactivatedEvent;
|
||||
import net.minecraft.core.*;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.IdMap;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
@ -42,7 +46,14 @@ import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.entity.BeaconBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.*;
|
||||
import net.minecraft.world.level.chunk.DataLayer;
|
||||
import net.minecraft.world.level.chunk.HashMapPalette;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.LinearPalette;
|
||||
import net.minecraft.world.level.chunk.Palette;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import net.minecraft.world.level.chunk.PalettedContainerRO;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@ -52,7 +63,17 @@ import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.*;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
@ -496,7 +517,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes());
|
||||
PalettedContainer<Holder<Biome>> paletteBiomes = setBiomesToPalettedContainer(
|
||||
biomes,
|
||||
setSectionIndex,
|
||||
existingSection.getBiomes()
|
||||
);
|
||||
if (paletteBiomes != null) {
|
||||
PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -538,11 +566,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
if (existingSection == null) {
|
||||
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
|
||||
biomeHolderIdMap,
|
||||
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
|
||||
.getInstance()
|
||||
.getBukkitImplAdapter()
|
||||
.getInternalBiomeId(
|
||||
BiomeTypes.PLAINS)),
|
||||
biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
|
||||
PalettedContainer.Strategy.SECTION_BIOMES
|
||||
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
|
||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||
@ -609,15 +633,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
existingSection.getBiomes()
|
||||
);
|
||||
|
||||
newSection =
|
||||
PaperweightPlatformAdapter.newChunkSection(
|
||||
layerNo,
|
||||
this::loadPrivately,
|
||||
setArr,
|
||||
adapter,
|
||||
biomeRegistry,
|
||||
biomeData
|
||||
);
|
||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||
layerNo,
|
||||
this::loadPrivately,
|
||||
setArr,
|
||||
adapter,
|
||||
biomeRegistry,
|
||||
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
||||
);
|
||||
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
||||
levelChunkSections,
|
||||
existingSection,
|
||||
@ -829,7 +852,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
queueHandler.async(finalizer, null);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
@ -1084,9 +1107,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
final int sectionIndex,
|
||||
final PalettedContainerRO<Holder<Biome>> data
|
||||
) {
|
||||
BiomeType[] sectionBiomes;
|
||||
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
|
||||
return null;
|
||||
}
|
||||
PalettedContainer<Holder<Biome>> biomeData;
|
||||
if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
||||
biomeData = palettedContainer;
|
||||
biomeData = palettedContainer.copy();
|
||||
} else {
|
||||
LOGGER.warn(
|
||||
"Cannot correctly set biomes to world, existing biomes may be lost. Expected class " +
|
||||
@ -1096,10 +1123,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
);
|
||||
biomeData = data.recreate();
|
||||
}
|
||||
BiomeType[] sectionBiomes;
|
||||
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
|
||||
return biomeData;
|
||||
}
|
||||
for (int y = 0, index = 0; y < 4; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, index++) {
|
||||
@ -1111,10 +1134,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
|
||||
.getInstance()
|
||||
.getBukkitImplAdapter()
|
||||
.getInternalBiomeId(biomeType))
|
||||
biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
private static final Field fieldTickingFluidCount;
|
||||
private static final Field fieldTickingBlockCount;
|
||||
private static final Field fieldNonEmptyBlockCount;
|
||||
private static final Field fieldBiomes;
|
||||
|
||||
private static final MethodHandle methodGetVisibleChunk;
|
||||
|
||||
@ -142,8 +142,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
fieldTickingFluidCount.setAccessible(true);
|
||||
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f"));
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e"));
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
Field tmpFieldBiomes;
|
||||
try {
|
||||
// It seems to actually be biomes, but is apparently obfuscated to "i"
|
||||
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes");
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i");
|
||||
}
|
||||
fieldBiomes = tmpFieldBiomes;
|
||||
fieldBiomes.setAccessible(true);
|
||||
|
||||
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
|
||||
"getVisibleChunkIfPresent",
|
||||
@ -407,7 +414,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
@Nullable PalettedContainer<Holder<Biome>> biomes
|
||||
) {
|
||||
if (set == null) {
|
||||
return newChunkSection(layer, biomeRegistry, biomes);
|
||||
return newChunkSection(biomeRegistry, biomes);
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
|
||||
@ -497,7 +504,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
@SuppressWarnings("deprecation") // Only deprecated in paper
|
||||
private static LevelChunkSection newChunkSection(
|
||||
int layer,
|
||||
Registry<Biome> biomeRegistry,
|
||||
@Nullable PalettedContainer<Holder<Biome>> biomes
|
||||
) {
|
||||
@ -512,6 +518,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
return new LevelChunkSection(dataPaletteBlocks, biomes);
|
||||
}
|
||||
|
||||
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
|
||||
try {
|
||||
fieldBiomes.set(section, biomes);
|
||||
} catch (IllegalAccessException e) {
|
||||
LOGGER.error("Could not set biomes to chunk section", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
|
||||
*/
|
||||
|
@ -29,7 +29,11 @@ import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import io.papermc.paper.event.block.BeaconDeactivatedEvent;
|
||||
import net.minecraft.core.*;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.IdMap;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
@ -43,7 +47,14 @@ import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.entity.BeaconBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.*;
|
||||
import net.minecraft.world.level.chunk.DataLayer;
|
||||
import net.minecraft.world.level.chunk.HashMapPalette;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.LinearPalette;
|
||||
import net.minecraft.world.level.chunk.Palette;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import net.minecraft.world.level.chunk.PalettedContainerRO;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@ -53,7 +64,17 @@ import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.*;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
@ -499,7 +520,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setBiomesToPalettedContainer(biomes, setSectionIndex, existingSection.getBiomes());
|
||||
PalettedContainer<Holder<Biome>> paletteBiomes = setBiomesToPalettedContainer(
|
||||
biomes,
|
||||
setSectionIndex,
|
||||
existingSection.getBiomes()
|
||||
);
|
||||
if (paletteBiomes != null) {
|
||||
PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -541,11 +569,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
if (existingSection == null) {
|
||||
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
|
||||
biomeHolderIdMap,
|
||||
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
|
||||
.getInstance()
|
||||
.getBukkitImplAdapter()
|
||||
.getInternalBiomeId(
|
||||
BiomeTypes.PLAINS)),
|
||||
biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
|
||||
PalettedContainer.Strategy.SECTION_BIOMES
|
||||
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
|
||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||
@ -612,18 +636,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
existingSection.getBiomes()
|
||||
);
|
||||
|
||||
newSection =
|
||||
PaperweightPlatformAdapter.newChunkSection(
|
||||
layerNo,
|
||||
this::loadPrivately,
|
||||
setArr,
|
||||
adapter,
|
||||
biomeRegistry,
|
||||
biomeData
|
||||
);
|
||||
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
||||
levelChunkSections,
|
||||
existingSection,
|
||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||
layerNo,
|
||||
this::loadPrivately,
|
||||
setArr,
|
||||
adapter,
|
||||
biomeRegistry,
|
||||
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
||||
);
|
||||
if (!PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, existingSection,
|
||||
newSection,
|
||||
getSectionIndex
|
||||
)) {
|
||||
@ -832,7 +853,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
queueHandler.async(finalizer, null);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
@ -1089,9 +1110,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
final int sectionIndex,
|
||||
final PalettedContainerRO<Holder<Biome>> data
|
||||
) {
|
||||
BiomeType[] sectionBiomes;
|
||||
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
|
||||
return null;
|
||||
}
|
||||
PalettedContainer<Holder<Biome>> biomeData;
|
||||
if (data instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
||||
biomeData = palettedContainer;
|
||||
biomeData = palettedContainer.copy();
|
||||
} else {
|
||||
LOGGER.warn(
|
||||
"Cannot correctly set biomes to world, existing biomes may be lost. Expected class " +
|
||||
@ -1101,10 +1126,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
);
|
||||
biomeData = data.recreate();
|
||||
}
|
||||
BiomeType[] sectionBiomes;
|
||||
if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) {
|
||||
return biomeData;
|
||||
}
|
||||
for (int y = 0, index = 0; y < 4; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, index++) {
|
||||
@ -1116,10 +1137,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
|
||||
.getInstance()
|
||||
.getBukkitImplAdapter()
|
||||
.getInternalBiomeId(biomeType))
|
||||
biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||
@ -77,7 +76,6 @@ import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -98,7 +96,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
private static final Field fieldTickingFluidCount;
|
||||
private static final Field fieldTickingBlockCount;
|
||||
private static final Field fieldNonEmptyBlockCount;
|
||||
private static final Field fieldBiomes;
|
||||
|
||||
private static final MethodHandle methodGetVisibleChunk;
|
||||
|
||||
@ -142,8 +140,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
fieldTickingFluidCount.setAccessible(true);
|
||||
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f"));
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("nonEmptyBlockCount", "e"));
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i"));
|
||||
fieldBiomes.setAccessible(true);
|
||||
|
||||
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
|
||||
"getVisibleChunkIfPresent",
|
||||
@ -405,7 +403,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
@Nullable PalettedContainer<Holder<Biome>> biomes
|
||||
) {
|
||||
if (set == null) {
|
||||
return newChunkSection(layer, biomeRegistry, biomes);
|
||||
return newChunkSection(biomeRegistry, biomes);
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
|
||||
@ -495,7 +493,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
|
||||
@SuppressWarnings("deprecation") // Only deprecated in paper
|
||||
private static LevelChunkSection newChunkSection(
|
||||
int layer,
|
||||
Registry<Biome> biomeRegistry,
|
||||
@Nullable PalettedContainer<Holder<Biome>> biomes
|
||||
) {
|
||||
@ -510,6 +507,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
return new LevelChunkSection(dataPaletteBlocks, biomes);
|
||||
}
|
||||
|
||||
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
|
||||
try {
|
||||
fieldBiomes.set(section, biomes);
|
||||
} catch (IllegalAccessException e) {
|
||||
LOGGER.error("Could not set biomes to chunk section", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
|
||||
*/
|
||||
|
@ -192,6 +192,9 @@ public class BukkitPlayerBlockBag extends BlockBag implements SlottableBlockBag
|
||||
@Override
|
||||
public BaseItem getItem(int slot) {
|
||||
loadInventory();
|
||||
if (items[slot] == null) {
|
||||
return null;
|
||||
}
|
||||
return BukkitAdapter.adapt(items[slot]);
|
||||
}
|
||||
|
||||
|
@ -137,6 +137,10 @@ public class WorldEditPlugin extends JavaPlugin {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
getDataFolder().mkdirs();
|
||||
|
||||
//FAWE start - Migrate from config-legacy to worldedit-config
|
||||
migrateLegacyConfig();
|
||||
//FAWE end
|
||||
|
||||
//FAWE start - Modify WorldEdit config name
|
||||
config = new BukkitConfiguration(new YAMLProcessor(new File(getDataFolder(), "worldedit-config.yml"), true), this);
|
||||
// Load config before we say we've loaded platforms as it is used in listeners of the event
|
||||
@ -151,10 +155,6 @@ public class WorldEditPlugin extends JavaPlugin {
|
||||
platform = new BukkitServerInterface(this, getServer());
|
||||
worldEdit.getPlatformManager().register(platform);
|
||||
|
||||
//FAWE start - Migrate from config-legacy to worldedit-config
|
||||
migrateLegacyConfig();
|
||||
//FAWE end
|
||||
|
||||
//FAWE start - Setup permission attachments
|
||||
permissionAttachmentManager = new BukkitPermissionAttachmentManager(this);
|
||||
//FAWE end
|
||||
|
@ -100,6 +100,9 @@ public class Config {
|
||||
}
|
||||
|
||||
public boolean load(File file) {
|
||||
if (!file.exists()) {
|
||||
return false;
|
||||
}
|
||||
existingMigrateNodes = new ArrayList<>();
|
||||
YamlConfiguration yml = YamlConfiguration.loadConfiguration(file);
|
||||
for (String key : yml.getKeys(true)) {
|
||||
|
@ -68,6 +68,7 @@ public class YamlConfiguration extends FileConfiguration {
|
||||
LOGGER.error("Could not read {}\n" + "Renamed to {}", file, dest.getAbsolutePath(), ex);
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,22 +21,17 @@ import com.sk89q.worldedit.internal.registry.AbstractFactory;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TransformFactory extends AbstractFactory<ResettableExtent> {
|
||||
|
||||
private final RichTransformParser richTransformParser;
|
||||
|
||||
/**
|
||||
* Create a new factory.
|
||||
*
|
||||
* @param worldEdit the WorldEdit instance
|
||||
*/
|
||||
public TransformFactory(WorldEdit worldEdit) {
|
||||
super(worldEdit, new NullTransformParser(worldEdit));
|
||||
|
||||
richTransformParser = new RichTransformParser(worldEdit);
|
||||
super(worldEdit, new NullTransformParser(worldEdit), new RichTransformParser(worldEdit));
|
||||
|
||||
// split and parse each sub-transform
|
||||
register(new RandomTransformParser(worldEdit));
|
||||
@ -51,68 +46,7 @@ public class TransformFactory extends AbstractFactory<ResettableExtent> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResettableExtent parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
List<ResettableExtent> transforms = new ArrayList<>();
|
||||
|
||||
for (String component : input.split(" ")) {
|
||||
if (component.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ResettableExtent match = richTransformParser.parseFromInput(component, context);
|
||||
if (match != null) {
|
||||
transforms.add(match);
|
||||
continue;
|
||||
}
|
||||
parseFromParsers(context, transforms, component);
|
||||
}
|
||||
|
||||
return getResettableExtent(input, transforms);
|
||||
}
|
||||
|
||||
private void parseFromParsers(
|
||||
final ParserContext context,
|
||||
final List<ResettableExtent> transforms,
|
||||
final String component
|
||||
) {
|
||||
ResettableExtent match = null;
|
||||
for (InputParser<ResettableExtent> parser : getParsers()) {
|
||||
match = parser.parseFromInput(component, context);
|
||||
|
||||
if (match != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match == null) {
|
||||
throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component)));
|
||||
}
|
||||
transforms.add(match);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a transform without considering parsing through the {@link RichTransformParser}, therefore not accepting
|
||||
* "richer" parsing where & and , are used. Exists to prevent stack overflows.
|
||||
*
|
||||
* @param input input string
|
||||
* @param context input context
|
||||
* @return parsed result
|
||||
* @throws InputParseException if no result found
|
||||
*/
|
||||
public ResettableExtent parseWithoutRich(String input, ParserContext context) throws InputParseException {
|
||||
List<ResettableExtent> transforms = new ArrayList<>();
|
||||
|
||||
for (String component : input.split(" ")) {
|
||||
if (component.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
parseFromParsers(context, transforms, component);
|
||||
}
|
||||
|
||||
return getResettableExtent(input, transforms);
|
||||
}
|
||||
|
||||
private ResettableExtent getResettableExtent(final String input, final List<ResettableExtent> transforms) {
|
||||
protected ResettableExtent getParsed(final String input, final List<ResettableExtent> transforms) {
|
||||
switch (transforms.size()) {
|
||||
case 0:
|
||||
throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input)));
|
||||
|
@ -37,14 +37,14 @@ public abstract class FaweParser<T> extends InputParser<T> implements AliasedPar
|
||||
for (int i = 0; i < toParse.length(); i++) {
|
||||
char c = toParse.charAt(i);
|
||||
switch (c) {
|
||||
case ',', '&' -> {
|
||||
case ',', '&', ' ' -> {
|
||||
if (expression) {
|
||||
continue;
|
||||
}
|
||||
String result = toParse.substring(last, i);
|
||||
if (!result.isEmpty()) {
|
||||
inputs.add(result);
|
||||
and.add(c == '&');
|
||||
and.add(c == '&' || c == ' ');
|
||||
} else {
|
||||
throw new InputParseException(Caption.of("fawe.error.parse.invalid-dangling-character", c));
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
package com.fastasyncworldedit.core.extension.factory.parser.common;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.fastasyncworldedit.core.extent.inventory.SlottableBlockBag;
|
||||
import com.fastasyncworldedit.core.limit.FaweLimit;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.blocks.BaseItem;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.input.DisallowedUsageException;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||
import com.sk89q.worldedit.internal.registry.SimpleInputParser;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public abstract class HotbarParser<T> extends SimpleInputParser<T> {
|
||||
|
||||
private final List<String> aliases = ImmutableList.of("#hotbar");
|
||||
|
||||
protected HotbarParser(final WorldEdit worldEdit) {
|
||||
super(worldEdit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMatchedAliases() {
|
||||
return aliases;
|
||||
}
|
||||
|
||||
protected List<BlockType> getBlockTypes(ParserContext context) {
|
||||
Player player = context.requirePlayer();
|
||||
BlockBag bag = player.getInventoryBlockBag();
|
||||
if (!(bag instanceof final SlottableBlockBag slottable)) {
|
||||
// Matches DefaultBlockParser
|
||||
throw new InputParseException(Caption.of("fawe.error.unsupported"));
|
||||
}
|
||||
List<BlockType> types = new ArrayList<>();
|
||||
FaweLimit limit = player.getLimit();
|
||||
boolean anyBlock = player.hasPermission("worldedit.anyblock");
|
||||
for (int slot = 0; slot < 9; slot++) {
|
||||
BaseItem item = slottable.getItem(slot);
|
||||
if (item != null && item.getType().hasBlockType()) {
|
||||
BlockType type = item.getType().getBlockType();
|
||||
if (!anyBlock && worldEdit.getConfiguration().disallowedBlocks.contains(type.id().toLowerCase(Locale.ROOT))) {
|
||||
throw new DisallowedUsageException(Caption.of(
|
||||
"worldedit.error.disallowed-block",
|
||||
TextComponent.of(type.getId())
|
||||
));
|
||||
}
|
||||
if (!limit.isUnlimited()) {
|
||||
if (limit.DISALLOWED_BLOCKS.contains(type.id().toLowerCase(Locale.ROOT))) {
|
||||
throw new DisallowedUsageException(Caption.of(
|
||||
"fawe.error.limit.disallowed-block",
|
||||
TextComponent.of(type.getId())
|
||||
));
|
||||
}
|
||||
}
|
||||
types.add(type);
|
||||
}
|
||||
}
|
||||
if (types.isEmpty()) {
|
||||
throw new InputParseException(Caption.of("fawe.error.no-valid-on-hotbar"));
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.fastasyncworldedit.core.extension.factory.parser.mask;
|
||||
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.common.HotbarParser;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.function.mask.BlockTypeMask;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
|
||||
public class HotbarMaskParser extends HotbarParser<Mask> {
|
||||
|
||||
public HotbarMaskParser(WorldEdit worldEdit) {
|
||||
super(worldEdit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask parseFromSimpleInput(String input, ParserContext context) {
|
||||
return new BlockTypeMask(context.getExtent(), getBlockTypes(context));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.fastasyncworldedit.core.extension.factory.parser.pattern;
|
||||
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.common.HotbarParser;
|
||||
import com.fastasyncworldedit.core.math.random.TrueRandom;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.function.pattern.RandomPattern;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
|
||||
public class HotbarPatternParser extends HotbarParser<Pattern> {
|
||||
|
||||
public HotbarPatternParser(WorldEdit worldEdit) {
|
||||
super(worldEdit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pattern parseFromSimpleInput(String input, ParserContext context) {
|
||||
RandomPattern random = new RandomPattern(new TrueRandom());
|
||||
for (BlockType type : getBlockTypes(context)) {
|
||||
random.add(type, 1);
|
||||
}
|
||||
return random;
|
||||
}
|
||||
|
||||
}
|
@ -19,7 +19,6 @@ import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.registry.state.AbstractProperty;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
@ -174,27 +173,23 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
ArrayList<HashMap<String, Object>> palette = new ArrayList<>();
|
||||
for (BlockVector3 point : region) {
|
||||
BlockState block = clipboard.getBlock(point);
|
||||
int combined = block.getInternalId();
|
||||
char ordinal = block.getOrdinalChar();
|
||||
BlockType type = block.getBlockType();
|
||||
|
||||
if (type == BlockTypes.STRUCTURE_VOID || indexes.containsKey(combined)) {
|
||||
if (type == BlockTypes.STRUCTURE_VOID || indexes.containsKey(ordinal)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
indexes.put(combined, (Integer) palette.size());
|
||||
indexes.put(ordinal, palette.size());
|
||||
HashMap<String, Object> paletteEntry = new HashMap<>();
|
||||
paletteEntry.put("Name", type.id());
|
||||
if (block.getInternalId() != type.getInternalId()) {
|
||||
Map<String, Object> properties = null;
|
||||
for (AbstractProperty property : (List<AbstractProperty<?>>) type.getProperties()) {
|
||||
int propIndex = property.getIndex(block.getInternalId());
|
||||
if (propIndex != 0) {
|
||||
if (properties == null) {
|
||||
properties = new HashMap<>();
|
||||
}
|
||||
Object value = property.getValues().get(propIndex);
|
||||
properties.put(property.getName(), value.toString());
|
||||
for (Map.Entry<Property<?>, Object> entry : block.getStates().entrySet()) {
|
||||
if (properties == null) {
|
||||
properties = new HashMap<>();
|
||||
}
|
||||
properties.put(entry.getKey().getName(), entry.getValue().toString());
|
||||
}
|
||||
if (properties != null) {
|
||||
paletteEntry.put("Properties", properties);
|
||||
@ -211,16 +206,23 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
for (BlockVector3 point : region) {
|
||||
BaseBlock block = clipboard.getFullBlock(point);
|
||||
if (block.getBlockType() != BlockTypes.STRUCTURE_VOID) {
|
||||
int combined = block.getInternalId();
|
||||
int index = indexes.get(combined);
|
||||
List<Integer> pos = Arrays.asList(point.x() - min.x(),
|
||||
point.y() - min.y(), point.z() - min.z()
|
||||
char ordinal = block.getOrdinalChar();
|
||||
int index = indexes.get(ordinal);
|
||||
List<Integer> pos = Arrays.asList(
|
||||
point.x() - min.x(),
|
||||
point.y() - min.y(),
|
||||
point.z() - min.z()
|
||||
);
|
||||
if (!block.hasNbtData()) {
|
||||
blocks.add(FaweCache.INSTANCE.asMap("state", index, "pos", pos));
|
||||
} else {
|
||||
Map<String, Tag> tag = new HashMap<>(block.getNbtData().getValue());
|
||||
tag.remove("x");
|
||||
tag.remove("y");
|
||||
tag.remove("z");
|
||||
CompoundTag cTag = new CompoundTag(tag);
|
||||
blocks.add(
|
||||
FaweCache.INSTANCE.asMap("state", index, "pos", pos, "nbt", block.getNbtData()));
|
||||
FaweCache.INSTANCE.asMap("state", index, "pos", pos, "nbt", cTag));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -231,16 +233,24 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
ArrayList<Map<String, Object>> entities = new ArrayList<>();
|
||||
for (Entity entity : clipboard.getEntities()) {
|
||||
Location loc = entity.getLocation();
|
||||
List<Double> pos = Arrays.asList(loc.x(), loc.y(), loc.z());
|
||||
List<Integer> blockPos = Arrays.asList(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
List<Double> pos = Arrays.asList(
|
||||
loc.x() - min.x(),
|
||||
loc.y() - min.y(),
|
||||
loc.z() - min.z()
|
||||
);
|
||||
List<Integer> blockPos = Arrays.asList(
|
||||
loc.getBlockX() - min.x(),
|
||||
loc.getBlockY() - min.y(),
|
||||
loc.getBlockZ() - min.z()
|
||||
);
|
||||
BaseEntity state = entity.getState();
|
||||
if (state != null) {
|
||||
CompoundTag nbt = state.getNbtData();
|
||||
Map<String, Tag> nbtMap = nbt.getValue();
|
||||
Map<String, Tag> nbtMap = new HashMap<>(nbt.getValue());
|
||||
// Replace rotation data
|
||||
nbtMap.put("Rotation", writeRotation(entity.getLocation()));
|
||||
nbtMap.put("id", new StringTag(state.getType().id()));
|
||||
Map<String, Object> entityMap = FaweCache.INSTANCE.asMap("pos", pos, "blockPos", blockPos, "nbt", nbt);
|
||||
Map<String, Object> entityMap = FaweCache.INSTANCE.asMap("pos", pos, "blockPos", blockPos, "nbt", new CompoundTag(nbtMap));
|
||||
entities.add(entityMap);
|
||||
}
|
||||
}
|
||||
|
@ -23,11 +23,16 @@ import com.sk89q.util.StringUtil;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.factory.parser.DefaultBlockParser;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.NoMatchException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.internal.registry.AbstractFactory;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -67,4 +72,21 @@ public class BlockFactory extends AbstractFactory<BaseBlock> {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
@Override
|
||||
public BaseBlock parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
BaseBlock match;
|
||||
|
||||
for (InputParser<BaseBlock> parser : parsers) {
|
||||
match = parser.parseFromInput(input, context);
|
||||
|
||||
if (match != null) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NoMatchException(TranslatableComponent.of("worldedit.error.no-match", TextComponent.of(input)));
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
}
|
||||
|
@ -22,7 +22,13 @@ package com.sk89q.worldedit.extension.factory;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.blocks.BaseItem;
|
||||
import com.sk89q.worldedit.extension.factory.parser.DefaultItemParser;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.NoMatchException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.internal.registry.AbstractFactory;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
|
||||
public class ItemFactory extends AbstractFactory<BaseItem> {
|
||||
|
||||
@ -35,4 +41,21 @@ public class ItemFactory extends AbstractFactory<BaseItem> {
|
||||
super(worldEdit, new DefaultItemParser(worldEdit));
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
@Override
|
||||
public BaseItem parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
BaseItem match;
|
||||
|
||||
for (InputParser<BaseItem> parser : parsers) {
|
||||
match = parser.parseFromInput(input, context);
|
||||
|
||||
if (match != null) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NoMatchException(TranslatableComponent.of("worldedit.error.no-match", TextComponent.of(input)));
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import com.fastasyncworldedit.core.extension.factory.parser.mask.AngleMaskParser
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.mask.BesideMaskParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.mask.ExtremaMaskParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.mask.FalseMaskParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.mask.HotbarMaskParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.mask.LiquidMaskParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.mask.ROCAngleMaskParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.mask.RadiusMaskParser;
|
||||
@ -52,16 +53,13 @@ import com.sk89q.worldedit.extension.factory.parser.mask.NoiseMaskParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.mask.OffsetMaskParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.mask.RegionMaskParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.mask.SolidMaskParser;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.NoMatchException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.MaskIntersection;
|
||||
import com.sk89q.worldedit.internal.registry.AbstractFactory;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -74,21 +72,13 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public final class MaskFactory extends AbstractFactory<Mask> {
|
||||
|
||||
//FAWE start - rich mask parsing
|
||||
private final RichMaskParser richMaskParser;
|
||||
//FAWE end
|
||||
|
||||
/**
|
||||
* Create a new mask registry.
|
||||
*
|
||||
* @param worldEdit the WorldEdit instance
|
||||
*/
|
||||
public MaskFactory(WorldEdit worldEdit) {
|
||||
super(worldEdit, new BlocksMaskParser(worldEdit));
|
||||
|
||||
//FAWE start - rich mask parsing
|
||||
richMaskParser = new RichMaskParser(worldEdit);
|
||||
//FAWE end
|
||||
super(worldEdit, new BlocksMaskParser(worldEdit), new RichMaskParser(worldEdit));
|
||||
|
||||
register(new ExistingMaskParser(worldEdit));
|
||||
register(new AirMaskParser(worldEdit));
|
||||
@ -110,6 +100,7 @@ public final class MaskFactory extends AbstractFactory<Mask> {
|
||||
register(new BesideMaskParser(worldEdit));
|
||||
register(new ExtremaMaskParser(worldEdit));
|
||||
register(new FalseMaskParser(worldEdit));
|
||||
register(new HotbarMaskParser(worldEdit));
|
||||
register(new LiquidMaskParser(worldEdit));
|
||||
register(new RadiusMaskParser(worldEdit));
|
||||
register(new RichOffsetMaskParser(worldEdit));
|
||||
@ -123,7 +114,6 @@ public final class MaskFactory extends AbstractFactory<Mask> {
|
||||
register(new ZAxisMaskParser(worldEdit));
|
||||
register(new SurfaceAngleMaskParser(worldEdit));
|
||||
//FAWE end
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -131,85 +121,24 @@ public final class MaskFactory extends AbstractFactory<Mask> {
|
||||
final String[] split = input.split(" ");
|
||||
if (split.length > 1) {
|
||||
String prev = input.substring(0, input.lastIndexOf(" ")) + " ";
|
||||
return super.getSuggestions(split[split.length - 1], parserContext).stream().map(s -> prev + s).collect(Collectors.toList());
|
||||
return super
|
||||
.getSuggestions(split[split.length - 1], parserContext)
|
||||
.stream()
|
||||
.map(s -> prev + s)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return super.getSuggestions(input, parserContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
List<Mask> masks = new ArrayList<>();
|
||||
|
||||
for (String component : input.split(" ")) {
|
||||
if (component.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//FAWE start - rich mask parsing
|
||||
Mask match = richMaskParser.parseFromInput(component, context);
|
||||
if (match != null) {
|
||||
masks.add(match);
|
||||
continue;
|
||||
}
|
||||
parseFromParsers(context, masks, component);
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
return getMask(input, masks);
|
||||
}
|
||||
|
||||
//FAWE start - rich mask parsing
|
||||
private void parseFromParsers(
|
||||
final ParserContext context,
|
||||
final List<Mask> masks,
|
||||
final String component
|
||||
) {
|
||||
Mask match = null;
|
||||
for (InputParser<Mask> parser : getParsers()) {
|
||||
match = parser.parseFromInput(component, context);
|
||||
|
||||
if (match != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match == null) {
|
||||
throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component)));
|
||||
}
|
||||
masks.add(match);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a mask without considering parsing through the {@link RichMaskParser}, therefore not accepting
|
||||
* "richer" parsing where & and , are used. Exists to prevent stack overflows.
|
||||
*
|
||||
* @param input input string
|
||||
* @param context input context
|
||||
* @return parsed result
|
||||
* @throws InputParseException if no result found
|
||||
*/
|
||||
public Mask parseWithoutRich(String input, ParserContext context) throws InputParseException {
|
||||
List<Mask> masks = new ArrayList<>();
|
||||
|
||||
for (String component : input.split(" ")) {
|
||||
if (component.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
parseFromParsers(context, masks, component);
|
||||
}
|
||||
|
||||
return getMask(input, masks);
|
||||
}
|
||||
|
||||
private Mask getMask(final String input, final List<Mask> masks) {
|
||||
switch (masks.size()) {
|
||||
case 0:
|
||||
throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input)));
|
||||
case 1:
|
||||
return masks.get(0).optimize();
|
||||
default:
|
||||
return new MaskIntersection(masks).optimize();
|
||||
}
|
||||
@Override
|
||||
protected Mask getParsed(final String input, final List<Mask> masks) {
|
||||
return switch (masks.size()) {
|
||||
case 0 -> throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input)));
|
||||
case 1 -> masks.get(0).optimize();
|
||||
default -> new MaskIntersection(masks).optimize();
|
||||
};
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
|
@ -30,6 +30,7 @@ import com.fastasyncworldedit.core.extension.factory.parser.pattern.DarkenPatter
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.DesaturatePatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.ExistingPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.ExpressionPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.HotbarPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.LightenPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.Linear2DPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.Linear3DPatternParser;
|
||||
@ -42,8 +43,6 @@ import com.fastasyncworldedit.core.extension.factory.parser.pattern.OffsetPatter
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.PerlinPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.RandomFullClipboardPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.RandomOffsetPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.TypeSwapPatternParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.RelativePatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.RichPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.RidgedMultiFractalPatternParser;
|
||||
@ -51,24 +50,22 @@ import com.fastasyncworldedit.core.extension.factory.parser.pattern.SaturatePatt
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.SimplexPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.SolidRandomOffsetPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.SurfaceRandomOffsetPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.TypeSwapPatternParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.VoronoiPatternParser;
|
||||
import com.fastasyncworldedit.core.math.random.TrueRandom;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.BlockCategoryPatternParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.ClipboardPatternParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.RandomStatePatternParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.SingleBlockPatternParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.TypeOrStateApplyingPatternParser;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.NoMatchException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.function.pattern.RandomPattern;
|
||||
import com.sk89q.worldedit.internal.registry.AbstractFactory;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -80,20 +77,14 @@ import java.util.List;
|
||||
*/
|
||||
public final class PatternFactory extends AbstractFactory<Pattern> {
|
||||
|
||||
//FAWE start - rich pattern parsing
|
||||
private final RichPatternParser richPatternParser;
|
||||
//FAWE end
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param worldEdit the WorldEdit instance
|
||||
*/
|
||||
public PatternFactory(WorldEdit worldEdit) {
|
||||
super(worldEdit, new SingleBlockPatternParser(worldEdit));
|
||||
|
||||
//FAWE start - rich pattern parsing
|
||||
richPatternParser = new RichPatternParser(worldEdit);
|
||||
super(worldEdit, new SingleBlockPatternParser(worldEdit), new RichPatternParser(worldEdit));
|
||||
//FAWE end
|
||||
|
||||
// split and parse each sub-pattern
|
||||
@ -116,6 +107,7 @@ public final class PatternFactory extends AbstractFactory<Pattern> {
|
||||
register(new DesaturatePatternParser(worldEdit));
|
||||
register(new ExistingPatternParser(worldEdit));
|
||||
register(new ExpressionPatternParser(worldEdit));
|
||||
register(new HotbarPatternParser(worldEdit));
|
||||
register(new LightenPatternParser(worldEdit));
|
||||
register(new Linear2DPatternParser(worldEdit));
|
||||
register(new Linear3DPatternParser(worldEdit));
|
||||
@ -136,75 +128,10 @@ public final class PatternFactory extends AbstractFactory<Pattern> {
|
||||
register(new SurfaceRandomOffsetPatternParser(worldEdit));
|
||||
register(new TypeSwapPatternParser(worldEdit));
|
||||
register(new VoronoiPatternParser(worldEdit));
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pattern parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
List<Pattern> patterns = new ArrayList<>();
|
||||
|
||||
for (String component : input.split(" ")) {
|
||||
if (component.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//FAWE start - rich pattern parsing
|
||||
Pattern match = richPatternParser.parseFromInput(component, context);
|
||||
if (match != null) {
|
||||
patterns.add(match);
|
||||
continue;
|
||||
}
|
||||
parseFromParsers(context, patterns, component);
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
return getPattern(input, patterns);
|
||||
}
|
||||
|
||||
//FAWE start - rich pattern parsing
|
||||
private void parseFromParsers(
|
||||
final ParserContext context,
|
||||
final List<Pattern> patterns,
|
||||
final String component
|
||||
) {
|
||||
Pattern match = null;
|
||||
for (InputParser<Pattern> parser : getParsers()) {
|
||||
match = parser.parseFromInput(component, context);
|
||||
|
||||
if (match != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match == null) {
|
||||
throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component)));
|
||||
}
|
||||
patterns.add(match);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a pattern without considering parsing through the {@link RichPatternParser}, therefore not accepting
|
||||
* "richer" parsing where & and , are used. Exists to prevent stack overflows.
|
||||
*
|
||||
* @param input input string
|
||||
* @param context input context
|
||||
* @return parsed result
|
||||
* @throws InputParseException if no result found
|
||||
*/
|
||||
public Pattern parseWithoutRich(String input, ParserContext context) throws InputParseException {
|
||||
List<Pattern> patterns = new ArrayList<>();
|
||||
|
||||
for (String component : input.split(" ")) {
|
||||
if (component.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
parseFromParsers(context, patterns, component);
|
||||
}
|
||||
|
||||
return getPattern(input, patterns);
|
||||
}
|
||||
|
||||
private Pattern getPattern(final String input, final List<Pattern> patterns) {
|
||||
protected Pattern getParsed(final String input, final List<Pattern> patterns) {
|
||||
switch (patterns.size()) {
|
||||
case 0:
|
||||
throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input)));
|
||||
|
@ -23,6 +23,7 @@ import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.factory.MaskFactory;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
@ -217,6 +218,20 @@ public class ParserContext {
|
||||
return actor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Player} set on this context.
|
||||
*
|
||||
* @return a player
|
||||
* @throws InputParseException thrown if no {@link Actor} is set
|
||||
*/
|
||||
public Player requirePlayer() throws InputParseException {
|
||||
Actor actor = getActor();
|
||||
if (!(actor instanceof Player player)) {
|
||||
throw new InputParseException(Caption.of("worldedit.error.missing-player"));
|
||||
}
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether there should be restrictions (as a result of
|
||||
* limits or permissions) considered when parsing the input.
|
||||
|
@ -21,6 +21,9 @@ package com.sk89q.worldedit.internal.registry;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.AliasedParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.FaweParser;
|
||||
import com.fastasyncworldedit.core.extension.factory.parser.pattern.RichPatternParser;
|
||||
import com.sk89q.util.StringUtil;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.NoMatchException;
|
||||
@ -43,7 +46,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
public abstract class AbstractFactory<E> {
|
||||
|
||||
protected final WorldEdit worldEdit;
|
||||
private final List<InputParser<E>> parsers = new ArrayList<>();
|
||||
//FAWE start
|
||||
protected final List<InputParser<E>> parsers = new ArrayList<>();
|
||||
private final FaweParser<E> richParser;
|
||||
//FWAE end
|
||||
|
||||
/**
|
||||
* Create a new factory.
|
||||
@ -52,11 +58,26 @@ public abstract class AbstractFactory<E> {
|
||||
* @param defaultParser the parser to fall back to
|
||||
*/
|
||||
protected AbstractFactory(WorldEdit worldEdit, InputParser<E> defaultParser) {
|
||||
//FAWE start
|
||||
this(worldEdit, defaultParser, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory with a given rich parser for FAWE rich parsing
|
||||
*
|
||||
* @param worldEdit the WorldEdit instance
|
||||
* @param defaultParser the parser to fall back to
|
||||
* @param richParser the rich parser
|
||||
* @since TODO
|
||||
*/
|
||||
protected AbstractFactory(WorldEdit worldEdit, InputParser<E> defaultParser, FaweParser<E> richParser) {
|
||||
checkNotNull(worldEdit);
|
||||
checkNotNull(defaultParser);
|
||||
this.worldEdit = worldEdit;
|
||||
this.parsers.add(defaultParser);
|
||||
this.richParser = richParser;
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
/**
|
||||
* Gets an immutable list of parsers.
|
||||
@ -71,7 +92,7 @@ public abstract class AbstractFactory<E> {
|
||||
return Collections.unmodifiableList(parsers);
|
||||
}
|
||||
|
||||
//FAWE start - javadoc
|
||||
//FAWE start
|
||||
|
||||
/**
|
||||
* Parse a string and context to each {@link InputParser} added to this factory. If no result found, throws {@link InputParseException}
|
||||
@ -81,20 +102,26 @@ public abstract class AbstractFactory<E> {
|
||||
* @return parsed result
|
||||
* @throws InputParseException if no result found
|
||||
*/
|
||||
//FAWE end
|
||||
public E parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
E match;
|
||||
|
||||
for (InputParser<E> parser : parsers) {
|
||||
match = parser.parseFromInput(input, context);
|
||||
|
||||
if (match != null) {
|
||||
return match;
|
||||
List<E> parsed = new ArrayList<>();
|
||||
for (String component : StringUtil.split(input,' ', '[', ']')) {
|
||||
if (component.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (richParser != null) {
|
||||
E match = richParser.parseFromInput(component, context);
|
||||
if (match != null) {
|
||||
parsed.add(match);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
parseFromParsers(context, parsed, component);
|
||||
}
|
||||
|
||||
throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(input)));
|
||||
return getParsed(input, parsed);
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
@Deprecated
|
||||
public List<String> getSuggestions(String input) {
|
||||
@ -133,4 +160,48 @@ public abstract class AbstractFactory<E> {
|
||||
});
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
protected void parseFromParsers(final ParserContext context, final List<E> parsed, final String component) {
|
||||
E match = null;
|
||||
for (InputParser<E> parser : getParsers()) {
|
||||
match = parser.parseFromInput(component, context);
|
||||
|
||||
if (match != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match == null) {
|
||||
throw new NoMatchException(Caption.of("worldedit.error.no-match", TextComponent.of(component)));
|
||||
}
|
||||
parsed.add(match);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a pattern without considering parsing through the {@link RichPatternParser}, therefore not accepting
|
||||
* "richer" parsing where & and , are used. Exists to prevent stack overflows.
|
||||
*
|
||||
* @param input input string
|
||||
* @param context input context
|
||||
* @return parsed result
|
||||
* @throws InputParseException if no result found
|
||||
*/
|
||||
public E parseWithoutRich(String input, ParserContext context) throws InputParseException {
|
||||
List<E> parsed = new ArrayList<>();
|
||||
|
||||
for (String component : StringUtil.split(input, ' ', '[', ']')) {
|
||||
if (component.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
parseFromParsers(context, parsed, component);
|
||||
}
|
||||
|
||||
return getParsed(input, parsed);
|
||||
}
|
||||
|
||||
protected E getParsed(final String input, final List<E> parsed) {
|
||||
return parsed.isEmpty() ? null : parsed.get(0);
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
}
|
||||
|
@ -139,6 +139,7 @@
|
||||
"fawe.error.occurred-continuing": "Ignorable error occurred during edit: {0}",
|
||||
"fawe.error.limit.max-brush-radius": "Maximum brush radius in limit: {0}",
|
||||
"fawe.error.limit.max-radius": "Maximum radius in limit: {0}",
|
||||
"fawe.error.no-valid-on-hotbar": "No valid block types on hotbar",
|
||||
"fawe.cancel.count": "Cancelled {0} edits.",
|
||||
"fawe.cancel.reason.confirm": "Use //confirm to execute {0}",
|
||||
"fawe.cancel.reason.confirm.region": "Your selection is large ({0} -> {1}, containing {3} blocks). Use //confirm to execute {2}",
|
||||
@ -240,6 +241,7 @@
|
||||
"worldedit.error.missing-session": "No LocalSession is known",
|
||||
"worldedit.error.missing-world": "You need to provide a world (Try //world)",
|
||||
"worldedit.error.missing-actor": "No actor is known",
|
||||
"worldedit.error.missing-player": "No player is known",
|
||||
"worldedit.error.no-file-selected": "No file selected.",
|
||||
"worldedit.error.file-resolution.outside-root": "Path is outside allowable root",
|
||||
"worldedit.error.file-resolution.resolve-failed": "Failed to resolve path",
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren