Package org.terasology.world.internal

Source Code of org.terasology.world.internal.WorldProviderCoreImpl

/*
* Copyright 2013 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.terasology.world.internal;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.engine.SimpleUri;
import org.terasology.entitySystem.entity.EntityManager;
import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.math.Region3i;
import org.terasology.math.TeraMath;
import org.terasology.math.Vector3i;
import org.terasology.registry.CoreRegistry;
import org.terasology.world.WorldChangeListener;
import org.terasology.world.WorldComponent;
import org.terasology.world.biomes.Biome;
import org.terasology.world.biomes.BiomeManager;
import org.terasology.world.block.Block;
import org.terasology.world.block.BlockManager;
import org.terasology.world.chunks.ChunkProvider;
import org.terasology.world.chunks.CoreChunk;
import org.terasology.world.chunks.LitChunk;
import org.terasology.world.chunks.RenderableChunk;
import org.terasology.world.chunks.internal.GeneratingChunkProvider;
import org.terasology.world.generation.Region;
import org.terasology.world.generation.World;
import org.terasology.world.liquid.LiquidData;
import org.terasology.world.propagation.*;
import org.terasology.world.propagation.light.LightPropagationRules;
import org.terasology.world.propagation.light.LightWorldView;
import org.terasology.world.propagation.light.SunlightPropagationRules;
import org.terasology.world.propagation.light.SunlightRegenPropagationRules;
import org.terasology.world.propagation.light.SunlightRegenWorldView;
import org.terasology.world.propagation.light.SunlightWorldView;
import org.terasology.world.time.WorldTime;
import org.terasology.world.time.WorldTimeImpl;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
* @author Immortius
*/
public class WorldProviderCoreImpl implements WorldProviderCore {
    private static final Logger logger = LoggerFactory.getLogger(WorldProviderCoreImpl.class);

    private String title;
    private String seed = "";
    private SimpleUri worldGenerator;

    private GeneratingChunkProvider chunkProvider;
    private WorldTime worldTime;

    private final List<WorldChangeListener> listeners = Lists.newArrayList();

    private Map<Vector3i, BlockChange> blockChanges = Maps.newHashMap();
    private Map<Vector3i, BiomeChange> biomeChanges = Maps.newHashMap();
    private List<BatchPropagator> propagators = Lists.newArrayList();

    public WorldProviderCoreImpl(String title, String seed, long time, SimpleUri worldGenerator, GeneratingChunkProvider chunkProvider) {
        this.title = (title == null) ? seed : title;
        this.seed = seed;
        this.worldGenerator = worldGenerator;
        this.chunkProvider = chunkProvider;
        CoreRegistry.put(ChunkProvider.class, chunkProvider);

        this.worldTime = new WorldTimeImpl();
        worldTime.setMilliseconds(time);

        propagators.add(new StandardBatchPropagator(new LightPropagationRules(), new LightWorldView(chunkProvider)));
        PropagatorWorldView regenWorldView = new SunlightRegenWorldView(chunkProvider);
        PropagationRules sunlightRules = new SunlightPropagationRules(regenWorldView);
        PropagatorWorldView sunlightWorldView = new SunlightWorldView(chunkProvider);
        BatchPropagator sunlightPropagator = new StandardBatchPropagator(sunlightRules, sunlightWorldView);
        propagators.add(new SunlightRegenBatchPropagator(new SunlightRegenPropagationRules(), regenWorldView, sunlightPropagator, sunlightWorldView));
        propagators.add(sunlightPropagator);
    }

    public WorldProviderCoreImpl(WorldInfo info, GeneratingChunkProvider chunkProvider) {
        this(info.getTitle(), info.getSeed(), info.getTime(), info.getWorldGenerator(), chunkProvider);
    }

    @Override
    public EntityRef getWorldEntity() {
        Iterator<EntityRef> iterator = CoreRegistry.get(EntityManager.class).getEntitiesWith(WorldComponent.class).iterator();
        if (iterator.hasNext()) {
            return iterator.next();
        }
        return EntityRef.NULL;
    }

    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public String getSeed() {
        return seed;
    }

    @Override
    public WorldInfo getWorldInfo() {
        return new WorldInfo(title, seed, worldTime.getMilliseconds(), worldGenerator);
    }

