use of org.spongepowered.api.world.ChunkTicketManager.PlayerLoadingTicket 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.spongepowered.api.world.ChunkTicketManager.PlayerLoadingTicket in project LanternServer by LanternPowered.
the class LanternLoadingTicketIO method save.
static void save(Path worldFolder, Set<LanternLoadingTicket> tickets) throws IOException {
final Path file = worldFolder.resolve(TICKETS_FILE);
if (!Files.exists(file)) {
Files.createFile(file);
}
final Multimap<String, LanternLoadingTicket> sortedByPlugin = HashMultimap.create();
for (LanternLoadingTicket ticket : tickets) {
sortedByPlugin.put(ticket.getPlugin(), ticket);
}
final List<DataView> ticketHolders = new ArrayList<>();
for (Entry<String, Collection<LanternLoadingTicket>> entry : sortedByPlugin.asMap().entrySet()) {
final Collection<LanternLoadingTicket> tickets0 = entry.getValue();
final List<DataView> ticketEntries = new ArrayList<>();
for (LanternLoadingTicket ticket0 : tickets0) {
final DataContainer ticketData = DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED);
ticketData.set(TICKET_TYPE, ticket0 instanceof EntityLoadingTicket ? TYPE_ENTITY : TYPE_NORMAL);
final int numChunks = ticket0.getNumChunks();
// Store the list depth for backwards compatible or something,
// the current forge version doesn't use it either
ticketData.set(CHUNK_LIST_DEPTH, (byte) Math.min(numChunks, 127));
// Storing the chunks number, this number is added by us
ticketData.set(CHUNK_NUMBER, numChunks);
if (ticket0 instanceof PlayerLoadingTicket) {
final PlayerLoadingTicket ticket1 = (PlayerLoadingTicket) ticket0;
// This is a bit strange, since it already added,
// but if forge uses it...
ticketData.set(MOD_ID, entry.getKey());
ticketData.set(PLAYER_UUID, ticket1.getPlayerUniqueId().toString());
}
if (ticket0.extraData != null) {
ticketData.set(MOD_DATA, ticket0.extraData);
}
if (ticket0 instanceof EntityChunkLoadingTicket) {
final EntityChunkLoadingTicket ticket1 = (EntityChunkLoadingTicket) ticket0;
ticket1.getOrCreateEntityReference().ifPresent(ref -> {
final Vector2i position = ref.getChunkCoords();
final UUID uniqueId = ref.getUniqueId();
ticketData.set(CHUNK_X, position.getX());
ticketData.set(CHUNK_Z, position.getY());
ticketData.set(ENTITY_UUID_MOST, uniqueId.getMostSignificantBits());
ticketData.set(ENTITY_UUID_LEAST, uniqueId.getLeastSignificantBits());
});
}
ticketEntries.add(ticketData);
}
ticketHolders.add(DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED).set(HOLDER_NAME, entry.getKey()).set(TICKETS, ticketEntries));
}
final DataContainer dataContainer = DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED).set(HOLDER_LIST, ticketHolders);
NbtStreamUtils.write(dataContainer, Files.newOutputStream(file), true);
}
Aggregations