Search in sources :

Example 1 with EntityItemFrameHandle

use of com.bergerkiller.generated.net.minecraft.world.entity.decoration.EntityItemFrameHandle in project BKCommonLib by bergerhealer.

the class CommonMapController method initItemFrameSetOfWorld.

private final List<EntityItemFrameHandle> initItemFrameSetOfWorld(World world) {
    List<EntityItemFrameHandle> itemFrames = new ArrayList<EntityItemFrameHandle>();
    for (Object entityHandle : (Iterable<?>) WorldServerHandle.T.getEntities.raw.invoke(HandleConversion.toWorldHandle(world))) {
        if (EntityItemFrameHandle.T.isAssignableFrom(entityHandle)) {
            EntityItemFrameHandle itemFrame = EntityItemFrameHandle.createHandle(entityHandle);
            getItemFrameEntities(new ItemFrameClusterKey(itemFrame)).add(itemFrame);
            itemFrames.add(itemFrame);
        }
    }
    return itemFrames;
}
Also used : ArrayList(java.util.ArrayList) EntityItemFrameHandle(com.bergerkiller.generated.net.minecraft.world.entity.decoration.EntityItemFrameHandle)

Example 2 with EntityItemFrameHandle

use of com.bergerkiller.generated.net.minecraft.world.entity.decoration.EntityItemFrameHandle in project BKCommonLib by bergerhealer.

the class CommonMapController method findCluster.

/**
 * Finds a cluster of all connected item frames that an item frame is part of
 *
 * @param itemFrame Start item frame
 * @param itemFramePosition Start block position of itemFrame
 * @param includingEmpty Whether to include frames in the cluster that have no item
 * @return cluster
 */
public final synchronized ItemFrameCluster findCluster(final EntityItemFrameHandle itemFrame, final IntVector3 itemFramePosition, final boolean includingEmpty) {
    final Predicate<EntityItemFrameHandle> itemFrameFilter;
    if (includingEmpty && ItemUtil.isEmpty(itemFrame.getItem())) {
        // Proceed only filling empty item frames
        itemFrameFilter = e -> ItemUtil.isEmpty(e.getItem());
    } else {
        final UUID itemFrameMapUUID;
        if (this.isFrameTilingSupported && (itemFrameMapUUID = itemFrame.getItemMapDisplayDynamicOnlyUUID()) != null) {
            if (includingEmpty) {
                itemFrameFilter = e -> {
                    return itemFrameMapUUID.equals(e.getItemMapDisplayDynamicOnlyUUID()) || ItemUtil.isEmpty(e.getItem());
                };
            } else {
                itemFrameFilter = e -> {
                    return itemFrameMapUUID.equals(e.getItemMapDisplayDynamicOnlyUUID());
                };
            }
        } else {
            // no neighbours or tiling disabled
            return new ItemFrameCluster(OfflineWorld.of(itemFrame.getBukkitWorld()), itemFrame.getFacing(), Collections.singleton(itemFramePosition), 0);
        }
    }
    // Look up in cache first
    World world = itemFrame.getBukkitWorld();
    Map<IntVector3, ItemFrameCluster> cachedClusters;
    if (!includingEmpty && itemFrameClustersByWorldEnabled) {
        cachedClusters = itemFrameClustersByWorld.get(world);
        if (cachedClusters == null) {
            cachedClusters = new HashMap<>();
            itemFrameClustersByWorld.put(world, cachedClusters);
        }
        ItemFrameCluster fromCache = cachedClusters.get(itemFramePosition);
        if (fromCache != null) {
            return fromCache;
        }
    } else {
        cachedClusters = null;
    }
    // Take cache entry
    FindNeighboursCache cache = this.findNeighboursCache;
    if (cache != null) {
        cache.reset();
        this.findNeighboursCache = null;
    } else {
        cache = new FindNeighboursCache();
    }
    try {
        // Find all item frames that:
        // - Are on the same world as this item frame
        // - Facing the same way
        // - Along the same x/y/z (facing)
        // - Same ItemStack map UUID (or, if includingEmpty, are empty)
        ItemFrameClusterKey key = new ItemFrameClusterKey(world, itemFrame.getFacing(), itemFramePosition);
        for (EntityItemFrameHandle otherFrame : getItemFrameEntities(key)) {
            if (otherFrame.getId() != itemFrame.getId() && itemFrameFilter.test(otherFrame)) {
                cache.put(otherFrame);
            }
        }
        BlockFace[] neighbourAxis;
        if (FaceUtil.isAlongY(key.facing)) {
            neighbourAxis = NEIGHBOUR_AXIS_ALONG_Y;
        } else if (FaceUtil.isAlongX(key.facing)) {
            neighbourAxis = NEIGHBOUR_AXIS_ALONG_X;
        } else {
            neighbourAxis = NEIGHBOUR_AXIS_ALONG_Z;
        }
        // Find the most common item frame rotation in use
        // Only 4 possible rotations can be used for maps, so this is easy
        int[] rotation_counts = new int[4];
        rotation_counts[(new FindNeighboursCache.Frame(itemFrame)).rotation]++;
        // Make sure the neighbours result are a single contiguous blob
        // Islands (can not reach the input item frame) are removed
        Set<IntVector3> result = new HashSet<IntVector3>(cache.cache.size());
        result.add(itemFramePosition);
        cache.pendingList.add(itemFramePosition);
        do {
            IntVector3 pending = cache.pendingList.poll();
            for (BlockFace side : neighbourAxis) {
                IntVector3 sidePoint = pending.add(side);
                FindNeighboursCache.Frame frame = cache.cache.remove(sidePoint);
                if (frame != null) {
                    rotation_counts[frame.rotation]++;
                    cache.pendingList.add(sidePoint);
                    result.add(sidePoint);
                }
            }
        } while (!cache.pendingList.isEmpty());
        // Find maximum rotation index
        int rotation_idx = 0;
        for (int i = 1; i < rotation_counts.length; i++) {
            if (rotation_counts[i] > rotation_counts[rotation_idx]) {
                rotation_idx = i;
            }
        }
        // The final combined result
        ItemFrameCluster cluster = new ItemFrameCluster(OfflineWorld.of(key.world), key.facing, result, rotation_idx * 90);
        if (cachedClusters != null) {
            for (IntVector3 position : cluster.coordinates) {
                cachedClusters.put(position, cluster);
            }
        }
        return cluster;
    } finally {
        // Return to cache
        this.findNeighboursCache = cache;
    }
}
Also used : ItemFrame(org.bukkit.entity.ItemFrame) BlockFace(org.bukkit.block.BlockFace) World(org.bukkit.World) OfflineWorld(com.bergerkiller.bukkit.common.offline.OfflineWorld) EntityItemFrameHandle(com.bergerkiller.generated.net.minecraft.world.entity.decoration.EntityItemFrameHandle) MapUUID(com.bergerkiller.bukkit.common.map.util.MapUUID) UUID(java.util.UUID) IntVector3(com.bergerkiller.bukkit.common.bases.IntVector3) HashSet(java.util.HashSet)

