From 2723a0580709e443ffda2b2f41f63c32a6ee12c9 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 20 Jun 2021 22:09:29 -0700 Subject: [PATCH 001/119] refactor(rendering): rework chunk mesh generation with RXJava --- engine/build.gradle | 1 + .../terasology/engine/core/GameThread.java | 19 ++ .../rendering/primitives/ChunkMesh.java | 105 ++++------ .../world/ChunkMeshUpdateManager.java | 193 ------------------ .../rendering/world/RenderableWorld.java | 2 - .../rendering/world/RenderableWorldImpl.java | 110 ++++++---- .../rendering/world/WorldRendererImpl.java | 1 - .../terasology/engine/world/chunks/Chunk.java | 8 +- .../world/chunks/internal/ChunkImpl.java | 15 -- 9 files changed, 138 insertions(+), 316 deletions(-) delete mode 100644 engine/src/main/java/org/terasology/engine/rendering/world/ChunkMeshUpdateManager.java diff --git a/engine/build.gradle b/engine/build.gradle index 5995bdb8899..4dab0d3e95d 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -72,6 +72,7 @@ dependencies { implementation "org.terasology:reflections:0.9.12-MB" implementation group: 'org.javassist', name: 'javassist', version: '3.27.0-GA' implementation group: 'com.esotericsoftware', name: 'reflectasm', version: '1.11.9' + implementation group: 'io.reactivex.rxjava3', name: 'rxjava', version: '3.0.13' // Graphics, 3D, UI, etc api platform("org.lwjgl:lwjgl-bom:$LwjglVersion") diff --git a/engine/src/main/java/org/terasology/engine/core/GameThread.java b/engine/src/main/java/org/terasology/engine/core/GameThread.java index 052bec296bf..12c4ae98f13 100644 --- a/engine/src/main/java/org/terasology/engine/core/GameThread.java +++ b/engine/src/main/java/org/terasology/engine/core/GameThread.java @@ -4,9 +4,13 @@ import com.google.common.collect.Lists; import com.google.common.collect.Queues; +import io.reactivex.rxjava3.core.Scheduler; +import io.reactivex.rxjava3.schedulers.Schedulers; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.concurrent.BlockingDeque; +import java.util.concurrent.Executor; import java.util.concurrent.Semaphore; /** @@ -23,6 +27,21 @@ public final class GameThread { private static volatile Thread gameThread; private static BlockingDeque pendingRunnables = Queues.newLinkedBlockingDeque(); + private static final Scheduler MAIN; + + static { + MAIN = Schedulers.from(new Executor() { + @Override + public void execute(@NotNull Runnable runnable) { + pendingRunnables.add(runnable); + } + }); + } + + public static Scheduler main() { + return MAIN; + } + private GameThread() { } diff --git a/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkMesh.java b/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkMesh.java index 5bbb3c5a65e..1f5ad01b64d 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkMesh.java +++ b/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkMesh.java @@ -68,9 +68,6 @@ public enum RenderPhase { private boolean disposed; - /* CONCURRENCY */ - private ReentrantLock lock = new ReentrantLock(); - /* MEASUREMENTS */ private int timeToGenerateBlockVertices; private int timeToGenerateOptimizedBuffers; @@ -95,46 +92,39 @@ public boolean hasVertexElements() { * @return True if something was generated */ public boolean generateVBOs() { - if (lock.tryLock()) { - try { - // IMPORTANT: A mesh can only be generated once. - if (vertexElements == null || disposed) { - return false; - } - // Make sure that if it has already been generated, the previous buffers are freed - dispose(); - disposed = false; - - for (RenderType type : RenderType.values()) { - generateVBO(type); - } + // IMPORTANT: A mesh can only be generated once. + if (vertexElements == null || disposed) { + return false; + } - // Calculate the final amount of triangles - triangleCount = (vertexCount[0] + vertexCount[1] + vertexCount[2] + vertexCount[3]) / 3; - } finally { - lock.unlock(); - } + // Make sure that if it has already been generated, the previous buffers are freed + dispose(); + disposed = false; - return true; + for (RenderType type : RenderType.values()) { + generateVBO(type); } - return false; + // Calculate the final amount of triangles + triangleCount = (vertexCount[0] + vertexCount[1] + vertexCount[2] + vertexCount[3]) / 3; + + return true; } private void generateVBO(RenderType type) { VertexElements elements = vertexElements[type.ordinal()]; int id = type.getIndex(); if (!disposed && elements.buffer.elements() > 0) { - vertexBuffers[id] = GL15.glGenBuffers(); - idxBuffers[id] = GL15.glGenBuffers(); + vertexBuffers[id] = GL30.glGenBuffers(); + idxBuffers[id] = GL30.glGenBuffers(); vaoCount[id] = GL30.glGenVertexArrays(); GL30.glBindVertexArray(vaoCount[id]); - GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vertexBuffers[id]); + GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, vertexBuffers[id]); elements.buffer.writeBuffer(buffer -> { - GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL30.GL_STATIC_DRAW); + GL30.glBufferData(GL30.GL_ARRAY_BUFFER, buffer, GL30.GL_STATIC_DRAW); }); for (VertexResource.VertexDefinition definition : elements.buffer.definitions()) { @@ -171,19 +161,13 @@ public void discardData() { } private void renderVbo(int id) { - if (lock.tryLock()) { - try { - if (vertexBuffers[id] <= 0 || disposed) { - return; - } - - GL30.glBindVertexArray(vaoCount[id]); - GL30.glDrawElements(GL30.GL_TRIANGLES, vertexCount[id], GL30.GL_UNSIGNED_INT, 0); - GL30.glBindVertexArray(0); - } finally { - lock.unlock(); - } + if (vertexBuffers[id] <= 0 || disposed) { + return; } + + GL30.glBindVertexArray(vaoCount[id]); + GL30.glDrawElements(GL30.GL_TRIANGLES, vertexCount[id], GL30.GL_UNSIGNED_INT, 0); + GL30.glBindVertexArray(0); } /** @@ -223,33 +207,28 @@ public int render(RenderPhase type) { * ChunkMesh instances cannot be un-disposed. */ public void dispose() { - lock.lock(); - try { - if (!disposed) { - for (int i = 0; i < vertexBuffers.length; i++) { - int id = vertexBuffers[i]; - if (id != 0) { - GL15.glDeleteBuffers(id); - vertexBuffers[i] = 0; - } - - id = idxBuffers[i]; - if (id != 0) { - GL15.glDeleteBuffers(id); - idxBuffers[i] = 0; - } - - id = vaoCount[i]; - if (id != 0) { - GL30.glDeleteVertexArrays(id); - vaoCount[i] = 0; - } + if (!disposed) { + for (int i = 0; i < vertexBuffers.length; i++) { + int id = vertexBuffers[i]; + if (id != 0) { + GL15.glDeleteBuffers(id); + vertexBuffers[i] = 0; } - disposed = true; + id = idxBuffers[i]; + if (id != 0) { + GL15.glDeleteBuffers(id); + idxBuffers[i] = 0; + } + + id = vaoCount[i]; + if (id != 0) { + GL30.glDeleteVertexArrays(id); + vaoCount[i] = 0; + } } - } finally { - lock.unlock(); + + disposed = true; } } diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/ChunkMeshUpdateManager.java b/engine/src/main/java/org/terasology/engine/rendering/world/ChunkMeshUpdateManager.java deleted file mode 100644 index 27d4a2bfa0c..00000000000 --- a/engine/src/main/java/org/terasology/engine/rendering/world/ChunkMeshUpdateManager.java +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2021 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 -package org.terasology.engine.rendering.world; - -import com.google.common.collect.Lists; -import com.google.common.collect.Queues; -import org.joml.RoundingMode; -import org.joml.Vector3f; -import org.joml.Vector3i; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.terasology.engine.monitoring.chunk.ChunkMonitor; -import org.terasology.engine.rendering.primitives.ChunkMesh; -import org.terasology.engine.rendering.primitives.ChunkTessellator; -import org.terasology.engine.utilities.concurrency.TaskMaster; -import org.terasology.engine.world.ChunkView; -import org.terasology.engine.world.WorldProvider; -import org.terasology.engine.world.chunks.Chunk; -import org.terasology.engine.world.chunks.Chunks; -import org.terasology.engine.world.chunks.pipeline.ChunkTask; -import org.terasology.engine.world.chunks.pipeline.ShutdownChunkTask; - -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Set; -import java.util.concurrent.BlockingDeque; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Provides the mechanism for updating and generating chunk meshes. - * - */ -public final class ChunkMeshUpdateManager { - private static final int NUM_TASK_THREADS = 8; - - private static final Logger logger = LoggerFactory.getLogger(ChunkMeshUpdateManager.class); - - /* CHUNK UPDATES */ - private final Set chunksProcessing = Collections.newSetFromMap(new ConcurrentHashMap<>()); - - private final BlockingDeque chunksComplete = Queues.newLinkedBlockingDeque(); - - private TaskMaster chunkUpdater; - - private final ChunkTessellator tessellator; - private final WorldProvider worldProvider; - /** - * This variable is volatile, so that it's value is visible to worker thread that calculates the best task to - * process - */ - private volatile float cameraChunkPosX; - private volatile float cameraChunkPosY; - private volatile float cameraChunkPosZ; - - public ChunkMeshUpdateManager(ChunkTessellator tessellator, WorldProvider worldProvider) { - this.tessellator = tessellator; - this.worldProvider = worldProvider; - - chunkUpdater = TaskMaster.createDynamicPriorityTaskMaster("Chunk-Updater", NUM_TASK_THREADS, new ChunkUpdaterComparator()); - } - - /** - * Updates the given chunk using a new thread from the thread pool. If the maximum amount of chunk updates - * is reached, the chunk update is ignored. Chunk updates can be forced though. - * - * @param chunk The chunk to update - * @return True if a chunk update was executed - */ - // TODO: Review this system - public boolean queueChunkUpdate(Chunk chunk) { - - if (!chunksProcessing.contains(chunk)) { - executeChunkUpdate(chunk); - return true; - } - - return false; - } - - /** - * The method tells the chunk mesh update manager where the camera is, so that is able to prioritize chunks near the - * camera. It stores the values in volatile variables so that the change is visible to the chunk updating threads - * immediately. - */ - public void setCameraPosition(Vector3f cameraPosition) { - Vector3i chunkPos = Chunks.toChunkPos(new Vector3i(cameraPosition, RoundingMode.FLOOR)); - cameraChunkPosX = chunkPos.x; - cameraChunkPosY = chunkPos.y; - cameraChunkPosZ = chunkPos.z; - } - - public List availableChunksForUpdate() { - List result = Lists.newArrayListWithExpectedSize(chunksComplete.size()); - chunksComplete.drainTo(result); - chunksProcessing.removeAll(result); - return result; - } - - private void executeChunkUpdate(final Chunk c) { - chunksProcessing.add(c); - - ChunkUpdateTask task = new ChunkUpdateTask(c, tessellator, worldProvider, this); - try { - chunkUpdater.put(task); - } catch (InterruptedException e) { - logger.error("Failed to enqueue task {}", task, e); - } - } - - private void finishedProcessing(Chunk c) { - chunksComplete.add(c); - } - - public void shutdown() { - chunkUpdater.shutdown(new ShutdownChunkTask(), false); - } - - - private static class ChunkUpdateTask implements ChunkTask { - - private Chunk c; - private ChunkTessellator tessellator; - private WorldProvider worldProvider; - private ChunkMeshUpdateManager chunkMeshUpdateManager; - - ChunkUpdateTask(Chunk chunk, ChunkTessellator tessellator, WorldProvider worldProvider, ChunkMeshUpdateManager chunkMeshUpdateManager) { - this.chunkMeshUpdateManager = chunkMeshUpdateManager; - this.c = chunk; - this.tessellator = tessellator; - this.worldProvider = worldProvider; - } - - - @Override - public String getName() { - return "Update chunk"; - } - - @Override - public boolean isTerminateSignal() { - return false; - } - - @Override - public void run() { - ChunkMesh newMesh; - ChunkView chunkView = worldProvider.getLocalView(c.getPosition(new org.joml.Vector3i())); - if (chunkView != null) { - /* - * Important set dirty flag first, so that a concurrent modification of the chunk in the mean time we - * will end up with a dirty chunk. - */ - c.setDirty(false); - if (chunkView.isValidView()) { - newMesh = tessellator.generateMesh(chunkView); - - c.setPendingMesh(newMesh); - ChunkMonitor.fireChunkTessellated(c.getPosition(new org.joml.Vector3i()), newMesh); - } - - } - chunkMeshUpdateManager.finishedProcessing(c); - // Clean these up because the task executor holds the object in memory. - c = null; - tessellator = null; - worldProvider = null; - } - - @Override - public Chunk getChunk() { - return (Chunk) c; - } - } - - private class ChunkUpdaterComparator implements Comparator { - @Override - public int compare(ChunkTask o1, ChunkTask o2) { - return score(o1) - score(o2); - } - - private int score(ChunkTask task) { - if (task.isTerminateSignal()) { - return -1; - } - return distFromRegion(task.getPosition(), new Vector3i(cameraChunkPosX, cameraChunkPosY, cameraChunkPosZ, RoundingMode.FLOOR)); - } - - private int distFromRegion(Vector3i pos, Vector3i regionCenter) { - return (int) pos.gridDistance(regionCenter); - } - } -} diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorld.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorld.java index 9ad1e31d45e..975bc06e5b1 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorld.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorld.java @@ -24,8 +24,6 @@ public interface RenderableWorld { boolean updateChunksInProximity(ViewDistance viewDistance, int chunkLods); - void generateVBOs(); - int queueVisibleChunks(boolean isFirstRenderingStageForCurrentFrame); void dispose(); diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index bf5dc85d66c..f828c2ecd20 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -4,6 +4,19 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.core.MaybeSource; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.core.Scheduler; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.functions.Action; +import io.reactivex.rxjava3.functions.Consumer; +import io.reactivex.rxjava3.functions.Function; +import io.reactivex.rxjava3.schedulers.Schedulers; +import org.checkerframework.checker.nullness.Opt; +import org.joml.Random; import org.joml.Vector3f; import org.joml.Vector3fc; import org.joml.Vector3i; @@ -13,7 +26,9 @@ import org.terasology.engine.config.Config; import org.terasology.engine.config.RenderingConfig; import org.terasology.engine.context.Context; +import org.terasology.engine.core.GameThread; import org.terasology.engine.monitoring.PerformanceMonitor; +import org.terasology.engine.monitoring.chunk.ChunkMonitor; import org.terasology.engine.registry.CoreRegistry; import org.terasology.engine.rendering.cameras.Camera; import org.terasology.engine.rendering.logic.ChunkMeshRenderer; @@ -33,17 +48,25 @@ import org.terasology.joml.geom.AABBfc; import org.terasology.math.TeraMath; +import javax.swing.text.html.Option; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.PriorityQueue; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; /** * TODO: write javadoc unless this class gets slated for removal, which might be. */ class RenderableWorldImpl implements RenderableWorld { + private static final Logger logger = LoggerFactory.getLogger(RenderableWorldImpl.class); private static final int MAX_ANIMATED_CHUNKS = 64; private static final int MAX_BILLBOARD_CHUNKS = 64; @@ -51,8 +74,6 @@ class RenderableWorldImpl implements RenderableWorld { ViewDistance.MEGA.getChunkDistance().x() * ViewDistance.MEGA.getChunkDistance().y() * ViewDistance.MEGA.getChunkDistance().z(); private static final Vector3fc CHUNK_CENTER_OFFSET = new Vector3f(Chunks.CHUNK_SIZE).div(2); - private static final Logger logger = LoggerFactory.getLogger(RenderableWorldImpl.class); - private final int maxChunksForShadows = TeraMath.clamp(CoreRegistry.get(Config.class).getRendering().getMaxChunksUsedForShadowMapping(), 64, 1024); @@ -61,7 +82,7 @@ class RenderableWorldImpl implements RenderableWorld { private LodChunkProvider lodChunkProvider; private ChunkTessellator chunkTessellator; - private final ChunkMeshUpdateManager chunkMeshUpdateManager; +// private final ChunkMeshUpdateManager chunkMeshUpdateManager; private final List chunksInProximityOfCamera = Lists.newArrayListWithCapacity(MAX_LOADABLE_CHUNKS); private BlockRegion renderableRegion = new BlockRegion(BlockRegion.INVALID); private ViewDistance currentViewDistance; @@ -78,13 +99,14 @@ class RenderableWorldImpl implements RenderableWorld { private int statVisibleChunks; private int statIgnoredPhases; + private Map chunkMeshProcessing = Maps.newHashMap(); RenderableWorldImpl(Context context, Camera playerCamera) { worldProvider = context.get(WorldProvider.class); chunkProvider = context.get(ChunkProvider.class); chunkTessellator = context.get(ChunkTessellator.class); - chunkMeshUpdateManager = new ChunkMeshUpdateManager(chunkTessellator, worldProvider); +// chunkMeshUpdateManager = new ChunkMeshUpdateManager(chunkTessellator, worldProvider); this.playerCamera = playerCamera; WorldGenerator worldGenerator = context.get(WorldGenerator.class); @@ -128,12 +150,17 @@ public void onChunkLoaded(Vector3ic chunkCoordinates) { @Override public void onChunkUnloaded(Vector3ic chunkCoordinates) { + Disposable disposable = chunkMeshProcessing.remove(chunkCoordinates); + if (disposable != null && !disposable.isDisposed()) { + disposable.dispose(); + } + if (renderableRegion.contains(chunkCoordinates)) { Chunk chunk; Iterator iterator = chunksInProximityOfCamera.iterator(); while (iterator.hasNext()) { chunk = iterator.next(); - if (chunk.getPosition(new org.joml.Vector3i()).equals(chunkCoordinates)) { + if (chunk.getPosition().equals(chunkCoordinates)) { chunk.disposeMesh(); iterator.remove(); break; @@ -220,7 +247,7 @@ public boolean updateChunksInProximity(BlockRegion newRenderableRegion) { Iterator nearbyChunks = chunksInProximityOfCamera.iterator(); for (Iterator it = nearbyChunks; it.hasNext();) { chunk = it.next(); - if (chunk.getPosition(new org.joml.Vector3i()).equals(chunkPositionToRemove)) { + if (chunk.getPosition().equals(chunkPositionToRemove)) { chunk.disposeMesh(); nearbyChunks.remove(); break; @@ -283,32 +310,6 @@ private Vector3i calcCameraCoordinatesInChunkUnits() { return Chunks.toChunkPos(cameraCoordinates, new Vector3i()); } - @Override - public void generateVBOs() { - PerformanceMonitor.startActivity("Building Mesh VBOs"); - ChunkMesh pendingMesh; - chunkMeshUpdateManager.setCameraPosition(playerCamera.getPosition()); - for (Chunk chunk : chunkMeshUpdateManager.availableChunksForUpdate()) { - - if (chunk.hasPendingMesh() && chunksInProximityOfCamera.contains(chunk)) { - pendingMesh = chunk.getPendingMesh(); - pendingMesh.generateVBOs(); - pendingMesh.discardData(); - if (chunk.hasMesh()) { - chunk.getMesh().dispose(); - } - chunk.setMesh(pendingMesh); - chunk.setPendingMesh(null); - - } else { - if (chunk.hasPendingMesh()) { - chunk.getPendingMesh().dispose(); - chunk.setPendingMesh(null); - } - } - } - PerformanceMonitor.endActivity(); - } /** * Updates the currently visible chunks (in sight of the player). @@ -386,9 +387,44 @@ && isChunkVisibleFromMainLight(chunk)) { if (isFirstRenderingStageForCurrentFrame) { for (Chunk chunk : chunksInProximityOfCamera) { - if (isChunkValidForRender(chunk) && (chunk.isDirty() || !chunk.hasMesh())) { + if (isChunkValidForRender(chunk) && (chunk.isDirty() || !chunk.hasMesh()) && !chunkMeshProcessing.containsKey(chunk.getPosition())) { statDirtyChunks++; - chunkMeshUpdateManager.queueChunkUpdate(chunk); + final Chunk currentChunk = chunk; + chunkMeshProcessing.put(chunk.getPosition(), Observable + .just(currentChunk) + .observeOn(Schedulers.io()) + .delay(500 * processedChunks, TimeUnit.MILLISECONDS) // delay chunks so everything is not all evaluated at once + .mapOptional(c -> { + ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); + if (chunkView != null) { + /* + * Important set dirty flag first, so that a concurrent modification of the chunk in the mean time we + * will end up with a dirty chunk. + */ + c.setDirty(false); + if (chunkView.isValidView()) { + ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); + ChunkMonitor.fireChunkTessellated(new Vector3i(chunk.getPosition()), newMesh); + return Optional.of(newMesh); + } + } + return Optional.empty(); + }) + .observeOn(GameThread.main()) + .doFinally(() -> { + chunkMeshProcessing.remove(currentChunk.getPosition()); + }).subscribe(chunkMesh -> { + if (chunksInProximityOfCamera.contains(currentChunk)) { + chunkMesh.generateVBOs(); + chunkMesh.discardData(); + if (currentChunk.hasMesh()) { + currentChunk.getMesh().dispose(); + } + currentChunk.setMesh(chunkMesh); + } + }, throwable -> { + logger.error("Failed to build mesh {}", throwable); + })); processedChunks++; } } @@ -408,7 +444,11 @@ private int triangleCount(ChunkMesh mesh, ChunkMesh.RenderPhase renderPhase) { @Override public void dispose() { - chunkMeshUpdateManager.shutdown(); + for(Disposable dsp: chunkMeshProcessing.values()) { + if(!dsp.isDisposed()) { + dsp.dispose(); + } + } if (lodChunkProvider != null) { lodChunkProvider.shutdown(); } diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/WorldRendererImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/WorldRendererImpl.java index 59eaa54f373..74720194c27 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/WorldRendererImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/WorldRendererImpl.java @@ -295,7 +295,6 @@ private void preRenderUpdate(RenderingStage renderingStage) { playerCamera.update(secondsSinceLastFrame); renderableWorld.update(); - renderableWorld.generateVBOs(); secondsSinceLastFrame = 0; displayResolutionDependentFbo.update(); diff --git a/engine/src/main/java/org/terasology/engine/world/chunks/Chunk.java b/engine/src/main/java/org/terasology/engine/world/chunks/Chunk.java index 9e19bf58ecc..3f293d278d1 100644 --- a/engine/src/main/java/org/terasology/engine/world/chunks/Chunk.java +++ b/engine/src/main/java/org/terasology/engine/world/chunks/Chunk.java @@ -13,7 +13,7 @@ import org.terasology.gestalt.module.sandbox.API; /** - * Chunks are a box-shaped logical grouping of Terasology's blocks, for performance reasons. + * Chunks are a box-shaped logical grouping of Terasology's blocks, for performance reasons. * * For example the renderer renders a single mesh for all opaque blocks in a chunk rather * than rendering each block as a separate mesh. @@ -356,10 +356,4 @@ default Vector3f getRenderPosition() { boolean isDirty(); void setDirty(boolean dirty); - - void setPendingMesh(ChunkMesh newPendingMesh); - - boolean hasPendingMesh(); - - ChunkMesh getPendingMesh(); } diff --git a/engine/src/main/java/org/terasology/engine/world/chunks/internal/ChunkImpl.java b/engine/src/main/java/org/terasology/engine/world/chunks/internal/ChunkImpl.java index d9dc7b6bf75..27450b2ebb2 100644 --- a/engine/src/main/java/org/terasology/engine/world/chunks/internal/ChunkImpl.java +++ b/engine/src/main/java/org/terasology/engine/world/chunks/internal/ChunkImpl.java @@ -66,7 +66,6 @@ public class ChunkImpl implements Chunk { // Rendering private ChunkMesh activeMesh; - private ChunkMesh pendingMesh; public ChunkImpl(int x, int y, int z, BlockManager blockManager, ExtraBlockDataManager extraDataManager) { this(new Vector3i(x, y, z), blockManager, extraDataManager); @@ -422,11 +421,6 @@ public void setMesh(ChunkMesh mesh) { this.activeMesh = mesh; } - @Override - public void setPendingMesh(ChunkMesh mesh) { - this.pendingMesh = mesh; - } - @Override public void setAnimated(boolean animated) { this.animated = animated; @@ -442,21 +436,12 @@ public boolean hasMesh() { return activeMesh != null; } - @Override - public boolean hasPendingMesh() { - return pendingMesh != null; - } @Override public ChunkMesh getMesh() { return activeMesh; } - @Override - public ChunkMesh getPendingMesh() { - return pendingMesh; - } - @Override public void markReady() { ready = true; From f0ac4104d5fc68b8a77513fad4a5ddd36eb7fcf3 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 20 Jun 2021 22:43:27 -0700 Subject: [PATCH 002/119] cleanup --- .../rendering/world/RenderableWorldImpl.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index f828c2ecd20..527f844abb0 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -5,18 +5,9 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import io.reactivex.rxjava3.core.Flowable; -import io.reactivex.rxjava3.core.MaybeSource; import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.core.Scheduler; import io.reactivex.rxjava3.disposables.Disposable; -import io.reactivex.rxjava3.functions.Action; -import io.reactivex.rxjava3.functions.Consumer; -import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.schedulers.Schedulers; -import org.checkerframework.checker.nullness.Opt; -import org.joml.Random; import org.joml.Vector3f; import org.joml.Vector3fc; import org.joml.Vector3i; @@ -48,18 +39,14 @@ import org.terasology.joml.geom.AABBfc; import org.terasology.math.TeraMath; -import javax.swing.text.html.Option; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.PriorityQueue; -import java.util.Set; -import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** @@ -82,7 +69,6 @@ class RenderableWorldImpl implements RenderableWorld { private LodChunkProvider lodChunkProvider; private ChunkTessellator chunkTessellator; -// private final ChunkMeshUpdateManager chunkMeshUpdateManager; private final List chunksInProximityOfCamera = Lists.newArrayListWithCapacity(MAX_LOADABLE_CHUNKS); private BlockRegion renderableRegion = new BlockRegion(BlockRegion.INVALID); private ViewDistance currentViewDistance; @@ -106,7 +92,6 @@ class RenderableWorldImpl implements RenderableWorld { worldProvider = context.get(WorldProvider.class); chunkProvider = context.get(ChunkProvider.class); chunkTessellator = context.get(ChunkTessellator.class); -// chunkMeshUpdateManager = new ChunkMeshUpdateManager(chunkTessellator, worldProvider); this.playerCamera = playerCamera; WorldGenerator worldGenerator = context.get(WorldGenerator.class); From ca841b795469a1125deb9d83984fba3d1a834c4e Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 21 Jun 2021 07:17:16 -0700 Subject: [PATCH 003/119] chore: replace with computation --- .../terasology/engine/rendering/world/RenderableWorldImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index 527f844abb0..c8f1b25cd9c 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -377,7 +377,7 @@ && isChunkVisibleFromMainLight(chunk)) { final Chunk currentChunk = chunk; chunkMeshProcessing.put(chunk.getPosition(), Observable .just(currentChunk) - .observeOn(Schedulers.io()) + .observeOn(Schedulers.computation()) .delay(500 * processedChunks, TimeUnit.MILLISECONDS) // delay chunks so everything is not all evaluated at once .mapOptional(c -> { ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); From 093921c1b71fb5fe0f85b055d42f1cbe21a7ea9d Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 22 Jun 2021 22:16:29 -0700 Subject: [PATCH 004/119] refactor(rendering): rework chunk mesh generation with RXJava Flowable --- .../rendering/world/RenderableWorldImpl.java | 148 +++++++++++------- .../world/chunks/internal/ChunkImpl.java | 1 + 2 files changed, 94 insertions(+), 55 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index c8f1b25cd9c..afa7d9d4d3b 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -4,9 +4,10 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import io.reactivex.rxjava3.core.Observable; -import io.reactivex.rxjava3.disposables.Disposable; +import com.google.common.collect.Sets; +import io.reactivex.rxjava3.core.BackpressureStrategy; +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.core.FlowableEmitter; import io.reactivex.rxjava3.schedulers.Schedulers; import org.joml.Vector3f; import org.joml.Vector3fc; @@ -44,10 +45,9 @@ import java.util.Comparator; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.PriorityQueue; -import java.util.concurrent.TimeUnit; +import java.util.Set; /** * TODO: write javadoc unless this class gets slated for removal, which might be. @@ -85,7 +85,15 @@ class RenderableWorldImpl implements RenderableWorld { private int statVisibleChunks; private int statIgnoredPhases; - private Map chunkMeshProcessing = Maps.newHashMap(); + + private final Set chunkMeshProcessing = Sets.newHashSet(); + private FlowableEmitter chunkMeshPublisher; +// private Disposable meshDispose; + + private static class ChunkMeshPayload { + Chunk chunk; + ChunkMesh mesh; + } RenderableWorldImpl(Context context, Camera playerCamera) { @@ -109,6 +117,81 @@ class RenderableWorldImpl implements RenderableWorld { new PriorityQueue<>(MAX_LOADABLE_CHUNKS, new ChunkFrontToBackComparator()), new PriorityQueue<>(MAX_LOADABLE_CHUNKS, new ChunkFrontToBackComparator()), new PriorityQueue<>(MAX_LOADABLE_CHUNKS, new ChunkBackToFrontComparator())); + + Flowable.create(emitter -> chunkMeshPublisher = emitter, BackpressureStrategy.BUFFER) + .distinct(Chunk::getPosition, () -> chunkMeshProcessing) + .parallel(4).runOn(Schedulers.computation()) + .mapOptional(c -> { + ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); + if (chunkView != null) { + c.setDirty(false); + if (chunkView.isValidView()) { + ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); + ChunkMonitor.fireChunkTessellated(new Vector3i(c.getPosition()), newMesh); + ChunkMeshPayload payload = new ChunkMeshPayload(); + payload.chunk = c; + payload.mesh = newMesh; + return Optional.of(payload); + } + } + return Optional.empty(); + }) + .sequential() + .observeOn(GameThread.main()) + .doOnNext(k -> { + chunkMeshProcessing.remove(k.chunk.getPosition()); + }) + .subscribe(payload -> { + if (chunksInProximityOfCamera.contains(payload.chunk)) { + payload.mesh.generateVBOs(); + payload.mesh.discardData(); + if (payload.chunk.hasMesh()) { + payload.chunk.getMesh().dispose(); + } + payload.chunk.setMesh(payload.mesh); + } + }, throwable -> { + logger.error("Failed to build mesh {}", throwable); + }); +// +// meshDispose = chunkMeshPublisher +// .distinct(Chunk::getPosition, () -> chunkMeshProcessing) +// .toFlowable(BackpressureStrategy.BUFFER) +// .parallel() +// .runOn(Schedulers.computation()) +// .mapOptional(c -> { +// ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); +// if (chunkView != null) { +// c.setDirty(false); +// +// if (chunkView.isValidView()) { +// ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); +// ChunkMonitor.fireChunkTessellated(new Vector3i(c.getPosition()), newMesh); +// ChunkMeshPayload payload = new ChunkMeshPayload(); +// payload.chunk = c; +// payload.mesh = newMesh; +// return Optional.of(payload); +// } +// } +// return Optional.empty(); +// }) +// .sequential() +// .observeOn(GameThread.main()) +// .doOnNext(k -> { +// chunkMeshProcessing.remove(k.chunk.getPosition()); +// }) +// .subscribe(payload -> { +// if (chunksInProximityOfCamera.contains(payload.chunk)) { +// payload.mesh.generateVBOs(); +// payload.mesh.discardData(); +// if (payload.chunk.hasMesh()) { +// payload.chunk.getMesh().dispose(); +// } +// payload.chunk.setMesh(payload.mesh); +// } +// }, throwable -> { +// logger.error("Failed to build mesh {}", throwable); +// }); } @Override @@ -135,11 +218,6 @@ public void onChunkLoaded(Vector3ic chunkCoordinates) { @Override public void onChunkUnloaded(Vector3ic chunkCoordinates) { - Disposable disposable = chunkMeshProcessing.remove(chunkCoordinates); - if (disposable != null && !disposable.isDisposed()) { - disposable.dispose(); - } - if (renderableRegion.contains(chunkCoordinates)) { Chunk chunk; Iterator iterator = chunksInProximityOfCamera.iterator(); @@ -372,51 +450,15 @@ && isChunkVisibleFromMainLight(chunk)) { if (isFirstRenderingStageForCurrentFrame) { for (Chunk chunk : chunksInProximityOfCamera) { - if (isChunkValidForRender(chunk) && (chunk.isDirty() || !chunk.hasMesh()) && !chunkMeshProcessing.containsKey(chunk.getPosition())) { + if (isChunkValidForRender(chunk) && chunk.isDirty()) { statDirtyChunks++; - final Chunk currentChunk = chunk; - chunkMeshProcessing.put(chunk.getPosition(), Observable - .just(currentChunk) - .observeOn(Schedulers.computation()) - .delay(500 * processedChunks, TimeUnit.MILLISECONDS) // delay chunks so everything is not all evaluated at once - .mapOptional(c -> { - ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); - if (chunkView != null) { - /* - * Important set dirty flag first, so that a concurrent modification of the chunk in the mean time we - * will end up with a dirty chunk. - */ - c.setDirty(false); - if (chunkView.isValidView()) { - ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); - ChunkMonitor.fireChunkTessellated(new Vector3i(chunk.getPosition()), newMesh); - return Optional.of(newMesh); - } - } - return Optional.empty(); - }) - .observeOn(GameThread.main()) - .doFinally(() -> { - chunkMeshProcessing.remove(currentChunk.getPosition()); - }).subscribe(chunkMesh -> { - if (chunksInProximityOfCamera.contains(currentChunk)) { - chunkMesh.generateVBOs(); - chunkMesh.discardData(); - if (currentChunk.hasMesh()) { - currentChunk.getMesh().dispose(); - } - currentChunk.setMesh(chunkMesh); - } - }, throwable -> { - logger.error("Failed to build mesh {}", throwable); - })); - processedChunks++; + chunkMeshPublisher.onNext(chunk); } } } PerformanceMonitor.endActivity(); - return processedChunks; + return chunkMeshProcessing.size(); } private int triangleCount(ChunkMesh mesh, ChunkMesh.RenderPhase renderPhase) { @@ -429,11 +471,7 @@ private int triangleCount(ChunkMesh mesh, ChunkMesh.RenderPhase renderPhase) { @Override public void dispose() { - for(Disposable dsp: chunkMeshProcessing.values()) { - if(!dsp.isDisposed()) { - dsp.dispose(); - } - } +// meshDispose.dispose(); if (lodChunkProvider != null) { lodChunkProvider.shutdown(); } diff --git a/engine/src/main/java/org/terasology/engine/world/chunks/internal/ChunkImpl.java b/engine/src/main/java/org/terasology/engine/world/chunks/internal/ChunkImpl.java index 27450b2ebb2..94d9a79a7e7 100644 --- a/engine/src/main/java/org/terasology/engine/world/chunks/internal/ChunkImpl.java +++ b/engine/src/main/java/org/terasology/engine/world/chunks/internal/ChunkImpl.java @@ -462,6 +462,7 @@ public void prepareForReactivation() { public void dispose() { disposed = true; ready = false; + dirty = true; disposeMesh(); /* * Explicitly do not clear data, so that background threads that work with the chunk can finish. From 77912542e8254cc5acd90f27d67aecf07dfbd324 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 23 Jun 2021 07:28:34 -0700 Subject: [PATCH 005/119] update tessellator --- .../primitives/ChunkTessellator.java | 10 +- .../rendering/world/RenderableWorldImpl.java | 112 ++++++------------ 2 files changed, 38 insertions(+), 84 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkTessellator.java b/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkTessellator.java index bafe231cbd2..004e4e61434 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkTessellator.java +++ b/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkTessellator.java @@ -33,15 +33,11 @@ public ChunkMesh generateMesh(ChunkView chunkView, float scale, int border) { final Stopwatch watch = Stopwatch.createStarted(); - watch.stop(); - mesh.setTimeToGenerateBlockVertices((int) watch.elapsed(TimeUnit.MILLISECONDS)); - watch.reset().start(); - // The mesh extends into the borders in the horizontal directions, but not vertically upwards, in order to cover // gaps between LOD chunks of different scales, but also avoid multiple overlapping ocean surfaces. - for (int x = 0; x < Chunks.SIZE_X; x++) { + for (int y = 0; y < Chunks.SIZE_Y - border * 2; y++) { for (int z = 0; z < Chunks.SIZE_Z; z++) { - for (int y = 0; y < Chunks.SIZE_Y - border * 2; y++) { + for (int x = 0; x < Chunks.SIZE_X; x++) { Block block = chunkView.getBlock(x, y, z); if (block != null && block.getMeshGenerator() != null) { block.getMeshGenerator().generateChunkMesh(chunkView, mesh, x, y, z); @@ -63,7 +59,7 @@ public ChunkMesh generateMesh(ChunkView chunkView, float scale, int border) { } watch.stop(); - mesh.setTimeToGenerateOptimizedBuffers((int) watch.elapsed(TimeUnit.MILLISECONDS)); + mesh.setTimeToGenerateBlockVertices((int) watch.elapsed(TimeUnit.MILLISECONDS)); statVertexArrayUpdateCount++; PerformanceMonitor.endActivity(); diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index afa7d9d4d3b..6b5d60d0b32 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -6,9 +6,8 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; import io.reactivex.rxjava3.core.BackpressureStrategy; -import io.reactivex.rxjava3.core.Flowable; -import io.reactivex.rxjava3.core.FlowableEmitter; import io.reactivex.rxjava3.schedulers.Schedulers; +import io.reactivex.rxjava3.subjects.PublishSubject; import org.joml.Vector3f; import org.joml.Vector3fc; import org.joml.Vector3i; @@ -85,10 +84,8 @@ class RenderableWorldImpl implements RenderableWorld { private int statVisibleChunks; private int statIgnoredPhases; - private final Set chunkMeshProcessing = Sets.newHashSet(); - private FlowableEmitter chunkMeshPublisher; -// private Disposable meshDispose; + private PublishSubject chunkMeshPublisher = PublishSubject.create(); private static class ChunkMeshPayload { Chunk chunk; @@ -118,80 +115,41 @@ private static class ChunkMeshPayload { new PriorityQueue<>(MAX_LOADABLE_CHUNKS, new ChunkFrontToBackComparator()), new PriorityQueue<>(MAX_LOADABLE_CHUNKS, new ChunkBackToFrontComparator())); - Flowable.create(emitter -> chunkMeshPublisher = emitter, BackpressureStrategy.BUFFER) - .distinct(Chunk::getPosition, () -> chunkMeshProcessing) - .parallel(4).runOn(Schedulers.computation()) - .mapOptional(c -> { - ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); - if (chunkView != null) { - c.setDirty(false); - if (chunkView.isValidView()) { - ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); - ChunkMonitor.fireChunkTessellated(new Vector3i(c.getPosition()), newMesh); - ChunkMeshPayload payload = new ChunkMeshPayload(); - payload.chunk = c; - payload.mesh = newMesh; - return Optional.of(payload); - } + chunkMeshPublisher.toFlowable(BackpressureStrategy.BUFFER) + .distinct(Chunk::getPosition, () -> chunkMeshProcessing) + .parallel(4).runOn(Schedulers.computation()) + .mapOptional(c -> { + ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); + if (chunkView != null) { + c.setDirty(false); + if (chunkView.isValidView()) { + ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); + ChunkMonitor.fireChunkTessellated(new Vector3i(c.getPosition()), newMesh); + ChunkMeshPayload payload = new ChunkMeshPayload(); + payload.chunk = c; + payload.mesh = newMesh; + return Optional.of(payload); } - return Optional.empty(); - }) - .sequential() - .observeOn(GameThread.main()) - .doOnNext(k -> { - chunkMeshProcessing.remove(k.chunk.getPosition()); - }) - .subscribe(payload -> { - if (chunksInProximityOfCamera.contains(payload.chunk)) { - payload.mesh.generateVBOs(); - payload.mesh.discardData(); - if (payload.chunk.hasMesh()) { - payload.chunk.getMesh().dispose(); - } - payload.chunk.setMesh(payload.mesh); + } + return Optional.empty(); + }) + .sequential() + .observeOn(GameThread.main()) + .doOnNext(k -> { + chunkMeshProcessing.remove(k.chunk.getPosition()); + }) + .subscribe(payload -> { + if (chunksInProximityOfCamera.contains(payload.chunk)) { + payload.mesh.generateVBOs(); + payload.mesh.discardData(); + if (payload.chunk.hasMesh()) { + payload.chunk.getMesh().dispose(); } - }, throwable -> { - logger.error("Failed to build mesh {}", throwable); - }); -// -// meshDispose = chunkMeshPublisher -// .distinct(Chunk::getPosition, () -> chunkMeshProcessing) -// .toFlowable(BackpressureStrategy.BUFFER) -// .parallel() -// .runOn(Schedulers.computation()) -// .mapOptional(c -> { -// ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); -// if (chunkView != null) { -// c.setDirty(false); -// -// if (chunkView.isValidView()) { -// ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); -// ChunkMonitor.fireChunkTessellated(new Vector3i(c.getPosition()), newMesh); -// ChunkMeshPayload payload = new ChunkMeshPayload(); -// payload.chunk = c; -// payload.mesh = newMesh; -// return Optional.of(payload); -// } -// } -// return Optional.empty(); -// }) -// .sequential() -// .observeOn(GameThread.main()) -// .doOnNext(k -> { -// chunkMeshProcessing.remove(k.chunk.getPosition()); -// }) -// .subscribe(payload -> { -// if (chunksInProximityOfCamera.contains(payload.chunk)) { -// payload.mesh.generateVBOs(); -// payload.mesh.discardData(); -// if (payload.chunk.hasMesh()) { -// payload.chunk.getMesh().dispose(); -// } -// payload.chunk.setMesh(payload.mesh); -// } -// }, throwable -> { -// logger.error("Failed to build mesh {}", throwable); -// }); + payload.chunk.setMesh(payload.mesh); + } + }, throwable -> { + logger.error("Failed to build mesh {}", throwable); + }); } @Override From 8016258fb21706069c6e08a7b2711c6f8c0b579c Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 24 Jun 2021 19:49:35 -0700 Subject: [PATCH 006/119] chore: cleanup --- .../rendering/world/RenderableWorldImpl.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index 6b5d60d0b32..163fb7bf35c 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -117,19 +117,17 @@ private static class ChunkMeshPayload { chunkMeshPublisher.toFlowable(BackpressureStrategy.BUFFER) .distinct(Chunk::getPosition, () -> chunkMeshProcessing) + .doOnNext(k -> k.setDirty(false)) .parallel(4).runOn(Schedulers.computation()) .mapOptional(c -> { ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); - if (chunkView != null) { - c.setDirty(false); - if (chunkView.isValidView()) { - ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); - ChunkMonitor.fireChunkTessellated(new Vector3i(c.getPosition()), newMesh); - ChunkMeshPayload payload = new ChunkMeshPayload(); - payload.chunk = c; - payload.mesh = newMesh; - return Optional.of(payload); - } + if (chunkView != null && chunkView.isValidView()) { + ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); + ChunkMonitor.fireChunkTessellated(new Vector3i(c.getPosition()), newMesh); + ChunkMeshPayload payload = new ChunkMeshPayload(); + payload.chunk = c; + payload.mesh = newMesh; + return Optional.of(payload); } return Optional.empty(); }) From dea78158d7fa4c6ed6a42327722ae315dbc11f61 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 26 Jun 2021 08:07:45 -0700 Subject: [PATCH 007/119] chore: cleanup --- .../main/java/org/terasology/engine/core/GameThread.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/core/GameThread.java b/engine/src/main/java/org/terasology/engine/core/GameThread.java index 12c4ae98f13..b79b71ee91d 100644 --- a/engine/src/main/java/org/terasology/engine/core/GameThread.java +++ b/engine/src/main/java/org/terasology/engine/core/GameThread.java @@ -6,11 +6,9 @@ import com.google.common.collect.Queues; import io.reactivex.rxjava3.core.Scheduler; import io.reactivex.rxjava3.schedulers.Schedulers; -import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.concurrent.BlockingDeque; -import java.util.concurrent.Executor; import java.util.concurrent.Semaphore; /** @@ -30,12 +28,7 @@ public final class GameThread { private static final Scheduler MAIN; static { - MAIN = Schedulers.from(new Executor() { - @Override - public void execute(@NotNull Runnable runnable) { - pendingRunnables.add(runnable); - } - }); + MAIN = Schedulers.from(runnable -> pendingRunnables.add(runnable)); } public static Scheduler main() { From 5902bbd5aa256846e660a5803bf63f78d17758bb Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 27 Jun 2021 15:00:03 -0700 Subject: [PATCH 008/119] chore: add info --- .../terasology/engine/rendering/world/RenderableWorldImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index 163fb7bf35c..807ad5fb762 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -118,7 +118,7 @@ private static class ChunkMeshPayload { chunkMeshPublisher.toFlowable(BackpressureStrategy.BUFFER) .distinct(Chunk::getPosition, () -> chunkMeshProcessing) .doOnNext(k -> k.setDirty(false)) - .parallel(4).runOn(Schedulers.computation()) + .parallel(4).runOn(Schedulers.computation()) // allocation is pretty heavy :/ .mapOptional(c -> { ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); if (chunkView != null && chunkView.isValidView()) { From 9b04a7102e4c56b99f222bad9cf62965395af28f Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 27 Jun 2021 16:16:57 -0700 Subject: [PATCH 009/119] chore: better handle processing chunks that are unloaded --- .../engine/rendering/world/RenderableWorldImpl.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index 807ad5fb762..03250e4e21b 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -84,7 +84,7 @@ class RenderableWorldImpl implements RenderableWorld { private int statVisibleChunks; private int statIgnoredPhases; - private final Set chunkMeshProcessing = Sets.newHashSet(); + private final Set chunkMeshProcessing = Sets.newConcurrentHashSet(); private PublishSubject chunkMeshPublisher = PublishSubject.create(); private static class ChunkMeshPayload { @@ -121,7 +121,7 @@ private static class ChunkMeshPayload { .parallel(4).runOn(Schedulers.computation()) // allocation is pretty heavy :/ .mapOptional(c -> { ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); - if (chunkView != null && chunkView.isValidView()) { + if (chunkView != null && chunkView.isValidView() && chunkMeshProcessing.remove(c.getPosition())) { ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); ChunkMonitor.fireChunkTessellated(new Vector3i(c.getPosition()), newMesh); ChunkMeshPayload payload = new ChunkMeshPayload(); @@ -133,9 +133,6 @@ private static class ChunkMeshPayload { }) .sequential() .observeOn(GameThread.main()) - .doOnNext(k -> { - chunkMeshProcessing.remove(k.chunk.getPosition()); - }) .subscribe(payload -> { if (chunksInProximityOfCamera.contains(payload.chunk)) { payload.mesh.generateVBOs(); @@ -174,6 +171,8 @@ public void onChunkLoaded(Vector3ic chunkCoordinates) { @Override public void onChunkUnloaded(Vector3ic chunkCoordinates) { + chunkMeshProcessing.remove(chunkCoordinates); + if (renderableRegion.contains(chunkCoordinates)) { Chunk chunk; Iterator iterator = chunksInProximityOfCamera.iterator(); From 543a293d8c40d85d74752e993cba6c3b76eeaaa0 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 3 Jul 2021 12:49:44 -0700 Subject: [PATCH 010/119] chore: replace with reactor --- engine/build.gradle | 2 +- .../terasology/engine/core/GameThread.java | 6 +-- .../rendering/world/RenderableWorldImpl.java | 40 +++++++++++-------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/engine/build.gradle b/engine/build.gradle index 4dab0d3e95d..16cc11b1b53 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -72,7 +72,7 @@ dependencies { implementation "org.terasology:reflections:0.9.12-MB" implementation group: 'org.javassist', name: 'javassist', version: '3.27.0-GA' implementation group: 'com.esotericsoftware', name: 'reflectasm', version: '1.11.9' - implementation group: 'io.reactivex.rxjava3', name: 'rxjava', version: '3.0.13' + implementation group: 'io.projectreactor', name: 'reactor-core', version: '3.4.7' // Graphics, 3D, UI, etc api platform("org.lwjgl:lwjgl-bom:$LwjglVersion") diff --git a/engine/src/main/java/org/terasology/engine/core/GameThread.java b/engine/src/main/java/org/terasology/engine/core/GameThread.java index b79b71ee91d..f246e07c303 100644 --- a/engine/src/main/java/org/terasology/engine/core/GameThread.java +++ b/engine/src/main/java/org/terasology/engine/core/GameThread.java @@ -4,8 +4,8 @@ import com.google.common.collect.Lists; import com.google.common.collect.Queues; -import io.reactivex.rxjava3.core.Scheduler; -import io.reactivex.rxjava3.schedulers.Schedulers; +import reactor.core.scheduler.Scheduler; +import reactor.core.scheduler.Schedulers; import java.util.List; import java.util.concurrent.BlockingDeque; @@ -28,7 +28,7 @@ public final class GameThread { private static final Scheduler MAIN; static { - MAIN = Schedulers.from(runnable -> pendingRunnables.add(runnable)); + MAIN = Schedulers.fromExecutor(runnable -> pendingRunnables.add(runnable)); } public static Scheduler main() { diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index 03250e4e21b..9201a057dac 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -4,10 +4,8 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; +import com.google.common.collect.Queues; import com.google.common.collect.Sets; -import io.reactivex.rxjava3.core.BackpressureStrategy; -import io.reactivex.rxjava3.schedulers.Schedulers; -import io.reactivex.rxjava3.subjects.PublishSubject; import org.joml.Vector3f; import org.joml.Vector3fc; import org.joml.Vector3i; @@ -38,6 +36,9 @@ import org.terasology.engine.world.generator.WorldGenerator; import org.terasology.joml.geom.AABBfc; import org.terasology.math.TeraMath; +import reactor.core.publisher.Sinks; +import reactor.core.publisher.SynchronousSink; +import reactor.core.scheduler.Schedulers; import java.util.ArrayList; import java.util.Collections; @@ -85,7 +86,10 @@ class RenderableWorldImpl implements RenderableWorld { private int statIgnoredPhases; private final Set chunkMeshProcessing = Sets.newConcurrentHashSet(); - private PublishSubject chunkMeshPublisher = PublishSubject.create(); + private Sinks.Many chunkMeshPublisher = Sinks.many().unicast().onBackpressureBuffer(Queues.newArrayBlockingQueue(100)); + + private SynchronousSink chunkSink; + private static class ChunkMeshPayload { Chunk chunk; @@ -115,11 +119,11 @@ private static class ChunkMeshPayload { new PriorityQueue<>(MAX_LOADABLE_CHUNKS, new ChunkFrontToBackComparator()), new PriorityQueue<>(MAX_LOADABLE_CHUNKS, new ChunkBackToFrontComparator())); - chunkMeshPublisher.toFlowable(BackpressureStrategy.BUFFER) + chunkMeshPublisher.asFlux() .distinct(Chunk::getPosition, () -> chunkMeshProcessing) .doOnNext(k -> k.setDirty(false)) - .parallel(4).runOn(Schedulers.computation()) // allocation is pretty heavy :/ - .mapOptional(c -> { + .parallel(6).runOn(Schedulers.boundedElastic()) + .>map(c -> { ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); if (chunkView != null && chunkView.isValidView() && chunkMeshProcessing.remove(c.getPosition())) { ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); @@ -131,17 +135,19 @@ private static class ChunkMeshPayload { } return Optional.empty(); }) - .sequential() - .observeOn(GameThread.main()) + .sequential().publishOn(GameThread.main()) .subscribe(payload -> { - if (chunksInProximityOfCamera.contains(payload.chunk)) { - payload.mesh.generateVBOs(); - payload.mesh.discardData(); - if (payload.chunk.hasMesh()) { - payload.chunk.getMesh().dispose(); + payload.ifPresent(result -> { + if (chunksInProximityOfCamera.contains(result.chunk)) { + result.mesh.generateVBOs(); + result.mesh.discardData(); + if (result.chunk.hasMesh()) { + result.chunk.getMesh().dispose(); + } + result.chunk.setMesh(result.mesh); } - payload.chunk.setMesh(payload.mesh); - } + }); + }, throwable -> { logger.error("Failed to build mesh {}", throwable); }); @@ -407,7 +413,7 @@ && isChunkVisibleFromMainLight(chunk)) { for (Chunk chunk : chunksInProximityOfCamera) { if (isChunkValidForRender(chunk) && chunk.isDirty()) { statDirtyChunks++; - chunkMeshPublisher.onNext(chunk); + chunkMeshPublisher.tryEmitNext(chunk); } } } From 08cafdc7295bdbe6bf7e6808b34e0ad4bdf5dffd Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 3 Jul 2021 18:54:44 -0700 Subject: [PATCH 011/119] chore: batch process chunks --- .../rendering/world/RenderableWorldImpl.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index 9201a057dac..ecf0fefdcd7 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -10,6 +10,7 @@ import org.joml.Vector3fc; import org.joml.Vector3i; import org.joml.Vector3ic; +import org.reactivestreams.Publisher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.engine.config.Config; @@ -37,9 +38,9 @@ import org.terasology.joml.geom.AABBfc; import org.terasology.math.TeraMath; import reactor.core.publisher.Sinks; -import reactor.core.publisher.SynchronousSink; import reactor.core.scheduler.Schedulers; +import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -88,9 +89,6 @@ class RenderableWorldImpl implements RenderableWorld { private final Set chunkMeshProcessing = Sets.newConcurrentHashSet(); private Sinks.Many chunkMeshPublisher = Sinks.many().unicast().onBackpressureBuffer(Queues.newArrayBlockingQueue(100)); - private SynchronousSink chunkSink; - - private static class ChunkMeshPayload { Chunk chunk; ChunkMesh mesh; @@ -122,7 +120,14 @@ private static class ChunkMeshPayload { chunkMeshPublisher.asFlux() .distinct(Chunk::getPosition, () -> chunkMeshProcessing) .doOnNext(k -> k.setDirty(false)) - .parallel(6).runOn(Schedulers.boundedElastic()) + .bufferTimeout(100, Duration.ofMillis(100)) + .parallel().runOn(Schedulers.boundedElastic()) + .flatMap(chunks -> (Publisher) res -> { + chunks.sort(new ChunkFrontToBackComparator()); + for (Chunk c : chunks) { + res.onNext(c); + } + }) .>map(c -> { ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); if (chunkView != null && chunkView.isValidView() && chunkMeshProcessing.remove(c.getPosition())) { @@ -134,8 +139,8 @@ private static class ChunkMeshPayload { return Optional.of(payload); } return Optional.empty(); - }) - .sequential().publishOn(GameThread.main()) + }).sequential() + .publishOn(GameThread.main()) .subscribe(payload -> { payload.ifPresent(result -> { if (chunksInProximityOfCamera.contains(result.chunk)) { From 8c6e91860b91abfe58493edb6bacb59028905e8d Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 4 Jul 2021 00:13:05 -0700 Subject: [PATCH 012/119] chore: minor cleanup --- .../rendering/world/RenderableWorldImpl.java | 71 ++++++++----------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index ecf0fefdcd7..4935ace0d60 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -4,13 +4,11 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; -import com.google.common.collect.Queues; import com.google.common.collect.Sets; import org.joml.Vector3f; import org.joml.Vector3fc; import org.joml.Vector3i; import org.joml.Vector3ic; -import org.reactivestreams.Publisher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.engine.config.Config; @@ -40,7 +38,6 @@ import reactor.core.publisher.Sinks; import reactor.core.scheduler.Schedulers; -import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -87,7 +84,7 @@ class RenderableWorldImpl implements RenderableWorld { private int statIgnoredPhases; private final Set chunkMeshProcessing = Sets.newConcurrentHashSet(); - private Sinks.Many chunkMeshPublisher = Sinks.many().unicast().onBackpressureBuffer(Queues.newArrayBlockingQueue(100)); + private Sinks.Many chunkMeshPublisher = Sinks.many().unicast().onBackpressureBuffer(); private static class ChunkMeshPayload { Chunk chunk; @@ -118,44 +115,38 @@ private static class ChunkMeshPayload { new PriorityQueue<>(MAX_LOADABLE_CHUNKS, new ChunkBackToFrontComparator())); chunkMeshPublisher.asFlux() - .distinct(Chunk::getPosition, () -> chunkMeshProcessing) - .doOnNext(k -> k.setDirty(false)) - .bufferTimeout(100, Duration.ofMillis(100)) - .parallel().runOn(Schedulers.boundedElastic()) - .flatMap(chunks -> (Publisher) res -> { - chunks.sort(new ChunkFrontToBackComparator()); - for (Chunk c : chunks) { - res.onNext(c); - } - }) - .>map(c -> { - ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); - if (chunkView != null && chunkView.isValidView() && chunkMeshProcessing.remove(c.getPosition())) { - ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); - ChunkMonitor.fireChunkTessellated(new Vector3i(c.getPosition()), newMesh); - ChunkMeshPayload payload = new ChunkMeshPayload(); - payload.chunk = c; - payload.mesh = newMesh; - return Optional.of(payload); - } - return Optional.empty(); - }).sequential() - .publishOn(GameThread.main()) - .subscribe(payload -> { - payload.ifPresent(result -> { - if (chunksInProximityOfCamera.contains(result.chunk)) { - result.mesh.generateVBOs(); - result.mesh.discardData(); - if (result.chunk.hasMesh()) { - result.chunk.getMesh().dispose(); - } - result.chunk.setMesh(result.mesh); + .subscribeOn(Schedulers.newSingle("chunk reactor")) + .distinct(Chunk::getPosition, () -> chunkMeshProcessing) + .doOnNext(k -> k.setDirty(false)) + .parallel().runOn(Schedulers.parallel()) + .>map(c -> { + ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); + if (chunkView != null && chunkView.isValidView() && chunkMeshProcessing.remove(c.getPosition())) { + ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); + ChunkMonitor.fireChunkTessellated(new Vector3i(c.getPosition()), newMesh); + ChunkMeshPayload payload = new ChunkMeshPayload(); + payload.chunk = c; + payload.mesh = newMesh; + return Optional.of(payload); } - }); + return Optional.empty(); + }).filter(Optional::isPresent).sequential() + .publishOn(GameThread.main()) + .subscribe(payload -> { + payload.ifPresent(result -> { + if (chunksInProximityOfCamera.contains(result.chunk)) { + result.mesh.generateVBOs(); + result.mesh.discardData(); + if (result.chunk.hasMesh()) { + result.chunk.getMesh().dispose(); + } + result.chunk.setMesh(result.mesh); + } + }); - }, throwable -> { - logger.error("Failed to build mesh {}", throwable); - }); + }, throwable -> { + logger.error("Failed to build mesh {}", throwable); + }); } @Override From f53e6bc743404986b23cb63bdfe6ad38b255fbff Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 4 Jul 2021 10:03:19 -0700 Subject: [PATCH 013/119] chore: limit number of parallel rails --- .../terasology/engine/rendering/world/RenderableWorldImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index 4935ace0d60..25f404513cf 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -115,10 +115,9 @@ private static class ChunkMeshPayload { new PriorityQueue<>(MAX_LOADABLE_CHUNKS, new ChunkBackToFrontComparator())); chunkMeshPublisher.asFlux() - .subscribeOn(Schedulers.newSingle("chunk reactor")) .distinct(Chunk::getPosition, () -> chunkMeshProcessing) .doOnNext(k -> k.setDirty(false)) - .parallel().runOn(Schedulers.parallel()) + .parallel(5).runOn(Schedulers.parallel()) .>map(c -> { ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); if (chunkView != null && chunkView.isValidView() && chunkMeshProcessing.remove(c.getPosition())) { From fef81c6ebab3e761fb77bfde0e39a13a30493367 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 28 Aug 2021 17:05:58 -0700 Subject: [PATCH 014/119] chore: remove duplicate reactor and scheulders --- engine/build.gradle | 1 - .../engine/rendering/world/RenderableWorldImpl.java | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/engine/build.gradle b/engine/build.gradle index 48928597e0f..22e24e785e6 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -82,7 +82,6 @@ dependencies { implementation "org.terasology:reflections:0.9.12-MB" implementation group: 'org.javassist', name: 'javassist', version: '3.27.0-GA' implementation group: 'com.esotericsoftware', name: 'reflectasm', version: '1.11.9' - implementation group: 'io.projectreactor', name: 'reactor-core', version: '3.4.7' // Graphics, 3D, UI, etc api platform("org.lwjgl:lwjgl-bom:$LwjglVersion") diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index 8b2a500b6c3..073c3277119 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -14,6 +14,7 @@ import org.terasology.engine.config.Config; import org.terasology.engine.config.RenderingConfig; import org.terasology.engine.context.Context; +import org.terasology.engine.core.GameScheduler; import org.terasology.engine.core.GameThread; import org.terasology.engine.monitoring.PerformanceMonitor; import org.terasology.engine.monitoring.chunk.ChunkMonitor; @@ -36,7 +37,6 @@ import org.terasology.joml.geom.AABBfc; import org.terasology.math.TeraMath; import reactor.core.publisher.Sinks; -import reactor.core.scheduler.Schedulers; import java.util.ArrayList; import java.util.Comparator; @@ -115,7 +115,7 @@ private static class ChunkMeshPayload { chunkMeshPublisher.asFlux() .distinct(Chunk::getPosition, () -> chunkMeshProcessing) .doOnNext(k -> k.setDirty(false)) - .parallel(5).runOn(Schedulers.parallel()) + .parallel(5).runOn(GameScheduler.parallel()) .>map(c -> { ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); if (chunkView != null && chunkView.isValidView() && chunkMeshProcessing.remove(c.getPosition())) { @@ -534,5 +534,4 @@ public int compare(RenderableChunk chunk1, RenderableChunk chunk2) { return Double.compare(distance2, distance1); } } - } From cfc7d58f7fe033808f9fef10a9f838f07c31bfa3 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 28 Aug 2021 21:32:52 -0700 Subject: [PATCH 015/119] chore: update interfaces --- .../terasology/engine/core/GameThread.java | 12 ------- .../rendering/world/RenderableWorldImpl.java | 31 +++++++------------ 2 files changed, 11 insertions(+), 32 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/core/GameThread.java b/engine/src/main/java/org/terasology/engine/core/GameThread.java index f246e07c303..052bec296bf 100644 --- a/engine/src/main/java/org/terasology/engine/core/GameThread.java +++ b/engine/src/main/java/org/terasology/engine/core/GameThread.java @@ -4,8 +4,6 @@ import com.google.common.collect.Lists; import com.google.common.collect.Queues; -import reactor.core.scheduler.Scheduler; -import reactor.core.scheduler.Schedulers; import java.util.List; import java.util.concurrent.BlockingDeque; @@ -25,16 +23,6 @@ public final class GameThread { private static volatile Thread gameThread; private static BlockingDeque pendingRunnables = Queues.newLinkedBlockingDeque(); - private static final Scheduler MAIN; - - static { - MAIN = Schedulers.fromExecutor(runnable -> pendingRunnables.add(runnable)); - } - - public static Scheduler main() { - return MAIN; - } - private GameThread() { } diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index 073c3277119..1f5d5a8ca81 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -15,7 +15,6 @@ import org.terasology.engine.config.RenderingConfig; import org.terasology.engine.context.Context; import org.terasology.engine.core.GameScheduler; -import org.terasology.engine.core.GameThread; import org.terasology.engine.monitoring.PerformanceMonitor; import org.terasology.engine.monitoring.chunk.ChunkMonitor; import org.terasology.engine.registry.CoreRegistry; @@ -37,6 +36,8 @@ import org.terasology.joml.geom.AABBfc; import org.terasology.math.TeraMath; import reactor.core.publisher.Sinks; +import reactor.util.function.Tuple2; +import reactor.util.function.Tuples; import java.util.ArrayList; import java.util.Comparator; @@ -84,11 +85,6 @@ class RenderableWorldImpl implements RenderableWorld { private final Set chunkMeshProcessing = Sets.newConcurrentHashSet(); private Sinks.Many chunkMeshPublisher = Sinks.many().unicast().onBackpressureBuffer(); - private static class ChunkMeshPayload { - Chunk chunk; - ChunkMesh mesh; - } - RenderableWorldImpl(Context context, Camera playerCamera) { worldProvider = context.get(WorldProvider.class); @@ -116,28 +112,25 @@ private static class ChunkMeshPayload { .distinct(Chunk::getPosition, () -> chunkMeshProcessing) .doOnNext(k -> k.setDirty(false)) .parallel(5).runOn(GameScheduler.parallel()) - .>map(c -> { + .>>map(c -> { ChunkView chunkView = worldProvider.getLocalView(c.getPosition()); if (chunkView != null && chunkView.isValidView() && chunkMeshProcessing.remove(c.getPosition())) { ChunkMesh newMesh = chunkTessellator.generateMesh(chunkView); ChunkMonitor.fireChunkTessellated(new Vector3i(c.getPosition()), newMesh); - ChunkMeshPayload payload = new ChunkMeshPayload(); - payload.chunk = c; - payload.mesh = newMesh; - return Optional.of(payload); + return Optional.of(Tuples.of(c, newMesh)); } return Optional.empty(); }).filter(Optional::isPresent).sequential() - .publishOn(GameThread.main()) + .publishOn(GameScheduler.gameMain()) .subscribe(payload -> { payload.ifPresent(result -> { - if (chunksInProximityOfCamera.contains(result.chunk)) { - result.mesh.generateVBOs(); - result.mesh.discardData(); - if (result.chunk.hasMesh()) { - result.chunk.getMesh().dispose(); + if (chunksInProximityOfCamera.contains(result.getT1())) { + result.getT2().generateVBOs(); + result.getT2().discardData(); + if (result.getT1().hasMesh()) { + result.getT1().getMesh().dispose(); } - result.chunk.setMesh(result.mesh); + result.getT1().setMesh(result.getT2()); } }); @@ -338,7 +331,6 @@ public int queueVisibleChunks(boolean isFirstRenderingStageForCurrentFrame) { statVisibleChunks = 0; statIgnoredPhases = 0; - int processedChunks = 0; int chunkCounter = 0; renderQueues.clear(); @@ -423,7 +415,6 @@ private int triangleCount(ChunkMesh mesh, ChunkMesh.RenderPhase renderPhase) { @Override public void dispose() { -// meshDispose.dispose(); if (lodChunkProvider != null) { lodChunkProvider.shutdown(); } From 73085f8c29beebb599bae236eb01e0800b395a0f Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 2 Sep 2021 21:20:40 -0700 Subject: [PATCH 016/119] chore: clean up RenderableWorldImpl --- .../rendering/primitives/ChunkMesh.java | 2 -- .../rendering/world/RenderableWorldImpl.java | 23 +++++++++++-------- .../terasology/engine/world/chunks/Chunk.java | 1 - 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkMesh.java b/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkMesh.java index 1802350ba46..026c92ef915 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkMesh.java +++ b/engine/src/main/java/org/terasology/engine/rendering/primitives/ChunkMesh.java @@ -19,8 +19,6 @@ import org.terasology.nui.Color; import org.terasology.nui.Colorc; -import java.util.concurrent.locks.ReentrantLock; - /** * Chunk meshes store, manipulate and render the vertex data of tessellated chunks. */ diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index 1f5d5a8ca81..4bf3e3717e4 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -5,6 +5,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import org.joml.Math; import org.joml.Vector3f; import org.joml.Vector3fc; import org.joml.Vector3i; @@ -34,7 +35,6 @@ import org.terasology.engine.world.generator.ScalableWorldGenerator; import org.terasology.engine.world.generator.WorldGenerator; import org.terasology.joml.geom.AABBfc; -import org.terasology.math.TeraMath; import reactor.core.publisher.Sinks; import reactor.util.function.Tuple2; import reactor.util.function.Tuples; @@ -58,14 +58,13 @@ class RenderableWorldImpl implements RenderableWorld { ViewDistance.MEGA.getChunkDistance().x() * ViewDistance.MEGA.getChunkDistance().y() * ViewDistance.MEGA.getChunkDistance().z(); private static final Vector3fc CHUNK_CENTER_OFFSET = new Vector3f(Chunks.CHUNK_SIZE).div(2); - private final int maxChunksForShadows = - TeraMath.clamp(CoreRegistry.get(Config.class).getRendering().getMaxChunksUsedForShadowMapping(), 64, 1024); + private final int maxChunksForShadows; private final WorldProvider worldProvider; private final ChunkProvider chunkProvider; private final LodChunkProvider lodChunkProvider; - private ChunkTessellator chunkTessellator; + private final ChunkTessellator chunkTessellator; private final List chunksInProximityOfCamera = Lists.newArrayListWithCapacity(MAX_LOADABLE_CHUNKS); private BlockRegion renderableRegion = new BlockRegion(BlockRegion.INVALID); private ViewDistance currentViewDistance; @@ -75,21 +74,25 @@ class RenderableWorldImpl implements RenderableWorld { private final Camera playerCamera; private Camera shadowMapCamera; - private final Config config = CoreRegistry.get(Config.class); - private final RenderingConfig renderingConfig = config.getRendering(); + private final Config config; + private final RenderingConfig renderingConfig; private int statDirtyChunks; private int statVisibleChunks; private int statIgnoredPhases; private final Set chunkMeshProcessing = Sets.newConcurrentHashSet(); - private Sinks.Many chunkMeshPublisher = Sinks.many().unicast().onBackpressureBuffer(); + private final Sinks.Many chunkMeshPublisher = Sinks.many().unicast().onBackpressureBuffer(); RenderableWorldImpl(Context context, Camera playerCamera) { - worldProvider = context.get(WorldProvider.class); - chunkProvider = context.get(ChunkProvider.class); - chunkTessellator = context.get(ChunkTessellator.class); + this.worldProvider = context.get(WorldProvider.class); + this.chunkProvider = context.get(ChunkProvider.class); + this.chunkTessellator = context.get(ChunkTessellator.class); + this.config = context.get(Config.class); + + this.renderingConfig = config.getRendering(); + this.maxChunksForShadows = Math.clamp(config.getRendering().getMaxChunksUsedForShadowMapping(), 64, 1024); this.playerCamera = playerCamera; WorldGenerator worldGenerator = context.get(WorldGenerator.class); diff --git a/engine/src/main/java/org/terasology/engine/world/chunks/Chunk.java b/engine/src/main/java/org/terasology/engine/world/chunks/Chunk.java index d4bba789a88..c368b832f9a 100644 --- a/engine/src/main/java/org/terasology/engine/world/chunks/Chunk.java +++ b/engine/src/main/java/org/terasology/engine/world/chunks/Chunk.java @@ -5,7 +5,6 @@ import org.joml.Vector3f; import org.joml.Vector3i; import org.joml.Vector3ic; -import org.terasology.engine.rendering.primitives.ChunkMesh; import org.terasology.engine.world.block.Block; import org.terasology.engine.world.block.BlockRegionc; import org.terasology.gestalt.module.sandbox.API; From 79f80f6d5c3b8172d89e8bdc9d113d62ce62450f Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 2 Sep 2021 21:32:41 -0700 Subject: [PATCH 017/119] chore: remove ChunkTask --- .../world/chunks/pipeline/ChunkTask.java | 21 ---------- .../chunks/pipeline/ShutdownChunkTask.java | 38 ------------------- 2 files changed, 59 deletions(-) delete mode 100644 engine/src/main/java/org/terasology/engine/world/chunks/pipeline/ChunkTask.java delete mode 100644 engine/src/main/java/org/terasology/engine/world/chunks/pipeline/ShutdownChunkTask.java diff --git a/engine/src/main/java/org/terasology/engine/world/chunks/pipeline/ChunkTask.java b/engine/src/main/java/org/terasology/engine/world/chunks/pipeline/ChunkTask.java deleted file mode 100644 index 775effe3c28..00000000000 --- a/engine/src/main/java/org/terasology/engine/world/chunks/pipeline/ChunkTask.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2021 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 - -package org.terasology.engine.world.chunks.pipeline; - -import org.joml.Vector3i; -import org.terasology.engine.utilities.concurrency.Task; -import org.terasology.engine.world.chunks.Chunk; - -/** - * @deprecated Use {@link org.terasology.engine.world.chunks.pipeline.stages.ChunkTask} instead - */ -@Deprecated -public interface ChunkTask extends Task { - - Chunk getChunk(); - - default Vector3i getPosition() { - return new Vector3i(); - } -} diff --git a/engine/src/main/java/org/terasology/engine/world/chunks/pipeline/ShutdownChunkTask.java b/engine/src/main/java/org/terasology/engine/world/chunks/pipeline/ShutdownChunkTask.java deleted file mode 100644 index 2c79e26a72a..00000000000 --- a/engine/src/main/java/org/terasology/engine/world/chunks/pipeline/ShutdownChunkTask.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2021 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 - -package org.terasology.engine.world.chunks.pipeline; - -import org.joml.Vector3i; -import org.terasology.engine.utilities.concurrency.TaskMaster; -import org.terasology.engine.world.chunks.Chunk; - -/** - * Special Chunk task for shutdown {@link ChunkProcessingPipeline} and it's {@link TaskMaster} - */ -public final class ShutdownChunkTask implements ChunkTask { - - @Override - public String getName() { - return "Shutdown"; - } - - @Override - public void run() { - } - - @Override - public boolean isTerminateSignal() { - return true; - } - - @Override - public Chunk getChunk() { - return null; - } - - @Override - public Vector3i getPosition() { - return new Vector3i(); - } -} From e15b975b7387209976b85ad31252769f5d2c1980 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 5 Sep 2021 16:59:55 -0700 Subject: [PATCH 018/119] chore: simplify consumer --- engine/build.gradle | 4 +++- .../rendering/world/RenderableWorldImpl.java | 23 ++++++++----------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/engine/build.gradle b/engine/build.gradle index f6a6786054a..998ecf5c1fa 100644 --- a/engine/build.gradle +++ b/engine/build.gradle @@ -99,8 +99,10 @@ dependencies { implementation "org.lwjgl:lwjgl-openal" api "org.lwjgl:lwjgl-opengl" implementation "org.lwjgl:lwjgl-stb" - + api group: 'io.projectreactor', name: 'reactor-core', version: '3.4.7' + api group: 'io.projectreactor.addons', name: 'reactor-extra', version: '3.4.4' + api group: 'org.joml', name: 'joml', version: '1.10.0' api group: 'org.terasology.joml-ext', name: 'joml-geometry', version: '0.1.0' diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index 664ba336cd7..c8a3d265c6c 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -36,6 +36,7 @@ import org.terasology.engine.world.generator.WorldGenerator; import org.terasology.joml.geom.AABBfc; import reactor.core.publisher.Sinks; +import reactor.function.TupleUtils; import reactor.util.function.Tuple2; import reactor.util.function.Tuples; @@ -125,21 +126,17 @@ class RenderableWorldImpl implements RenderableWorld { return Optional.empty(); }).filter(Optional::isPresent).sequential() .publishOn(GameScheduler.gameMain()) - .subscribe(payload -> { - payload.ifPresent(result -> { - if (chunksInProximityOfCamera.contains(result.getT1())) { - result.getT2().generateVBOs(); - result.getT2().discardData(); - if (result.getT1().hasMesh()) { - result.getT1().getMesh().dispose(); - } - result.getT1().setMesh(result.getT2()); + .subscribe(result -> result.ifPresent(TupleUtils.consumer((chunk, chunkMesh) -> { + if (chunksInProximityOfCamera.contains(chunk)) { + chunkMesh.generateVBOs(); + chunkMesh.discardData(); + if (chunk.hasMesh()) { + chunk.getMesh().dispose(); } - }); + chunk.setMesh(chunkMesh); + } - }, throwable -> { - logger.error("Failed to build mesh {}", throwable); - }); + })), throwable -> logger.error("Failed to build mesh {}", throwable)); } @Override From 950acbe9b3730f3a2f65bfc7b10169088d778960 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 5 Sep 2021 17:07:29 -0700 Subject: [PATCH 019/119] handle emission error when submitting chunk for mesh --- .../engine/rendering/world/RenderableWorldImpl.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java index c8a3d265c6c..aabd70037b2 100644 --- a/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java +++ b/engine/src/main/java/org/terasology/engine/rendering/world/RenderableWorldImpl.java @@ -396,7 +396,10 @@ && isChunkVisibleFromMainLight(chunk)) { for (Chunk chunk : chunksInProximityOfCamera) { if (isChunkValidForRender(chunk) && chunk.isDirty()) { statDirtyChunks++; - chunkMeshPublisher.tryEmitNext(chunk); + Sinks.EmitResult result = chunkMeshPublisher.tryEmitNext(chunk); + if (result.isFailure()) { + logger.error("failed to process chunk {} : {}", chunk, result); + } } } } From 502985ef9de69d8dd9208bc1e22d3d6e126e5602 Mon Sep 17 00:00:00 2001 From: Josephine Rueckert Date: Sat, 4 Dec 2021 23:02:15 +0100 Subject: [PATCH 020/119] chore: prepare snapshot builds for 5.3.0 --- .../src/main/resources/org/terasology/unittest/module.txt | 2 +- engine/src/main/resources/org/terasology/engine/module.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engine-tests/src/main/resources/org/terasology/unittest/module.txt b/engine-tests/src/main/resources/org/terasology/unittest/module.txt index 7525f19dd58..1a5f8d6bdd2 100644 --- a/engine-tests/src/main/resources/org/terasology/unittest/module.txt +++ b/engine-tests/src/main/resources/org/terasology/unittest/module.txt @@ -1,6 +1,6 @@ { "id" : "unittest", - "version" : "5.2.0", + "version" : "5.3.0-SNAPSHOT", "displayName" : "Terasology Engine Test", "description" : "Engine unit test content" } diff --git a/engine/src/main/resources/org/terasology/engine/module.txt b/engine/src/main/resources/org/terasology/engine/module.txt index 64b0b0ccec0..72816ed0df8 100644 --- a/engine/src/main/resources/org/terasology/engine/module.txt +++ b/engine/src/main/resources/org/terasology/engine/module.txt @@ -1,6 +1,6 @@ { "id" : "engine", - "version" : "5.2.0", + "version" : "5.3.0-SNAPSHOT", "displayName" : "Terasology Engine", "description" : "Core engine content" } From 1f0349f4d6464cd4a831b70fb19a67ed41ad8ce1 Mon Sep 17 00:00:00 2001 From: Nail Khanipov Date: Sun, 5 Dec 2021 16:19:57 +0300 Subject: [PATCH 021/119] feat(gestaltv7-eventsystem): Migration Event and @ReceiveEvent to gestalt's (#4898) --- .../entitySystem/PojoEventSystemTests.java | 17 +++++---- .../characters/VisualCharacterSystemTest.java | 2 +- .../logic/delay/DelayedActionSystemTest.java | 2 +- .../event/VectorEventSerializer.java | 8 ++-- .../recording/EventSystemReplayImplTest.java | 4 +- .../world/EntityAwareWorldProviderTest.java | 4 +- .../LocalChunkProviderTest.java | 2 +- .../terasology/input/InputSystemTests.java | 2 +- .../engine/audio/system/AudioSystem.java | 2 +- .../core/bootstrap/EntitySystemSetupUtil.java | 2 +- .../AbstractEventSystemDecorator.java | 2 +- .../AwaitedLocalCharacterSpawnEvent.java | 2 +- .../LoadingChunkEventSystem.java | 2 +- .../core/module/ExternalApiWhitelist.java | 1 + .../engine/entitySystem/entity/EntityRef.java | 2 +- .../entity/internal/BaseEntityRef.java | 2 +- .../entity/internal/NullEntityRef.java | 2 +- .../BeforeDeactivateComponent.java | 2 +- .../lifecycleEvents/BeforeEntityCreated.java | 2 +- .../BeforeRemoveComponent.java | 2 +- .../lifecycleEvents/OnActivatedComponent.java | 2 +- .../lifecycleEvents/OnAddedComponent.java | 2 +- .../lifecycleEvents/OnChangedComponent.java | 2 +- .../event/AbstractValueModifiableEvent.java | 1 + .../engine/entitySystem/event/Activity.java | 14 +++++++ .../entitySystem/event/BeforeAfterEvent.java | 2 + .../entitySystem/event/ConsumableEvent.java | 2 + .../engine/entitySystem/event/Event.java | 10 ----- .../entitySystem/event/PendingEvent.java | 1 + .../engine/entitySystem/event/Priority.java | 20 ++++++++++ .../entitySystem/event/ReceiveEvent.java | 33 ---------------- .../event/internal/EventReceiver.java | 2 +- .../event/internal/EventSystem.java | 4 +- .../event/internal/EventSystemImpl.java | 38 ++++++++++++++----- .../entitySystem/metadata/EventLibrary.java | 2 +- .../entitySystem/metadata/EventMetadata.java | 10 ++--- .../sectors/LoadedSectorUpdateEvent.java | 2 +- .../sectors/SectorEntityLoad.java | 2 +- .../sectors/SectorEntityUnload.java | 2 +- .../sectors/SectorSimulationEvent.java | 2 +- .../sectors/SectorSimulationSystem.java | 2 +- .../entitySystem/systems/NetFilterEvent.java | 20 ++++++++++ .../systems/UpdateSubscriberSystem.java | 4 +- .../input/cameraTarget/CameraOutEvent.java | 2 +- .../input/cameraTarget/CameraOverEvent.java | 2 +- .../CameraTargetChangedEvent.java | 2 +- .../engine/logic/actions/PlaySoundAction.java | 4 +- .../logic/actions/SpawnPrefabAction.java | 2 +- .../engine/logic/afk/AfkAuthoritySystem.java | 2 +- .../engine/logic/afk/AfkClientSystem.java | 6 ++- .../engine/logic/behavior/BehaviorSystem.java | 2 +- .../behavior/CollectiveBehaviorSystem.java | 2 +- .../nui/BehaviorTreeClientSystem.java | 4 +- .../nui/BehaviorTreeEditorSystem.java | 4 +- .../CharacterHeldItemAuthoritySystem.java | 2 +- .../characters/CharacterImpulseEvent.java | 2 +- .../characters/CharacterScalingSystem.java | 9 +++-- .../characters/CharacterSoundSystem.java | 2 +- .../logic/characters/CharacterSystem.java | 21 +++++++--- .../characters/CharacterTeleportEvent.java | 2 +- .../ClientCharacterPredictionSystem.java | 2 +- .../logic/characters/GazeAuthoritySystem.java | 6 ++- .../ServerCharacterPredictionSystem.java | 2 +- .../characters/VisualCharacterSystem.java | 6 ++- .../events/ActivationRequestDenied.java | 2 +- .../events/ChangeHeldItemRequest.java | 2 +- .../characters/events/CollisionEvent.java | 2 +- .../logic/characters/events/DeathEvent.java | 2 +- .../characters/events/FootstepEvent.java | 2 +- .../logic/characters/events/JumpEvent.java | 2 +- .../characters/events/OnEnterBlockEvent.java | 2 +- .../logic/characters/events/OnScaleEvent.java | 2 +- .../characters/events/PlayerDeathEvent.java | 2 +- .../events/SetMovementModeEvent.java | 2 +- .../characters/events/SwimStrokeEvent.java | 2 +- .../interactions/InteractionEndEvent.java | 2 +- .../interactions/InteractionEndPredicted.java | 2 +- .../interactions/InteractionEndRequest.java | 2 +- .../InteractionStartPredicted.java | 2 +- .../interactions/InteractionSystem.java | 16 +++++--- .../engine/logic/chat/ChatSystem.java | 2 +- .../logic/common/lifespan/LifespanSystem.java | 2 +- .../engine/logic/console/CommandEvent.java | 4 +- .../engine/logic/console/ConsoleSystem.java | 10 +++-- .../engine/logic/console/MessageEvent.java | 2 +- .../logic/debug/ChunkEventErrorLogger.java | 2 +- .../logic/delay/DelayedActionSystem.java | 2 +- .../delay/DelayedActionTriggeredEvent.java | 2 +- .../delay/PeriodicActionTriggeredEvent.java | 2 +- .../engine/logic/health/DestroyEvent.java | 2 +- .../engine/logic/health/DoDestroyEvent.java | 2 +- .../EntityDestructionAuthoritySystem.java | 2 +- .../logic/inventory/ItemCommonSystem.java | 2 +- .../inventory/ItemPickupAuthoritySystem.java | 2 +- .../logic/inventory/events/DropItemEvent.java | 2 +- .../logic/inventory/events/GiveItemEvent.java | 2 +- .../engine/logic/location/Location.java | 6 ++- .../logic/location/LocationChangedEvent.java | 2 +- .../logic/location/LocationChangedSystem.java | 2 +- .../logic/location/LocationResynchEvent.java | 2 +- .../logic/nameTags/NameTagClientSystem.java | 2 +- .../logic/nameTags/PlayerNameTagSystem.java | 6 +-- .../notifications/NotificationSystem.java | 2 +- .../logic/players/CameraClientSystem.java | 2 +- .../logic/players/DebugControlSystem.java | 6 ++- .../players/FirstPersonClientSystem.java | 2 +- .../logic/players/LocalPlayerSystem.java | 2 +- .../logic/players/MenuControlSystem.java | 6 +-- .../engine/logic/players/PlayerSystem.java | 11 ++++-- .../players/PlayerTargetChangedEvent.java | 2 +- .../logic/players/SetDirectionEvent.java | 2 +- .../ThirdPersonRemoteClientSystem.java | 2 +- .../logic/players/WorldtimeResyncSystem.java | 2 +- .../event/LocalPlayerInitializedEvent.java | 2 +- .../players/event/OnPlayerRespawnedEvent.java | 2 +- .../players/event/OnPlayerSpawnedEvent.java | 2 +- .../logic/players/event/ResetCameraEvent.java | 2 +- .../players/event/RespawnRequestEvent.java | 2 +- .../event/SynchronizeClientTimeSystem.java | 2 +- .../players/event/WorldtimeResetEvent.java | 2 +- .../selection/ApplyBlockSelectionEvent.java | 4 +- ...LocalPlayerBlockSelectionByItemSystem.java | 2 +- .../selection/MovableSelectionEndEvent.java | 4 +- .../selection/MovableSelectionStartEvent.java | 2 +- .../engine/logic/time/TimeClientSystem.java | 6 ++- .../engine/logic/time/TimeResynchEvent.java | 2 +- .../logic/time/WorldtimeResyncEvent.java | 2 +- .../org/terasology/engine/network/Client.java | 4 +- .../engine/network/ClientPingSystem.java | 2 +- .../engine/network/NetworkEvent.java | 2 +- .../network/NetworkEventSystemDecorator.java | 4 +- .../org/terasology/engine/network/Server.java | 2 +- .../engine/network/ServerPingSystem.java | 2 +- .../engine/network/events/ConnectedEvent.java | 2 +- .../network/events/DisconnectedEvent.java | 2 +- .../network/events/PingFromClientEvent.java | 2 +- .../network/events/PingFromServerEvent.java | 2 +- .../network/events/SubscribePingEvent.java | 2 +- .../network/events/UnSubscribePingEvent.java | 2 +- .../engine/network/internal/LocalClient.java | 4 +- .../engine/network/internal/NetClient.java | 2 +- .../network/internal/NetworkEntitySystem.java | 8 +++- .../network/internal/NetworkSystemImpl.java | 2 +- .../engine/network/internal/ServerImpl.java | 2 +- .../particles/ParticleSystemManagerImpl.java | 2 +- .../events/ParticleSystemUpdateEvent.java | 2 +- .../internal/DelayedEntityRef.java | 2 +- .../serializers/EventSerializer.java | 2 +- .../physics/bullet/VoxelWorldSystem.java | 2 +- .../engine/physics/engine/PhysicsSystem.java | 13 +++++-- .../physics/events/ChangeVelocityEvent.java | 2 +- .../engine/physics/events/ForceEvent.java | 2 +- .../engine/physics/events/ImpulseEvent.java | 2 +- .../engine/physics/events/MovedEvent.java | 2 +- .../physics/events/PhysicsResynchEvent.java | 2 +- .../engine/recording/EventCatcher.java | 2 +- .../engine/recording/EventCopier.java | 6 +-- .../recording/EventSystemReplayImpl.java | 36 ++++++++++++++---- .../engine/recording/RecordedEntityRef.java | 2 +- .../engine/recording/RecordedEvent.java | 2 +- .../RecordingEventSystemDecorator.java | 2 +- .../engine/rendering/logic/AnimEndEvent.java | 2 +- .../rendering/logic/ChunkMeshRenderer.java | 2 +- .../rendering/logic/FloatingTextRenderer.java | 2 +- .../rendering/logic/LightFadeSystem.java | 2 +- .../engine/rendering/logic/MeshRenderer.java | 2 +- .../logic/RegionOutlineRenderer.java | 2 +- .../rendering/logic/SkeletonRenderer.java | 2 +- .../rendering/nui/FocusChangedEvent.java | 2 +- .../rendering/nui/ScreenLayerClosedEvent.java | 4 +- .../engine/rendering/nui/SortOrderSystem.java | 4 +- .../nui/editor/systems/NUIEditorSystem.java | 9 +++-- .../editor/systems/NUISkinEditorSystem.java | 9 +++-- .../nui/internal/NUIManagerInternal.java | 21 ++++++---- .../rendering/world/WorldRendererSystem.java | 2 +- .../ClientViewDistanceSystem.java | 2 +- .../ServerViewDistanceSystem.java | 2 +- .../ViewDistanceChangedEvent.java | 2 +- .../engine/world/OnChangedBlock.java | 2 +- .../world/block/BlockLifecycleEvent.java | 2 +- .../world/block/entity/BlockEntitySystem.java | 23 ++++++----- .../LargeBlockUpdateFinished.java | 2 +- .../LargeBlockUpdateStarting.java | 2 +- .../NeighbourBlockFamilyUpdateSystem.java | 6 +-- .../entity/placement/BlockPlacingSystem.java | 6 ++- .../world/block/items/BlockItemSystem.java | 10 ++--- .../world/block/items/OnBlockItemPlaced.java | 2 +- .../world/block/items/OnBlockToItem.java | 2 +- .../block/regions/BlockRegionSystem.java | 6 ++- .../BlockStructuralSupportSystem.java | 2 +- .../structure/SideBlockSupportRequired.java | 2 +- .../typeEntity/BlockTypeClientSystem.java | 2 +- .../world/chunks/event/BeforeChunkUnload.java | 2 +- .../world/chunks/event/OnChunkGenerated.java | 2 +- .../world/chunks/event/OnChunkLoaded.java | 2 +- .../world/chunks/event/PurgeWorldEvent.java | 2 +- .../localChunkProvider/RelevanceSystem.java | 2 +- .../internal/EntityAwareWorldProvider.java | 2 +- .../world/selection/BlockSelectionSystem.java | 4 +- .../engine/world/time/TimeEventBase.java | 2 +- .../discordrpc/DiscordRPCSystem.java | 2 +- 201 files changed, 462 insertions(+), 339 deletions(-) create mode 100644 engine/src/main/java/org/terasology/engine/entitySystem/event/Activity.java delete mode 100644 engine/src/main/java/org/terasology/engine/entitySystem/event/Event.java create mode 100644 engine/src/main/java/org/terasology/engine/entitySystem/event/Priority.java delete mode 100644 engine/src/main/java/org/terasology/engine/entitySystem/event/ReceiveEvent.java create mode 100644 engine/src/main/java/org/terasology/engine/entitySystem/systems/NetFilterEvent.java diff --git a/engine-tests/src/test/java/org/terasology/engine/entitySystem/PojoEventSystemTests.java b/engine-tests/src/test/java/org/terasology/engine/entitySystem/PojoEventSystemTests.java index e26a406816b..d854ce4b426 100644 --- a/engine-tests/src/test/java/org/terasology/engine/entitySystem/PojoEventSystemTests.java +++ b/engine-tests/src/test/java/org/terasology/engine/entitySystem/PojoEventSystemTests.java @@ -7,24 +7,25 @@ import org.junit.jupiter.api.Test; import org.reflections.Reflections; import org.terasology.engine.context.internal.ContextImpl; -import org.terasology.gestalt.assets.ResourceUrn; import org.terasology.engine.entitySystem.entity.EntityRef; import org.terasology.engine.entitySystem.entity.internal.PojoEntityManager; import org.terasology.engine.entitySystem.event.AbstractConsumableEvent; -import org.terasology.engine.entitySystem.event.Event; import org.terasology.engine.entitySystem.event.EventPriority; -import org.terasology.engine.entitySystem.event.ReceiveEvent; +import org.terasology.engine.entitySystem.event.Priority; import org.terasology.engine.entitySystem.event.internal.EventReceiver; import org.terasology.engine.entitySystem.event.internal.EventSystemImpl; import org.terasology.engine.entitySystem.metadata.ComponentLibrary; import org.terasology.engine.entitySystem.metadata.EntitySystemLibrary; import org.terasology.engine.entitySystem.prefab.internal.PojoPrefabManager; -import org.terasology.unittest.stubs.IntegerComponent; -import org.terasology.unittest.stubs.StringComponent; import org.terasology.engine.entitySystem.systems.BaseComponentSystem; import org.terasology.engine.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.engine.registry.CoreRegistry; +import org.terasology.gestalt.assets.ResourceUrn; +import org.terasology.gestalt.entitysystem.event.Event; +import org.terasology.gestalt.entitysystem.event.ReceiveEvent; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; +import org.terasology.unittest.stubs.IntegerComponent; +import org.terasology.unittest.stubs.StringComponent; import java.util.List; @@ -250,7 +251,8 @@ public static class TestHighPriorityEventHandler extends BaseComponentSystem { List receivedList = Lists.newArrayList(); - @ReceiveEvent(components = StringComponent.class, priority = EventPriority.PRIORITY_HIGH) + @Priority(EventPriority.PRIORITY_HIGH) + @ReceiveEvent(components = StringComponent.class) public void handleStringEvent(TestEvent event, EntityRef entity) { receivedList.add(new Received(event, entity)); if (cancel) { @@ -258,7 +260,8 @@ public void handleStringEvent(TestEvent event, EntityRef entity) { } } - @ReceiveEvent(components = IntegerComponent.class, priority = EventPriority.PRIORITY_HIGH) + @Priority(EventPriority.PRIORITY_HIGH) + @ReceiveEvent(components = IntegerComponent.class) public void handleIntegerEvent(TestEvent event, EntityRef entity) { receivedList.add(new Received(event, entity)); } diff --git a/engine-tests/src/test/java/org/terasology/engine/logic/characters/VisualCharacterSystemTest.java b/engine-tests/src/test/java/org/terasology/engine/logic/characters/VisualCharacterSystemTest.java index 07b5d236f97..70a6cad4842 100644 --- a/engine-tests/src/test/java/org/terasology/engine/logic/characters/VisualCharacterSystemTest.java +++ b/engine-tests/src/test/java/org/terasology/engine/logic/characters/VisualCharacterSystemTest.java @@ -14,10 +14,10 @@ import org.terasology.engine.entitySystem.entity.EntityManager; import org.terasology.engine.entitySystem.entity.EntityRef; import org.terasology.engine.entitySystem.entity.lifecycleEvents.OnActivatedComponent; -import org.terasology.engine.entitySystem.event.Event; import org.terasology.engine.logic.characters.events.CreateVisualCharacterEvent; import org.terasology.engine.logic.players.LocalPlayer; import org.terasology.engine.registry.InjectionHelper; +import org.terasology.gestalt.entitysystem.event.Event; import java.util.ArrayList; import java.util.Arrays; diff --git a/engine-tests/src/test/java/org/terasology/engine/logic/delay/DelayedActionSystemTest.java b/engine-tests/src/test/java/org/terasology/engine/logic/delay/DelayedActionSystemTest.java index 5549512fa5c..f445cc0ea46 100644 --- a/engine-tests/src/test/java/org/terasology/engine/logic/delay/DelayedActionSystemTest.java +++ b/engine-tests/src/test/java/org/terasology/engine/logic/delay/DelayedActionSystemTest.java @@ -8,7 +8,7 @@ import org.terasology.engine.TerasologyTestingEnvironment; import org.terasology.engine.core.Time; import org.terasology.engine.entitySystem.entity.EntityRef; -import org.terasology.engine.entitySystem.event.ReceiveEvent; +import org.terasology.gestalt.entitysystem.event.ReceiveEvent; import java.util.ArrayList; import java.util.Arrays; diff --git a/engine-tests/src/test/java/org/terasology/engine/persistence/typeHandling/event/VectorEventSerializer.java b/engine-tests/src/test/java/org/terasology/engine/persistence/typeHandling/event/VectorEventSerializer.java index bbad6c8a408..0225cf41c3f 100644 --- a/engine-tests/src/test/java/org/terasology/engine/persistence/typeHandling/event/VectorEventSerializer.java +++ b/engine-tests/src/test/java/org/terasology/engine/persistence/typeHandling/event/VectorEventSerializer.java @@ -11,15 +11,16 @@ import org.joml.Vector4fc; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.terasology.engine.core.module.ModuleManager; -import org.terasology.gestalt.assets.ResourceUrn; import org.terasology.engine.context.internal.ContextImpl; -import org.terasology.engine.entitySystem.event.Event; +import org.terasology.engine.core.module.ModuleManager; import org.terasology.engine.entitySystem.metadata.EntitySystemLibrary; import org.terasology.engine.entitySystem.metadata.EventMetadata; import org.terasology.engine.persistence.serializers.EventSerializer; import org.terasology.engine.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.engine.registry.CoreRegistry; +import org.terasology.engine.testUtil.ModuleManagerFactory; +import org.terasology.gestalt.assets.ResourceUrn; +import org.terasology.gestalt.entitysystem.event.Event; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; import org.terasology.protobuf.EntityData; import org.terasology.reflection.ModuleTypeRegistry; @@ -27,7 +28,6 @@ import org.terasology.reflection.metadata.FieldMetadata; import org.terasology.reflection.reflect.ReflectFactory; import org.terasology.reflection.reflect.ReflectionReflectFactory; -import org.terasology.engine.testUtil.ModuleManagerFactory; import java.io.IOException; import java.util.HashMap; diff --git a/engine-tests/src/test/java/org/terasology/engine/recording/EventSystemReplayImplTest.java b/engine-tests/src/test/java/org/terasology/engine/recording/EventSystemReplayImplTest.java index b976690a33b..8dac97f01dc 100644 --- a/engine-tests/src/test/java/org/terasology/engine/recording/EventSystemReplayImplTest.java +++ b/engine-tests/src/test/java/org/terasology/engine/recording/EventSystemReplayImplTest.java @@ -13,8 +13,6 @@ import org.terasology.engine.entitySystem.entity.EntityRef; import org.terasology.engine.entitySystem.entity.internal.PojoEntityManager; import org.terasology.engine.entitySystem.event.AbstractConsumableEvent; -import org.terasology.engine.entitySystem.event.Event; -import org.terasology.engine.entitySystem.event.ReceiveEvent; import org.terasology.engine.entitySystem.event.internal.EventSystem; import org.terasology.engine.entitySystem.metadata.EntitySystemLibrary; import org.terasology.engine.entitySystem.prefab.internal.PojoPrefabManager; @@ -25,6 +23,8 @@ import org.terasology.engine.network.NetworkSystem; import org.terasology.engine.persistence.typeHandling.TypeHandlerLibraryImpl; import org.terasology.engine.registry.CoreRegistry; +import org.terasology.gestalt.entitysystem.event.Event; +import org.terasology.gestalt.entitysystem.event.ReceiveEvent; import org.terasology.gestalt.module.ModuleEnvironment; import org.terasology.persistence.typeHandling.TypeHandlerLibrary; import org.terasology.reflection.TypeRegistry; diff --git a/engine-tests/src/test/java/org/terasology/engine/world/EntityAwareWorldProviderTest.java b/engine-tests/src/test/java/org/terasology/engine/world/EntityAwareWorldProviderTest.java index 6a451ab4cc1..f80edb8dccc 100644 --- a/engine-tests/src/test/java/org/terasology/engine/world/EntityAwareWorldProviderTest.java +++ b/engine-tests/src/test/java/org/terasology/engine/world/EntityAwareWorldProviderTest.java @@ -18,8 +18,6 @@ import org.terasology.engine.entitySystem.entity.lifecycleEvents.OnActivatedComponent; import org.terasology.engine.entitySystem.entity.lifecycleEvents.OnAddedComponent; import org.terasology.engine.entitySystem.entity.lifecycleEvents.OnChangedComponent; -import org.terasology.engine.entitySystem.event.Event; -import org.terasology.engine.entitySystem.event.ReceiveEvent; import org.terasology.engine.entitySystem.event.internal.EventReceiver; import org.terasology.engine.entitySystem.event.internal.EventSystem; import org.terasology.engine.entitySystem.prefab.Prefab; @@ -39,6 +37,8 @@ import org.terasology.gestalt.assets.ResourceUrn; import org.terasology.gestalt.assets.management.AssetManager; import org.terasology.gestalt.entitysystem.component.Component; +import org.terasology.gestalt.entitysystem.event.Event; +import org.terasology.gestalt.entitysystem.event.ReceiveEvent; import org.terasology.unittest.stubs.ForceBlockActiveComponent; import org.terasology.unittest.stubs.IntegerComponent; import org.terasology.unittest.stubs.RetainedOnBlockChangeComponent; diff --git a/engine-tests/src/test/java/org/terasology/engine/world/chunks/localChunkProvider/LocalChunkProviderTest.java b/engine-tests/src/test/java/org/terasology/engine/world/chunks/localChunkProvider/LocalChunkProviderTest.java index d56a25328aa..5a73af0b3c3 100644 --- a/engine-tests/src/test/java/org/terasology/engine/world/chunks/localChunkProvider/LocalChunkProviderTest.java +++ b/engine-tests/src/test/java/org/terasology/engine/world/chunks/localChunkProvider/LocalChunkProviderTest.java @@ -12,7 +12,6 @@ import org.mockito.ArgumentCaptor; import org.terasology.engine.entitySystem.entity.EntityManager; import org.terasology.engine.entitySystem.entity.EntityRef; -import org.terasology.engine.entitySystem.event.Event; import org.terasology.engine.world.BlockEntityRegistry; import org.terasology.engine.world.block.BeforeDeactivateBlocks; import org.terasology.engine.world.block.Block; @@ -30,6 +29,7 @@ import org.terasology.fixtures.TestChunkStore; import org.terasology.fixtures.TestStorageManager; import org.terasology.fixtures.TestWorldGenerator; +import org.terasology.gestalt.entitysystem.event.Event; import java.time.Duration; import java.time.temporal.ChronoUnit; diff --git a/engine-tests/src/test/java/org/terasology/input/InputSystemTests.java b/engine-tests/src/test/java/org/terasology/input/InputSystemTests.java index fe30e1c0fb9..89a8a870631 100644 --- a/engine-tests/src/test/java/org/terasology/input/InputSystemTests.java +++ b/engine-tests/src/test/java/org/terasology/input/InputSystemTests.java @@ -15,7 +15,6 @@ import org.terasology.engine.core.subsystem.config.BindsManager; import org.terasology.engine.core.subsystem.headless.device.TimeSystem; import org.terasology.engine.entitySystem.entity.EntityRef; -import org.terasology.engine.entitySystem.event.Event; import org.terasology.engine.entitySystem.systems.internal.DoNotAutoRegister; import org.terasology.engine.input.BindButtonEvent; import org.terasology.engine.input.BindableButton; @@ -30,6 +29,7 @@ import org.terasology.engine.recording.DirectionAndOriginPosRecorderList; import org.terasology.engine.recording.RecordAndReplayCurrentStatus; import org.terasology.engine.registry.InjectionHelper; +import org.terasology.gestalt.entitysystem.event.Event; import org.terasology.input.Keyboard.Key; import org.terasology.input.Keyboard.KeyId; import org.terasology.input.device.CharKeyboardAction; diff --git a/engine/src/main/java/org/terasology/engine/audio/system/AudioSystem.java b/engine/src/main/java/org/terasology/engine/audio/system/AudioSystem.java index 09ce2fc4422..d0e60ea6b5c 100644 --- a/engine/src/main/java/org/terasology/engine/audio/system/AudioSystem.java +++ b/engine/src/main/java/org/terasology/engine/audio/system/AudioSystem.java @@ -11,7 +11,6 @@ import org.terasology.engine.audio.events.PlaySoundEvent; import org.terasology.engine.audio.events.PlaySoundForOwnerEvent; import org.terasology.engine.entitySystem.entity.EntityRef; -import org.terasology.engine.entitySystem.event.ReceiveEvent; import org.terasology.engine.entitySystem.systems.BaseComponentSystem; import org.terasology.engine.entitySystem.systems.RegisterSystem; import org.terasology.engine.entitySystem.systems.UpdateSubscriberSystem; @@ -25,6 +24,7 @@ import org.terasology.engine.network.NetworkSystem; import org.terasology.engine.registry.In; import org.terasology.engine.utilities.Assets; +import org.terasology.gestalt.entitysystem.event.ReceiveEvent; /** * This system handles receiving the PlaySound events and activating the AudioManager to play them diff --git a/engine/src/main/java/org/terasology/engine/core/bootstrap/EntitySystemSetupUtil.java b/engine/src/main/java/org/terasology/engine/core/bootstrap/EntitySystemSetupUtil.java index 781b8c9a928..ac906357e4c 100644 --- a/engine/src/main/java/org/terasology/engine/core/bootstrap/EntitySystemSetupUtil.java +++ b/engine/src/main/java/org/terasology/engine/core/bootstrap/EntitySystemSetupUtil.java @@ -10,7 +10,6 @@ import org.terasology.engine.entitySystem.entity.EntityRef; import org.terasology.engine.entitySystem.entity.internal.EngineEntityManager; import org.terasology.engine.entitySystem.entity.internal.PojoEntityManager; -import org.terasology.engine.entitySystem.event.Event; import org.terasology.engine.entitySystem.event.internal.EventSystem; import org.terasology.engine.entitySystem.event.internal.EventSystemImpl; import org.terasology.engine.entitySystem.metadata.ComponentLibrary; @@ -39,6 +38,7 @@ import org.terasology.engine.recording.RecordingEventSystemDecorator; import org.terasology.gestalt.assets.ResourceUrn; import org.terasology.gestalt.entitysystem.component.Component; +import org.terasology.gestalt.entitysystem.event.Event; import org.terasology.gestalt.module.ModuleEnvironment; import org.terasology.gestalt.naming.Name; import org.terasology.nui.properties.OneOfProviderFactory; diff --git a/engine/src/main/java/org/terasology/engine/core/bootstrap/eventSystem/AbstractEventSystemDecorator.java b/engine/src/main/java/org/terasology/engine/core/bootstrap/eventSystem/AbstractEventSystemDecorator.java index a5214a8f37e..8b14075c11f 100644 --- a/engine/src/main/java/org/terasology/engine/core/bootstrap/eventSystem/AbstractEventSystemDecorator.java +++ b/engine/src/main/java/org/terasology/engine/core/bootstrap/eventSystem/AbstractEventSystemDecorator.java @@ -4,12 +4,12 @@ package org.terasology.engine.core.bootstrap.eventSystem; import org.terasology.engine.entitySystem.entity.EntityRef; -import org.terasology.engine.entitySystem.event.Event; import org.terasology.engine.entitySystem.event.internal.EventReceiver; import org.terasology.engine.entitySystem.event.internal.EventSystem; import org.terasology.engine.entitySystem.systems.ComponentSystem; import org.terasology.gestalt.assets.ResourceUrn; import org.terasology.gestalt.entitysystem.component.Component; +import org.terasology.gestalt.entitysystem.event.Event; public abstract class AbstractEventSystemDecorator implements EventSystem { private final EventSystem eventSystem; diff --git a/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/AwaitedLocalCharacterSpawnEvent.java b/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/AwaitedLocalCharacterSpawnEvent.java index 21cf3d990a6..68b80c024ba 100644 --- a/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/AwaitedLocalCharacterSpawnEvent.java +++ b/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/AwaitedLocalCharacterSpawnEvent.java @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.core.modes.loadProcesses; -import org.terasology.engine.entitySystem.event.Event; import org.terasology.engine.entitySystem.systems.BaseComponentSystem; +import org.terasology.gestalt.entitysystem.event.Event; import org.terasology.gestalt.module.sandbox.API; /** diff --git a/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/LoadingChunkEventSystem.java b/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/LoadingChunkEventSystem.java index 9feb6f987db..b72f1cc5d1b 100644 --- a/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/LoadingChunkEventSystem.java +++ b/engine/src/main/java/org/terasology/engine/core/modes/loadProcesses/LoadingChunkEventSystem.java @@ -6,12 +6,12 @@ import org.terasology.engine.core.GameEngine; import org.terasology.engine.core.modes.GameState; import org.terasology.engine.entitySystem.entity.EntityRef; -import org.terasology.engine.entitySystem.event.ReceiveEvent; import org.terasology.engine.entitySystem.systems.BaseComponentSystem; import org.terasology.engine.entitySystem.systems.RegisterSystem; import org.terasology.engine.registry.In; import org.terasology.engine.world.WorldComponent; import org.terasology.engine.world.chunks.event.OnChunkLoaded; +import org.terasology.gestalt.entitysystem.event.ReceiveEvent; /** * A system to send new chunk events to the current game state, which can be diff --git a/engine/src/main/java/org/terasology/engine/core/module/ExternalApiWhitelist.java b/engine/src/main/java/org/terasology/engine/core/module/ExternalApiWhitelist.java index f2feb864355..e93d9ab45e8 100644 --- a/engine/src/main/java/org/terasology/engine/core/module/ExternalApiWhitelist.java +++ b/engine/src/main/java/org/terasology/engine/core/module/ExternalApiWhitelist.java @@ -50,6 +50,7 @@ public final class ExternalApiWhitelist { private static final Set GESTALT_ECS_PACKAGES = new ImmutableSet.Builder() .add("org.terasology.gestalt.entitysystem.component") + .add("org.terasology.gestalt.entitysystem.event") .build(); public static final Set PACKAGES = new ImmutableSet.Builder() diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/entity/EntityRef.java b/engine/src/main/java/org/terasology/engine/entitySystem/entity/EntityRef.java index f4c64b918a4..1e5d577b699 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/entity/EntityRef.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/entity/EntityRef.java @@ -6,9 +6,9 @@ import org.terasology.engine.entitySystem.MutableComponentContainer; import org.terasology.engine.entitySystem.entity.internal.EntityScope; import org.terasology.engine.entitySystem.entity.internal.NullEntityRef; -import org.terasology.engine.entitySystem.event.Event; import org.terasology.engine.entitySystem.prefab.Prefab; import org.terasology.engine.entitySystem.sectors.SectorSimulationComponent; +import org.terasology.gestalt.entitysystem.event.Event; /** * A wrapper around an entity id providing access to common functionality diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/entity/internal/BaseEntityRef.java b/engine/src/main/java/org/terasology/engine/entitySystem/entity/internal/BaseEntityRef.java index a0d08befd56..bfb2ea3377c 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/entity/internal/BaseEntityRef.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/entity/internal/BaseEntityRef.java @@ -6,13 +6,13 @@ import org.slf4j.LoggerFactory; import org.terasology.engine.entitySystem.entity.EntityRef; import org.terasology.engine.entitySystem.entity.LowLevelEntityManager; -import org.terasology.engine.entitySystem.event.Event; import org.terasology.engine.entitySystem.prefab.Prefab; import org.terasology.engine.entitySystem.sectors.SectorSimulationComponent; import org.terasology.engine.network.NetworkComponent; import org.terasology.engine.persistence.serializers.EntityDataJSONFormat; import org.terasology.engine.persistence.serializers.EntitySerializer; import org.terasology.gestalt.entitysystem.component.Component; +import org.terasology.gestalt.entitysystem.event.Event; import java.security.AccessController; import java.security.PrivilegedAction; diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/entity/internal/NullEntityRef.java b/engine/src/main/java/org/terasology/engine/entitySystem/entity/internal/NullEntityRef.java index e5644fc7620..0d3d375a1cf 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/entity/internal/NullEntityRef.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/entity/internal/NullEntityRef.java @@ -3,9 +3,9 @@ package org.terasology.engine.entitySystem.entity.internal; import org.terasology.engine.entitySystem.entity.EntityRef; -import org.terasology.engine.entitySystem.event.Event; import org.terasology.engine.entitySystem.prefab.Prefab; import org.terasology.gestalt.entitysystem.component.Component; +import org.terasology.gestalt.entitysystem.event.Event; import java.util.Collections; import java.util.List; diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/BeforeDeactivateComponent.java b/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/BeforeDeactivateComponent.java index 627d12b6798..600bf1d0b03 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/BeforeDeactivateComponent.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/BeforeDeactivateComponent.java @@ -3,7 +3,7 @@ package org.terasology.engine.entitySystem.entity.lifecycleEvents; -import org.terasology.engine.entitySystem.event.Event; +import org.terasology.gestalt.entitysystem.event.Event; /** * When a component is about to leave the active state, either due to being removed, the entity it is attached to being destroyed, diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/BeforeEntityCreated.java b/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/BeforeEntityCreated.java index 38a98ab3c64..40f8ad6d749 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/BeforeEntityCreated.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/BeforeEntityCreated.java @@ -4,9 +4,9 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import org.terasology.engine.entitySystem.event.Event; import org.terasology.engine.entitySystem.prefab.Prefab; import org.terasology.gestalt.entitysystem.component.Component; +import org.terasology.gestalt.entitysystem.event.Event; import java.util.Iterator; import java.util.Map; diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/BeforeRemoveComponent.java b/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/BeforeRemoveComponent.java index fcb40e8baae..4bf26a89603 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/BeforeRemoveComponent.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/BeforeRemoveComponent.java @@ -3,7 +3,7 @@ package org.terasology.engine.entitySystem.entity.lifecycleEvents; -import org.terasology.engine.entitySystem.event.Event; +import org.terasology.gestalt.entitysystem.event.Event; /** * When a component is about to be removed from an entity, or an entity is about to be destroyed, this event is sent. diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/OnActivatedComponent.java b/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/OnActivatedComponent.java index be370490420..f4da8e6557a 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/OnActivatedComponent.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/OnActivatedComponent.java @@ -3,7 +3,7 @@ package org.terasology.engine.entitySystem.entity.lifecycleEvents; -import org.terasology.engine.entitySystem.event.Event; +import org.terasology.gestalt.entitysystem.event.Event; /** * This event occurs after an entity is created, an entity is loaded or a component is added to an entity. This occurs diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/OnAddedComponent.java b/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/OnAddedComponent.java index f1c7642a04e..043880019c7 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/OnAddedComponent.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/OnAddedComponent.java @@ -3,7 +3,7 @@ package org.terasology.engine.entitySystem.entity.lifecycleEvents; -import org.terasology.engine.entitySystem.event.Event; +import org.terasology.gestalt.entitysystem.event.Event; /** * This event is sent when an entity is created or a component added to an existing entity. diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/OnChangedComponent.java b/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/OnChangedComponent.java index 8eb63bb7426..98911ffc5e7 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/OnChangedComponent.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/entity/lifecycleEvents/OnChangedComponent.java @@ -3,7 +3,7 @@ package org.terasology.engine.entitySystem.entity.lifecycleEvents; -import org.terasology.engine.entitySystem.event.Event; +import org.terasology.gestalt.entitysystem.event.Event; /** * This event occurs whenever a component is changed and saved. diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/event/AbstractValueModifiableEvent.java b/engine/src/main/java/org/terasology/engine/entitySystem/event/AbstractValueModifiableEvent.java index 6a0a5ce2346..fd146a2aed2 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/event/AbstractValueModifiableEvent.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/event/AbstractValueModifiableEvent.java @@ -5,6 +5,7 @@ import gnu.trove.iterator.TFloatIterator; import gnu.trove.list.TFloatList; import gnu.trove.list.array.TFloatArrayList; +import org.terasology.gestalt.entitysystem.event.Event; /** * A generic event for getting a value for a property. diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/event/Activity.java b/engine/src/main/java/org/terasology/engine/entitySystem/event/Activity.java new file mode 100644 index 00000000000..1992324e9df --- /dev/null +++ b/engine/src/main/java/org/terasology/engine/entitySystem/event/Activity.java @@ -0,0 +1,14 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.engine.entitySystem.event; + +import org.terasology.gestalt.entitysystem.event.ReceiveEvent; + +/** + * Additional for {@link ReceiveEvent}. + * Activate performance monitoring for Event Handler. + */ +public @interface Activity { + String value(); +} diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/event/BeforeAfterEvent.java b/engine/src/main/java/org/terasology/engine/entitySystem/event/BeforeAfterEvent.java index e15525230ee..3d9ae875ff3 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/event/BeforeAfterEvent.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/event/BeforeAfterEvent.java @@ -3,6 +3,8 @@ package org.terasology.engine.entitySystem.event; +import org.terasology.gestalt.entitysystem.event.Event; + /** * Immutable event to notify a change in a certain value. *

diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/event/ConsumableEvent.java b/engine/src/main/java/org/terasology/engine/entitySystem/event/ConsumableEvent.java index 1d57ab88dfd..d51dae216a7 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/event/ConsumableEvent.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/event/ConsumableEvent.java @@ -2,6 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.entitySystem.event; +import org.terasology.gestalt.entitysystem.event.Event; + /** * A consumable event is an event that can be prevented from continuing through remaining event receivers. This is * primarily useful for input event. diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/event/Event.java b/engine/src/main/java/org/terasology/engine/entitySystem/event/Event.java deleted file mode 100644 index 2981525854b..00000000000 --- a/engine/src/main/java/org/terasology/engine/entitySystem/event/Event.java +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2021 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 -package org.terasology.engine.entitySystem.event; - -/** - * Marker interface for classes that can be sent to entities as events - * - */ -public interface Event { -} diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/event/PendingEvent.java b/engine/src/main/java/org/terasology/engine/entitySystem/event/PendingEvent.java index b95b0d5edf2..937dfb2986b 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/event/PendingEvent.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/event/PendingEvent.java @@ -5,6 +5,7 @@ import org.terasology.engine.entitySystem.entity.EntityRef; import org.terasology.gestalt.entitysystem.component.Component; +import org.terasology.gestalt.entitysystem.event.Event; public class PendingEvent { private EntityRef entity; diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/event/Priority.java b/engine/src/main/java/org/terasology/engine/entitySystem/event/Priority.java new file mode 100644 index 00000000000..4613156f8bf --- /dev/null +++ b/engine/src/main/java/org/terasology/engine/entitySystem/event/Priority.java @@ -0,0 +1,20 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.engine.entitySystem.event; + +import org.terasology.gestalt.entitysystem.event.ReceiveEvent; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Provide priority possible for events. use with {@link ReceiveEvent} + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Priority { + int value(); +} diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/event/ReceiveEvent.java b/engine/src/main/java/org/terasology/engine/entitySystem/event/ReceiveEvent.java deleted file mode 100644 index 7b6e8cdfa76..00000000000 --- a/engine/src/main/java/org/terasology/engine/entitySystem/event/ReceiveEvent.java +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2021 The Terasology Foundation -// SPDX-License-Identifier: Apache-2.0 -package org.terasology.engine.entitySystem.event; - -import org.terasology.engine.entitySystem.systems.RegisterMode; -import org.terasology.gestalt.entitysystem.component.Component; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This annotation is used to mark up methods that can be registered to receive events through the EventSystem - *

- * These methods should have the form - * public void handlerMethod(EventType event, EntityRef entity) - * - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface ReceiveEvent { - /** - * What components that the entity must have for this method to be invoked - */ - Class[] components() default {}; - - RegisterMode netFilter() default RegisterMode.ALWAYS; - - int priority() default EventPriority.PRIORITY_NORMAL; - - String activity() default ""; -} diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/event/internal/EventReceiver.java b/engine/src/main/java/org/terasology/engine/entitySystem/event/internal/EventReceiver.java index 1cca11746ec..2d2348b41b8 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/event/internal/EventReceiver.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/event/internal/EventReceiver.java @@ -4,7 +4,7 @@ package org.terasology.engine.entitySystem.event.internal; import org.terasology.engine.entitySystem.entity.EntityRef; -import org.terasology.engine.entitySystem.event.Event; +import org.terasology.gestalt.entitysystem.event.Event; /** * Interface for a single event receiver diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/event/internal/EventSystem.java b/engine/src/main/java/org/terasology/engine/entitySystem/event/internal/EventSystem.java index 9d07b5f2425..4ddfaa55ebf 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/event/internal/EventSystem.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/event/internal/EventSystem.java @@ -3,10 +3,10 @@ package org.terasology.engine.entitySystem.event.internal; import org.terasology.engine.entitySystem.entity.EntityRef; -import org.terasology.engine.entitySystem.event.Event; import org.terasology.engine.entitySystem.systems.ComponentSystem; import org.terasology.gestalt.assets.ResourceUrn; import org.terasology.gestalt.entitysystem.component.Component; +import org.terasology.gestalt.entitysystem.event.Event; /** * Event system propagates events to registered handlers @@ -28,7 +28,7 @@ public interface EventSystem { void registerEvent(ResourceUrn uri, Class eventType); /** - * Registers an object as an event handler - all methods with the {@link org.terasology.engine.entitySystem.event.ReceiveEvent} + * Registers an object as an event handler - all methods with the {@link org.terasology.gestalt.entitysystem.event.ReceiveEvent} * annotation will be registered * * @param handler diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/event/internal/EventSystemImpl.java b/engine/src/main/java/org/terasology/engine/entitySystem/event/internal/EventSystemImpl.java index f1ca75223f7..6fccd116dc4 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/event/internal/EventSystemImpl.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/event/internal/EventSystemImpl.java @@ -19,16 +19,20 @@ import org.slf4j.LoggerFactory; import org.terasology.engine.entitySystem.entity.EntityRef; import org.terasology.engine.entitySystem.event.AbstractConsumableEvent; +import org.terasology.engine.entitySystem.event.Activity; import org.terasology.engine.entitySystem.event.ConsumableEvent; -import org.terasology.engine.entitySystem.event.Event; import org.terasology.engine.entitySystem.event.EventPriority; import org.terasology.engine.entitySystem.event.PendingEvent; -import org.terasology.engine.entitySystem.event.ReceiveEvent; +import org.terasology.engine.entitySystem.event.Priority; import org.terasology.engine.entitySystem.systems.ComponentSystem; +import org.terasology.engine.entitySystem.systems.NetFilterEvent; import org.terasology.engine.monitoring.PerformanceMonitor; import org.terasology.gestalt.assets.ResourceUrn; import org.terasology.gestalt.entitysystem.component.Component; +import org.terasology.gestalt.entitysystem.event.Event; +import org.terasology.gestalt.entitysystem.event.ReceiveEvent; +import javax.annotation.Nullable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; @@ -99,9 +103,26 @@ public void registerEventHandler(ComponentSystem handler) { for (Method method : handlerClass.getMethods()) { ReceiveEvent receiveEventAnnotation = method.getAnnotation(ReceiveEvent.class); if (receiveEventAnnotation != null) { - if (!receiveEventAnnotation.netFilter().isValidFor(isAutority, false)) { + + NetFilterEvent netFilterAnnotation = method.getAnnotation(NetFilterEvent.class); + if (netFilterAnnotation != null && !netFilterAnnotation.netFilter().isValidFor(isAutority, false)) { continue; } + + int priority; + Priority priorityAnnotation = method.getAnnotation(Priority.class); + if (priorityAnnotation != null) { + priority = priorityAnnotation.value(); + } else { + priority = EventPriority.PRIORITY_NORMAL; + } + + String activity = null; + Activity activityAnnotation = method.getAnnotation(Activity.class); + if (activityAnnotation != null) { + activity = activityAnnotation.value(); + } + Set> requiredComponents = Sets.newLinkedHashSet(); method.setAccessible(true); Class[] types = method.getParameterTypes(); @@ -123,10 +144,9 @@ public void registerEventHandler(ComponentSystem handler) { requiredComponents.add((Class) types[i]); componentParams.add((Class) types[i]); } - ByteCodeEventHandlerInfo handlerInfo = new ByteCodeEventHandlerInfo(handler, method, - receiveEventAnnotation.priority(), - receiveEventAnnotation.activity(), requiredComponents, componentParams); + priority, + activity, requiredComponents, componentParams); addEventHandler((Class) types[0], handlerInfo, requiredComponents); } } @@ -333,7 +353,7 @@ private static class ByteCodeEventHandlerInfo implements EventHandlerInfo { ByteCodeEventHandlerInfo(ComponentSystem handler, Method method, int priority, - String activity, + @Nullable String activity, Collection> filterComponents, Collection> componentParams) { @@ -372,13 +392,13 @@ public void invoke(EntityRef entity, Event event) { } - if (!activity.isEmpty()) { + if (activity != null) { PerformanceMonitor.startActivity(activity); } try { methodAccess.invoke(handler, methodIndex, params); } finally { - if (!activity.isEmpty()) { + if (activity != null) { PerformanceMonitor.endActivity(); } } diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/metadata/EventLibrary.java b/engine/src/main/java/org/terasology/engine/entitySystem/metadata/EventLibrary.java index d65a6d49b49..2b90088af09 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/metadata/EventLibrary.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/metadata/EventLibrary.java @@ -5,7 +5,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.gestalt.assets.ResourceUrn; -import org.terasology.engine.entitySystem.event.Event; +import org.terasology.gestalt.entitysystem.event.Event; import org.terasology.gestalt.module.ModuleEnvironment; import org.terasology.reflection.copy.CopyStrategyLibrary; import org.terasology.reflection.metadata.ClassMetadata; diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/metadata/EventMetadata.java b/engine/src/main/java/org/terasology/engine/entitySystem/metadata/EventMetadata.java index 3395bd13d9a..2a73a84f75d 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/metadata/EventMetadata.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/metadata/EventMetadata.java @@ -5,15 +5,15 @@ import com.google.common.base.Predicates; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.terasology.engine.network.BroadcastEvent; +import org.terasology.engine.network.OwnerEvent; +import org.terasology.engine.network.ServerEvent; import org.terasology.gestalt.assets.ResourceUrn; -import org.terasology.reflection.metadata.ClassMetadata; +import org.terasology.gestalt.entitysystem.event.Event; import org.terasology.reflection.copy.CopyStrategyLibrary; +import org.terasology.reflection.metadata.ClassMetadata; import org.terasology.reflection.reflect.InaccessibleFieldException; import org.terasology.reflection.reflect.ReflectFactory; -import org.terasology.engine.entitySystem.event.Event; -import org.terasology.engine.network.BroadcastEvent; -import org.terasology.engine.network.OwnerEvent; -import org.terasology.engine.network.ServerEvent; import java.lang.reflect.Field; import java.lang.reflect.Modifier; diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/sectors/LoadedSectorUpdateEvent.java b/engine/src/main/java/org/terasology/engine/entitySystem/sectors/LoadedSectorUpdateEvent.java index f9fa8df4983..008a9d7267c 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/sectors/LoadedSectorUpdateEvent.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/sectors/LoadedSectorUpdateEvent.java @@ -3,7 +3,7 @@ package org.terasology.engine.entitySystem.sectors; import org.joml.Vector3i; -import org.terasology.engine.entitySystem.event.Event; +import org.terasology.gestalt.entitysystem.event.Event; import org.terasology.gestalt.module.sandbox.API; import java.util.Set; diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorEntityLoad.java b/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorEntityLoad.java index e78cb9935d2..3ca0f233f9e 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorEntityLoad.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorEntityLoad.java @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.entitySystem.sectors; -import org.terasology.engine.entitySystem.event.Event; +import org.terasology.gestalt.entitysystem.event.Event; /** * Event sent to sector-scope entities when the first of its watched chunks load. diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorEntityUnload.java b/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorEntityUnload.java index ac550590ee7..3674a914c88 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorEntityUnload.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorEntityUnload.java @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 package org.terasology.engine.entitySystem.sectors; -import org.terasology.engine.entitySystem.event.Event; +import org.terasology.gestalt.entitysystem.event.Event; /** * Event sent to sector-scope entities when all of its watched chunks unload. diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorSimulationEvent.java b/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorSimulationEvent.java index caf69c51f71..005bda9000d 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorSimulationEvent.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorSimulationEvent.java @@ -3,7 +3,7 @@ package org.terasology.engine.entitySystem.sectors; import org.terasology.engine.entitySystem.entity.EntityRef; -import org.terasology.engine.entitySystem.event.Event; +import org.terasology.gestalt.entitysystem.event.Event; import org.terasology.gestalt.module.sandbox.API; /** diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorSimulationSystem.java b/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorSimulationSystem.java index 40501d80fda..3ffaeb312ad 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorSimulationSystem.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/sectors/SectorSimulationSystem.java @@ -10,7 +10,6 @@ import org.terasology.engine.entitySystem.entity.lifecycleEvents.BeforeRemoveComponent; import org.terasology.engine.entitySystem.entity.lifecycleEvents.OnAddedComponent; import org.terasology.engine.entitySystem.entity.lifecycleEvents.OnChangedComponent; -import org.terasology.engine.entitySystem.event.ReceiveEvent; import org.terasology.engine.entitySystem.systems.BaseComponentSystem; import org.terasology.engine.entitySystem.systems.RegisterSystem; import org.terasology.engine.logic.delay.DelayManager; @@ -20,6 +19,7 @@ import org.terasology.engine.world.chunks.ChunkProvider; import org.terasology.engine.world.chunks.event.BeforeChunkUnload; import org.terasology.engine.world.chunks.event.OnChunkLoaded; +import org.terasology.gestalt.entitysystem.event.ReceiveEvent; import java.util.stream.Collectors; diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/systems/NetFilterEvent.java b/engine/src/main/java/org/terasology/engine/entitySystem/systems/NetFilterEvent.java new file mode 100644 index 00000000000..4b0ba248ed3 --- /dev/null +++ b/engine/src/main/java/org/terasology/engine/entitySystem/systems/NetFilterEvent.java @@ -0,0 +1,20 @@ +// Copyright 2021 The Terasology Foundation +// SPDX-License-Identifier: Apache-2.0 + +package org.terasology.engine.entitySystem.systems; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks event handlers condition. when should be registered. {@link RegisterMode} + * Using with {@link org.terasology.gestalt.entitysystem.event.ReceiveEvent} + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface NetFilterEvent { + + RegisterMode netFilter(); +} diff --git a/engine/src/main/java/org/terasology/engine/entitySystem/systems/UpdateSubscriberSystem.java b/engine/src/main/java/org/terasology/engine/entitySystem/systems/UpdateSubscriberSystem.java index a26713afc57..60593025c4f 100644 --- a/engine/src/main/java/org/terasology/engine/entitySystem/systems/UpdateSubscriberSystem.java +++ b/engine/src/main/java/org/terasology/engine/entitySystem/systems/UpdateSubscriberSystem.java @@ -12,8 +12,8 @@ * In most cases it will be sufficient to: *