    @Override
    public void processPropagation() {
        for (BatchPropagator propagator : propagators) {
            propagator.process(blockChanges.values());
        }
        blockChanges.clear();
    }

    @Override
    public void registerListener(WorldChangeListener listener) {
        synchronized (listeners) {
            listeners.add(listener);
        }
    }

    @Override
    public void unregisterListener(WorldChangeListener listener) {
        synchronized (listeners) {
            listeners.remove(listener);
        }
    }

    @Override
    public ChunkViewCore getLocalView(Vector3i chunkPos) {
        return chunkProvider.getLocalView(chunkPos);
    }

    @Override
    public ChunkViewCore getWorldViewAround(Vector3i chunk) {
        return chunkProvider.getSubviewAroundChunk(chunk);
    }

    @Override
    public boolean isBlockRelevant(int x, int y, int z) {
        return chunkProvider.isChunkReady(TeraMath.calcChunkPos(x, y, z));
    }

    @Override
    public boolean isRegionRelevant(Region3i region) {
        for (Vector3i chunkPos : TeraMath.calcChunkPos(region)) {
            if (!chunkProvider.isChunkReady(chunkPos)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public Block setBlock(Vector3i worldPos, Block type) {
        Vector3i chunkPos = TeraMath.calcChunkPos(worldPos);
        CoreChunk chunk = chunkProvider.getChunk(chunkPos);
        if (chunk != null) {
            Vector3i blockPos = TeraMath.calcBlockPos(worldPos);
            chunk.lock();
            Block oldBlockType = chunk.setBlock(blockPos, type);
            chunk.unlock();
            if (oldBlockType != type) {
                BlockChange oldChange = blockChanges.get(worldPos);
                if (oldChange == null) {
                    blockChanges.put(worldPos, new BlockChange(worldPos, oldBlockType, type));
                } else {
                    oldChange.setTo(type);
                }
                for (Vector3i pos : TeraMath.getChunkRegionAroundWorldPos(worldPos, 1)) {
                    RenderableChunk dirtiedChunk = chunkProvider.getChunk(pos);
                    if (dirtiedChunk != null) {
                        dirtiedChunk.setDirty(true);
                    }
                }
                notifyBlockChanged(worldPos, type, oldBlockType);
            }
            return oldBlockType;

        }
        return null;
    }

    private void notifyBlockChanged(Vector3i pos, Block type, Block oldType) {
        // TODO: Could use a read/write lock.
        // TODO: Review, should only happen on main thread (as should changes to listeners)
        synchronized (listeners) {
            for (WorldChangeListener listener : listeners) {
                listener.onBlockChanged(pos, type, oldType);
            }
        }
    }

    private void notifyBiomeChanged(Vector3i pos, Biome newBiome, Biome originalBiome) {
        // TODO: Could use a read/write lock.
        // TODO: Review, should only happen on main thread (as should changes to listeners)
        synchronized (listeners) {
            for (WorldChangeListener listener : listeners) {
                listener.onBiomeChanged(pos, newBiome, originalBiome);
            }
        }
    }

    @Override
    public boolean setLiquid(int x, int y, int z, LiquidData newState, LiquidData oldState) {
        Vector3i chunkPos = TeraMath.calcChunkPos(x, y, z);
        CoreChunk chunk = chunkProvider.getChunk(chunkPos);
        if (chunk != null) {
            chunk.lock();
            try {
                Vector3i blockPos = TeraMath.calcBlockPos(x, y, z);
                LiquidData liquidState = chunk.getLiquid(blockPos);
                if (liquidState.equals(oldState)) {
                    chunk.setLiquid(blockPos, newState);
                    return true;
                }
            } finally {
                chunk.unlock();
            }
        }
        return false;
    }

    @Override
    public LiquidData getLiquid(int x, int y, int z) {
        Vector3i chunkPos = TeraMath.calcChunkPos(x, y, z);
        CoreChunk chunk = chunkProvider.getChunk(chunkPos);
        if (chunk != null) {
            Vector3i blockPos = TeraMath.calcBlockPos(x, y, z);
            return chunk.getLiquid(blockPos);
        }
        logger.warn("Attempted to access unavailable chunk via liquid data at {}, {}, {}", x, y, z);
        return new LiquidData();
    }

    @Override
    public Block getBlock(int x, int y, int z) {
        Vector3i chunkPos = TeraMath.calcChunkPos(x, y, z);
        CoreChunk chunk = chunkProvider.getChunk(chunkPos);
        if (chunk != null) {
            Vector3i blockPos = TeraMath.calcBlockPos(x, y, z);
            return chunk.getBlock(blockPos);
        }
        logger.warn("Attempted to access unavailable chunk via block at {}, {}, {}", x, y, z);
        return BlockManager.getAir();
    }

    @Override
    public Biome getBiome(Vector3i pos) {
        Vector3i chunkPos = TeraMath.calcChunkPos(pos);
        CoreChunk chunk = chunkProvider.getChunk(chunkPos);
        if (chunk != null) {
            Vector3i blockPos = TeraMath.calcBlockPos(pos);
            return chunk.getBiome(blockPos.x, blockPos.y, blockPos.z);
        }
        logger.warn("Attempted to access unavailable chunk via block at {}, {}, {}", pos.x, pos.y, pos.z);
        return BiomeManager.getUnknownBiome();
    }

    @Override
    public Biome setBiome(Vector3i worldPos, Biome biome) {
        Vector3i chunkPos = TeraMath.calcChunkPos(worldPos);
        CoreChunk chunk = chunkProvider.getChunk(chunkPos);
        if (chunk != null) {
            Vector3i blockPos = TeraMath.calcBlockPos(worldPos);
            chunk.lock();
            Biome oldBiomeType = chunk.setBiome(blockPos.x, blockPos.y, blockPos.z, biome);
            chunk.unlock();
            if (oldBiomeType != biome) {
                BiomeChange oldChange = biomeChanges.get(worldPos);
                if (oldChange == null) {
                    biomeChanges.put(worldPos, new BiomeChange(worldPos, oldBiomeType, biome));
                } else {
                    oldChange.setTo(biome);
                }
                for (Vector3i pos : TeraMath.getChunkRegionAroundWorldPos(worldPos, 1)) {
                    RenderableChunk dirtiedChunk = chunkProvider.getChunk(pos);
                    if (dirtiedChunk != null) {
                        dirtiedChunk.setDirty(true);
                    }
                }
                notifyBiomeChanged(worldPos, biome, oldBiomeType);
            }
            return oldBiomeType;

        }
        return null;
    }

    @Override
    public byte getLight(int x, int y, int z) {
        Vector3i chunkPos = TeraMath.calcChunkPos(x, y, z);
        LitChunk chunk = chunkProvider.getChunk(chunkPos);
        if (chunk != null) {
            Vector3i blockPos = TeraMath.calcBlockPos(x, y, z);
            return chunk.getLight(blockPos);
        }
        logger.warn("Attempted to access unavailable chunk via light at {}, {}, {}", x, y, z);
        return 0;
    }

    @Override
    public byte getSunlight(int x, int y, int z) {
        Vector3i chunkPos = TeraMath.calcChunkPos(x, y, z);
        LitChunk chunk = chunkProvider.getChunk(chunkPos);
        if (chunk != null) {
            Vector3i blockPos = TeraMath.calcBlockPos(x, y, z);
            return chunk.getSunlight(blockPos);
        }
        logger.warn("Attempted to access unavailable chunk via sunlight at {}, {}, {}", x, y, z);
        return 0;
    }

    @Override
    public byte getTotalLight(int x, int y, int z) {
        Vector3i chunkPos = TeraMath.calcChunkPos(x, y, z);
        LitChunk chunk = chunkProvider.getChunk(chunkPos);
        if (chunk != null) {
            Vector3i blockPos = TeraMath.calcBlockPos(x, y, z);
            return (byte) Math.max(chunk.getSunlight(blockPos), chunk.getLight(blockPos));
        }
        logger.warn("Attempted to access unavailable chunk via total light at {}, {}, {}", x, y, z);
        return 0;
    }

    @Override
    public void dispose() {
        chunkProvider.dispose();

    }

    @Override
    public WorldTime getTime() {
        return worldTime;
    }

}
TOP

Related Classes of org.terasology.world.internal.WorldProviderCoreImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.