Example 3 with EntityItemFrameHandle

use of com.bergerkiller.generated.net.minecraft.world.entity.decoration.EntityItemFrameHandle in project BKCommonLib by bergerhealer.

the class MapDisplayItemMapIdUpdater method updateMapIds.

public void updateMapIds() {
    // Remove non-existing maps from the internal mapping
    if (controller.idGenerationCounter > GENERATION_COUNTER_CLEANUP_INTERVAL) {
        controller.idGenerationCounter = 0;
        // Find all map UUIDs that exist on the server
        HashSet<MapUUID> validUUIDs = new HashSet<MapUUID>();
        for (Set<EntityItemFrameHandle> itemFrameSet : controller.itemFrameEntities.values()) {
            for (EntityItemFrameHandle itemFrame : itemFrameSet) {
                MapUUID mapUUID = controller.getItemFrameMapUUID(itemFrame);
                if (mapUUID != null) {
                    validUUIDs.add(mapUUID);
                }
            }
        }
        for (Player player : Bukkit.getOnlinePlayers()) {
            PlayerInventory inv = player.getInventory();
            for (int i = 0; i < inv.getSize(); i++) {
                ItemStack item = inv.getItem(i);
                UUID mapUUID = CommonMapUUIDStore.getMapUUID(item);
                if (mapUUID != null) {
                    validUUIDs.add(new MapUUID(mapUUID));
                }
            }
        }
        // Perform the cleanup (synchronized access required!)
        controller.cleanupUnusedUUIDs(validUUIDs);
    }
    // Refresh items known to clients when Map Ids are re-assigned
    // Swap around the tmp and main set every tick
    final SetMultimap<UUID, MapUUID> dirtyMaps = controller.swapDirtyMapUUIDs();
    if (!dirtyMaps.isEmpty()) {
        // This will result in new SetItemSlot packets being sent, refreshing the map Id
        for (Player player : Bukkit.getOnlinePlayers()) {
            PlayerInventory inv = player.getInventory();
            for (int i = 0; i < inv.getSize(); i++) {
                ItemStack item = inv.getItem(i);
                UUID uuid = CommonMapUUIDStore.getMapUUID(item);
                if (dirtyMaps.containsKey(uuid)) {
                    inv.setItem(i, item.clone());
                }
            }
        }
        // Refresh all item frames that display this map
        // This will result in a new EntityMetadata packets being sent, refreshing the map Id
        // After updating all item frames, resend the maps
        dirtyMaps.keySet().stream().map(controller.maps::get).filter(Objects::nonNull).forEach(info -> {
            // Refresh item of all affected item frames
            // This re-sends metadata packets
            final Set<MapUUID> mapUUIDs = dirtyMaps.get(info.getUniqueId());
            for (ItemFrameInfo itemFrameInfo : info.getItemFrames()) {
                if (mapUUIDs.contains(itemFrameInfo.lastMapUUID)) {
                    itemFrameInfo.itemFrameHandle.refreshItem();
                }
            }
            // Resend map data for all affected tiles
            for (MapSession session : info.getSessions()) {
                for (MapDisplayTile tile : session.tiles) {
                    if (mapUUIDs.contains(tile.getMapTileUUID())) {
                        session.onlineOwners.forEach(o -> o.sendDirtyTile(tile));
                    }
                }
            }
        });
        // Done processing, wipe
        dirtyMaps.clear();
    }
}
Also used : Player(org.bukkit.entity.Player) PlayerInventory(org.bukkit.inventory.PlayerInventory) MapSession(com.bergerkiller.bukkit.common.map.MapSession) ItemFrameInfo(com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo) MapUUID(com.bergerkiller.bukkit.common.map.util.MapUUID) EntityItemFrameHandle(com.bergerkiller.generated.net.minecraft.world.entity.decoration.EntityItemFrameHandle) ItemStack(org.bukkit.inventory.ItemStack) MapUUID(com.bergerkiller.bukkit.common.map.util.MapUUID) UUID(java.util.UUID) HashSet(java.util.HashSet) MapDisplayTile(com.bergerkiller.bukkit.common.map.MapDisplayTile)

