Update WorldEdit for Sponge to API 9 (1.18.2) (#2217)

* Update WorldEdit for Sponge to API 9 (1.18.2)

* Fix SpongeTransmogrifier, switch to use native Property API

* Minor style fixes
This commit is contained in:
Lignium 2023-06-08 14:15:59 +03:00 committed by GitHub
parent 9667101730
commit 716ce64194
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 136 additions and 100 deletions

View File

@ -19,7 +19,7 @@
applyCommonJavaConfiguration(
sourcesJar = name in setOf("worldedit-core", "worldedit-bukkit", "worldedit-fabric"),
javaRelease = javaRelease,
banSlf4j = name !in setOf("worldedit-fabric", "worldedit-forge"),
banSlf4j = name !in setOf("worldedit-fabric", "worldedit-forge", "worldedit-sponge"),
)
ext["internalVersion"] = "$version+${rootProject.ext["gitCommitHash"]}"

View File

@ -7,7 +7,7 @@
id("org.spongepowered.gradle.vanilla")
}
applyPlatformAndCoreConfiguration()
applyPlatformAndCoreConfiguration(javaRelease = 17)
applyShadowConfiguration()
repositories {
@ -15,10 +15,10 @@
}
minecraft {
version("1.16.5")
version("1.18.2")
}
val spongeApiVersion = "8.1.0";
val spongeApiVersion = "9.0.0";
sponge {
apiVersion(spongeApiVersion)

View File

@ -23,21 +23,22 @@
import com.sk89q.worldedit.world.registry.BlockCategoryRegistry;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.registry.Registry;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.tag.Tag;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
public class SpongeBlockCategoryRegistry implements BlockCategoryRegistry {
@Override
public Set<BlockType> getCategorisedByName(String category) {
return Sponge.game().registry(RegistryTypes.BLOCK_TYPE_TAGS)
.findValue(ResourceKey.resolve(category))
.map(org.spongepowered.api.tag.Tag::values)
.orElse(Collections.emptyList())
Registry<org.spongepowered.api.block.BlockType> blockTypeRegistry =
Sponge.game().registry(RegistryTypes.BLOCK_TYPE);
return blockTypeRegistry.taggedValues(Tag.of(RegistryTypes.BLOCK_TYPE, ResourceKey.resolve(category)))
.stream()
.map(b -> BlockType.REGISTRY.get(Sponge.game().registry(RegistryTypes.BLOCK_TYPE).valueKey(b).formatted()))
.map(blockType -> BlockType.REGISTRY.get(blockTypeRegistry.valueKey(blockType).formatted()))
.collect(Collectors.toSet());
}
}

View File

@ -23,7 +23,10 @@
import com.sk89q.worldedit.world.registry.ItemCategoryRegistry;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.BlockType;
import org.spongepowered.api.registry.Registry;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.tag.Tag;
import java.util.Collections;
import java.util.Set;
@ -32,12 +35,12 @@
public class SpongeItemCategoryRegistry implements ItemCategoryRegistry {
@Override
public Set<ItemType> getCategorisedByName(String category) {
return Sponge.game().registry(RegistryTypes.ITEM_TYPE_TAGS)
.findValue(ResourceKey.resolve(category))
.map(org.spongepowered.api.tag.Tag::values)
.orElse(Collections.emptyList())
Registry<org.spongepowered.api.item.ItemType> itemTypeRegistry =
Sponge.game().registry(RegistryTypes.ITEM_TYPE);
return itemTypeRegistry.taggedValues(Tag.of(RegistryTypes.ITEM_TYPE, ResourceKey.resolve(category)))
.stream()
.map(b -> ItemType.REGISTRY.get(Sponge.game().registry(RegistryTypes.ITEM_TYPE).valueKey(b).formatted()))
.map(itemType -> ItemType.REGISTRY.get(itemTypeRegistry.valueKey(itemType).formatted()))
.collect(Collectors.toSet());
}
}

View File

@ -40,8 +40,12 @@
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.level.block.entity.StructureBlockEntity;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.BlockState;
import org.spongepowered.api.data.Keys;
import org.spongepowered.api.data.type.HandTypes;
import org.spongepowered.api.entity.living.player.Player;
@ -230,18 +234,23 @@ public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B bl
if (block == null) {
player.resetBlockChange(pos.getX(), pos.getY(), pos.getZ());
} else {
player.sendBlockChange(pos.getX(), pos.getY(), pos.getZ(), SpongeAdapter.adapt(block.toImmutableState()));
BlockState spongeBlock = SpongeAdapter.adapt(block.toImmutableState());
player.sendBlockChange(pos.getX(), pos.getY(), pos.getZ(), spongeBlock);
if (block instanceof BaseBlock && block.getBlockType().equals(com.sk89q.worldedit.world.block.BlockTypes.STRUCTURE_BLOCK)) {
final BaseBlock baseBlock = (BaseBlock) block;
final BaseBlock baseBlock = block.toBaseBlock();
final CompoundTag nbtData = baseBlock.getNbtData();
if (nbtData != null) {
net.minecraft.server.level.ServerPlayer mcPlayer =
net.minecraft.world.level.block.state.BlockState nativeBlock =
(net.minecraft.world.level.block.state.BlockState) spongeBlock;
net.minecraft.nbt.CompoundTag nativeNbtData = NbtAdapter.adaptNMSToWorldEdit(nbtData);
net.minecraft.server.level.ServerPlayer nativePlayer =
((net.minecraft.server.level.ServerPlayer) player);
mcPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket(
new net.minecraft.core.BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()),
STRUCTURE_BLOCK_PACKET_ID,
NbtAdapter.adaptNMSToWorldEdit(nbtData))
);
StructureBlockEntity structureBlockEntity =
new StructureBlockEntity(new BlockPos(pos.getX(), pos.getY(), pos.getZ()), nativeBlock);
structureBlockEntity.load(nativeNbtData);
nativePlayer.connection.send(
ClientboundBlockEntityDataPacket.create(structureBlockEntity, it -> nativeNbtData));
}
}
}

