Search in sources :

Example 6 with ItemFrameInfo

use of com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo in project BKCommonLib by bergerhealer.

the class CommonMapController method fillItemFrames.

/**
 * Flood-fills all item frames with the same item that are considered to be a single map display
 * cluster. Empty item frames are filled into as well, and are considered to be part of the
 * start item frame. This allows an existing display to be enlarged.
 *
 * @param startItemFrame
 * @param item
 */
public synchronized void fillItemFrames(ItemFrame startItemFrame, ItemStack item) {
    if (!this.isFrameDisplaysEnabled) {
        throw new UnsupportedOperationException("Item frame map displays are disabled in BKCommonLib's configuration");
    }
    if (!this.isFrameTilingSupported) {
        throw new UnsupportedOperationException("Item frame map display tiling is disabled in BKCommonLib's configuration");
    }
    if (startItemFrame.isDead()) {
        throw new IllegalArgumentException("Input item frame was removed (dead)");
    }
    ItemFrameInfo info = this.getItemFrame(startItemFrame.getEntityId());
    if (info == null) {
        throw new IllegalStateException("Item frame had no metadata information for some reason");
    }
    // Find this item frame cluster
    ItemFrameCluster cluster = this.findCluster(info.itemFrameHandle, info.coordinates, true);
    for (ItemFrameInfo frame : this.findClusterItemFrames(cluster)) {
        // Update the item inside this item frame. Also schedule it for an instant refresh!
        // We could spin up the display and such here too, but let's keep it simple for now.
        frame.itemFrameHandle.setItem(item);
        frame.needsItemRefresh.set(true);
    }
}
Also used : ItemFrameInfo(com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo)

Example 7 with ItemFrameInfo

use of com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo 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 8 with ItemFrameInfo

use of com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo in project BKCommonLib by bergerhealer.

the class CommonMapController method onPacketSend.

@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public synchronized void onPacketSend(PacketSendEvent event) {
    // Check if any virtual single maps are attached to this map
    if (event.getType() == PacketType.OUT_MAP) {
        int itemid = event.getPacket().read(PacketType.OUT_MAP.mapId);
        this.storeStaticMapId(itemid);
    // This used to be used to just cancel interfering plugins
    // However, sometimes map data is sent before any item frame
    // set-item or similar packets. So, we'll have to act sooner.
    // 
    // Note that we send packets with an ignoreListeners flag, causing
    // such packets to not go through this listener.
    /*
            MapUUID mapUUID = mapUUIDById.get(itemid);
            if (mapUUID == null) {
                this.storeStaticMapId(itemid);
            } else if (CommonMapUUIDStore.getStaticMapId(mapUUID.getUUID()) == -1) {
                event.setCancelled(true);
            }
            */
    }
    // This is always tile 0,0 (held map)
    if (event.getType() == PacketType.OUT_WINDOW_ITEMS) {
        List<ItemStack> items = event.getPacket().read(PacketType.OUT_WINDOW_ITEMS.items);
        ListIterator<ItemStack> iter = items.listIterator();
        while (iter.hasNext()) {
            ItemStack newItem = this.handleItemSync(iter.next(), 0, 0);
            if (newItem != null) {
                iter.set(newItem);
            }
        }
    }
    if (event.getType() == PacketType.OUT_WINDOW_SET_SLOT) {
        ItemStack oldItem = event.getPacket().read(PacketType.OUT_WINDOW_SET_SLOT.item);
        ItemStack newItem = this.handleItemSync(oldItem, 0, 0);
        if (newItem != null) {
            event.getPacket().write(PacketType.OUT_WINDOW_SET_SLOT.item, newItem);
        }
    }
    // Correct the ItemStack displayed in Item Frames
    if (this.isFrameDisplaysEnabled && event.getType() == PacketType.OUT_ENTITY_METADATA) {
        int entityId = event.getPacket().read(PacketType.OUT_ENTITY_METADATA.entityId);
        ItemFrameInfo frameInfo = this.itemFrames.get(entityId);
        if (frameInfo == null) {
            // To prevent glitches, track that in the itemFrameMetaMisses set
            if (hasMapItemInMetadata(event.getPacket())) {
                itemFrameMetaMisses.add(entityId);
            }
            // no information available or not an item frame
            return;
        }
        // loaded on the main thread.
        if (frameInfo.lastFrameItemUpdateNeeded || frameInfo.requiresFurtherLoading || frameInfo.lastMapUUID == null) {
            // Map item metadata is sent, once the frame itself loads in, we must resend the item
            if (hasMapItemInMetadata(event.getPacket())) {
                frameInfo.sentMapInfoToPlayers = true;
            }
            // not yet loaded or not a map
            return;
        }
        // Presumed to contain a map item, so mark it that players have received it
        int staticMapId = CommonMapUUIDStore.getStaticMapId(frameInfo.lastMapUUID.getUUID());
        if (staticMapId != -1) {
            frameInfo.sentMapInfoToPlayers = true;
            this.storeStaticMapId(staticMapId);
            // static Id, not dynamic, no re-assignment
            return;
        }
        // Map Id is dynamically assigned, adjust metadata items to use this new Id
        // Avoid using any Bukkit or Wrapper types here for performance reasons
        int newMapId = this.getMapId(frameInfo.lastMapUUID);
        List<DataWatcher.Item<Object>> items = event.getPacket().read(PacketType.OUT_ENTITY_METADATA.watchedObjects);
        if (items != null) {
            ListIterator<DataWatcher.Item<Object>> itemsIter = items.listIterator();
            while (itemsIter.hasNext()) {
                DataWatcher.Item<ItemStack> item = itemsIter.next().translate(EntityItemFrameHandle.DATA_ITEM);
                if (item == null) {
                    continue;
                }
                // Check item is actually a map item and do some logic
                ItemStack metaItem = item.getValue();
                int oldMapId;
                if (metaItem == null || (oldMapId = CommonMapUUIDStore.getItemMapId(metaItem)) == -1) {
                    break;
                }
                // Map information is sent, if the map id we use differs, update it
                frameInfo.sentMapInfoToPlayers = true;
                if (oldMapId != newMapId) {
                    ItemStack newMapItem = ItemUtil.cloneItem(metaItem);
                    CommonMapUUIDStore.setItemMapId(newMapItem, newMapId);
                    item = item.clone();
                    item.setValue(newMapItem, item.isChanged());
                    itemsIter.set((DataWatcher.Item<Object>) (DataWatcher.Item) item);
                }
                break;
            }
        }
    }
}
Also used : ItemStack(org.bukkit.inventory.ItemStack) ItemFrameInfo(com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo) DataWatcher(com.bergerkiller.bukkit.common.wrappers.DataWatcher)