Example 4 with EntityItemFrameHandle

use of com.bergerkiller.generated.net.minecraft.world.entity.decoration.EntityItemFrameHandle in project BKCommonLib by bergerhealer.

the class CommonMapController method onEntityRemoved.

@EventHandler(priority = EventPriority.MONITOR)
protected synchronized void onEntityRemoved(EntityRemoveEvent event) {
    if (event.getEntity() instanceof ItemFrame) {
        ItemFrame frame = (ItemFrame) event.getEntity();
        EntityItemFrameHandle frameHandle = EntityItemFrameHandle.fromBukkit(frame);
        getItemFrameEntities(new ItemFrameClusterKey(frameHandle)).remove(frameHandle);
        ItemFrameInfo info = itemFrames.get(frame.getEntityId());
        if (info != null) {
            info.removed = true;
            info.needsItemRefresh.set(false);
        }
    }
}
Also used : EntityItemFrameHandle(com.bergerkiller.generated.net.minecraft.world.entity.decoration.EntityItemFrameHandle) ItemFrame(org.bukkit.entity.ItemFrame) ItemFrameInfo(com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo) EventHandler(org.bukkit.event.EventHandler)

Example 5 with EntityItemFrameHandle

use of com.bergerkiller.generated.net.minecraft.world.entity.decoration.EntityItemFrameHandle in project BKCommonLib by bergerhealer.

the class CommonMapController method onEnable.

/**
 * Starts all continuous background update tasks for maps
 *
 * @param plugin
 * @param startedTasks
 */