View File

@ -52,7 +52,8 @@
import com.sk89q.worldedit.world.weather.WeatherType;
import com.sk89q.worldedit.world.weather.WeatherTypes;
import net.minecraft.core.BlockPos;
import net.minecraft.data.worldgen.Features;
import net.minecraft.data.worldgen.features.EndFeatures;
import net.minecraft.data.worldgen.features.TreeFeatures;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
@ -303,43 +304,43 @@ public boolean regenerate(Region region, Extent extent, RegenOptions options) {
switch (type) {
// Based off of the SaplingGenerator class, as well as uses of DefaultBiomeFeatures fields
case TREE:
return Features.OAK;
return TreeFeatures.OAK.value();
case BIG_TREE:
return Features.FANCY_OAK;
return TreeFeatures.FANCY_OAK.value();
case REDWOOD:
return Features.SPRUCE;
return TreeFeatures.SPRUCE.value();
case TALL_REDWOOD:
return Features.MEGA_SPRUCE;
return TreeFeatures.MEGA_SPRUCE.value();
case MEGA_REDWOOD:
return Features.MEGA_PINE;
return TreeFeatures.MEGA_PINE.value();
case BIRCH:
return Features.BIRCH;
return TreeFeatures.BIRCH.value();
case JUNGLE:
return Features.MEGA_JUNGLE_TREE;
return TreeFeatures.MEGA_JUNGLE_TREE.value();
case SMALL_JUNGLE:
return Features.JUNGLE_TREE;
return TreeFeatures.JUNGLE_TREE.value();
case SHORT_JUNGLE:
return Features.JUNGLE_TREE_NO_VINE;
return TreeFeatures.JUNGLE_TREE_NO_VINE.value();
case JUNGLE_BUSH:
return Features.JUNGLE_BUSH;
return TreeFeatures.JUNGLE_BUSH.value();
case SWAMP:
return Features.SWAMP_TREE;
return TreeFeatures.SWAMP_OAK.value();
case ACACIA:
return Features.ACACIA;
return TreeFeatures.ACACIA.value();
case DARK_OAK:
return Features.DARK_OAK;
return TreeFeatures.DARK_OAK.value();
case TALL_BIRCH:
return Features.BIRCH_TALL;
return TreeFeatures.SUPER_BIRCH_BEES.value(); // TODO Bees???
case RED_MUSHROOM:
return Features.HUGE_RED_MUSHROOM;
return TreeFeatures.HUGE_RED_MUSHROOM.value();
case BROWN_MUSHROOM:
return Features.HUGE_BROWN_MUSHROOM;
return TreeFeatures.HUGE_BROWN_MUSHROOM.value();
case WARPED_FUNGUS:
return Features.WARPED_FUNGI;
return TreeFeatures.WARPED_FUNGUS.value();
case CRIMSON_FUNGUS:
return Features.CRIMSON_FUNGI;
return TreeFeatures.CRIMSON_FUNGUS.value();
case CHORUS_PLANT:
return Features.CHORUS_PLANT;
return EndFeatures.CHORUS_PLANT.value();
case RANDOM:
return createTreeFeatureGenerator(TreeGenerator.TreeType.values()[ThreadLocalRandom.current().nextInt(TreeGenerator.TreeType.values().length)]);
default:

View File

@ -190,13 +190,13 @@ public void serverStarted(StartedEngineEvent<Server> event) {
});
}
event.game().registry(RegistryTypes.BLOCK_TYPE_TAGS).streamEntries().forEach(blockTypeTag -> {
event.game().registry(RegistryTypes.BLOCK_TYPE).tags().forEach(blockTypeTag -> {
String id = blockTypeTag.key().asString();
if (!BlockCategory.REGISTRY.keySet().contains(id)) {
BlockCategory.REGISTRY.register(id, new BlockCategory(id));
}
});
event.game().registry(RegistryTypes.ITEM_TYPE_TAGS).streamEntries().forEach(itemTypeTag -> {
event.game().registry(RegistryTypes.ITEM_TYPE).tags().forEach(itemTypeTag -> {
String id = itemTypeTag.key().asString();
if (!ItemCategory.REGISTRY.keySet().contains(id)) {
ItemCategory.REGISTRY.register(id, new ItemCategory(id));

View File

@ -35,9 +35,6 @@
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.registry.RegistryTypes;
import org.spongepowered.api.state.BooleanStateProperty;
import org.spongepowered.api.state.EnumStateProperty;
import org.spongepowered.api.state.IntegerStateProperty;
import org.spongepowered.api.state.StateProperty;
import java.util.Comparator;
@ -51,26 +48,32 @@
*/
public class SpongeTransmogrifier {
private static final LoadingCache<StateProperty<?>, Property<?>> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<StateProperty<?>, Property<?>>() {
private static final LoadingCache<StateProperty<?>, Property<?>> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<>() {
@Override
public Property<?> load(StateProperty<?> property) throws Exception {
if (property instanceof BooleanStateProperty) {
return new BooleanProperty(property.name(), ImmutableList.copyOf(((BooleanStateProperty) property).possibleValues()));
public Property<?> load(StateProperty<?> property) {
net.minecraft.world.level.block.state.properties.Property<?> nativeProperty =
(net.minecraft.world.level.block.state.properties.Property<?>) property;
String propertyName = nativeProperty.getName();
if (nativeProperty instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
return new BooleanProperty(propertyName,
ImmutableList.copyOf(((net.minecraft.world.level.block.state.properties.BooleanProperty) nativeProperty).getPossibleValues()));
}
if (property instanceof IntegerStateProperty) {
return new IntegerProperty(property.name(), ImmutableList.copyOf(((IntegerStateProperty) property).possibleValues()));
if (nativeProperty instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(propertyName,
ImmutableList.copyOf(((net.minecraft.world.level.block.state.properties.IntegerProperty) nativeProperty).getPossibleValues()));
}
if (isDirectionProperty(property)) {
return new DirectionalProperty(property.name(),
((EnumStateProperty<?>) property).possibleValues().stream()
if (isDirectionProperty(nativeProperty)) {
return new DirectionalProperty(propertyName,
((net.minecraft.world.level.block.state.properties.EnumProperty<?>) nativeProperty).getPossibleValues().stream()
.map(x -> adaptDirection((net.minecraft.core.Direction) x))
.collect(Collectors.toList())
);
}
if (property instanceof EnumStateProperty) {
return new EnumProperty(property.name(), ((EnumStateProperty<?>) property).possibleValues().stream()
.map(x -> ((StringRepresentable) x).getSerializedName())
.collect(Collectors.toList()));
if (nativeProperty instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(propertyName,
((net.minecraft.world.level.block.state.properties.EnumProperty<?>) nativeProperty).getPossibleValues().stream()
.map(StringRepresentable::getSerializedName)
.collect(Collectors.toList()));
}
throw new IllegalStateException("Unknown property type");
}
@ -80,23 +83,27 @@ public static Property<?> transmogToWorldEditProperty(StateProperty<?> property)
return PROPERTY_CACHE.getUnchecked(property);
}
private static Map<Property<?>, Object> transmogToWorldEditProperties(BlockType block, Map<StateProperty<?>, ?> mcProps) {
Map<Property<?>, Object> props = new TreeMap<>(Comparator.comparing(Property::getName));
for (Map.Entry<StateProperty<?>, ?> prop : mcProps.entrySet()) {
Object value = prop.getValue();
if (isDirectionProperty(prop.getKey())) {
value = adaptDirection((net.minecraft.core.Direction) value);
} else if (prop.getKey() instanceof EnumStateProperty) {
private static Map<Property<?>, Object> transmogToWorldEditProperties(
BlockType block,
net.minecraft.world.level.block.state.BlockState blockState
) {
Map<Property<?>, Object> properties = new TreeMap<>(Comparator.comparing(Property::getName));
for (net.minecraft.world.level.block.state.properties.Property<?> nativeProperty: blockState.getProperties()) {
Object value = blockState.getValue(nativeProperty);
if (isDirectionProperty(nativeProperty)) {
net.minecraft.core.Direction nativeDirectionValue = (net.minecraft.core.Direction) value;
value = adaptDirection(nativeDirectionValue);
} else if (nativeProperty instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
value = ((StringRepresentable) value).getSerializedName();
}
props.put(block.getProperty(prop.getKey().name()), value);
properties.put(block.getProperty(nativeProperty.getName()), value);
}
return props;
return properties;
}
private static boolean isDirectionProperty(StateProperty<?> property) {
return property instanceof EnumStateProperty
&& property.valueClass().isAssignableFrom(net.minecraft.core.Direction.class);
private static boolean isDirectionProperty(net.minecraft.world.level.block.state.properties.Property<?> property) {
return property instanceof net.minecraft.world.level.block.state.properties.EnumProperty
&& property.getValueClass().isAssignableFrom(net.minecraft.core.Direction.class);
}
private static Direction adaptDirection(net.minecraft.core.Direction direction) {
@ -137,36 +144,50 @@ private static net.minecraft.core.Direction adaptDirection(Direction direction)
}
}
private static net.minecraft.world.level.block.state.properties.Property<?> findPropertyByName(
net.minecraft.world.level.block.state.BlockState blockState,
String propertyName
) {
for (net.minecraft.world.level.block.state.properties.Property<?> property: blockState.getProperties()) {
if (property.getName().equals(propertyName)) {
return property;
}
}
throw new IllegalStateException("Missing property in " + blockState.getBlock() + ": " + propertyName);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static org.spongepowered.api.block.BlockState transmogToMinecraftProperties(
org.spongepowered.api.block.BlockState newState,
org.spongepowered.api.block.BlockState blockState,
Map<Property<?>, Object> states
) {
org.spongepowered.api.block.BlockType type = newState.type();
for (Map.Entry<Property<?>, Object> state : states.entrySet()) {
StateProperty<?> property = type.findStateProperty(state.getKey().getName())
.orElseThrow(() -> new IllegalStateException(
"Missing property in " + type + ": " + state.getKey().getName())
);
Comparable value = (Comparable) state.getValue();
// we may need to adapt this value, depending on the source prop
if (state.getKey() instanceof DirectionalProperty) {
Direction dir = (Direction) value;
value = adaptDirection(dir);
} else if (state.getKey() instanceof EnumProperty) {
String enumName = (String) value;
value = property.parseValue(enumName).orElseThrow(() -> new IllegalStateException(
"Failed to parse '" + enumName + "' into " + state.getKey().getName()
));
net.minecraft.world.level.block.state.BlockState nativeBlockState =
(net.minecraft.world.level.block.state.BlockState) blockState;
for (Map.Entry<Property<?>, Object> stateEntry: states.entrySet()) {
Property<?> property = stateEntry.getKey();
Object value = stateEntry.getValue();
net.minecraft.world.level.block.state.properties.Property<?> nativeProperty =
findPropertyByName(nativeBlockState, property.getName());
Comparable<?> nativeValue;
if (property instanceof DirectionalProperty) {
Direction directionValue = (Direction) value;
nativeValue = adaptDirection(directionValue);
} else if (property instanceof EnumProperty) {
String valueName = (String) value;
Optional<? extends Comparable<?>> nativeValueOpt = nativeProperty.getValue(valueName);
if (nativeValueOpt.isEmpty()) {
throw new IllegalStateException("Failed to parse " + valueName + " into " + property.getName());
}
nativeValue = nativeValueOpt.get();
} else {
nativeValue = (Comparable<?>) value;
}
Optional<org.spongepowered.api.block.BlockState> optional =
newState.withStateProperty((StateProperty) property, value);
newState = optional.orElseThrow(() -> new IllegalStateException(
"Failed to change state property " + property.name()
));
nativeBlockState = nativeBlockState.setValue(
(net.minecraft.world.level.block.state.properties.Property) nativeProperty, (Comparable) nativeValue);
}
return newState;
return (org.spongepowered.api.block.BlockState) nativeBlockState;
}
public static org.spongepowered.api.block.BlockState transmogToMinecraft(BlockState blockState) {
@ -181,7 +202,8 @@ public static BlockState transmogToWorldEdit(org.spongepowered.api.block.BlockSt
BlockType blockType = BlockType.REGISTRY.get(
blockState.type().key(RegistryTypes.BLOCK_TYPE).asString()
);
return blockType.getState(transmogToWorldEditProperties(blockType, blockState.statePropertyMap()));
return blockType.getState(transmogToWorldEditProperties(blockType,
(net.minecraft.world.level.block.state.BlockState) blockState));
}
private SpongeTransmogrifier() {

View File

@ -105,8 +105,8 @@ public boolean updateTileEntity(BlockPos position, com.sk89q.jnbt.CompoundTag ta
if (tileEntity == null) {
return false;
}
tileEntity.setLevelAndPosition(getWorld(), position);
tileEntity.load(getWorld().getBlockState(position), nativeTag);
tileEntity.setLevel(getWorld());
tileEntity.load(nativeTag);
return true;
}