Search in sources :

Example 16 with CauseStack

use of org.lanternpowered.server.event.CauseStack in project LanternServer by LanternPowered.

the class PlayerContainerSession method setRawOpenContainer.

private boolean setRawOpenContainer(CauseStack causeStack, @Nullable LanternContainer container, boolean sendClose, boolean client) {
    try (CauseStack.Frame frame = causeStack.pushCauseFrame()) {
        if (this.openContainer != container) {
            frame.addContext(EventContextKeys.PLAYER, this.player);
            ItemStackSnapshot cursorItem = ItemStackSnapshot.NONE;
            if (this.openContainer != null) {
                final ItemStackSnapshot cursorItemSnapshot = this.openContainer.getCursorSlot().peek().map(LanternItemStackSnapshot::wrap).orElse(LanternItemStackSnapshot.none());
                final InteractInventoryEvent.Close event = SpongeEventFactory.createInteractInventoryEventClose(frame.getCurrentCause(), new Transaction<>(cursorItemSnapshot, ItemStackSnapshot.NONE), this.openContainer);
                Sponge.getEventManager().post(event);
                if (event.isCancelled()) {
                    // Stop the client from closing the container, resend the open message
                    if (client) {
                        // This can't be done to the player inventory, player inventory uses index 0
                        // The optional should always return something at this point, otherwise
                        // something is broken
                        final ClientContainer clientContainer = getClientContainer();
                        if (clientContainer.getContainerId() != 0) {
                            // Reinitialize the client container
                            clientContainer.init();
                            return false;
                        }
                    } else {
                        // Just return
                        return false;
                    }
                }
                final Transaction<ItemStackSnapshot> transaction = event.getCursorTransaction();
                if (transaction.isValid()) {
                    if (transaction.getFinal().isEmpty()) {
                        // Add the event that caused the drop to the cause
                        frame.pushCause(event);
                        LanternEventHelper.handleDroppedItemSpawning(this.player.getTransform(), transaction.getOriginal());
                        frame.popCause();
                    } else {
                        cursorItem = transaction.getFinal();
                    }
                }
                // Close the inventory
                this.openContainer.close(causeStack);
            } else {
                sendClose = false;
            }
            if (container != null) {
                final Transaction<ItemStackSnapshot> cursorTransaction = new Transaction<>(ItemStackSnapshot.NONE, cursorItem);
                final InteractInventoryEvent.Open event = SpongeEventFactory.createInteractInventoryEventOpen(frame.getCurrentCause(), cursorTransaction, container);
                Sponge.getEventManager().post(event);
                if (event.isCancelled()) {
                    if (cursorTransaction.isValid()) {
                        final ItemStackSnapshot cursorItem1 = cursorTransaction.getFinal();
                        if (!cursorItem1.isEmpty()) {
                            // Add the event that caused the drop to the cause
                            frame.pushCause(event);
                            LanternEventHelper.handleDroppedItemSpawning(this.player.getTransform(), cursorItem1);
                            frame.popCause();
                        }
                    }
                    return false;
                }
                if (cursorTransaction.isValid()) {
                    final ItemStackSnapshot cursorItem1 = cursorTransaction.getFinal();
                    container.getCursorSlot().setRawItemStack(cursorItem1.createStack());
                }
                sendClose = false;
                container.addViewer(this.player);
            }
            if (sendClose && getContainerId() != 0) {
                this.player.getConnection().send(new MessagePlayInOutCloseWindow(getContainerId()));
            }
            if (this.openContainer != null) {
                this.openContainer.removeViewer(this.player);
            }
        }
        this.openContainer = container;
        return true;
    }
}
Also used : CauseStack(org.lanternpowered.server.event.CauseStack) Transaction(org.spongepowered.api.data.Transaction) MessagePlayInOutCloseWindow(org.lanternpowered.server.network.vanilla.message.type.play.MessagePlayInOutCloseWindow) InteractInventoryEvent(org.spongepowered.api.event.item.inventory.InteractInventoryEvent) TradingClientContainer(org.lanternpowered.server.inventory.client.TradingClientContainer) PlayerClientContainer(org.lanternpowered.server.inventory.client.PlayerClientContainer) BeaconClientContainer(org.lanternpowered.server.inventory.client.BeaconClientContainer) EnchantmentTableClientContainer(org.lanternpowered.server.inventory.client.EnchantmentTableClientContainer) AnvilClientContainer(org.lanternpowered.server.inventory.client.AnvilClientContainer) ClientContainer(org.lanternpowered.server.inventory.client.ClientContainer) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot)

Example 17 with CauseStack

use of org.lanternpowered.server.event.CauseStack in project LanternServer by LanternPowered.

