Search in sources :

Example 1 with PlayerLoadingTicket

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);
        }
    }
}
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 2 with PlayerLoadingTicket

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);
}
Also used : Path(java.nio.file.Path) ArrayList(java.util.ArrayList) EntityLoadingTicket(org.spongepowered.api.world.ChunkTicketManager.EntityLoadingTicket) DataView(org.spongepowered.api.data.DataView) DataContainer(org.spongepowered.api.data.DataContainer) PlayerLoadingTicket(org.spongepowered.api.world.ChunkTicketManager.PlayerLoadingTicket) Collection(java.util.Collection) Vector2i(com.flowpowered.math.vector.Vector2i) UUID(java.util.UUID)

Aggregations

Vector2i (com.flowpowered.math.vector.Vector2i)2 Path (java.nio.file.Path)2 ArrayList (java.util.ArrayList)2 Collection (java.util.Collection)2 UUID (java.util.UUID)2 Vector3i (com.flowpowered.math.vector.Vector3i)1 Preconditions.checkNotNull (com.google.common.base.Preconditions.checkNotNull)1 ImmutableList (com.google.common.collect.ImmutableList)1 ImmutableListMultimap (com.google.common.collect.ImmutableListMultimap)1 ImmutableSet (com.google.common.collect.ImmutableSet)1 ImmutableSetMultimap (com.google.common.collect.ImmutableSetMultimap)1 ListMultimap (com.google.common.collect.ListMultimap)1 MapMaker (com.google.common.collect.MapMaker)1 Multimap (com.google.common.collect.Multimap)1 Sets (com.google.common.collect.Sets)1 Inject (com.google.inject.Inject)1 Named (com.google.inject.name.Named)1 IOException (java.io.IOException)1 Arrays (java.util.Arrays)1 HashSet (java.util.HashSet)1