use of org.spongepowered.api.block.BlockSnapshot in project SpongeCommon by SpongePowered.
the class MixinBlockLiquid method onSetBlockState.
// Capture Lava and Water mixing forming CobbleStone or Obsidian
@Inject(method = "checkForMixing", cancellable = true, locals = LocalCapture.CAPTURE_FAILSOFT, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;)Z"))
private void onSetBlockState(World worldIn, BlockPos pos, IBlockState state, CallbackInfoReturnable<Boolean> cir, boolean flag, Integer integer) {
IBlockState newState = integer == 0 ? Blocks.OBSIDIAN.getDefaultState() : Blocks.COBBLESTONE.getDefaultState();
ChangeBlockEvent.Modify event = SpongeCommonEventFactory.callChangeBlockEventModifyLiquidMix(worldIn, pos, newState, null);
Transaction<BlockSnapshot> transaction = event.getTransactions().get(0);
if (event.isCancelled() || !transaction.isValid()) {
cir.setReturnValue(false);
return;
}
boolean success = worldIn.setBlockState(pos, BlockUtil.toNative(transaction.getFinal().getState()));
if (!success) {
cir.setReturnValue(false);
}
}
use of org.spongepowered.api.block.BlockSnapshot in project SpongeCommon by SpongePowered.
the class MixinEntityLightningBolt method onLivingTimeExpired.
@Inject(method = "onUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/effect/EntityLightningBolt;setDead()V"))
public void onLivingTimeExpired(CallbackInfo ci) {
if (this.isDead || this.world.isRemote) {
return;
}
Sponge.getCauseStackManager().pushCause(this);
LightningEvent.Strike strike = SpongeEventFactory.createLightningEventStrike(Sponge.getCauseStackManager().getCurrentCause(), this.struckEntities, this.struckBlocks);
Sponge.getEventManager().post(strike);
if (!strike.isCancelled()) {
for (Transaction<BlockSnapshot> bt : strike.getTransactions()) {
if (bt.isValid()) {
BlockSnapshot bs = bt.getFinal();
this.world.setBlockState(((IMixinLocation) (Object) bs.getLocation().get()).getBlockPos(), ((IBlockState) bs.getState()));
}
}
for (Entity e : strike.getEntities()) {
((net.minecraft.entity.Entity) e).onStruckByLightning((EntityLightningBolt) (Object) this);
}
SpongeImpl.postEvent(SpongeEventFactory.createLightningEventPost(Sponge.getCauseStackManager().getCurrentCause()));
}
Sponge.getCauseStackManager().popCause();
}
use of org.spongepowered.api.block.BlockSnapshot in project SpongeCommon by SpongePowered.
the class EntityTickPhaseState method unwind.
@SuppressWarnings("unchecked")
@Override
public void unwind(EntityTickContext phaseContext) {
final Entity tickingEntity = phaseContext.getSource(Entity.class).orElseThrow(TrackingUtil.throwWithContext("Not ticking on an Entity!", phaseContext));
final Optional<User> creator = phaseContext.getOwner();
final Optional<User> notifier = phaseContext.getNotifier();
final User entityCreator = notifier.orElseGet(() -> creator.orElse(null));
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(tickingEntity);
phaseContext.addNotifierAndOwnerToCauseStack();
phaseContext.getCapturedEntitySupplier().acceptAndClearIfNotEmpty(entities -> {
final List<Entity> experience = new ArrayList<Entity>(entities.size());
final List<Entity> nonExp = new ArrayList<Entity>(entities.size());
final List<Entity> breeding = new ArrayList<Entity>(entities.size());
final List<Entity> projectile = new ArrayList<Entity>(entities.size());
for (Entity entity : entities) {
if (entity instanceof EntityXPOrb) {
experience.add(entity);
} else if (tickingEntity instanceof Ageable && tickingEntity.getClass() == entity.getClass()) {
breeding.add(entity);
} else if (entity instanceof Projectile) {
projectile.add(entity);
} else {
nonExp.add(entity);
}
}
if (!experience.isEmpty()) {
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.EXPERIENCE);
if (EntityUtil.isEntityDead(tickingEntity)) {
if (tickingEntity instanceof EntityLivingBase) {
CombatEntry entry = ((EntityLivingBase) tickingEntity).getCombatTracker().getBestCombatEntry();
if (entry != null) {
if (entry.damageSrc != null) {
Sponge.getCauseStackManager().addContext(EventContextKeys.LAST_DAMAGE_SOURCE, (DamageSource) entry.damageSrc);
}
}
}
}
final SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), experience);
if (!SpongeImpl.postEvent(event)) {
for (Entity entity : event.getEntities()) {
if (entityCreator != null) {
EntityUtil.toMixin(entity).setCreator(entityCreator.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
Sponge.getCauseStackManager().removeContext(EventContextKeys.LAST_DAMAGE_SOURCE);
}
if (!breeding.isEmpty()) {
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.BREEDING);
if (tickingEntity instanceof EntityAnimal) {
final EntityPlayer playerInLove = ((EntityAnimal) tickingEntity).getLoveCause();
if (playerInLove != null) {
Sponge.getCauseStackManager().addContext(EventContextKeys.PLAYER, (Player) playerInLove);
}
}
SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), breeding);
if (!SpongeImpl.postEvent(event)) {
for (Entity entity : event.getEntities()) {
if (entityCreator != null) {
EntityUtil.toMixin(entity).setCreator(entityCreator.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
Sponge.getCauseStackManager().removeContext(EventContextKeys.PLAYER);
}
if (!projectile.isEmpty()) {
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.PROJECTILE);
final SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), projectile);
SpongeImpl.postEvent(event);
if (!event.isCancelled()) {
for (Entity entity : event.getEntities()) {
if (entityCreator != null) {
entity.setCreator(entityCreator.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
}
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.PASSIVE);
final SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), nonExp);
SpongeImpl.postEvent(event);
if (!event.isCancelled()) {
for (Entity entity : event.getEntities()) {
if (entityCreator != null) {
entity.setCreator(entityCreator.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
});
phaseContext.getCapturedItemsSupplier().acceptAndClearIfNotEmpty(entities -> {
final ArrayList<Entity> capturedEntities = new ArrayList<>();
for (EntityItem entity : entities) {
capturedEntities.add(EntityUtil.fromNative(entity));
}
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.DROPPED_ITEM);
final DropItemEvent.Custom event = SpongeEventFactory.createDropItemEventCustom(Sponge.getCauseStackManager().getCurrentCause(), capturedEntities);
SpongeImpl.postEvent(event);
if (!event.isCancelled()) {
for (Entity entity : event.getEntities()) {
if (entityCreator != null) {
EntityUtil.toMixin(entity).setCreator(entityCreator.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
});
phaseContext.getCapturedBlockSupplier().acceptAndClearIfNotEmpty(blockSnapshots -> TrackingUtil.processBlockCaptures(blockSnapshots, this, phaseContext));
phaseContext.getBlockItemDropSupplier().acceptIfNotEmpty(map -> {
final List<BlockSnapshot> capturedBlocks = phaseContext.getCapturedBlocks();
for (BlockSnapshot snapshot : capturedBlocks) {
final BlockPos blockPos = ((IMixinLocation) (Object) snapshot.getLocation().get()).getBlockPos();
final Collection<EntityItem> entityItems = map.get(blockPos);
if (!entityItems.isEmpty()) {
Sponge.getCauseStackManager().pushCause(snapshot);
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.DROPPED_ITEM);
final List<Entity> items = entityItems.stream().map(EntityUtil::fromNative).collect(Collectors.toList());
final DropItemEvent.Destruct event = SpongeEventFactory.createDropItemEventDestruct(Sponge.getCauseStackManager().getCurrentCause(), items);
SpongeImpl.postEvent(event);
if (!event.isCancelled()) {
for (Entity entity : event.getEntities()) {
creator.ifPresent(user -> entity.setCreator(user.getUniqueId()));
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
Sponge.getCauseStackManager().popCause();
}
}
});
phaseContext.getCapturedItemStackSupplier().acceptAndClearIfNotEmpty(drops -> {
final List<EntityItem> items = drops.stream().map(drop -> drop.create(EntityUtil.getMinecraftWorld(tickingEntity))).collect(Collectors.toList());
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.DROPPED_ITEM);
final List<Entity> entities = (List<Entity>) (List<?>) items;
if (!entities.isEmpty()) {
DropItemEvent.Custom event = SpongeEventFactory.createDropItemEventCustom(Sponge.getCauseStackManager().getCurrentCause(), entities);
SpongeImpl.postEvent(event);
if (!event.isCancelled()) {
for (Entity droppedItem : event.getEntities()) {
EntityUtil.getMixinWorld(droppedItem).forceSpawnEntity(droppedItem);
}
}
}
});
this.fireMovementEvents(EntityUtil.toNative(tickingEntity));
}
}
use of org.spongepowered.api.block.BlockSnapshot in project SpongeCommon by SpongePowered.
the class EntityUtil method handleDisplaceEntityPortalEvent.
@Nullable
public static MoveEntityEvent.Teleport.Portal handleDisplaceEntityPortalEvent(Entity entityIn, int targetDimensionId, @Nullable Teleporter teleporter) {
SpongeImplHooks.registerPortalAgentType(teleporter);
final MinecraftServer mcServer = SpongeImpl.getServer();
final IMixinPlayerList mixinPlayerList = (IMixinPlayerList) mcServer.getPlayerList();
final IMixinEntity mixinEntity = (IMixinEntity) entityIn;
final Transform<World> fromTransform = mixinEntity.getTransform();
final WorldServer fromWorld = ((WorldServer) entityIn.world);
final IMixinWorldServer fromMixinWorld = (IMixinWorldServer) fromWorld;
boolean sameDimension = entityIn.dimension == targetDimensionId;
// handle the end
if (targetDimensionId == 1 && fromWorld.provider instanceof WorldProviderEnd) {
targetDimensionId = 0;
}
WorldServer toWorld = mcServer.getWorld(targetDimensionId);
// not being loaded then short-circuit to prevent unnecessary logic from running
if (!sameDimension && fromWorld == toWorld) {
return null;
}
if (teleporter == null) {
teleporter = toWorld.getDefaultTeleporter();
}
final Map<String, String> portalAgents = fromMixinWorld.getActiveConfig().getConfig().getWorld().getPortalAgents();
String worldName = "";
String teleporterClassName = teleporter.getClass().getName();
// check for new destination in config
if (teleporterClassName.equals("net.minecraft.world.Teleporter")) {
worldName = portalAgents.get("minecraft:default_" + toWorld.provider.getDimensionType().getName().toLowerCase(Locale.ENGLISH));
if (worldName == null && toWorld.provider instanceof WorldProviderHell) {
worldName = portalAgents.get("minecraft:default_nether");
}
} else {
// custom
worldName = portalAgents.get("minecraft:" + teleporter.getClass().getSimpleName());
}
if (worldName != null && !worldName.equals("")) {
for (WorldProperties worldProperties : Sponge.getServer().getAllWorldProperties()) {
if (worldProperties.getWorldName().equalsIgnoreCase(worldName)) {
Optional<World> spongeWorld = Sponge.getServer().loadWorld(worldProperties);
if (spongeWorld.isPresent()) {
toWorld = (WorldServer) spongeWorld.get();
teleporter = toWorld.getDefaultTeleporter();
if (fromWorld.provider.isNether() || toWorld.provider.isNether()) {
((IMixinTeleporter) teleporter).setNetherPortalType(true);
} else {
((IMixinTeleporter) teleporter).setNetherPortalType(false);
}
}
}
}
}
adjustEntityPostionForTeleport(mixinPlayerList, entityIn, fromWorld, toWorld);
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame();
TeleportingContext context = EntityPhase.State.CHANGING_DIMENSION.createPhaseContext().setTargetWorld(toWorld).buildAndSwitch()) {
Sponge.getCauseStackManager().pushCause(teleporter);
Sponge.getCauseStackManager().pushCause(mixinEntity);
Sponge.getCauseStackManager().addContext(EventContextKeys.TELEPORT_TYPE, TeleportTypes.PORTAL);
if (entityIn.isEntityAlive() && !(fromWorld.provider instanceof WorldProviderEnd)) {
fromWorld.profiler.startSection("placing");
// Note: We must always use placeInPortal to support mods.
if (!((IMixinTeleporter) teleporter).isVanilla() || entityIn.getLastPortalVec() != null) {
teleporter.placeInPortal(entityIn, entityIn.rotationYaw);
}
fromWorld.profiler.endSection();
}
// Complete phases, just because we need to. The phases don't actually do anything, because the processing resides here.
// Grab the exit location of entity after being placed into portal
final Transform<World> portalExitTransform = mixinEntity.getTransform().setExtent((World) toWorld);
// Use setLocationAndAngles to avoid firing MoveEntityEvent to plugins
mixinEntity.setLocationAndAngles(fromTransform);
final MoveEntityEvent.Teleport.Portal event = SpongeEventFactory.createMoveEntityEventTeleportPortal(Sponge.getCauseStackManager().getCurrentCause(), fromTransform, portalExitTransform, (PortalAgent) teleporter, mixinEntity, true);
SpongeImpl.postEvent(event);
final Vector3i chunkPosition = mixinEntity.getLocation().getChunkPosition();
final IMixinTeleporter toMixinTeleporter = (IMixinTeleporter) teleporter;
final List<BlockSnapshot> capturedBlocks = context.getCapturedBlocks();
final Transform<World> toTransform = event.getToTransform();
if (event.isCancelled()) {
// We need to make sure to only restore the location if
if (!portalExitTransform.getExtent().getUniqueId().equals(mixinEntity.getLocation().getExtent().getUniqueId())) {
// update cache
((IMixinTeleporter) teleporter).removePortalPositionFromCache(ChunkPos.asLong(chunkPosition.getX(), chunkPosition.getZ()));
if (!capturedBlocks.isEmpty()) {
for (BlockSnapshot original : Lists.reverse(capturedBlocks)) {
original.restore(true, BlockChangeFlags.NONE);
}
capturedBlocks.clear();
}
mixinEntity.setLocationAndAngles(fromTransform);
} else {
// Call setTransform to let plugins know mods changed the position
// Guarantees plugins such as Nucleus can track changed locations properly
mixinEntity.setTransform(mixinEntity.getTransform());
}
return event;
}
if (!portalExitTransform.equals(toTransform)) {
// if plugin set to same world, just set the transform
if (fromWorld == toTransform.getExtent()) {
// force cancel so we know to skip remaining logic
event.setCancelled(true);
// update cache
toMixinTeleporter.removePortalPositionFromCache(ChunkPos.asLong(chunkPosition.getX(), chunkPosition.getZ()));
// Undo created portal
if (!capturedBlocks.isEmpty()) {
for (BlockSnapshot original : Lists.reverse(capturedBlocks)) {
original.restore(true, BlockChangeFlags.NONE);
}
}
capturedBlocks.clear();
mixinEntity.setLocationAndAngles(toTransform);
return event;
}
} else {
if (toWorld.provider instanceof WorldProviderEnd) {
BlockPos blockpos = entityIn.world.getTopSolidOrLiquidBlock(toWorld.getSpawnPoint());
entityIn.moveToBlockPosAndAngles(blockpos, entityIn.rotationYaw, entityIn.rotationPitch);
}
}
if (!capturedBlocks.isEmpty() && !TrackingUtil.processBlockCaptures(capturedBlocks, EntityPhase.State.CHANGING_DIMENSION, context)) {
toMixinTeleporter.removePortalPositionFromCache(ChunkPos.asLong(chunkPosition.getX(), chunkPosition.getZ()));
}
if (!event.getKeepsVelocity()) {
entityIn.motionX = 0;
entityIn.motionY = 0;
entityIn.motionZ = 0;
}
return event;
}
}
use of org.spongepowered.api.block.BlockSnapshot in project SpongeCommon by SpongePowered.
the class PacketUtil method firePreEvents.
private static boolean firePreEvents(Packet<?> packetIn, EntityPlayerMP playerMP) {
if (packetIn instanceof CPacketAnimation) {
CPacketAnimation packet = (CPacketAnimation) packetIn;
SpongeCommonEventFactory.lastAnimationPacketTick = SpongeImpl.getServer().getTickCounter();
SpongeCommonEventFactory.lastAnimationPlayer = new WeakReference<>(playerMP);
HandType handType = packet.getHand() == EnumHand.MAIN_HAND ? HandTypes.MAIN_HAND : HandTypes.OFF_HAND;
final ItemStack heldItem = playerMP.getHeldItem(packet.getHand());
Sponge.getCauseStackManager().addContext(EventContextKeys.USED_ITEM, ItemStackUtil.snapshotOf(heldItem));
AnimateHandEvent event = SpongeEventFactory.createAnimateHandEvent(Sponge.getCauseStackManager().getCurrentCause(), handType, (Humanoid) playerMP);
if (SpongeImpl.postEvent(event)) {
return true;
}
return false;
} else if (packetIn instanceof CPacketPlayerDigging) {
SpongeCommonEventFactory.lastPrimaryPacketTick = SpongeImpl.getServer().getTickCounter();
CPacketPlayerDigging packet = (CPacketPlayerDigging) packetIn;
ItemStack stack = playerMP.getHeldItemMainhand();
Sponge.getCauseStackManager().addContext(EventContextKeys.USED_ITEM, ItemStackUtil.snapshotOf(stack));
switch(packet.getAction()) {
case DROP_ITEM:
case DROP_ALL_ITEMS:
if (!stack.isEmpty() && !playerMP.isSpectator()) {
((IMixinEntityPlayerMP) playerMP).setPacketItem(stack.copy());
}
return false;
case START_DESTROY_BLOCK:
case ABORT_DESTROY_BLOCK:
case STOP_DESTROY_BLOCK:
final BlockPos pos = packet.getPosition();
final Vector3d interactionPoint = VecHelper.toVector3d(pos);
final BlockSnapshot blockSnapshot = new Location<>((World) playerMP.world, interactionPoint).createSnapshot();
final RayTraceResult result = SpongeImplHooks.rayTraceEyes(playerMP, SpongeImplHooks.getBlockReachDistance(playerMP));
if (SpongeCommonEventFactory.callInteractItemEventPrimary(playerMP, stack, EnumHand.MAIN_HAND, result == null ? null : VecHelper.toVector3d(result.hitVec), blockSnapshot).isCancelled()) {
((IMixinEntityPlayerMP) playerMP).sendBlockChange(pos, playerMP.world.getBlockState(pos));
return true;
}
double d0 = playerMP.posX - ((double) pos.getX() + 0.5D);
double d1 = playerMP.posY - ((double) pos.getY() + 0.5D) + 1.5D;
double d2 = playerMP.posZ - ((double) pos.getZ() + 0.5D);
double d3 = d0 * d0 + d1 * d1 + d2 * d2;
double dist = SpongeImplHooks.getBlockReachDistance(playerMP) + 1;
dist *= dist;
if (d3 > dist) {
return true;
} else if (pos.getY() >= SpongeImpl.getServer().getBuildLimit()) {
return true;
}
if (packet.getAction() == CPacketPlayerDigging.Action.START_DESTROY_BLOCK) {
if (SpongeCommonEventFactory.callInteractBlockEventPrimary(playerMP, blockSnapshot, EnumHand.MAIN_HAND, packet.getFacing(), result == null ? null : VecHelper.toVector3d(result.hitVec)).isCancelled()) {
((IMixinEntityPlayerMP) playerMP).sendBlockChange(pos, playerMP.world.getBlockState(pos));
return true;
}
}
return false;
default:
break;
}
} else if (packetIn instanceof CPacketPlayerTryUseItem) {
CPacketPlayerTryUseItem packet = (CPacketPlayerTryUseItem) packetIn;
SpongeCommonEventFactory.lastSecondaryPacketTick = SpongeImpl.getServer().getTickCounter();
long packetDiff = System.currentTimeMillis() - lastTryBlockPacketTimeStamp;
// If the time between packets is small enough, use the last result.
if (packetDiff < 100) {
// Use previous result and avoid firing a second event
return lastTryBlockPacketItemResult;
}
final ItemStack heldItem = playerMP.getHeldItem(packet.getHand());
Sponge.getCauseStackManager().addContext(EventContextKeys.USED_ITEM, ItemStackUtil.snapshotOf(heldItem));
final RayTraceResult result = SpongeImplHooks.rayTraceEyes(playerMP, SpongeImplHooks.getBlockReachDistance(playerMP));
final boolean isCancelled = SpongeCommonEventFactory.callInteractItemEventSecondary(playerMP, heldItem, packet.getHand(), result == null ? null : VecHelper.toVector3d(result.hitVec), BlockSnapshot.NONE).isCancelled();
SpongeCommonEventFactory.callInteractBlockEventSecondary(playerMP, heldItem, result == null ? null : VecHelper.toVector3d(result.hitVec), BlockSnapshot.NONE, Direction.NONE, packet.getHand());
if (isCancelled) {
// Multiple slots may have been changed on the client. Right
// clicking armor is one example - the client changes it
// without the server telling it to.
playerMP.sendAllContents(playerMP.openContainer, playerMP.openContainer.getInventory());
return true;
}
} else if (packetIn instanceof CPacketPlayerTryUseItemOnBlock) {
CPacketPlayerTryUseItemOnBlock packet = (CPacketPlayerTryUseItemOnBlock) packetIn;
lastTryBlockPacketTimeStamp = System.currentTimeMillis();
SpongeCommonEventFactory.lastSecondaryPacketTick = SpongeImpl.getServer().getTickCounter();
Vector3d interactionPoint = VecHelper.toVector3d(packet.getPos());
final RayTraceResult result = SpongeImplHooks.rayTraceEyes(playerMP, SpongeImplHooks.getBlockReachDistance(playerMP));
BlockSnapshot blockSnapshot = new Location<>((World) playerMP.world, interactionPoint).createSnapshot();
final ItemStack heldItem = playerMP.getHeldItem(packet.getHand());
Sponge.getCauseStackManager().addContext(EventContextKeys.USED_ITEM, ItemStackUtil.snapshotOf(heldItem));
boolean isCancelled = SpongeCommonEventFactory.callInteractItemEventSecondary(playerMP, heldItem, packet.getHand(), result == null ? null : VecHelper.toVector3d(result.hitVec), blockSnapshot).isCancelled();
lastTryBlockPacketItemResult = isCancelled;
if (isCancelled) {
// update client
BlockPos pos = packet.getPos();
playerMP.connection.sendPacket(new SPacketBlockChange(playerMP.world, pos));
playerMP.connection.sendPacket(new SPacketBlockChange(playerMP.world, pos.offset(packet.getDirection())));
// See above
playerMP.sendAllContents(playerMP.openContainer, playerMP.openContainer.getInventory());
return true;
}
}
return false;
}
Aggregations