public void onEnable(CommonPlugin plugin, List<Task> startedTasks) {
    this.isFrameTilingSupported = plugin.isFrameTilingSupported();
    this.isFrameDisplaysEnabled = plugin.isFrameDisplaysEnabled();
    plugin.register((Listener) this);
    plugin.register((PacketListener) this, PACKET_TYPES);
    plugin.register(new MapDisplayItemChangeListener(this));
    startedTasks.add(new MapDisplayHeldMapUpdater(plugin, this).start(1, 1));
    startedTasks.add(new MapDisplayItemMapIdUpdater(plugin, this).start(1, 1));
    startedTasks.add(new MapDisplayInputUpdater(plugin, this).start(1, 1));
    startedTasks.add(new MapDisplayCreativeDraggedMapItemCleaner(plugin, this).start(100, CreativeDraggedMapItem.CACHED_ITEM_CLEAN_INTERVAL));
    // These tasks only run when map displays on item frames are enabled
    if (this.isFrameDisplaysEnabled) {
        startedTasks.add(new MapDisplayFramedMapUpdater(plugin, this).start(1, 1));
        // every minute
        startedTasks.add(new ByWorldItemFrameSetRefresher(plugin).start(1200, 1200));
    }
    // Whether this sort of stuff is relevant at all, in case it's set from somewhere
    // Avoids a memory leak
    this.mapsWithItemFrameResolutionChanges.setEnabled(this.isFrameDisplaysEnabled && this.isFrameTilingSupported);
    this.mapsWithItemFrameViewerChanges.setEnabled(this.isFrameDisplaysEnabled);
    this.itemFramesThatNeedItemRefresh.setEnabled(this.isFrameDisplaysEnabled);
    // No actual initialization is done yet, this happens next tick cycle!
    if (this.isFrameDisplaysEnabled) {
        for (World world : Bukkit.getWorlds()) {
            for (EntityItemFrameHandle itemFrame : initItemFrameSetOfWorld(world)) {
                onAddItemFrame(itemFrame);
            }
        }
    }
    // This ensures updated map details are refreshed during the item update discovery
    if (CommonUtil.getServerTicks() > 0) {
        this.getItemFrames().forEach(info -> {
            if (CommonMapUUIDStore.isMap(getItemFrameItem(info.itemFrame))) {
                info.sentMapInfoToPlayers = true;
            }
        });
    }
    // If this is a reload, that means players have already been watching maps potentially
    // To minimize glitches and problems, restore the map id data from last run
    CommonMapReloadFile.load(plugin, reloadFile -> {
        // Static reserved ids (other plugins have been using it)
        for (Integer staticId : reloadFile.staticReservedIds) {
            storeStaticMapId(staticId.intValue());
        }
        // To avoid 'popping', make sure to pre-cache the same ones
        for (CommonMapReloadFile.DynamicMappedId dynamicMapId : reloadFile.dynamicMappedIds) {
            if (mapUUIDById.contains(dynamicMapId.id)) {
                // Already assigned, skip
                continue;
            }
            if (mapIdByUUID.containsKey(dynamicMapId.uuid)) {
                // Already assigned, skip
                continue;
            }
            // Store
            mapIdByUUID.put(dynamicMapId.uuid, dynamicMapId.id);
            mapUUIDById.put(dynamicMapId.id, dynamicMapId.uuid);
        }
        // Give a hint about Map UUID to avoid 'popping' when the item is refreshed
        for (CommonMapReloadFile.ItemFrameDisplayUUID displayUUID : reloadFile.itemFrameDisplayUUIDs) {
            ItemFrameInfo itemFrame = itemFrames.get(displayUUID.entityId);
            if (itemFrame != null) {
                itemFrame.preReloadMapUUID = displayUUID.uuid;
            }
        }
    });
    // Done!
    this.isEnabled = true;
}
Also used : World(org.bukkit.World) OfflineWorld(com.bergerkiller.bukkit.common.offline.OfflineWorld) ItemFrameInfo(com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo) EntityItemFrameHandle(com.bergerkiller.generated.net.minecraft.world.entity.decoration.EntityItemFrameHandle) CommonMapReloadFile(com.bergerkiller.bukkit.common.internal.CommonMapReloadFile)

Aggregations

EntityItemFrameHandle (com.bergerkiller.generated.net.minecraft.world.entity.decoration.EntityItemFrameHandle)6 ItemFrameInfo (com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo)3 ItemFrame (org.bukkit.entity.ItemFrame)3 MapUUID (com.bergerkiller.bukkit.common.map.util.MapUUID)2 OfflineWorld (com.bergerkiller.bukkit.common.offline.OfflineWorld)2 HashSet (java.util.HashSet)2 UUID (java.util.UUID)2 World (org.bukkit.World)2 EventHandler (org.bukkit.event.EventHandler)2 IntVector3 (com.bergerkiller.bukkit.common.bases.IntVector3)1 CommonMapReloadFile (com.bergerkiller.bukkit.common.internal.CommonMapReloadFile)1 MapDisplayTile (com.bergerkiller.bukkit.common.map.MapDisplayTile)1 MapSession (com.bergerkiller.bukkit.common.map.MapSession)1 ArrayList (java.util.ArrayList)1 BlockFace (org.bukkit.block.BlockFace)1 Player (org.bukkit.entity.Player)1 ItemStack (org.bukkit.inventory.ItemStack)1 PlayerInventory (org.bukkit.inventory.PlayerInventory)1