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);
}
}
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);
}
}
}
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;
}
}
}
}
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;
}
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;
}
}
Aggregations