the class PlayerContainerSession method openPlayerContainer.

/**
 * Opens the players container when this is caused
 * by a players client.
 */
private void openPlayerContainer() {
    final CauseStack causeStack = CauseStack.current();
    causeStack.pushCause(this.player);
    setRawOpenContainer(causeStack, this.player.getInventoryContainer());
    causeStack.popCause();
}
Also used : CauseStack(org.lanternpowered.server.event.CauseStack)

Example 18 with CauseStack

use of org.lanternpowered.server.event.CauseStack in project LanternServer by LanternPowered.

the class LanternChunk method pulse.

public void pulse() {
    // The update entry
    LanternScheduledBlockUpdate update;
    while ((update = this.scheduledBlockUpdateQueue.peek()) != null && update.getTicks() <= 0) {
        // Remove the entry from the queue
        this.scheduledBlockUpdateQueue.poll();
    // TODO: Update
    }
    final CauseStack causeStack = CauseStack.current();
    // Add the chunk that is being pulsed
    causeStack.pushCause(this);
    getTileEntities().forEach(tileEntity -> {
        // Add the tile entity to the cause
        causeStack.pushCause(tileEntity);
        try {
            ((LanternTileEntity) tileEntity).pulse();
        } catch (Throwable t) {
            final Vector3i pos = tileEntity.getLocation().getBlockPosition();
            Lantern.getLogger().error("Failed to pulse TileEntity at ({};{};{})", pos.getX(), pos.getY(), pos.getZ(), t);
        } finally {
            // Pop the tile entity
            causeStack.popCause();
        }
    });
    // Pop the chunk
    causeStack.popCause();
}
Also used : CauseStack(org.lanternpowered.server.event.CauseStack) LanternScheduledBlockUpdate(org.lanternpowered.server.block.LanternScheduledBlockUpdate) Vector3i(com.flowpowered.math.vector.Vector3i) LanternTileEntity(org.lanternpowered.server.block.tile.LanternTileEntity)

Example 19 with CauseStack

use of org.lanternpowered.server.event.CauseStack in project LanternServer by LanternPowered.

the class LanternChunkManager method loadTickets.

