Пример #1
0
        private void NotifyChunkToClients(ChunkEntry entry)
        {
            int notifyState = Interlocked.CompareExchange(ref entry.NotifyStatus, ChunkEntry.Notified,
                                                          ChunkEntry.NotNotified);

            if (notifyState == ChunkEntry.Notified || entry.Requests.IsEmpty)
                return;

            Task.Factory.StartNew(() =>
            {
                Parallel.For(0, entry.Requests.Count, (i) =>
                {
                    ClientRequest req;

                    if (!entry.Requests.TryDequeue(out req))
                        return;

                    if (entry.ChunkRequested.LightToRecalculate)
                        entry.ChunkRequested.RecalculateSky();

                    req.ClientRequesting.Owner.LoadedChunks.TryUpdate(entry.ChunkRequested.Coords.ChunkPackedCoords,
                                                                      entry.ChunkRequested, null);
                    entry.ChunkRequested.AddClient(req.ClientRequesting);
                    req.ClientRequesting.SendPreChunk(entry.ChunkRequested.Coords.ChunkX, entry.ChunkRequested.Coords.ChunkZ, true, false);
                    req.ClientRequesting.SendChunk(entry.ChunkRequested, false);
                });
            });
        }
Пример #2
0
        private Chunk LoadChunk(UniversalCoords coords, bool create, Client client = null, bool sync = true)
        {
            ChunkEntry newEntry = new ChunkEntry();
            ChunkEntry entry;
            ChunkEntry removedEntry;

            entry = PendingChunks.GetOrAdd(coords.ChunkPackedCoords, newEntry);
            int state = Interlocked.CompareExchange(ref entry.State, ChunkEntry.InProgress, ChunkEntry.NotInitialized);
            Chunk chunk;

            if (state == ChunkEntry.NotInitialized)
            {
                int threads;

                Interlocked.Increment(ref entry.ThreadsWaiting);
                // The entry could have been just readded but the chunk is already initialized
                if ((chunk = Chunks[coords]) != null)
                {
                    threads = Interlocked.Decrement(ref entry.ThreadsWaiting);
                    if (threads == 0)
                        PendingChunks.TryRemove(coords.ChunkPackedCoords, out removedEntry);

                    entry.ChunkRequested = chunk;
                    entry.State = ChunkEntry.Initialized;

                    NotifyChunkToClients(entry);

                    entry.ChunkLock.Set();

                    return chunk;

                }

                if ((chunk = Chunk.Load(coords, this)) != null)
                    AddChunk(chunk);
                else if (create)
                    chunk = _generator.ProvideChunk(coords.ChunkX, coords.ChunkZ, this);

                if(chunk == null)
                {
                    threads = Interlocked.Decrement(ref entry.ThreadsWaiting);

                    if (threads == 0)
                        PendingChunks.TryRemove(coords.ChunkPackedCoords, out removedEntry);

                    entry.ChunkLock.Set();

                    return chunk;
                }

                entry.ChunkRequested = chunk;
                entry.State = ChunkEntry.Initialized;

                threads = Interlocked.Decrement(ref entry.ThreadsWaiting);

                if (threads == 0)
                    PendingChunks.TryRemove(coords.ChunkPackedCoords, out removedEntry);

                NotifyChunkToClients(entry);
                entry.ChunkLock.Set();

                if (chunk != null)
                {
                    chunk.InitGrowableCache();
                    ContainerFactory.LoadContainersFromDisk(chunk);
                }

                return chunk;
            }

            if (state == ChunkEntry.InProgress)
            {
                Interlocked.Increment(ref entry.ThreadsWaiting);

                if (!sync)
                    entry.Requests.Enqueue(new ClientRequest { ClientRequesting = client });
                else
                    entry.ChunkLock.WaitOne();

                int threads = Interlocked.Decrement(ref entry.ThreadsWaiting);
                if (threads == 0)
                    PendingChunks.TryRemove(coords.ChunkPackedCoords, out removedEntry);

                if(!sync)
                {
                    if (entry.State == ChunkEntry.Initialized)
                        NotifyChunkToClients(entry);

                    return null;
                }

                if (entry.State == ChunkEntry.Initialized)
                    chunk = Chunks[coords];
                else
                    return null;

                Debug.Assert(chunk != null, "RETURNING NULL CHUNK");
                return chunk;
            }

            chunk = Chunks[coords];

            Debug.Assert(chunk != null, "RETURNING NULL CHUNK");
            Debug.Assert(!PendingChunks.TryGetValue(coords.ChunkPackedCoords, out entry), "ENTRY INITIALIZED AND STILL LISTED");

            return chunk;
        }