diff --git a/SpongeAPI b/SpongeAPI index 09eb3b5de85..c55fcbba6a7 160000 --- a/SpongeAPI +++ b/SpongeAPI @@ -1 +1 @@ -Subproject commit 09eb3b5de858d97d41d21069099780bba4bf4a55 +Subproject commit c55fcbba6a7821469816e5980920179952455413 diff --git a/src/main/java/org/spongepowered/common/block/BlockStateSerializerDeserializer.java b/src/main/java/org/spongepowered/common/block/BlockStateSerializerDeserializer.java new file mode 100644 index 00000000000..279c83e3aec --- /dev/null +++ b/src/main/java/org/spongepowered/common/block/BlockStateSerializerDeserializer.java @@ -0,0 +1,113 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.block; + +import static com.google.common.base.Preconditions.checkNotNull; + +import net.minecraft.block.Block; +import net.minecraft.state.IProperty; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.registry.Registry; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.block.BlockStateMatcher; +import org.spongepowered.api.block.BlockType; +import org.spongepowered.api.state.StateProperty; +import org.spongepowered.api.util.Tuple; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class BlockStateSerializerDeserializer { + + @SuppressWarnings({"rawtypes", "unchecked"}) + private static final Function, Comparable>, String> MAP_ENTRY_TO_STRING = p_apply_1_ -> { + if (p_apply_1_ == null) { + return ""; + } else { + final IProperty iproperty = p_apply_1_.getKey(); + return iproperty.getName() + "=" + iproperty.getName(p_apply_1_.getValue()); + } + }; + + public static String serialize(final BlockState state) { + final StringBuilder stringbuilder = new StringBuilder(); + stringbuilder.append(Registry.BLOCK.getKey((Block) state.getType()).toString()); + if (!((net.minecraft.block.BlockState) state).getValues().isEmpty()) { + stringbuilder.append('['); + stringbuilder.append( + ((net.minecraft.block.BlockState) state).getValues() + .entrySet() + .stream() + .map(BlockStateSerializerDeserializer.MAP_ENTRY_TO_STRING) + .collect(Collectors.joining(",")) + ); + stringbuilder.append(']'); + } + + return stringbuilder.toString(); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public static Optional deserialize(final String string) { + final String state = checkNotNull(string, "Id cannot be null!").toLowerCase(Locale.ENGLISH); + if (state.contains("[")) { + final String[] split = state.split("\\["); + final ResourceLocation key = ResourceLocation.tryCreate(split[0]); + return Registry.BLOCK.getValue(key) + .flatMap(block -> { + final Collection> properties = block.getStateContainer().getProperties(); + final String propertyValues = split[1].replace("[", "").replace("]", ""); + if (properties.isEmpty()) { + throw new IllegalArgumentException("The properties cannot be specified and empty (omit [] if there are no properties)"); + } + final String[] propertyValuePairs = propertyValues.split(","); + final List, ?>> propertyValuesFound = Arrays.stream(propertyValuePairs) + .map(propertyValue -> propertyValue.split("=")) + .filter(pair -> pair.length == 2) + .map(pair -> Optional.ofNullable(block.getStateContainer().getProperty(pair[0])) + .flatMap(property -> property.parseValue(pair[1]).map(value -> Tuple.of(property, value)))) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); + final BlockStateMatcher.Builder matcher = BlockState.matcher((BlockType) block); + propertyValuesFound.forEach(tuple -> matcher.property((StateProperty) tuple.getFirst(), (Comparable) tuple.getSecond())); + + return matcher.build() + .getCompatibleStates() + .stream() + .findFirst(); + }); + + } + final ResourceLocation block = ResourceLocation.tryCreate(string); + return (Optional) (Optional) Registry.BLOCK.getValue(block).map(Block::getDefaultState); + } +} diff --git a/src/main/java/org/spongepowered/common/registry/SpongeBuilderRegistry.java b/src/main/java/org/spongepowered/common/registry/SpongeBuilderRegistry.java index 97d70e94802..c1c157e568b 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeBuilderRegistry.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeBuilderRegistry.java @@ -83,12 +83,12 @@ import org.spongepowered.api.item.inventory.type.ViewableInventory; import org.spongepowered.api.item.merchant.TradeOffer; import org.spongepowered.api.item.merchant.TradeOfferGenerator; +import org.spongepowered.api.item.recipe.cooking.CookingRecipe; import org.spongepowered.api.item.recipe.crafting.Ingredient; import org.spongepowered.api.item.recipe.crafting.ShapedCraftingRecipe; import org.spongepowered.api.item.recipe.crafting.ShapelessCraftingRecipe; import org.spongepowered.api.item.recipe.crafting.SpecialCraftingRecipe; import org.spongepowered.api.item.recipe.single.StoneCutterRecipe; -import org.spongepowered.api.item.recipe.cooking.CookingRecipe; import org.spongepowered.api.placeholder.PlaceholderComponent; import org.spongepowered.api.placeholder.PlaceholderContext; import org.spongepowered.api.placeholder.PlaceholderParser; @@ -106,12 +106,13 @@ import org.spongepowered.api.world.WorldBorder; import org.spongepowered.api.world.biome.VirtualBiomeType; import org.spongepowered.api.world.explosion.Explosion; +import org.spongepowered.api.world.schematic.PaletteType; import org.spongepowered.common.advancement.SpongeAdvancementBuilder; -import org.spongepowered.common.advancement.criterion.SpongeCriterionBuilder; import org.spongepowered.common.advancement.SpongeDisplayInfoBuilder; import org.spongepowered.common.advancement.SpongeFilteredTriggerBuilder; -import org.spongepowered.common.advancement.criterion.SpongeScoreCriterionBuilder; import org.spongepowered.common.advancement.SpongeTriggerBuilder; +import org.spongepowered.common.advancement.criterion.SpongeCriterionBuilder; +import org.spongepowered.common.advancement.criterion.SpongeScoreCriterionBuilder; import org.spongepowered.common.ban.SpongeBanBuilder; import org.spongepowered.common.block.SpongeBlockSnapshotBuilder; import org.spongepowered.common.block.SpongeBlockStateBuilder; @@ -165,12 +166,12 @@ import org.spongepowered.common.item.generation.SpongeItemStackGenerator; import org.spongepowered.common.item.merchant.SpongeTradeOfferBuilder; import org.spongepowered.common.item.merchant.SpongeTradeOfferGenerator; -import org.spongepowered.common.item.recipe.ingredient.SpongeIngredientBuilder; +import org.spongepowered.common.item.recipe.cooking.SpongeCookingRecipeBuilder; +import org.spongepowered.common.item.recipe.crafting.custom.SpongeSpecialCraftingRecipeBuilder; import org.spongepowered.common.item.recipe.crafting.shaped.SpongeShapedCraftingRecipeBuilder; import org.spongepowered.common.item.recipe.crafting.shapeless.SpongeShapelessCraftingRecipeBuilder; -import org.spongepowered.common.item.recipe.crafting.custom.SpongeSpecialCraftingRecipeBuilder; +import org.spongepowered.common.item.recipe.ingredient.SpongeIngredientBuilder; import org.spongepowered.common.item.recipe.stonecutting.SpongeStoneCutterRecipeBuilder; -import org.spongepowered.common.item.recipe.cooking.SpongeCookingRecipeBuilder; import org.spongepowered.common.placeholder.SpongePlaceholderComponentBuilder; import org.spongepowered.common.placeholder.SpongePlaceholderContextBuilder; import org.spongepowered.common.placeholder.SpongePlaceholderParserBuilder; @@ -183,6 +184,7 @@ import org.spongepowered.common.world.SpongeWorldArchetypeBuilder; import org.spongepowered.common.world.biome.SpongeVirtualBiomeTypeBuilder; import org.spongepowered.common.world.border.SpongeWorldBorderBuilder; +import org.spongepowered.common.world.schematic.SpongePaletteTypeBuilder; import java.util.Map; import java.util.function.Supplier; @@ -304,6 +306,7 @@ public void registerDefaultBuilders() { .register(MutableDataProviderBuilder.class, DataProviderRegistrator.SpongeMutableDataProviderBuilder::new) .register(ImmutableDataProviderBuilder.class, DataProviderRegistrator.SpongeImmutableDataProviderBuilder::new) .register(Query.Builder.class, SpongeQueryBuilder::new) + .register(PaletteType.Builder.class, SpongePaletteTypeBuilder::new) ; } } diff --git a/src/main/java/org/spongepowered/common/registry/SpongeCatalogRegistry.java b/src/main/java/org/spongepowered/common/registry/SpongeCatalogRegistry.java index 85d761386f0..e7bde7f0734 100644 --- a/src/main/java/org/spongepowered/common/registry/SpongeCatalogRegistry.java +++ b/src/main/java/org/spongepowered/common/registry/SpongeCatalogRegistry.java @@ -159,6 +159,7 @@ import org.spongepowered.api.world.dimension.DimensionType; import org.spongepowered.api.world.dimension.DimensionTypes; import org.spongepowered.api.world.portal.PortalType; +import org.spongepowered.api.world.schematic.PaletteType; import org.spongepowered.api.world.teleport.TeleportHelperFilter; import org.spongepowered.api.world.weather.Weather; import org.spongepowered.common.accessor.util.registry.SimpleRegistryAccessor; @@ -200,6 +201,7 @@ import org.spongepowered.common.registry.builtin.sponge.MovementTypeStreamGenerator; import org.spongepowered.common.registry.builtin.sponge.MusicDiscStreamGenerator; import org.spongepowered.common.registry.builtin.sponge.NotePitchStreamGenerator; +import org.spongepowered.common.registry.builtin.sponge.PaletteTypeStreamGenerator; import org.spongepowered.common.registry.builtin.sponge.ParrotTypeStreamGenerator; import org.spongepowered.common.registry.builtin.sponge.ParticleOptionStreamGenerator; import org.spongepowered.common.registry.builtin.sponge.PhaseTypeRegistrar; @@ -564,6 +566,7 @@ public void registerDefaultRegistries() { .generateRegistry(MooshroomType.class, ResourceKey.minecraft("mooshroom_type"), Arrays.stream(MooshroomEntity.Type.values()), true, false) .generateRegistry(MovementType.class, ResourceKey.sponge("movement_type"), MovementTypeStreamGenerator.stream(), true, true) .generateRegistry(MusicDisc.class, ResourceKey.minecraft("music_disc"), MusicDiscStreamGenerator.stream(), true, false) + .generateRegistry(PaletteType.class, ResourceKey.sponge("palette"), PaletteTypeStreamGenerator.stream(), true, true) .generateRegistry(PandaGene.class, ResourceKey.minecraft("panda_gene"), Arrays.stream(PandaEntity.Type.values()), true, false) .generateRegistry(ParticleOption.class, ResourceKey.sponge("particle_option"), ParticleOptionStreamGenerator.stream(), true, false) .generateRegistry(PhantomPhase.class, ResourceKey.minecraft("phantom_phase"), Arrays.stream(PhantomEntity.AttackPhase.values()), true, false) diff --git a/src/main/java/org/spongepowered/common/registry/builtin/sponge/PaletteTypeStreamGenerator.java b/src/main/java/org/spongepowered/common/registry/builtin/sponge/PaletteTypeStreamGenerator.java new file mode 100644 index 00000000000..0c3a5672f63 --- /dev/null +++ b/src/main/java/org/spongepowered/common/registry/builtin/sponge/PaletteTypeStreamGenerator.java @@ -0,0 +1,103 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.registry.builtin.sponge; + +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.biome.Biome; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.world.biome.BiomeType; +import org.spongepowered.api.world.biome.VirtualBiomeType; +import org.spongepowered.api.world.schematic.PaletteType; +import org.spongepowered.api.world.schematic.PaletteTypes; +import org.spongepowered.common.block.BlockStateSerializerDeserializer; +import org.spongepowered.common.world.schematic.GlobalPalette; +import org.spongepowered.common.world.schematic.MutableBimapPalette; +import org.spongepowered.common.world.schematic.SpongePaletteType; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +public final class PaletteTypeStreamGenerator { + + private PaletteTypeStreamGenerator() { + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public static Stream stream() { + final List paletteTypes = new ArrayList<>(); + paletteTypes.add(new SpongePaletteType( + ResourceKey.sponge("global_block_palette"), + GlobalPalette::getBlockPalette, + BlockStateSerializerDeserializer::serialize, + BlockStateSerializerDeserializer::deserialize + )); + paletteTypes.add(new SpongePaletteType<>( + ResourceKey.sponge("block_state_palette"), + () -> new MutableBimapPalette<>(PaletteTypes.BLOCK_STATE_PALETTE.get()), + BlockStateSerializerDeserializer::serialize, + BlockStateSerializerDeserializer::deserialize + )); + paletteTypes.add(new SpongePaletteType( + ResourceKey.sponge("global_biome_palette"), + GlobalPalette::getBiomePalette, + (type) -> { + final ResourceLocation key = Registry.BIOME.getKey((Biome) ( + type instanceof VirtualBiomeType + ? ((VirtualBiomeType) type).getPersistedType() + : type + )); + if (key == null) { + return "minecraft:plains"; + } + return key.toString(); + }, + (id) -> (Optional) (Optional) Registry.BIOME.getValue(ResourceLocation.tryCreate(id)) + )); + paletteTypes.add(new SpongePaletteType<>( + ResourceKey.sponge("biome_palette"), + () -> new MutableBimapPalette<>(PaletteTypes.BIOME_PALETTE.get()), + (type) -> { + final ResourceLocation key = Registry.BIOME.getKey((Biome) ( + type instanceof VirtualBiomeType + ? ((VirtualBiomeType) type).getPersistedType() + : type + )); + if (key == null) { + return "minecraft:plains"; + } + return key.toString(); + }, + (id) -> (Optional) (Optional) Registry.BIOME.getValue(ResourceLocation.tryCreate(id)) + )); + + return paletteTypes.stream(); + } + + +} diff --git a/src/main/java/org/spongepowered/common/util/MemoizedSupplier.java b/src/main/java/org/spongepowered/common/util/MemoizedSupplier.java new file mode 100644 index 00000000000..3b169f3e03e --- /dev/null +++ b/src/main/java/org/spongepowered/common/util/MemoizedSupplier.java @@ -0,0 +1,60 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.util; + + +import java.util.Objects; +import java.util.function.Supplier; + +public class MemoizedSupplier implements Supplier { + + public static Supplier memoize(final Supplier supplier) { + return new MemoizedSupplier<>(supplier); + } + + final Supplier delegate; + transient volatile boolean initialized; + transient T value; + + private MemoizedSupplier(final Supplier delegate) { + this.delegate = Objects.requireNonNull(delegate); + } + + @Override + public T get() { + if (!this.initialized) { + synchronized (this) { + if (!this.initialized) { + final T t = this.delegate.get(); + this.value = t; + this.initialized = true; + return t; + } + } + } + return this.value; + } + +} diff --git a/src/main/java/org/spongepowered/common/world/schematic/GlobalPalette.java b/src/main/java/org/spongepowered/common/world/schematic/GlobalPalette.java index b95a303378d..f5ee406b2b9 100644 --- a/src/main/java/org/spongepowered/common/world/schematic/GlobalPalette.java +++ b/src/main/java/org/spongepowered/common/world/schematic/GlobalPalette.java @@ -25,75 +25,82 @@ package org.spongepowered.common.world.schematic; import com.google.common.base.MoreObjects; +import com.google.common.collect.HashBiMap; import net.minecraft.block.Block; import net.minecraft.util.registry.Registry; import net.minecraft.world.biome.Biome; -import org.spongepowered.api.CatalogType; -import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockState; +import org.spongepowered.api.util.Tuple; import org.spongepowered.api.world.biome.BiomeType; import org.spongepowered.api.world.biome.VirtualBiomeType; import org.spongepowered.api.world.schematic.Palette; import org.spongepowered.api.world.schematic.PaletteType; import org.spongepowered.api.world.schematic.PaletteTypes; +import org.spongepowered.common.util.MemoizedSupplier; -import java.util.Collection; import java.util.Objects; import java.util.Optional; -import java.util.function.Function; +import java.util.OptionalInt; import java.util.function.IntFunction; - -import javax.annotation.Nullable; - -public class GlobalPalette implements Palette { - - @Nullable - private static Palette blockPalette; - @Nullable - private static GlobalPalette biomePalette; - - private final Function typeToInt; +import java.util.function.IntSupplier; +import java.util.function.Supplier; +import java.util.function.ToIntFunction; +import java.util.stream.Stream; + +public class GlobalPalette implements Palette.Immutable { + + + @SuppressWarnings({"unchecked", "rawtypes"}) + static final Supplier> GLOBAL_BLOCK_STATE_PALETTE = MemoizedSupplier.memoize( + () -> new GlobalPalette<>( + PaletteTypes.GLOBAL_BLOCK_PALETTE.get(), + () -> (Stream) (Stream) Registry.BLOCK.stream() + .flatMap(block -> block.getStateContainer().getValidStates().stream()), + (type) -> Block.BLOCK_STATE_IDS.get((net.minecraft.block.BlockState) type), + (id) -> (BlockState) Block.BLOCK_STATE_IDS.getByValue(id), + BlockState.class + ) + ); + + @SuppressWarnings({"unchecked", "rawtypes"}) + static final Supplier> GLOBAL_BIOME_PALETTE = MemoizedSupplier.memoize(() -> new GlobalPalette<>( + PaletteTypes.GLOBAL_BIOME_PALETTE.get(), + () -> (Stream) (Stream) Registry.BIOME.stream(), + (type) -> Registry.BIOME.getId((Biome) (type instanceof VirtualBiomeType ? ((VirtualBiomeType) type).getPersistedType() : type)), + (id) -> (BiomeType) Registry.BIOME.getByValue(id), + BiomeType.class + )); + + + private final ToIntFunction typeToInt; private final IntFunction intToType; private final PaletteType paletteType; private final Class catalogType; - private final int length; - - private GlobalPalette(final PaletteType paletteType, final Function map, final IntFunction identity, final Class catalogType) { - int highest = 0; - for (final T type : Sponge.getRegistry().getCatalogRegistry().getAllOf(catalogType)) { - final int id = map.apply(type); - if (id > highest) { - highest = id; - } - } - this.length = highest; + private final IntSupplier length; + private final Supplier> catalogSupplier; + + private GlobalPalette( + final PaletteType paletteType, + final Supplier> catalogSupplier, + final ToIntFunction map, + final IntFunction identity, + final Class catalogType + ) { + + this.length = () -> catalogSupplier.get().mapToInt(map).max().orElse(0); this.typeToInt = map; this.intToType = identity; this.paletteType = paletteType; this.catalogType = catalogType; + this.catalogSupplier = catalogSupplier; } - @SuppressWarnings("deprecation") public static Palette getBlockPalette() { - if (blockPalette == null) { - blockPalette = new GlobalPalette<>(PaletteTypes.GLOBAL_BLOCKS.get(), - (type) -> Block.BLOCK_STATE_IDS.get((net.minecraft.block.BlockState) type), - (id) -> (BlockState) Block.BLOCK_STATE_IDS.getByValue(id), - BlockState.class); - } - return blockPalette; + return GlobalPalette.GLOBAL_BLOCK_STATE_PALETTE.get(); } public static GlobalPalette getBiomePalette() { - if (biomePalette == null) { - biomePalette = new GlobalPalette<>(PaletteTypes.GLOBAL_BIOMES.get(), - (type) -> Registry.BIOME.getId((Biome) (type instanceof VirtualBiomeType ? ((VirtualBiomeType) type).getPersistedType() : type)), - (id) -> (BiomeType) Registry.BIOME.getByValue(id), - BiomeType.class - ); - - } - return biomePalette; + return GlobalPalette.GLOBAL_BIOME_PALETTE.get(); } @Override @@ -103,17 +110,12 @@ public PaletteType getType() { @Override public int getHighestId() { - return this.length; - } - - @Override - public Optional get(final T type) { - return Optional.of(this.typeToInt.apply(type)); + return this.length.getAsInt(); } @Override - public int getOrAssign(final T state) { - return this.typeToInt.apply(state); + public OptionalInt get(final T type) { + return OptionalInt.of(this.typeToInt.applyAsInt(type)); } @Override @@ -122,13 +124,17 @@ public Optional get(final int id) { } @Override - public boolean remove(final T state) { - throw new UnsupportedOperationException("Cannot remove blockstates from the global palette"); + public Stream stream() { + return this.catalogSupplier.get(); } @Override - public Collection getEntries() { - return Sponge.getRegistry().getCatalogRegistry().getAllOf(this.catalogType); + public Mutable asMutable() { + final HashBiMap copy = HashBiMap.create(this.length.getAsInt()); + this.catalogSupplier.get() + .map(it -> Tuple.of(it, this.typeToInt.applyAsInt(it))) + .forEach(tuple -> copy.put(tuple.getFirst(), tuple.getSecond())); + return new MutableBimapPalette(this.paletteType, copy); } @Override @@ -147,8 +153,8 @@ public boolean equals(final Object obj) { } final GlobalPalette other = (GlobalPalette) obj; return Objects.equals(this.paletteType, other.paletteType) - && Objects.equals(this.catalogType, other.catalogType) - && Objects.equals(this.length, other.length); + && Objects.equals(this.catalogType, other.catalogType) + && Objects.equals(this.length.getAsInt(), other.length.getAsInt()); } @Override @@ -156,7 +162,7 @@ public String toString() { return MoreObjects.toStringHelper(this) .add("paletteType", this.paletteType) .add("catalogType", this.catalogType) - .add("length", this.length) + .add("length", this.length.getAsInt()) .toString(); } } diff --git a/src/main/java/org/spongepowered/common/world/schematic/ImmutableBimapPalette.java b/src/main/java/org/spongepowered/common/world/schematic/ImmutableBimapPalette.java new file mode 100644 index 00000000000..0b03f596286 --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/schematic/ImmutableBimapPalette.java @@ -0,0 +1,111 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.world.schematic; + +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableBiMap; +import org.spongepowered.api.world.schematic.Palette; +import org.spongepowered.api.world.schematic.PaletteType; + +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.stream.Stream; + +public class ImmutableBimapPalette implements Palette.Immutable { + + private final ImmutableBiMap ids; + private final ImmutableBiMap idsr; + private final PaletteType paletteType; + private final int maxId; + + public ImmutableBimapPalette(final PaletteType paletteType, final BiMap reference) { + final ImmutableBiMap.Builder builder = ImmutableBiMap.builder(); + reference.forEach(builder::put); + this.ids = builder.build(); + this.idsr = this.ids.inverse(); + this.paletteType = paletteType; + int maxId = 0; + for (final Integer id : this.ids.keySet()) { + if (maxId < id) { + maxId = id; + } + } + this.maxId = maxId; + } + + @Override + public PaletteType getType() { + return this.paletteType; + } + + @Override + public int getHighestId() { + return this.maxId; + } + + @Override + public OptionalInt get(final T state) { + final Integer value = this.idsr.get(state); + if (value == null) { + return OptionalInt.empty(); + } + return OptionalInt.of(value); + } + + @Override + public Optional get(final int id) { + return Optional.ofNullable(this.ids.get(id)); + } + + @Override + public Stream stream() { + return this.idsr.keySet().stream(); + } + + @Override + public Mutable asMutable() { + return new MutableBimapPalette<>(this.paletteType, this.idsr); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || this.getClass() != o.getClass()) { + return false; + } + final ImmutableBimapPalette that = (ImmutableBimapPalette) o; + return this.maxId == that.maxId && + this.ids.equals(that.ids) && + this.paletteType.equals(that.paletteType); + } + + @Override + public int hashCode() { + return Objects.hash(this.ids, this.paletteType, this.maxId); + } +} diff --git a/src/main/java/org/spongepowered/common/world/schematic/BimapPalette.java b/src/main/java/org/spongepowered/common/world/schematic/MutableBimapPalette.java similarity index 76% rename from src/main/java/org/spongepowered/common/world/schematic/BimapPalette.java rename to src/main/java/org/spongepowered/common/world/schematic/MutableBimapPalette.java index 3462a48f244..40308d0c392 100644 --- a/src/main/java/org/spongepowered/common/world/schematic/BimapPalette.java +++ b/src/main/java/org/spongepowered/common/world/schematic/MutableBimapPalette.java @@ -26,32 +26,39 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; -import org.spongepowered.api.CatalogType; import org.spongepowered.api.world.schematic.Palette; import org.spongepowered.api.world.schematic.PaletteType; import java.util.BitSet; -import java.util.Collection; import java.util.Objects; import java.util.Optional; +import java.util.OptionalInt; +import java.util.stream.Stream; -public class BimapPalette implements Palette { +public class MutableBimapPalette implements Palette.Mutable { private static final int DEFAULT_ALLOCATION_SIZE = 64; private final BiMap ids; private final BiMap idsr; - private final BitSet allocation = new BitSet(DEFAULT_ALLOCATION_SIZE); + private final BitSet allocation = new BitSet(MutableBimapPalette.DEFAULT_ALLOCATION_SIZE); private final PaletteType paletteType; private int maxId = 0; - public BimapPalette(final PaletteType paletteType) { + public MutableBimapPalette(final PaletteType paletteType) { this.ids = HashBiMap.create(); this.idsr = this.ids.inverse(); this.paletteType = paletteType; } - public BimapPalette(final PaletteType paletteType, final int expectedSize) { + public MutableBimapPalette(final PaletteType paletteType, final BiMap reference) { + this.ids = HashBiMap.create(reference.size()); + this.idsr = this.ids.inverse(); + this.paletteType = paletteType; + reference.forEach((key, id) -> this.getOrAssign(key)); + } + + public MutableBimapPalette(final PaletteType paletteType, final int expectedSize) { this.ids = HashBiMap.create(expectedSize); this.idsr = this.ids.inverse(); this.paletteType = paletteType; @@ -68,8 +75,12 @@ public int getHighestId() { } @Override - public Optional get(final T state) { - return Optional.ofNullable(this.idsr.get(state)); + public OptionalInt get(final T state) { + final Integer value = this.idsr.get(state); + if (value == null) { + return OptionalInt.empty(); + } + return OptionalInt.of(value); } @Override @@ -115,8 +126,13 @@ public boolean remove(final T state) { } @Override - public Collection getEntries() { - return this.idsr.keySet(); + public Stream stream() { + return this.idsr.keySet().stream(); + } + + @Override + public Immutable asImmutable() { + return new ImmutableBimapPalette<>(this.paletteType, this.ids); } @Override @@ -127,7 +143,7 @@ public boolean equals(final Object o) { if (o == null || this.getClass() != o.getClass()) { return false; } - final BimapPalette that = (BimapPalette) o; + final MutableBimapPalette that = (MutableBimapPalette) o; return this.maxId == that.maxId && this.ids.equals(that.ids) && this.allocation.equals(that.allocation) && diff --git a/src/main/java/org/spongepowered/common/world/schematic/SpongePaletteType.java b/src/main/java/org/spongepowered/common/world/schematic/SpongePaletteType.java index 463c30af271..212903174f6 100644 --- a/src/main/java/org/spongepowered/common/world/schematic/SpongePaletteType.java +++ b/src/main/java/org/spongepowered/common/world/schematic/SpongePaletteType.java @@ -25,20 +25,30 @@ package org.spongepowered.common.world.schematic; import org.spongepowered.api.ResourceKey; -import org.spongepowered.api.CatalogType; import org.spongepowered.api.world.schematic.Palette; import org.spongepowered.api.world.schematic.PaletteType; import org.spongepowered.common.SpongeCatalogType; +import java.util.Optional; +import java.util.function.Function; import java.util.function.Supplier; -public class SpongePaletteType extends SpongeCatalogType implements PaletteType { +public class SpongePaletteType extends SpongeCatalogType implements PaletteType { private final Supplier> builder; + private final Function encoder; + private final Function> decoder; - public SpongePaletteType(final ResourceKey id, final Supplier> builder) { + public SpongePaletteType( + final ResourceKey id, + final Supplier> builder, + final Function encoder, + final Function> decoder + ) { super(id); this.builder = builder; + this.encoder = encoder; + this.decoder = decoder; } @Override @@ -46,4 +56,14 @@ public Palette create() { return this.builder.get(); } + @Override + public Function getEncoder() { + return this.encoder; + } + + @Override + public Function> getDecoder() { + return this.decoder; + } + } diff --git a/src/main/java/org/spongepowered/common/world/schematic/SpongePaletteTypeBuilder.java b/src/main/java/org/spongepowered/common/world/schematic/SpongePaletteTypeBuilder.java new file mode 100644 index 00000000000..c923409e0d0 --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/schematic/SpongePaletteTypeBuilder.java @@ -0,0 +1,69 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.common.world.schematic; + +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import org.spongepowered.api.ResourceKey; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.world.schematic.PaletteType; +import org.spongepowered.common.util.SpongeCatalogBuilder; + +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +public class SpongePaletteTypeBuilder extends SpongeCatalogBuilder, PaletteType.Builder> implements PaletteType.Builder { + private @MonotonicNonNull Function encoder; + private @MonotonicNonNull Function> decoder; + + @Override + public PaletteType.Builder encoder(final Function encoder) { + this.encoder = Objects.requireNonNull(encoder, "Encoder cannot be null"); + return this; + } + + @Override + public PaletteType.Builder decoder(final Function> decoder) { + this.decoder = Objects.requireNonNull(decoder, "Decoder cannot be null"); + return this; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + protected PaletteType build(final ResourceKey key) { + Objects.requireNonNull(key, "ResourceKey cannot be null"); + Objects.requireNonNull(this.encoder, "Encoder cannot be null"); + Objects.requireNonNull(this.decoder, "Decoder cannot be null"); + return new SpongePaletteType<>(key, () -> { + final PaletteType paletteType = Sponge.getRegistry() + .getCatalogRegistry() + .get(PaletteType.class, key) + .orElseThrow(() -> new IllegalStateException( + "PaletteType no longer registered, cannot create a Palette off an unregistered Palette Type" + )); + return new MutableBimapPalette<>(paletteType); + }, this.encoder, this.decoder); + } +} diff --git a/src/main/java/org/spongepowered/common/world/schematic/package-info.java b/src/main/java/org/spongepowered/common/world/schematic/package-info.java new file mode 100644 index 00000000000..72ec7683b48 --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/schematic/package-info.java @@ -0,0 +1,26 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +@org.checkerframework.framework.qual.DefaultQualifier(org.checkerframework.checker.nullness.qual.NonNull.class) +package org.spongepowered.common.world.schematic; \ No newline at end of file