public void loadTickets() throws IOException {
    final Multimap<String, LanternLoadingTicket> tickets = LanternLoadingTicketIO.load(this.worldFolder, this, this.chunkLoadService);
    final Iterator<Entry<String, LanternLoadingTicket>> it = tickets.entries().iterator();
    final CauseStack causeStack = CauseStack.current();
    while (it.hasNext()) {
        final LanternLoadingTicket ticket = it.next().getValue();
        if (ticket instanceof LanternEntityLoadingTicket) {
            final LanternEntityLoadingTicket ticket0 = (LanternEntityLoadingTicket) ticket;
            final EntityReference ref = ticket0.getEntityReference().orElse(null);
            if (ref != null) {
                causeStack.pushCause(ticket0);
                final LanternChunk chunk = getOrCreateChunk(ref.getChunkCoords(), causeStack, true, true);
                causeStack.popCause();
                final Entity entity = chunk.getEntity(ref.getUniqueId()).orElse(null);
                if (entity != null) {
                    ticket0.bindToEntity(entity);
                } else {
                    // The entity is gone?
                    it.remove();
                }
            } else {
                // The entity is gone?
                it.remove();
            }
        }
    }
    for (Entry<String, Collection<LanternLoadingTicket>> entry : tickets.asMap().entrySet()) {
        final Collection<ChunkTicketManager.Callback> callbacks = this.chunkLoadService.getCallbacks().get(entry.getKey());
        // These maps will be loaded lazily
        ImmutableListMultimap<UUID, LoadingTicket> playerLoadedTickets = null;
        ImmutableList<LoadingTicket> nonPlayerLoadedTickets = null;
        final Set<LoadingTicket> resultPlayerLoadedTickets = entry.getValue().stream().filter(ticket -> ticket instanceof PlayerLoadingTicket).collect(Collectors.toSet());
        final Set<LoadingTicket> resultNonPlayerLoadedTickets = entry.getValue().stream().filter(ticket -> !(ticket instanceof PlayerLoadingTicket)).collect(Collectors.toSet());
        final int maxTickets = this.chunkLoadService.getMaxTicketsById(entry.getKey());
        for (ChunkTicketManager.Callback callback : callbacks) {
            if (callback instanceof ChunkTicketManager.OrderedCallback) {
                if (nonPlayerLoadedTickets == null) {
                    nonPlayerLoadedTickets = ImmutableList.copyOf(resultNonPlayerLoadedTickets);
                    resultNonPlayerLoadedTickets.clear();
                }
                final List<LoadingTicket> result = ((ChunkTicketManager.OrderedCallback) callback).onLoaded(nonPlayerLoadedTickets, this.world, maxTickets);
                checkNotNull(result, "The OrderedCallback#onLoaded method may not return null, " + "error caused by (plugin=%s, clazz=%s)", entry.getKey(), callback.getClass().getName());
                resultNonPlayerLoadedTickets.addAll(result);
            }
            if (callback instanceof ChunkTicketManager.PlayerOrderedCallback) {
                if (playerLoadedTickets == null) {
                    final ImmutableListMultimap.Builder<UUID, LoadingTicket> mapBuilder = ImmutableListMultimap.builder();
                    resultPlayerLoadedTickets.forEach(ticket -> mapBuilder.put(((PlayerLoadingTicket) ticket).getPlayerUniqueId(), ticket));
                    resultPlayerLoadedTickets.clear();
                    playerLoadedTickets = mapBuilder.build();
                }
                final ListMultimap<UUID, LoadingTicket> result = ((ChunkTicketManager.PlayerOrderedCallback) callback).onPlayerLoaded(playerLoadedTickets, this.world);
                checkNotNull(result, "The PlayerOrderedCallback#onPlayerLoaded method may not return null, " + "error caused by (plugin=%s, clazz=%s)", entry.getKey(), callback.getClass().getName());
                resultPlayerLoadedTickets.addAll(result.values());
            }
        }
        final List<LoadingTicket> resultLoadedTickets = new ArrayList<>();
        resultLoadedTickets.addAll(resultPlayerLoadedTickets);
        resultLoadedTickets.addAll(resultNonPlayerLoadedTickets);
        // Lets see how many plugins attempted to add loading tickets
        final int sizeA = resultLoadedTickets.size();
        resultLoadedTickets.retainAll(entry.getValue());
        final int sizeB = resultLoadedTickets.size();
        if (sizeA != sizeB) {
            Lantern.getLogger().warn("The plugin {} attempted to add LoadingTicket's that were previously not present.", entry.getKey());
        }
        // Remove all the tickets that are already released
        resultLoadedTickets.removeIf(ticket -> ((ChunkLoadingTicket) ticket).isReleased());
        if (resultLoadedTickets.size() > maxTickets) {
            Lantern.getLogger().warn("The plugin {} has too many open chunk loading tickets {}. " + "Excess will be dropped", entry.getKey(), resultLoadedTickets.size());
            resultLoadedTickets.subList(maxTickets, resultLoadedTickets.size()).clear();
        }
        // Release all the tickets that were no longer usable
        final List<LoadingTicket> removedTickets = new ArrayList<>(entry.getValue());
        removedTickets.removeAll(resultLoadedTickets);
        removedTickets.forEach(LoadingTicket::release);
        final ImmutableList<LoadingTicket> loadedTickets = ImmutableList.copyOf(resultLoadedTickets);
        for (ChunkTicketManager.Callback callback : callbacks) {
            callback.onLoaded(loadedTickets, this.world);
        }
    }
}
Also used : ImmutableBlockVolume(org.spongepowered.api.world.extent.ImmutableBlockVolume) GenerationPopulator(org.spongepowered.api.world.gen.GenerationPopulator) Arrays(java.util.Arrays) ListMultimap(com.google.common.collect.ListMultimap) ChunkSection(org.lanternpowered.server.world.chunk.LanternChunk.ChunkSection) Inject(com.google.inject.Inject) ChunkTicketManager(org.spongepowered.api.world.ChunkTicketManager) ShortArrayMutableBiomeBuffer(org.lanternpowered.server.util.gen.biome.ShortArrayMutableBiomeBuffer) BiomeGenerationSettings(org.spongepowered.api.world.biome.BiomeGenerationSettings) Random(java.util.Random) BiomeTypes(org.spongepowered.api.world.biome.BiomeTypes) WorldConfig(org.lanternpowered.server.config.world.WorldConfig) BiomeGenerator(org.spongepowered.api.world.gen.BiomeGenerator) EventManager(org.spongepowered.api.event.EventManager) Future(java.util.concurrent.Future) Populator(org.spongepowered.api.world.gen.Populator) DirectoryKeys(org.lanternpowered.server.game.DirectoryKeys) ChunkIOService(org.lanternpowered.server.data.io.ChunkIOService) Map(java.util.Map) BlockRegistryModule(org.lanternpowered.server.game.registry.type.block.BlockRegistryModule) ShortArrayMutableBlockBuffer(org.lanternpowered.server.util.gen.block.ShortArrayMutableBlockBuffer) EntityLoadingTicket(org.spongepowered.api.world.ChunkTicketManager.EntityLoadingTicket) VirtualBiomeType(org.spongepowered.api.world.biome.VirtualBiomeType) Path(java.nio.file.Path) ObjectArrayImmutableBiomeBuffer(org.lanternpowered.server.util.gen.biome.ObjectArrayImmutableBiomeBuffer) PlayerLoadingTicket(org.spongepowered.api.world.ChunkTicketManager.PlayerLoadingTicket) ImmutableSetMultimap(com.google.common.collect.ImmutableSetMultimap) CHUNK_SECTIONS(org.lanternpowered.server.world.chunk.LanternChunk.CHUNK_SECTIONS) ImmutableSet(com.google.common.collect.ImmutableSet) CHUNK_AREA(org.lanternpowered.server.world.chunk.LanternChunk.CHUNK_AREA) Extent(org.spongepowered.api.world.extent.Extent) BlockTypes(org.spongepowered.api.block.BlockTypes) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Sponge(org.spongepowered.api.Sponge) Set(java.util.Set) UUID(java.util.UUID) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) LanternGame(org.lanternpowered.server.game.LanternGame) BlockState(org.spongepowered.api.block.BlockState) FastSoftThreadLocal(org.lanternpowered.server.util.concurrent.FastSoftThreadLocal) WorldGenerator(org.spongepowered.api.world.gen.WorldGenerator) Cause(org.spongepowered.api.event.cause.Cause) List(java.util.List) SoftBufferExtentViewDownsize(org.lanternpowered.server.world.extent.SoftBufferExtentViewDownsize) Lantern(org.lanternpowered.server.game.Lantern) ImmutableListMultimap(com.google.common.collect.ImmutableListMultimap) Entry(java.util.Map.Entry) Optional(java.util.Optional) Queue(java.util.Queue) ConcurrentLinkedQueue(java.util.concurrent.ConcurrentLinkedQueue) InternalPluginsInfo(org.lanternpowered.server.plugin.InternalPluginsInfo) AtomicShortArrayMutableBlockBuffer(org.lanternpowered.server.util.gen.block.AtomicShortArrayMutableBlockBuffer) ThreadPoolExecutor(java.util.concurrent.ThreadPoolExecutor) AbstractMutableBlockBuffer(org.lanternpowered.server.util.gen.block.AbstractMutableBlockBuffer) MutableBlockVolume(org.spongepowered.api.world.extent.MutableBlockVolume) BiomeType(org.spongepowered.api.world.biome.BiomeType) Callable(java.util.concurrent.Callable) Multimap(com.google.common.collect.Multimap) CHUNK_SECTION_VOLUME(org.lanternpowered.server.world.chunk.LanternChunk.CHUNK_SECTION_VOLUME) ImmutableBiomeVolume(org.spongepowered.api.world.extent.ImmutableBiomeVolume) ArrayList(java.util.ArrayList) Vector2i(com.flowpowered.math.vector.Vector2i) HashSet(java.util.HashSet) CHUNK_SECTION_SIZE(org.lanternpowered.server.world.chunk.LanternChunk.CHUNK_SECTION_SIZE) ThreadHelper(org.lanternpowered.server.util.ThreadHelper) CauseStack(org.lanternpowered.server.event.CauseStack) ImmutableList(com.google.common.collect.ImmutableList) ShortArrayImmutableBlockBuffer(org.lanternpowered.server.util.gen.block.ShortArrayImmutableBlockBuffer) LanternWorld(org.lanternpowered.server.world.LanternWorld) CHUNK_BIOME_VOLUME(org.lanternpowered.server.world.chunk.LanternChunkLayout.CHUNK_BIOME_VOLUME) LinkedList(java.util.LinkedList) PluginContainer(org.spongepowered.api.plugin.PluginContainer) Nullable(javax.annotation.Nullable) ExtentBufferHelper(org.lanternpowered.server.world.extent.ExtentBufferHelper) Iterator(java.util.Iterator) SpongeEventFactory(org.spongepowered.api.event.SpongeEventFactory) Preconditions.checkNotNull(com.google.common.base.Preconditions.checkNotNull) CHUNK_HEIGHT(org.lanternpowered.server.world.chunk.LanternChunk.CHUNK_HEIGHT) Chunk(org.spongepowered.api.world.Chunk) IOException(java.io.IOException) Entity(org.spongepowered.api.entity.Entity) LoadingTicket(org.spongepowered.api.world.ChunkTicketManager.LoadingTicket) TimeUnit(java.util.concurrent.TimeUnit) StorageType(org.spongepowered.api.world.extent.StorageType) Vector3i(com.flowpowered.math.vector.Vector3i) Named(com.google.inject.name.Named) PlayerEntityLoadingTicket(org.spongepowered.api.world.ChunkTicketManager.PlayerEntityLoadingTicket) MapMaker(com.google.common.collect.MapMaker) Conditions.checkPlugin(org.lanternpowered.server.util.Conditions.checkPlugin) Entity(org.spongepowered.api.entity.Entity) ArrayList(java.util.ArrayList) EntityLoadingTicket(org.spongepowered.api.world.ChunkTicketManager.EntityLoadingTicket) PlayerLoadingTicket(org.spongepowered.api.world.ChunkTicketManager.PlayerLoadingTicket) LoadingTicket(org.spongepowered.api.world.ChunkTicketManager.LoadingTicket) PlayerEntityLoadingTicket(org.spongepowered.api.world.ChunkTicketManager.PlayerEntityLoadingTicket) Entry(java.util.Map.Entry) PlayerLoadingTicket(org.spongepowered.api.world.ChunkTicketManager.PlayerLoadingTicket) ImmutableListMultimap(com.google.common.collect.ImmutableListMultimap) UUID(java.util.UUID) CauseStack(org.lanternpowered.server.event.CauseStack) ChunkTicketManager(org.spongepowered.api.world.ChunkTicketManager) Collection(java.util.Collection)

