Reverted last two commits because no one wants to fix the bugs
This commit is contained in:
parent
a222ea8f67
commit
41a2909f7c
@ -25,9 +25,8 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import glm.vec._3.i.Vec3i;
|
||||
|
||||
import ru.windcorp.progressia.common.world.block.BlockData;
|
||||
@ -50,7 +49,7 @@ public class DefaultChunkData implements ChunkData {
|
||||
public boolean isEmpty = false;
|
||||
public boolean isOpaque = false;
|
||||
|
||||
public static Set<BlockData> transparent = Collections.emptySet();
|
||||
public static HashSet<BlockData> transparent;
|
||||
|
||||
private final Vec3i position = new Vec3i();
|
||||
private final DefaultWorldData world;
|
||||
@ -206,9 +205,12 @@ public class DefaultChunkData implements ChunkData {
|
||||
this.generationHint = generationHint;
|
||||
}
|
||||
|
||||
public void computeOpaque() {
|
||||
for (int xyz = 0; xyz < BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK; xyz++) {
|
||||
if (transparent.contains(blocks[xyz])) {
|
||||
public void computeOpaque()
|
||||
{
|
||||
for (int xyz=0;xyz<BLOCKS_PER_CHUNK*BLOCKS_PER_CHUNK*BLOCKS_PER_CHUNK;xyz++)
|
||||
{
|
||||
if (transparent.contains( blocks[xyz]))
|
||||
{
|
||||
isOpaque = false;
|
||||
return;
|
||||
}
|
||||
@ -216,14 +218,18 @@ public class DefaultChunkData implements ChunkData {
|
||||
isOpaque = true;
|
||||
}
|
||||
|
||||
public boolean isOpaque() {
|
||||
public boolean isOpaque()
|
||||
{
|
||||
return isOpaque;
|
||||
}
|
||||
|
||||
public void computeEmpty() {
|
||||
public void computeEmpty()
|
||||
{
|
||||
BlockData air = new BlockData("Test:Air");
|
||||
for (int xyz = 0; xyz < BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK; xyz++) {
|
||||
if (blocks[xyz] != air) {
|
||||
for (int xyz=0;xyz<BLOCKS_PER_CHUNK*BLOCKS_PER_CHUNK*BLOCKS_PER_CHUNK;xyz++)
|
||||
{
|
||||
if (blocks[xyz] != air)
|
||||
{
|
||||
isEmpty = false;
|
||||
return;
|
||||
}
|
||||
@ -231,10 +237,12 @@ public class DefaultChunkData implements ChunkData {
|
||||
isEmpty = true;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of {@link TileDataStack} used internally by
|
||||
* {@link DefaultChunkData} to
|
||||
|
@ -72,9 +72,6 @@ public class Server {
|
||||
private final PlayerManager playerManager;
|
||||
private final LoadManager loadManager;
|
||||
|
||||
private final ChunkRequestDaemon chunkRequestDaemon;
|
||||
private final EntityRequestDaemon entityRequestDaemon;
|
||||
|
||||
private final TaskQueue taskQueue = new TaskQueue(this::isServerThread);
|
||||
|
||||
private final EventBus eventBus = ReportingEventBus.create("ServerEvents");
|
||||
@ -94,12 +91,9 @@ public class Server {
|
||||
this.playerManager = new PlayerManager(this);
|
||||
this.loadManager = new LoadManager(this);
|
||||
|
||||
this.chunkRequestDaemon = new ChunkRequestDaemon(loadManager.getChunkManager());
|
||||
this.entityRequestDaemon = new EntityRequestDaemon(loadManager.getEntityManager());
|
||||
|
||||
schedule(getClientManager()::processPackets);
|
||||
schedule(this.chunkRequestDaemon::tick);
|
||||
schedule(this.entityRequestDaemon::tick);
|
||||
schedule(new ChunkRequestDaemon(loadManager.getChunkManager())::tick);
|
||||
schedule(new EntityRequestDaemon(loadManager.getEntityManager())::tick);
|
||||
|
||||
// Must run after request daemons so it only schedules chunks that
|
||||
// hadn't unloaded
|
||||
@ -335,7 +329,6 @@ public class Server {
|
||||
* operation or fails to start.
|
||||
*/
|
||||
public void start() {
|
||||
this.chunkRequestDaemon.start();
|
||||
this.serverThread.start();
|
||||
}
|
||||
|
||||
@ -356,7 +349,6 @@ public class Server {
|
||||
public void shutdown(String message) {
|
||||
LogManager.getLogger().warn("Server.shutdown() is not yet implemented");
|
||||
serverThread.stop();
|
||||
chunkRequestDaemon.stop();
|
||||
}
|
||||
|
||||
private void scheduleWorldTicks(Server server) {
|
||||
|
@ -34,7 +34,7 @@ public class ServerState {
|
||||
}
|
||||
|
||||
public static void startServer() {
|
||||
Server server = new Server(new DefaultWorldData(), new TestGenerationConfig().getGenerator());
|
||||
Server server = new Server(new DefaultWorldData(), TestGenerationConfig.createGenerator());
|
||||
setInstance(server);
|
||||
server.start();
|
||||
}
|
||||
|
@ -20,9 +20,8 @@ package ru.windcorp.progressia.server.management.load;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import glm.vec._3.i.Vec3i;
|
||||
import ru.windcorp.progressia.common.Units;
|
||||
import ru.windcorp.progressia.common.world.generic.ChunkMap;
|
||||
@ -32,8 +31,7 @@ import ru.windcorp.progressia.common.world.generic.ChunkSets;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
|
||||
/**
|
||||
* Chunk request daemon gathers chunk requests from players (via
|
||||
* {@link VisionManager}) and loads or unloads chunks appropriately.
|
||||
* Chunk request daemon gathers chunk requests from players (via {@link VisionManager}) and loads or unloads chunks appropriately.
|
||||
*/
|
||||
public class ChunkRequestDaemon {
|
||||
|
||||
@ -47,6 +45,8 @@ public class ChunkRequestDaemon {
|
||||
private final ChunkSet toGenerate = ChunkSets.newHashSet();
|
||||
private final ChunkSet toRequestUnload = ChunkSets.newHashSet();
|
||||
|
||||
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
private final Collection<Vec3i> buffer = new ArrayList<>();
|
||||
|
||||
private static class ChunkUnloadRequest {
|
||||
@ -75,39 +75,16 @@ public class ChunkRequestDaemon {
|
||||
|
||||
private final ChunkMap<ChunkUnloadRequest> unloadSchedule = ChunkMaps.newHashMap();
|
||||
|
||||
private Thread thread = null;
|
||||
private final AtomicBoolean shouldRun = new AtomicBoolean(false);
|
||||
|
||||
public ChunkRequestDaemon(ChunkManager chunkManager) {
|
||||
this.chunkManager = chunkManager;
|
||||
this.loaded = getServer().getWorld().getData().getLoadedChunks();
|
||||
}
|
||||
|
||||
public synchronized void start() {
|
||||
if (this.thread != null) {
|
||||
throw new IllegalStateException("Already running");
|
||||
}
|
||||
|
||||
this.thread = new Thread(this::runOffthread, getClass().getSimpleName());
|
||||
this.shouldRun.set(true);
|
||||
this.thread.start();
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
this.shouldRun.set(false);
|
||||
|
||||
synchronized (this) {
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void tick() {
|
||||
public void tick() {
|
||||
synchronized (getServer().getWorld().getData()) {
|
||||
synchronized (getServer().getPlayerManager().getMutex()) {
|
||||
loadAndUnloadChunks();
|
||||
sendAndRevokeChunks();
|
||||
|
||||
notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -139,11 +116,16 @@ public class ChunkRequestDaemon {
|
||||
}
|
||||
|
||||
private void processLoadQueues() {
|
||||
toGenerate.forEach(getChunkManager()::loadOrGenerateChunk);
|
||||
toRequestUnload.forEach((pos) -> executor.submit(() -> scheduleUnload(pos)));
|
||||
toRequestUnload.clear();
|
||||
|
||||
toLoad.forEach((pos) -> executor.submit(() -> getChunkManager().loadOrGenerateChunk(pos)));
|
||||
toLoad.clear();
|
||||
|
||||
toGenerate.forEach((pos) -> executor.submit(() -> getChunkManager().loadOrGenerateChunk(pos)));
|
||||
toGenerate.clear();
|
||||
|
||||
toRequestUnload.forEach(this::scheduleUnload);
|
||||
toRequestUnload.clear();
|
||||
executor.submit(() -> unloadScheduledChunks());
|
||||
}
|
||||
|
||||
private void scheduleUnload(Vec3i chunkPos) {
|
||||
@ -158,6 +140,25 @@ public class ChunkRequestDaemon {
|
||||
unloadSchedule.put(chunkPosCopy, new ChunkUnloadRequest(chunkPosCopy, unloadAt));
|
||||
}
|
||||
|
||||
private void unloadScheduledChunks() {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
for (Iterator<ChunkUnloadRequest> it = unloadSchedule.values().iterator(); it.hasNext();) {
|
||||
ChunkUnloadRequest request = it.next();
|
||||
|
||||
if (request.getUnloadAt() < now) {
|
||||
|
||||
it.remove();
|
||||
|
||||
if (requested.contains(request.getChunkPos())) {
|
||||
continue; // do not unload chunks that became requested
|
||||
}
|
||||
|
||||
getChunkManager().unloadChunk(request.getChunkPos());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendAndRevokeChunks() {
|
||||
getChunkManager().getLoadManager().getVisionManager().forEachVision(vision -> {
|
||||
revokeChunks(vision);
|
||||
@ -179,8 +180,7 @@ public class ChunkRequestDaemon {
|
||||
buffer.add(chunk.getPosition());
|
||||
});
|
||||
|
||||
if (buffer.isEmpty())
|
||||
return;
|
||||
if (buffer.isEmpty()) return;
|
||||
for (Vec3i chunkPos : buffer) {
|
||||
getChunkManager().sendChunk(vision.getPlayer(), chunkPos);
|
||||
}
|
||||
@ -195,8 +195,7 @@ public class ChunkRequestDaemon {
|
||||
buffer.add(new Vec3i(chunkPos));
|
||||
});
|
||||
|
||||
if (buffer.isEmpty())
|
||||
return;
|
||||
if (buffer.isEmpty()) return;
|
||||
for (Vec3i chunkPos : buffer) {
|
||||
getChunkManager().revokeChunk(vision.getPlayer(), chunkPos);
|
||||
}
|
||||
@ -204,82 +203,6 @@ public class ChunkRequestDaemon {
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
* Off-thread activity
|
||||
*/
|
||||
|
||||
private void runOffthread() {
|
||||
while (true) {
|
||||
|
||||
processLoadQueue();
|
||||
processUnloadQueue();
|
||||
|
||||
synchronized (this) {
|
||||
try {
|
||||
// We're not afraid of spurious wakeups
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
// Pretend nothing happened
|
||||
}
|
||||
|
||||
if (!shouldRun.get()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void processQueueOffthread(ChunkSet queue, Consumer<Vec3i> action) {
|
||||
while (true) {
|
||||
synchronized (this) {
|
||||
Iterator<Vec3i> iterator = toLoad.iterator();
|
||||
if (!iterator.hasNext()) {
|
||||
return;
|
||||
}
|
||||
Vec3i position = iterator.next();
|
||||
iterator.remove();
|
||||
|
||||
action.accept(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processLoadQueue() {
|
||||
processQueueOffthread(toLoad, getChunkManager()::loadOrGenerateChunk);
|
||||
}
|
||||
|
||||
private void processUnloadQueue() {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
Collection<Vec3i> toUnload = null;
|
||||
|
||||
synchronized (this) {
|
||||
for (Iterator<ChunkUnloadRequest> it = unloadSchedule.values().iterator(); it.hasNext();) {
|
||||
ChunkUnloadRequest request = it.next();
|
||||
|
||||
if (request.getUnloadAt() < now) {
|
||||
it.remove();
|
||||
|
||||
if (requested.contains(request.getChunkPos())) {
|
||||
continue; // do not unload chunks that became requested
|
||||
}
|
||||
|
||||
if (toUnload == null) {
|
||||
toUnload = new ArrayList<>();
|
||||
}
|
||||
toUnload.add(request.getChunkPos());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (toUnload == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
toUnload.forEach(getChunkManager()::unloadChunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minimum amount of time a chunk will spend in the unload queue
|
||||
*/
|
||||
|
@ -34,7 +34,7 @@ import ru.windcorp.progressia.common.world.rels.RelFace;
|
||||
import ru.windcorp.progressia.common.world.TileDataStack;
|
||||
import ru.windcorp.progressia.common.world.generic.GenericChunks;
|
||||
import ru.windcorp.progressia.common.world.TileDataReference;
|
||||
import ru.windcorp.progressia.server.ServerState;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.world.block.BlockLogic;
|
||||
import ru.windcorp.progressia.server.world.block.BlockLogicRegistry;
|
||||
import ru.windcorp.progressia.server.world.block.TickableBlock;
|
||||
@ -226,7 +226,7 @@ public class DefaultChunkLogic implements ChunkLogic {
|
||||
}
|
||||
|
||||
private void tmp_generateTickLists() {
|
||||
ServerWorldContextRO context = ServerState.getInstance().createContext(getUp());
|
||||
ServerWorldContextRO context = Server.getCurrentServer().createContext(getUp());
|
||||
|
||||
GenericChunks.forEachBiC(blockInChunk -> {
|
||||
|
||||
|
@ -19,7 +19,6 @@
|
||||
package ru.windcorp.progressia.server.world;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ -44,7 +43,7 @@ public class DefaultWorldLogic implements WorldLogic {
|
||||
|
||||
private final WorldGenerator generator;
|
||||
|
||||
private final Map<DefaultChunkData, DefaultChunkLogic> chunks = Collections.synchronizedMap(new HashMap<>());
|
||||
private final Map<DefaultChunkData, DefaultChunkLogic> chunks = new HashMap<>();
|
||||
|
||||
private final Evaluation tickEntitiesTask = new TickEntitiesTask();
|
||||
|
||||
|
@ -49,18 +49,9 @@ public class TestGenerationConfig {
|
||||
private static final float CURVATURE = Units.get("100 m");
|
||||
private static final float INNER_RADIUS = Units.get("200 m");
|
||||
|
||||
private final Fields fields = new Fields(SEED);
|
||||
private final Function<Server, WorldGenerator> generator;
|
||||
private static final Fields FIELDS = new Fields(SEED);
|
||||
|
||||
public TestGenerationConfig() {
|
||||
this.generator = createGenerator();
|
||||
}
|
||||
|
||||
public Function<Server, WorldGenerator> getGenerator() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
private Function<Server, WorldGenerator> createGenerator() {
|
||||
public static Function<Server, WorldGenerator> createGenerator() {
|
||||
|
||||
Planet planet = new Planet(
|
||||
((int) PLANET_RADIUS) / Coordinates.CHUNK_SIZE,
|
||||
@ -69,7 +60,7 @@ public class TestGenerationConfig {
|
||||
INNER_RADIUS
|
||||
);
|
||||
|
||||
TestHeightMap heightMap = new TestHeightMap(planet, planet.getRadius() / 4, fields);
|
||||
TestHeightMap heightMap = new TestHeightMap(planet, planet.getRadius() / 4, FIELDS);
|
||||
|
||||
FloatRangeMap<TerrainLayer> layers = new ArrayFloatRangeMap<>();
|
||||
registerTerrainLayers(layers);
|
||||
@ -81,11 +72,11 @@ public class TestGenerationConfig {
|
||||
|
||||
}
|
||||
|
||||
private void registerTerrainLayers(FloatRangeMap<TerrainLayer> layers) {
|
||||
private static void registerTerrainLayers(FloatRangeMap<TerrainLayer> layers) {
|
||||
BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt");
|
||||
BlockData air = BlockDataRegistry.getInstance().get("Test:Air");
|
||||
|
||||
SurfaceFloatField cliffs = fields.get("Test:Cliff");
|
||||
SurfaceFloatField cliffs = FIELDS.get("Test:Cliff");
|
||||
|
||||
WorleyProceduralNoise.Builder<TerrainLayer> builder = WorleyProceduralNoise.builder();
|
||||
TestContent.ROCKS.getRocks().forEach(rock -> {
|
||||
@ -97,9 +88,9 @@ public class TestGenerationConfig {
|
||||
}
|
||||
}, 1);
|
||||
});
|
||||
SurfaceFloatField rockDepthOffsets = fields.register(
|
||||
SurfaceFloatField rockDepthOffsets = FIELDS.register(
|
||||
"Test:RockDepthOffsets",
|
||||
() -> tweak(fields.primitive(), 40, 5)
|
||||
() -> tweak(FIELDS.primitive(), 40, 5)
|
||||
);
|
||||
RockLayer rockLayer = new RockLayer(builder.build(SEED), rockDepthOffsets);
|
||||
|
||||
@ -114,28 +105,28 @@ public class TestGenerationConfig {
|
||||
layers.put(4, Float.POSITIVE_INFINITY, rockLayer);
|
||||
}
|
||||
|
||||
private void registerFeatures(List<SurfaceFeature> features) {
|
||||
private static void registerFeatures(List<SurfaceFeature> features) {
|
||||
|
||||
SurfaceFloatField forestiness = fields.register(
|
||||
SurfaceFloatField forestiness = FIELDS.register(
|
||||
"Test:Forest",
|
||||
() -> squash(scale(fields.primitive(), 200), 5)
|
||||
() -> squash(scale(FIELDS.primitive(), 200), 5)
|
||||
);
|
||||
|
||||
SurfaceFloatField grassiness = fields.register(
|
||||
SurfaceFloatField grassiness = FIELDS.register(
|
||||
"Test:Grass",
|
||||
f -> multiply(
|
||||
tweak(octaves(fields.primitive(), 2, 2), 40, 0.5, 1.2),
|
||||
squash(tweak(fields.get("Test:Forest", f), 1, -1, 1), 10),
|
||||
anti(squash(fields.get("Test:Cliff", f), 10))
|
||||
tweak(octaves(FIELDS.primitive(), 2, 2), 40, 0.5, 1.2),
|
||||
squash(tweak(FIELDS.get("Test:Forest", f), 1, -1, 1), 10),
|
||||
anti(squash(FIELDS.get("Test:Cliff", f), 10))
|
||||
)
|
||||
);
|
||||
|
||||
Function<String, SurfaceFloatField> floweriness = flowerName -> fields.register(
|
||||
Function<String, SurfaceFloatField> floweriness = flowerName -> FIELDS.register(
|
||||
"Test:Flower" + flowerName,
|
||||
f -> multiply(
|
||||
selectPositive(squash(scale(octaves(fields.primitive(), 2, 3), 100), 2), 1, 0.5),
|
||||
tweak(fields.get("Test:Forest", f), 1, -1, 1.1),
|
||||
anti(squash(fields.get("Test:Cliff", f), 10))
|
||||
selectPositive(squash(scale(octaves(FIELDS.primitive(), 2, 3), 100), 2), 1, 0.5),
|
||||
tweak(FIELDS.get("Test:Forest", f), 1, -1, 1.1),
|
||||
anti(squash(FIELDS.get("Test:Cliff", f), 10))
|
||||
)
|
||||
);
|
||||
|
||||
|
Reference in New Issue
Block a user