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