Example 20 with CauseStack

use of org.lanternpowered.server.event.CauseStack in project LanternServer by LanternPowered.

the class LanternChunkManager method force.

/**
 * Forces the specified chunk coordinates for a specific ticket.
 *
 * @param ticket the ticket
 * @param coords the coordinates
 * @param callEvents whether the force chunk events should be called
 */
void force(LanternLoadingTicket ticket, Vector2i coords, boolean callEvents) {
    final LanternChunk chunk = getChunk(coords, false);
    // The chunk at this coords is already loaded,
    // wa can call the event directly
    lockInternally(coords, ticket);
    // Remove from unload through loadChunk
    this.pendingForUnload.removeIf(e -> e.coords.equals(coords));
    // Whether the chunk should be queued for loading
    boolean queueLoad = false;
    if (chunk != null) {
        if (chunk.lock.isLocked() && chunk.lockState == LanternChunk.LockState.UNLOADING) {
            queueLoad = true;
        }
    // Queue the chunk to load
    } else {
        queueLoad = true;
    }
    if (queueLoad) {
        LanternChunkQueueTask task = this.chunkQueueTasks.get(coords);
        if (task == null || !(task.runnable instanceof LanternChunkLoadTask)) {
            this.chunkQueueTasks.computeIfAbsent(coords, coords1 -> queueTask(coords1, new LanternChunkLoadTask(coords1)));
        }
    }
    if (callEvents) {
        final Vector3i coords0 = new Vector3i(coords.getX(), 0, coords.getY());
        final CauseStack causeStack = CauseStack.currentOrNull();
        if (causeStack != null) {
            postForcedChunkEvent(causeStack, ticket, coords0);
        } else {
            Lantern.getScheduler().callSync(() -> postForcedChunkEvent(CauseStack.current(), ticket, coords0));
        }
    }
}
Also used : CauseStack(org.lanternpowered.server.event.CauseStack) Vector3i(com.flowpowered.math.vector.Vector3i)