Example 9 with ItemFrameInfo

use of com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo 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)

Example 10 with ItemFrameInfo

use of com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo in project BKCommonLib by bergerhealer.

the class CommonMapController method onAddItemFrame.

private void onAddItemFrame(EntityItemFrameHandle frame) {
    int entityId = frame.getId();
    if (itemFrames.containsKey(entityId)) {
        return;
    }
    // Add Item Frame Info
    ItemFrameInfo frameInfo = new ItemFrameInfo(this, frame);
    itemFrames.put(entityId, frameInfo);
    itemFrameUpdateList.add(frameInfo.updateEntry);
    if (itemFrameMetaMisses.remove(entityId)) {
        frameInfo.needsItemRefresh.set(true);
        frameInfo.sentMapInfoToPlayers = true;
    }
}
Also used : ItemFrameInfo(com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo)

Aggregations

ItemFrameInfo (com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo)12 MapDisplayInfo (com.bergerkiller.bukkit.common.map.binding.MapDisplayInfo)4 MapSession (com.bergerkiller.bukkit.common.map.MapSession)3 MapUUID (com.bergerkiller.bukkit.common.map.util.MapUUID)3 EntityItemFrameHandle (com.bergerkiller.generated.net.minecraft.world.entity.decoration.EntityItemFrameHandle)3 ItemFrame (org.bukkit.entity.ItemFrame)3 ItemStack (org.bukkit.inventory.ItemStack)3 OfflineWorld (com.bergerkiller.bukkit.common.offline.OfflineWorld)2 DataWatcher (com.bergerkiller.bukkit.common.wrappers.DataWatcher)2 IntHashMap (com.bergerkiller.bukkit.common.wrappers.IntHashMap)2 OutputTypeMap (com.bergerkiller.mountiplex.reflection.util.OutputTypeMap)2 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 IdentityHashMap (java.util.IdentityHashMap)2 Map (java.util.Map)2 UUID (java.util.UUID)2 World (org.bukkit.World)2 Entity (org.bukkit.entity.Entity)2 Player (org.bukkit.entity.Player)2 PlayerInventory (org.bukkit.inventory.PlayerInventory)2