use of org.spongepowered.common.event.tracking.context.ItemDropData in project SpongeCommon by SpongePowered.
the class MixinSpongeImplHooks_Item_Pre_Merge method addItemStackToListForSpawning.
/**
* @author gabizou - April 7th, 2016
* @reason Iterates over the collection to find possible matches for any merges that can take place.
*
* @param itemStacks The collection of item stacks to add on to
* @param data The item stack being merged in
*/
@Overwrite
public static void addItemStackToListForSpawning(Collection<ItemDropData> itemStacks, ItemDropData data) {
final net.minecraft.item.ItemStack itemStack = data.getStack();
if (itemStack.isEmpty()) {
return;
}
boolean addToList = true;
final boolean isPlayerDrop = data instanceof ItemDropData.Player;
if (itemStacks.isEmpty()) {
itemStacks.add(data);
return;
}
for (ItemDropData existingData : itemStacks) {
final net.minecraft.item.ItemStack existing = existingData.getStack();
if (existing.isEmpty()) {
continue;
}
final boolean isExistingPlayer = existingData instanceof ItemDropData.Player;
if (isExistingPlayer && !isPlayerDrop || !isExistingPlayer && isPlayerDrop) {
continue;
}
if (isExistingPlayer) {
final ItemDropData.Player existingPlayerData = (ItemDropData.Player) existingData;
final ItemDropData.Player playerData = (ItemDropData.Player) data;
if (existingPlayerData.isTrace() ^ playerData.isTrace()) {
continue;
}
if (existingPlayerData.isDropAround() ^ playerData.isDropAround()) {
continue;
}
}
if (existing.getItem() != itemStack.getItem()) {
continue;
} else if (existing.hasTagCompound() ^ itemStack.hasTagCompound()) {
continue;
} else if (existing.hasTagCompound() && !existing.getTagCompound().equals(itemStack.getTagCompound())) {
continue;
} else if (existing.isEmpty()) {
continue;
} else if (existing.getItem().getHasSubtypes() && existing.getMetadata() != itemStack.getMetadata()) {
continue;
}
// now to actually merge the itemstacks
final int existingStackSize = existing.getCount();
final int addingStackSize = itemStack.getCount();
final int existingMaxStackSize = existing.getMaxStackSize();
final int proposedStackSize = existingStackSize + addingStackSize;
if (existingMaxStackSize < proposedStackSize) {
existing.setCount(existingMaxStackSize);
itemStack.setCount(proposedStackSize - existingMaxStackSize);
addToList = true;
// Basically, if we are overflowing the current existing stack, we can delegate to the
// next "equals" item stack to potentially merge into that stack as well
} else {
existing.setCount(proposedStackSize);
itemStack.setCount(0);
addToList = false;
break;
}
}
if (addToList) {
if (!itemStack.isEmpty() || itemStack.getCount() > 0) {
itemStacks.add(data);
}
}
}
use of org.spongepowered.common.event.tracking.context.ItemDropData in project SpongeForge by SpongePowered.
the class MixinItemShears method itemInteractionForEntity.
/**
* @author gabizou - June 21st, 2016
* @reason Rewrites the forge handling of this to properly handle
* when sheared drops are captured by whatever current phase the
* {@link PhaseTracker} is in.
*
* Returns true if the item can be used on the given entity, e.g. shears on sheep.
*/
@Overwrite
@Override
public boolean itemInteractionForEntity(ItemStack itemstack, EntityPlayer player, EntityLivingBase entity, EnumHand hand) {
if (entity.world.isRemote) {
return false;
}
if (entity instanceof IShearable) {
IShearable target = (IShearable) entity;
BlockPos pos = new BlockPos(entity.posX, entity.posY, entity.posZ);
if (target.isShearable(itemstack, entity.world, pos)) {
List<ItemStack> drops = target.onSheared(itemstack, entity.world, pos, EnchantmentHelper.getEnchantmentLevel(Enchantments.FORTUNE, itemstack));
// Sponge Start - Handle drops according to the current phase
final PhaseTracker phaseTracker = PhaseTracker.getInstance();
final PhaseData currentData = phaseTracker.getCurrentPhaseData();
final IPhaseState<?> currentState = currentData.state;
final PhaseContext<?> phaseContext = currentData.context;
final Random random = EntityUtil.fromNative(entity).getRandom();
final IMixinEntity mixinEntity = EntityUtil.toMixin(entity);
final double posX = entity.posX;
final double posY = entity.posY + 1.0F;
final double posZ = entity.posZ;
final Vector3d position = new Vector3d(posX, posY, posZ);
// Now the real fun begins.
for (ItemStack drop : drops) {
final ItemStack item;
if (!drop.isEmpty()) {
try (final CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
// FIRST we want to throw the DropItemEvent.PRE
final ItemStackSnapshot snapshot = ItemStackUtil.snapshotOf(drop);
final List<ItemStackSnapshot> original = new ArrayList<>();
original.add(snapshot);
Sponge.getCauseStackManager().pushCause(entity);
final DropItemEvent.Pre dropEvent = SpongeEventFactory.createDropItemEventPre(Sponge.getCauseStackManager().getCurrentCause(), ImmutableList.of(snapshot), original);
if (dropEvent.isCancelled()) {
continue;
}
// SECOND throw the ConstructEntityEvent
Transform<World> suggested = new Transform<>(mixinEntity.getWorld(), position);
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, SpawnTypes.DROPPED_ITEM);
ConstructEntityEvent.Pre event = SpongeEventFactory.createConstructEntityEventPre(Sponge.getCauseStackManager().getCurrentCause(), EntityTypes.ITEM, suggested);
SpongeImpl.postEvent(event);
item = event.isCancelled() ? null : ItemStackUtil.fromSnapshotToNative(dropEvent.getDroppedItems().get(0));
}
} else {
continue;
}
if (item == null) {
continue;
}
if (!item.isEmpty()) {
if (!currentState.ignoresItemPreMerging() && SpongeImpl.getGlobalConfig().getConfig().getOptimizations().doDropsPreMergeItemDrops()) {
if (currentState.tracksEntitySpecificDrops()) {
final Multimap<UUID, ItemDropData> multimap = phaseContext.getCapturedEntityDropSupplier().get();
final Collection<ItemDropData> itemStacks = multimap.get(entity.getUniqueID());
SpongeImplHooks.addItemStackToListForSpawning(itemStacks, ItemDropData.item(item).motion(new Vector3d((random.nextFloat() - random.nextFloat()) * 0.1F, random.nextFloat() * 0.05F, (random.nextFloat() - random.nextFloat()) * 0.1F)).position(new Vector3d(posX, posY, posZ)).build());
continue;
}
final List<ItemDropData> itemStacks = phaseContext.getCapturedItemStackSupplier().get();
SpongeImplHooks.addItemStackToListForSpawning(itemStacks, ItemDropData.item(item).position(new Vector3d(posX, posY, posZ)).motion(new Vector3d((random.nextFloat() - random.nextFloat()) * 0.1F, random.nextFloat() * 0.05F, (random.nextFloat() - random.nextFloat()) * 0.1F)).build());
continue;
}
EntityItem entityitem = new EntityItem(entity.world, posX, posY, posZ, item);
entityitem.setDefaultPickupDelay();
entityitem.motionY += random.nextFloat() * 0.05F;
entityitem.motionX += (random.nextFloat() - random.nextFloat()) * 0.1F;
entityitem.motionZ += (random.nextFloat() - random.nextFloat()) * 0.1F;
// FIFTH - Capture the entity maybe?
if (currentState.doesCaptureEntityDrops()) {
if (currentState.tracksEntitySpecificDrops()) {
// We are capturing per entity drop
phaseContext.getCapturedEntityItemDropSupplier().get().put(entity.getUniqueID(), entityitem);
} else {
// We are adding to a general list - usually for EntityPhase.State.DEATH
phaseContext.getCapturedItemsSupplier().get().add(entityitem);
}
// Return the item, even if it wasn't spawned in the world.
continue;
}
// FINALLY - Spawn the entity in the world if all else didn't fail
entity.world.spawnEntity(entityitem);
}
}
// Sponge End
itemstack.damageItem(1, entity);
}
return true;
}
return false;
}
Aggregations