Aggregations

CauseStack (org.lanternpowered.server.event.CauseStack)54 ItemStack (org.spongepowered.api.item.inventory.ItemStack)18 Entity (org.spongepowered.api.entity.Entity)16 ArrayList (java.util.ArrayList)15 Nullable (javax.annotation.Nullable)15 World (org.spongepowered.api.world.World)15 Optional (java.util.Optional)14 Lantern (org.lanternpowered.server.game.Lantern)13 AbstractSlot (org.lanternpowered.server.inventory.AbstractSlot)13 LanternWorld (org.lanternpowered.server.world.LanternWorld)13 SpawnEntityEvent (org.spongepowered.api.event.entity.SpawnEntityEvent)13 Vector3i (com.flowpowered.math.vector.Vector3i)12 List (java.util.List)12 LanternPlayer (org.lanternpowered.server.entity.living.player.LanternPlayer)12 Keys (org.spongepowered.api.data.key.Keys)12 EventContextKeys (org.spongepowered.api.event.cause.EventContextKeys)12 Sponge (org.spongepowered.api.Sponge)11 Transform (org.spongepowered.api.entity.Transform)11 Player (org.spongepowered.api.entity.living.player.Player)11 SpongeEventFactory (org.spongepowered.api.event.SpongeEventFactory)11