/* * This file is part of LanternServer, licensed under the MIT License (MIT). * * Copyright (c) LanternPowered <https://www.lanternpowered.org> * Copyright (c) SpongePowered <https://www.spongepowered.org> * 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.lanternpowered.server.data.manipulator; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import org.lanternpowered.server.data.manipulator.immutable.IImmutableDataManipulator; import org.lanternpowered.server.data.manipulator.immutable.LanternImmutableColoredData; import org.lanternpowered.server.data.manipulator.immutable.LanternImmutableCommandData; import org.lanternpowered.server.data.manipulator.immutable.LanternImmutableDisplayNameData; import org.lanternpowered.server.data.manipulator.immutable.LanternImmutableDyeableData; import org.lanternpowered.server.data.manipulator.immutable.LanternImmutableFireworkEffectData; import org.lanternpowered.server.data.manipulator.immutable.LanternImmutableFireworkRocketData; import org.lanternpowered.server.data.manipulator.immutable.LanternImmutablePotionEffectData; import org.lanternpowered.server.data.manipulator.immutable.LanternImmutableRepresentedItemData; import org.lanternpowered.server.data.manipulator.immutable.LanternImmutableRepresentedPlayerData; import org.lanternpowered.server.data.manipulator.immutable.LanternImmutableRotationalData; import org.lanternpowered.server.data.manipulator.immutable.LanternImmutableSkullData; import org.lanternpowered.server.data.manipulator.immutable.LanternImmutableTargetedLocationData; import org.lanternpowered.server.data.manipulator.immutable.LanternImmutableWetData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableAuthorData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableBlockItemData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableBreakableData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableCoalData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableCookedFishData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableDurabilityData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableEnchantmentData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableFishData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableGenerationData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableGoldenAppleData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableHideData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableInventoryItemData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableLoreData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableMapItemData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutablePagedData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutablePlaceableData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableSpawnableData; import org.lanternpowered.server.data.manipulator.immutable.item.LanternImmutableStoredEnchantmentData; import org.lanternpowered.server.data.manipulator.mutable.IDataManipulator; import org.lanternpowered.server.data.manipulator.mutable.LanternColoredData; import org.lanternpowered.server.data.manipulator.mutable.LanternCommandData; import org.lanternpowered.server.data.manipulator.mutable.LanternDisplayNameData; import org.lanternpowered.server.data.manipulator.mutable.LanternDyeableData; import org.lanternpowered.server.data.manipulator.mutable.LanternFireworkEffectData; import org.lanternpowered.server.data.manipulator.mutable.LanternFireworkRocketData; import org.lanternpowered.server.data.manipulator.mutable.LanternPotionEffectData; import org.lanternpowered.server.data.manipulator.mutable.LanternRepresentedItemData; import org.lanternpowered.server.data.manipulator.mutable.LanternRepresentedPlayerData; import org.lanternpowered.server.data.manipulator.mutable.LanternRotationalData; import org.lanternpowered.server.data.manipulator.mutable.LanternSkullData; import org.lanternpowered.server.data.manipulator.mutable.LanternTargetedLocationData; import org.lanternpowered.server.data.manipulator.mutable.LanternWetData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternAuthorData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternBlockItemData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternBreakableData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternCoalData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternCookedFishData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternDurabilityData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternEnchantmentData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternFishData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternGenerationData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternGoldenAppleData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternHideData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternInventoryItemData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternLoreData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternMapItemData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternPagedData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternPlaceableData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternSpawnableData; import org.lanternpowered.server.data.manipulator.mutable.item.LanternStoredEnchantmentData; import org.spongepowered.api.data.key.Key; import org.spongepowered.api.data.manipulator.DataManipulator; import org.spongepowered.api.data.manipulator.ImmutableDataManipulator; import org.spongepowered.api.data.manipulator.immutable.ImmutableColoredData; import org.spongepowered.api.data.manipulator.immutable.ImmutableCommandData; import org.spongepowered.api.data.manipulator.immutable.ImmutableDisplayNameData; import org.spongepowered.api.data.manipulator.immutable.ImmutableDyeableData; import org.spongepowered.api.data.manipulator.immutable.ImmutableFireworkEffectData; import org.spongepowered.api.data.manipulator.immutable.ImmutableFireworkRocketData; import org.spongepowered.api.data.manipulator.immutable.ImmutablePotionEffectData; import org.spongepowered.api.data.manipulator.immutable.ImmutableRepresentedItemData; import org.spongepowered.api.data.manipulator.immutable.ImmutableRepresentedPlayerData; import org.spongepowered.api.data.manipulator.immutable.ImmutableRotationalData; import org.spongepowered.api.data.manipulator.immutable.ImmutableSkullData; import org.spongepowered.api.data.manipulator.immutable.ImmutableTargetedLocationData; import org.spongepowered.api.data.manipulator.immutable.ImmutableWetData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableAuthorData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableBlockItemData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableBreakableData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableCoalData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableCookedFishData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableDurabilityData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableEnchantmentData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableFishData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableGenerationData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableGoldenAppleData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableHideData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableInventoryItemData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableLoreData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableMapItemData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutablePagedData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutablePlaceableData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableSpawnableData; import org.spongepowered.api.data.manipulator.immutable.item.ImmutableStoredEnchantmentData; import org.spongepowered.api.data.manipulator.mutable.ColoredData; import org.spongepowered.api.data.manipulator.mutable.CommandData; import org.spongepowered.api.data.manipulator.mutable.DisplayNameData; import org.spongepowered.api.data.manipulator.mutable.DyeableData; import org.spongepowered.api.data.manipulator.mutable.FireworkEffectData; import org.spongepowered.api.data.manipulator.mutable.FireworkRocketData; import org.spongepowered.api.data.manipulator.mutable.PotionEffectData; import org.spongepowered.api.data.manipulator.mutable.RepresentedItemData; import org.spongepowered.api.data.manipulator.mutable.RepresentedPlayerData; import org.spongepowered.api.data.manipulator.mutable.RotationalData; import org.spongepowered.api.data.manipulator.mutable.SkullData; import org.spongepowered.api.data.manipulator.mutable.TargetedLocationData; import org.spongepowered.api.data.manipulator.mutable.WetData; import org.spongepowered.api.data.manipulator.mutable.item.AuthorData; import org.spongepowered.api.data.manipulator.mutable.item.BlockItemData; import org.spongepowered.api.data.manipulator.mutable.item.BreakableData; import org.spongepowered.api.data.manipulator.mutable.item.CoalData; import org.spongepowered.api.data.manipulator.mutable.item.CookedFishData; import org.spongepowered.api.data.manipulator.mutable.item.DurabilityData; import org.spongepowered.api.data.manipulator.mutable.item.EnchantmentData; import org.spongepowered.api.data.manipulator.mutable.item.FishData; import org.spongepowered.api.data.manipulator.mutable.item.GenerationData; import org.spongepowered.api.data.manipulator.mutable.item.GoldenAppleData; import org.spongepowered.api.data.manipulator.mutable.item.HideData; import org.spongepowered.api.data.manipulator.mutable.item.InventoryItemData; import org.spongepowered.api.data.manipulator.mutable.item.LoreData; import org.spongepowered.api.data.manipulator.mutable.item.MapItemData; import org.spongepowered.api.data.manipulator.mutable.item.PagedData; import org.spongepowered.api.data.manipulator.mutable.item.PlaceableData; import org.spongepowered.api.data.manipulator.mutable.item.SpawnableData; import org.spongepowered.api.data.manipulator.mutable.item.StoredEnchantmentData; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; public class DataManipulatorRegistry { private static final DataManipulatorRegistry INSTANCE = new DataManipulatorRegistry(); public static DataManipulatorRegistry get() { return INSTANCE; } private final Map<Class, DataManipulatorRegistration> registrationByClass = new HashMap<>(); { register(ColoredData.class, LanternColoredData::new, LanternColoredData::new, LanternColoredData::new, ImmutableColoredData.class, LanternImmutableColoredData::new, LanternImmutableColoredData::new); register(CommandData.class, LanternCommandData::new, LanternCommandData::new, LanternCommandData::new, ImmutableCommandData.class, LanternImmutableCommandData::new, LanternImmutableCommandData::new); register(DisplayNameData.class, LanternDisplayNameData::new, LanternDisplayNameData::new, LanternDisplayNameData::new, ImmutableDisplayNameData.class, LanternImmutableDisplayNameData::new, LanternImmutableDisplayNameData::new); register(DyeableData.class, LanternDyeableData::new, LanternDyeableData::new, LanternDyeableData::new, ImmutableDyeableData.class, LanternImmutableDyeableData::new, LanternImmutableDyeableData::new); register(FireworkEffectData.class, LanternFireworkEffectData::new, LanternFireworkEffectData::new, LanternFireworkEffectData::new, ImmutableFireworkEffectData.class, LanternImmutableFireworkEffectData::new, LanternImmutableFireworkEffectData::new); register(FireworkRocketData.class, LanternFireworkRocketData::new, LanternFireworkRocketData::new, LanternFireworkRocketData::new, ImmutableFireworkRocketData.class, LanternImmutableFireworkRocketData::new, LanternImmutableFireworkRocketData::new); register(PotionEffectData.class, LanternPotionEffectData::new, LanternPotionEffectData::new, LanternPotionEffectData::new, ImmutablePotionEffectData.class, LanternImmutablePotionEffectData::new, LanternImmutablePotionEffectData::new); register(RepresentedItemData.class, LanternRepresentedItemData::new, LanternRepresentedItemData::new, LanternRepresentedItemData::new, ImmutableRepresentedItemData.class, LanternImmutableRepresentedItemData::new, LanternImmutableRepresentedItemData::new); register(RepresentedPlayerData.class, LanternRepresentedPlayerData::new, LanternRepresentedPlayerData::new, LanternRepresentedPlayerData::new, ImmutableRepresentedPlayerData.class, LanternImmutableRepresentedPlayerData::new, LanternImmutableRepresentedPlayerData::new); register(RotationalData.class, LanternRotationalData::new, LanternRotationalData::new, LanternRotationalData::new, ImmutableRotationalData.class, LanternImmutableRotationalData::new, LanternImmutableRotationalData::new); register(SkullData.class, LanternSkullData::new, LanternSkullData::new, LanternSkullData::new, ImmutableSkullData.class, LanternImmutableSkullData::new, LanternImmutableSkullData::new); register(TargetedLocationData.class, LanternTargetedLocationData::new, LanternTargetedLocationData::new, LanternTargetedLocationData::new, ImmutableTargetedLocationData.class, LanternImmutableTargetedLocationData::new, LanternImmutableTargetedLocationData::new); register(WetData.class, LanternWetData::new, LanternWetData::new, LanternWetData::new, ImmutableWetData.class, LanternImmutableWetData::new, LanternImmutableWetData::new); // item package register(AuthorData.class, LanternAuthorData::new, LanternAuthorData::new, LanternAuthorData::new, ImmutableAuthorData.class, LanternImmutableAuthorData::new, LanternImmutableAuthorData::new); register(BlockItemData.class, LanternBlockItemData::new, LanternBlockItemData::new, LanternBlockItemData::new, ImmutableBlockItemData.class, LanternImmutableBlockItemData::new, LanternImmutableBlockItemData::new); register(BreakableData.class, LanternBreakableData::new, LanternBreakableData::new, LanternBreakableData::new, ImmutableBreakableData.class, LanternImmutableBreakableData::new, LanternImmutableBreakableData::new); register(CoalData.class, LanternCoalData::new, LanternCoalData::new, LanternCoalData::new, ImmutableCoalData.class, LanternImmutableCoalData::new, LanternImmutableCoalData::new); register(CookedFishData.class, LanternCookedFishData::new, LanternCookedFishData::new, LanternCookedFishData::new, ImmutableCookedFishData.class, LanternImmutableCookedFishData::new, LanternImmutableCookedFishData::new); register(DurabilityData.class, LanternDurabilityData::new, LanternDurabilityData::new, LanternDurabilityData::new, ImmutableDurabilityData.class, LanternImmutableDurabilityData::new, LanternImmutableDurabilityData::new); register(EnchantmentData.class, LanternEnchantmentData::new, LanternEnchantmentData::new, LanternEnchantmentData::new, ImmutableEnchantmentData.class, LanternImmutableEnchantmentData::new, LanternImmutableEnchantmentData::new); register(FishData.class, LanternFishData::new, LanternFishData::new, LanternFishData::new, ImmutableFishData.class, LanternImmutableFishData::new, LanternImmutableFishData::new); register(GenerationData.class, LanternGenerationData::new, LanternGenerationData::new, LanternGenerationData::new, ImmutableGenerationData.class, LanternImmutableGenerationData::new, LanternImmutableGenerationData::new); register(GoldenAppleData.class, LanternGoldenAppleData::new, LanternGoldenAppleData::new, LanternGoldenAppleData::new, ImmutableGoldenAppleData.class, LanternImmutableGoldenAppleData::new, LanternImmutableGoldenAppleData::new); register(HideData.class, LanternHideData::new, LanternHideData::new, LanternHideData::new, ImmutableHideData.class, LanternImmutableHideData::new, LanternImmutableHideData::new); register(InventoryItemData.class, LanternInventoryItemData::new, LanternInventoryItemData::new, LanternInventoryItemData::new, ImmutableInventoryItemData.class, LanternImmutableInventoryItemData::new, LanternImmutableInventoryItemData::new); register(LoreData.class, LanternLoreData::new, LanternLoreData::new, LanternLoreData::new, ImmutableLoreData.class, LanternImmutableLoreData::new, LanternImmutableLoreData::new); register(MapItemData.class, LanternMapItemData::new, LanternMapItemData::new, LanternMapItemData::new, ImmutableMapItemData.class, LanternImmutableMapItemData::new, LanternImmutableMapItemData::new); register(PagedData.class, LanternPagedData::new, LanternPagedData::new, LanternPagedData::new, ImmutablePagedData.class, LanternImmutablePagedData::new, LanternImmutablePagedData::new); register(PlaceableData.class, LanternPlaceableData::new, LanternPlaceableData::new, LanternPlaceableData::new, ImmutablePlaceableData.class, LanternImmutablePlaceableData::new, LanternImmutablePlaceableData::new); register(SpawnableData.class, LanternSpawnableData::new, LanternSpawnableData::new, LanternSpawnableData::new, ImmutableSpawnableData.class, LanternImmutableSpawnableData::new, LanternImmutableSpawnableData::new); register(StoredEnchantmentData.class, LanternStoredEnchantmentData::new, LanternStoredEnchantmentData::new, LanternStoredEnchantmentData::new, ImmutableStoredEnchantmentData.class, LanternImmutableStoredEnchantmentData::new, LanternImmutableStoredEnchantmentData::new); } public <M extends DataManipulator<M, I>, I extends ImmutableDataManipulator<I, M>> DataManipulatorRegistration<M, I> register( Class<M> manipulatorType, Supplier<M> manipulatorSupplier, Function<M, M> manipulatorCopyFunction, Function<I, M> immutableToMutableFunction, Class<I> immutableManipulatorType, Supplier<I> immutableManipulatorSupplier, Function<M, I> mutableToImmutableFunction) { checkNotNull(manipulatorType, "manipulatorType"); checkNotNull(manipulatorSupplier, "manipulatorSupplier"); checkNotNull(immutableManipulatorType, "immutableManipulatorType"); checkNotNull(immutableManipulatorSupplier, "immutableManipulatorSupplier"); final M manipulator = manipulatorSupplier.get(); checkArgument(manipulator instanceof IDataManipulator, "The mutable manipulator implementation must implement IDataManipulator."); //noinspection unchecked final Class<M> manipulatorType1 = ((IDataManipulator<M, I>) manipulator).getMutableType(); checkArgument(manipulatorType1 == manipulatorType, "The mutable data manipulator returns a different manipulator type, expected %s, but got %s", manipulatorType, manipulatorType1); final I immutableManipulator = immutableManipulatorSupplier.get(); checkArgument(immutableManipulator instanceof IImmutableDataManipulator, "The immutable manipulator implementation must implement IImmutableData."); //noinspection unchecked final Class<I> immutableManipulatorType1 = ((IImmutableDataManipulator<I, M>) immutableManipulator).getImmutableType(); checkArgument(immutableManipulatorType1 == immutableManipulatorType, "The immutable data manipulator returns a different manipulator type, expected %s, but got %s", immutableManipulatorType, immutableManipulatorType1); final Set<Key<?>> requiredKeys = new HashSet<>(manipulator.getKeys()); final DataManipulatorRegistration<M, I> registration = new DataManipulatorRegistration<>( manipulatorType, manipulatorSupplier, manipulatorCopyFunction, immutableToMutableFunction, immutableManipulatorType, immutableManipulatorSupplier, mutableToImmutableFunction, requiredKeys); this.registrationByClass.put(manipulatorType, registration); this.registrationByClass.put(immutableManipulatorType, registration); return registration; } public Collection<DataManipulatorRegistration> getAll() { return Collections.unmodifiableCollection(this.registrationByClass.values()); } public <M extends DataManipulator<M, I>, I extends ImmutableDataManipulator<I, M>> Optional<DataManipulatorRegistration<M, I>> getByMutable( Class<M> manipulatorType) { //noinspection unchecked return Optional.ofNullable(this.registrationByClass.get(checkNotNull(manipulatorType, "manipulatorType"))); } public <M extends DataManipulator<M, I>, I extends ImmutableDataManipulator<I, M>> Optional<DataManipulatorRegistration<M, I>> getByImmutable( Class<I> immutableManipulatorType) { //noinspection unchecked return Optional.ofNullable(this.registrationByClass.get(checkNotNull(immutableManipulatorType, "immutableManipulatorType"))); } }