From 5cfa17b5e307c2aeae676381ba7ab639daf22762 Mon Sep 17 00:00:00 2001 From: graefjk Date: Sat, 23 Sep 2023 15:50:22 +0200 Subject: [PATCH 01/14] limit draw updates to 62.5 Draws/Second --- .../internal/playfield/StandardPlayfield.java | 57 ++++++++++++++----- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index fa804b10..3995cf10 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -54,6 +54,30 @@ public class StandardPlayfield implements Playfield { private Consumer> drawablesChangedListener; + private long lastEntityDraw = 0; + private boolean delayedEntityDraw = false; + + private Runnable delayedEntitiesDrawRunnable = () -> { + long timeSinceLastEntityDraw = System.nanoTime() - this.lastEntityDraw; + if (timeSinceLastEntityDraw < 16000000) { //update once every 16ms (62.5 Hz) + try { + Thread.sleep(16 - timeSinceLastEntityDraw / 1000000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + this.lastEntityDraw = System.nanoTime(); + this.delayedEntityDraw = false; + try { + Thread.sleep(1); // leave some time between this.delayedEntityDraw = false; and drawEntitiesInternal(), so as to not lose any draw calls due to poor timing + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + this.drawEntitiesInternal(); + }; + /** * Initialize the playfield for the given simulation * @@ -86,6 +110,13 @@ public Simulation getSimulation() { * Converts all entities to drawables and sends them to the playfield drawer. */ public void drawEntities() { + if (!this.delayedEntityDraw) { + this.delayedEntityDraw = true; + new Thread(this.delayedEntitiesDrawRunnable).start(); + } + } + + private void drawEntitiesInternal() { final List drawables = new ArrayList<>(); for (final Entity entity : this.getAllEntities()) { try { @@ -102,6 +133,7 @@ public void drawEntities() { } catch (@SuppressWarnings("unused") final IllegalStateException e) { //If we are not attached to a simultion we do not need to draw anything } + this.lastEntityDraw = System.nanoTime(); } @Override @@ -174,9 +206,8 @@ public void addEntity(final Position pos, final Entity entity) { if (entity == null) throw new IllegalArgumentException("The given entity is null."); synchronized (this.playfieldLock) { - if ( - this.entityPositions.containsKey(entity) - ) throw new EntityAlreadyOnFieldExcpetion("The given entity" + entity + "is already on this playfield."); + if (this.entityPositions.containsKey(entity)) + throw new EntityAlreadyOnFieldExcpetion("The given entity" + entity + "is already on this playfield."); entity.initOnPlayfield(this); @@ -243,9 +274,8 @@ public void moveEntity(final Entity entity, final Position pos, final EntityMove if (entity == null) throw new IllegalArgumentException("The given entity is null."); synchronized (this.playfieldLock) { - if ( - !this.entityPositions.containsKey(entity) - ) throw new EntityNotOnFieldException("The given entity" + entity + "is not on this playfield."); + if (!this.entityPositions.containsKey(entity)) + throw new EntityNotOnFieldException("The given entity" + entity + "is not on this playfield."); EntityMoveAction actionToLog = action; @@ -254,12 +284,10 @@ public void moveEntity(final Entity entity, final Position pos, final EntityMove if (actionToLog == null) { actionToLog = new EntityTeleportAction(this.getSimulation().getSimulationClock().getLastTickNumber(), entity, oldPos, pos); } else { - if ( - !actionToLog.getEntity().equals(entity) - ) throw new IllegalArgumentException("Given action wasn't caused by given entity."); - if ( - !actionToLog.from().equals(oldPos) - ) throw new IllegalArgumentException("Given action does not start at current position of given entity."); + if (!actionToLog.getEntity().equals(entity)) + throw new IllegalArgumentException("Given action wasn't caused by given entity."); + if (!actionToLog.from().equals(oldPos)) + throw new IllegalArgumentException("Given action does not start at current position of given entity."); if (!actionToLog.to().equals(pos)) throw new IllegalArgumentException("Given action does not end at given pos."); } @@ -294,9 +322,8 @@ public void removeEntity(final Entity entity) { if (entity == null) throw new IllegalArgumentException("The given entity is null."); synchronized (this.playfieldLock) { - if ( - !this.entityPositions.containsKey(entity) - ) throw new EntityNotOnFieldException("The given entity" + entity + "is not on this playfield."); + if (!this.entityPositions.containsKey(entity)) + throw new EntityNotOnFieldException("The given entity" + entity + "is not on this playfield."); final Position pos = this.entityPositions.get(entity); this.removeEntityFromCell(pos, entity); From 0ae7060e2883465ae8161cc1cd6e5fac0c0e5aa4 Mon Sep 17 00:00:00 2001 From: graefjk Date: Sat, 23 Sep 2023 16:01:58 +0200 Subject: [PATCH 02/14] make time between draw calls changeable --- .../internal/playfield/StandardPlayfield.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index 3995cf10..7321132e 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -56,12 +56,13 @@ public class StandardPlayfield implements Playfield { private long lastEntityDraw = 0; private boolean delayedEntityDraw = false; + private long timeBetweenDraws = 16; //the time between draw calls in milliseconds private Runnable delayedEntitiesDrawRunnable = () -> { long timeSinceLastEntityDraw = System.nanoTime() - this.lastEntityDraw; - if (timeSinceLastEntityDraw < 16000000) { //update once every 16ms (62.5 Hz) + if (timeSinceLastEntityDraw < this.timeBetweenDraws * 1000000) { //update once every 16ms (62.5 Hz) try { - Thread.sleep(16 - timeSinceLastEntityDraw / 1000000); + Thread.sleep(this.timeBetweenDraws - timeSinceLastEntityDraw / 1000000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -435,4 +436,23 @@ public void removeDrawablesChangedListener() { public String toString() { return this.getClass().getSimpleName() + "@" + Integer.toHexString(this.hashCode()); } + + /** + * Get's {@link #timeBetweenDraws timeBetweenDraws} + * + * @return time waiting between draw calls in milliseconds + */ + public long getTimeBetweenDraws() { + return this.timeBetweenDraws; + } + + /** + * Set's {@link #timeBetweenDraws timeBetweenDraws} + * + * @param timeBetweenDraws + * time waiting between draw calls in milliseconds + */ + public void setTimeBetweenDraws(long timeBetweenDraws) { + this.timeBetweenDraws = timeBetweenDraws; + } } From cf61e4ecba082ef57f1b9f225af7a0b6d11e1a9d Mon Sep 17 00:00:00 2001 From: graefjk Date: Sat, 23 Sep 2023 16:04:00 +0200 Subject: [PATCH 03/14] adjust wait time before drawing Entities --- .../icge/simulation/internal/playfield/StandardPlayfield.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index 7321132e..58ae47c1 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -71,7 +71,7 @@ public class StandardPlayfield implements Playfield { this.lastEntityDraw = System.nanoTime(); this.delayedEntityDraw = false; try { - Thread.sleep(1); // leave some time between this.delayedEntityDraw = false; and drawEntitiesInternal(), so as to not lose any draw calls due to poor timing + Thread.sleep(10); // leave some time between this.delayedEntityDraw = false; and drawEntitiesInternal(), so as to not lose any draw calls due to poor timing } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); From 2e52ff16e37d3d1272a3dac6ccf933ae7cb4da9c Mon Sep 17 00:00:00 2001 From: graefjk Date: Sat, 23 Sep 2023 16:15:01 +0200 Subject: [PATCH 04/14] formating --- .../internal/playfield/StandardPlayfield.java | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index 58ae47c1..8db45b20 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -107,9 +107,6 @@ public Simulation getSimulation() { return simulation; } - /** - * Converts all entities to drawables and sends them to the playfield drawer. - */ public void drawEntities() { if (!this.delayedEntityDraw) { this.delayedEntityDraw = true; @@ -117,6 +114,9 @@ public void drawEntities() { } } + /** + * Converts all entities to drawables and sends them to the playfield drawer. + */ private void drawEntitiesInternal() { final List drawables = new ArrayList<>(); for (final Entity entity : this.getAllEntities()) { @@ -207,8 +207,9 @@ public void addEntity(final Position pos, final Entity entity) { if (entity == null) throw new IllegalArgumentException("The given entity is null."); synchronized (this.playfieldLock) { - if (this.entityPositions.containsKey(entity)) - throw new EntityAlreadyOnFieldExcpetion("The given entity" + entity + "is already on this playfield."); + if ( + this.entityPositions.containsKey(entity) + ) throw new EntityAlreadyOnFieldExcpetion("The given entity" + entity + "is already on this playfield."); entity.initOnPlayfield(this); @@ -275,8 +276,9 @@ public void moveEntity(final Entity entity, final Position pos, final EntityMove if (entity == null) throw new IllegalArgumentException("The given entity is null."); synchronized (this.playfieldLock) { - if (!this.entityPositions.containsKey(entity)) - throw new EntityNotOnFieldException("The given entity" + entity + "is not on this playfield."); + if ( + !this.entityPositions.containsKey(entity) + ) throw new EntityNotOnFieldException("The given entity" + entity + "is not on this playfield."); EntityMoveAction actionToLog = action; @@ -285,10 +287,12 @@ public void moveEntity(final Entity entity, final Position pos, final EntityMove if (actionToLog == null) { actionToLog = new EntityTeleportAction(this.getSimulation().getSimulationClock().getLastTickNumber(), entity, oldPos, pos); } else { - if (!actionToLog.getEntity().equals(entity)) - throw new IllegalArgumentException("Given action wasn't caused by given entity."); - if (!actionToLog.from().equals(oldPos)) - throw new IllegalArgumentException("Given action does not start at current position of given entity."); + if ( + !actionToLog.getEntity().equals(entity) + ) throw new IllegalArgumentException("Given action wasn't caused by given entity."); + if ( + !actionToLog.from().equals(oldPos) + ) throw new IllegalArgumentException("Given action does not start at current position of given entity."); if (!actionToLog.to().equals(pos)) throw new IllegalArgumentException("Given action does not end at given pos."); } @@ -323,8 +327,9 @@ public void removeEntity(final Entity entity) { if (entity == null) throw new IllegalArgumentException("The given entity is null."); synchronized (this.playfieldLock) { - if (!this.entityPositions.containsKey(entity)) - throw new EntityNotOnFieldException("The given entity" + entity + "is not on this playfield."); + if ( + !this.entityPositions.containsKey(entity) + ) throw new EntityNotOnFieldException("The given entity" + entity + "is not on this playfield."); final Position pos = this.entityPositions.get(entity); this.removeEntityFromCell(pos, entity); From fe7134f7ba885ce4a7009786b59e07bcce729650 Mon Sep 17 00:00:00 2001 From: graefjk Date: Mon, 25 Sep 2023 03:15:10 +0200 Subject: [PATCH 05/14] only allow one DrawEntities per time slot. --- .../internal/playfield/StandardPlayfield.java | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index 8db45b20..93223d0a 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -54,13 +54,14 @@ public class StandardPlayfield implements Playfield { private Consumer> drawablesChangedListener; - private long lastEntityDraw = 0; - private boolean delayedEntityDraw = false; - private long timeBetweenDraws = 16; //the time between draw calls in milliseconds + private long lastEntityDraw = 0; + private boolean delayedEntityDraw = false; + private long timeBetweenDraws = 32; //the time between draw calls in milliseconds + private Thread delayedDrawEntitiesThread = new Thread(); private Runnable delayedEntitiesDrawRunnable = () -> { long timeSinceLastEntityDraw = System.nanoTime() - this.lastEntityDraw; - if (timeSinceLastEntityDraw < this.timeBetweenDraws * 1000000) { //update once every 16ms (62.5 Hz) + if (timeSinceLastEntityDraw < this.timeBetweenDraws * 1000000) { try { Thread.sleep(this.timeBetweenDraws - timeSinceLastEntityDraw / 1000000); } catch (InterruptedException e) { @@ -68,15 +69,20 @@ public class StandardPlayfield implements Playfield { e.printStackTrace(); } } - this.lastEntityDraw = System.nanoTime(); this.delayedEntityDraw = false; + drawEntitiesInternal(); + this.lastEntityDraw = System.nanoTime(); + }; + + private Runnable restartDelayedEntitiesDrawThreadRunnable = () -> { try { - Thread.sleep(10); // leave some time between this.delayedEntityDraw = false; and drawEntitiesInternal(), so as to not lose any draw calls due to poor timing + this.delayedDrawEntitiesThread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } - this.drawEntitiesInternal(); + this.delayedDrawEntitiesThread = new Thread(this.delayedEntitiesDrawRunnable); + this.delayedDrawEntitiesThread.start(); }; /** @@ -107,10 +113,15 @@ public Simulation getSimulation() { return simulation; } + + /** + * Converts all entities to drawables and sends them to the playfield drawer if the last draw has not occurred + * recently. + */ public void drawEntities() { if (!this.delayedEntityDraw) { this.delayedEntityDraw = true; - new Thread(this.delayedEntitiesDrawRunnable).start(); + new Thread(this.restartDelayedEntitiesDrawThreadRunnable).start(); } } @@ -134,7 +145,6 @@ private void drawEntitiesInternal() { } catch (@SuppressWarnings("unused") final IllegalStateException e) { //If we are not attached to a simultion we do not need to draw anything } - this.lastEntityDraw = System.nanoTime(); } @Override @@ -328,7 +338,7 @@ public void removeEntity(final Entity entity) { synchronized (this.playfieldLock) { if ( - !this.entityPositions.containsKey(entity) + !this.entityPositions.containsKey(entity) ) throw new EntityNotOnFieldException("The given entity" + entity + "is not on this playfield."); final Position pos = this.entityPositions.get(entity); From ed3cd726cbe7c6f3075f5f23acb49bef1e421011 Mon Sep 17 00:00:00 2001 From: graefjk Date: Mon, 25 Sep 2023 03:31:03 +0200 Subject: [PATCH 06/14] formating --- .../icge/simulation/internal/playfield/StandardPlayfield.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index 93223d0a..8c14c9bd 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -338,7 +338,7 @@ public void removeEntity(final Entity entity) { synchronized (this.playfieldLock) { if ( - !this.entityPositions.containsKey(entity) + !this.entityPositions.containsKey(entity) ) throw new EntityNotOnFieldException("The given entity" + entity + "is not on this playfield."); final Position pos = this.entityPositions.get(entity); From 03ec09ce7dee3762195c9feafa616a3e85a42e3e Mon Sep 17 00:00:00 2001 From: graefjk Date: Mon, 25 Sep 2023 03:43:14 +0200 Subject: [PATCH 07/14] formatting --- .../icge/simulation/internal/playfield/StandardPlayfield.java | 1 - 1 file changed, 1 deletion(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index 8c14c9bd..7de6f584 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -113,7 +113,6 @@ public Simulation getSimulation() { return simulation; } - /** * Converts all entities to drawables and sends them to the playfield drawer if the last draw has not occurred * recently. From d79be28690891e9dd606558ba85257fb7e8e0e9b Mon Sep 17 00:00:00 2001 From: graefjk Date: Mon, 25 Sep 2023 04:19:07 +0200 Subject: [PATCH 08/14] made boolean volatile --- .../simulation/internal/playfield/StandardPlayfield.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index 7de6f584..517e8b5c 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -54,10 +54,10 @@ public class StandardPlayfield implements Playfield { private Consumer> drawablesChangedListener; - private long lastEntityDraw = 0; - private boolean delayedEntityDraw = false; - private long timeBetweenDraws = 32; //the time between draw calls in milliseconds - private Thread delayedDrawEntitiesThread = new Thread(); + private long lastEntityDraw = 0; + private volatile boolean delayedEntityDraw = false; + private long timeBetweenDraws = 32; //the time between draw calls in milliseconds + private Thread delayedDrawEntitiesThread = new Thread(); private Runnable delayedEntitiesDrawRunnable = () -> { long timeSinceLastEntityDraw = System.nanoTime() - this.lastEntityDraw; From 67cfc230f7ebed3e03f1a1be95e1193c596cf6bb Mon Sep 17 00:00:00 2001 From: graefjk <49717341+graefjk@users.noreply.github.com> Date: Tue, 26 Sep 2023 17:20:05 +0200 Subject: [PATCH 09/14] rename delayedEntityDraw to awaitingEntityDraw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fabian Bühler --- .../icge/simulation/internal/playfield/StandardPlayfield.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index 517e8b5c..5ddba623 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -55,7 +55,7 @@ public class StandardPlayfield implements Playfield { private Consumer> drawablesChangedListener; private long lastEntityDraw = 0; - private volatile boolean delayedEntityDraw = false; + private volatile boolean awaitingEntityDraw = false; private long timeBetweenDraws = 32; //the time between draw calls in milliseconds private Thread delayedDrawEntitiesThread = new Thread(); From 953b60e79fbcba7123a50088cc6411da5386e4d8 Mon Sep 17 00:00:00 2001 From: graefjk Date: Tue, 26 Sep 2023 17:26:10 +0200 Subject: [PATCH 10/14] rename all instances of delayedEntityDraw to awaitingEntityDraw --- .../simulation/internal/playfield/StandardPlayfield.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index 5ddba623..76f71fd0 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -69,7 +69,7 @@ public class StandardPlayfield implements Playfield { e.printStackTrace(); } } - this.delayedEntityDraw = false; + this.awaitingEntityDraw = false; drawEntitiesInternal(); this.lastEntityDraw = System.nanoTime(); }; @@ -118,8 +118,8 @@ public Simulation getSimulation() { * recently. */ public void drawEntities() { - if (!this.delayedEntityDraw) { - this.delayedEntityDraw = true; + if (!this.awaitingEntityDraw) { + this.awaitingEntityDraw = true; new Thread(this.restartDelayedEntitiesDrawThreadRunnable).start(); } } From 49c14ad371e98977415376eeb1deef20dcd1d693 Mon Sep 17 00:00:00 2001 From: graefjk Date: Tue, 26 Sep 2023 20:53:51 +0200 Subject: [PATCH 11/14] change implementation to use a timer --- .../internal/playfield/StandardPlayfield.java | 76 +++++++------------ 1 file changed, 29 insertions(+), 47 deletions(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index 76f71fd0..65ed8203 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -14,6 +14,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -54,36 +56,8 @@ public class StandardPlayfield implements Playfield { private Consumer> drawablesChangedListener; - private long lastEntityDraw = 0; - private volatile boolean awaitingEntityDraw = false; - private long timeBetweenDraws = 32; //the time between draw calls in milliseconds - private Thread delayedDrawEntitiesThread = new Thread(); - - private Runnable delayedEntitiesDrawRunnable = () -> { - long timeSinceLastEntityDraw = System.nanoTime() - this.lastEntityDraw; - if (timeSinceLastEntityDraw < this.timeBetweenDraws * 1000000) { - try { - Thread.sleep(this.timeBetweenDraws - timeSinceLastEntityDraw / 1000000); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - this.awaitingEntityDraw = false; - drawEntitiesInternal(); - this.lastEntityDraw = System.nanoTime(); - }; - - private Runnable restartDelayedEntitiesDrawThreadRunnable = () -> { - try { - this.delayedDrawEntitiesThread.join(); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - this.delayedDrawEntitiesThread = new Thread(this.delayedEntitiesDrawRunnable); - this.delayedDrawEntitiesThread.start(); - }; + private boolean awaitingEntityDraw = false; + private long timeBetweenDraws = 32; //the time between draw calls in milliseconds /** * Initialize the playfield for the given simulation @@ -99,6 +73,15 @@ public void initialize(final StandardSimulation simulation) { }); this.simualtionTreeRootNode = new SimulationTreeNode("root", "Entities", "", false); + + new Timer().scheduleAtFixedRate(new TimerTask() { + + @Override + public void run() { + drawEntitiesInternal(); + } + + }, 0, this.timeBetweenDraws); } /** @@ -118,31 +101,30 @@ public Simulation getSimulation() { * recently. */ public void drawEntities() { - if (!this.awaitingEntityDraw) { - this.awaitingEntityDraw = true; - new Thread(this.restartDelayedEntitiesDrawThreadRunnable).start(); - } + this.awaitingEntityDraw = true; } /** * Converts all entities to drawables and sends them to the playfield drawer. */ private void drawEntitiesInternal() { - final List drawables = new ArrayList<>(); - for (final Entity entity : this.getAllEntities()) { - try { - drawables.add(entity.getDrawInformation()); - } catch (@SuppressWarnings("unused") final EntityNotOnFieldException e) { - //Entity has been removed from the field while this loop was running. - //Just don't draw it and ignore the exception. + if (this.awaitingEntityDraw) { + final List drawables = new ArrayList<>(); + for (final Entity entity : this.getAllEntities()) { + try { + drawables.add(entity.getDrawInformation()); + } catch (@SuppressWarnings("unused") final EntityNotOnFieldException e) { + //Entity has been removed from the field while this loop was running. + //Just don't draw it and ignore the exception. + } } - } - try { - if (this.drawablesChangedListener != null) { - this.drawablesChangedListener.accept(drawables); + try { + if (this.drawablesChangedListener != null) { + this.drawablesChangedListener.accept(drawables); + } + } catch (@SuppressWarnings("unused") final IllegalStateException e) { + //If we are not attached to a simultion we do not need to draw anything } - } catch (@SuppressWarnings("unused") final IllegalStateException e) { - //If we are not attached to a simultion we do not need to draw anything } } From 5bf039a4f152aa2d79570e8afbaad14076ef7d1b Mon Sep 17 00:00:00 2001 From: graefjk Date: Tue, 26 Sep 2023 20:56:10 +0200 Subject: [PATCH 12/14] remove unusable getter and setter for timeBetweenDraws --- .../internal/playfield/StandardPlayfield.java | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index 65ed8203..3b8f0934 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -97,8 +97,7 @@ public Simulation getSimulation() { } /** - * Converts all entities to drawables and sends them to the playfield drawer if the last draw has not occurred - * recently. + * Converts all entities to drawables and sends them to the playfield drawer every 32ms. */ public void drawEntities() { this.awaitingEntityDraw = true; @@ -432,23 +431,4 @@ public void removeDrawablesChangedListener() { public String toString() { return this.getClass().getSimpleName() + "@" + Integer.toHexString(this.hashCode()); } - - /** - * Get's {@link #timeBetweenDraws timeBetweenDraws} - * - * @return time waiting between draw calls in milliseconds - */ - public long getTimeBetweenDraws() { - return this.timeBetweenDraws; - } - - /** - * Set's {@link #timeBetweenDraws timeBetweenDraws} - * - * @param timeBetweenDraws - * time waiting between draw calls in milliseconds - */ - public void setTimeBetweenDraws(long timeBetweenDraws) { - this.timeBetweenDraws = timeBetweenDraws; - } } From bca1ed9da984ac1d098028e0c0355dc4c2273d5e Mon Sep 17 00:00:00 2001 From: graefjk <49717341+graefjk@users.noreply.github.com> Date: Wed, 27 Sep 2023 14:10:58 +0200 Subject: [PATCH 13/14] Update javadoc for drawEntities() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fabian Bühler --- .../icge/simulation/internal/playfield/StandardPlayfield.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index 3b8f0934..6d91ffd6 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -97,7 +97,7 @@ public Simulation getSimulation() { } /** - * Converts all entities to drawables and sends them to the playfield drawer every 32ms. + * Queues a draw update to the playfield drawer. Draw updates are sent to the playfield drawer automatically every 32ms. */ public void drawEntities() { this.awaitingEntityDraw = true; From e6689ab7da61cf84af2b013a4fddec6a4adc4fe2 Mon Sep 17 00:00:00 2001 From: graefjk Date: Wed, 27 Sep 2023 14:16:21 +0200 Subject: [PATCH 14/14] changed awaitingEntityDraw check for better readability --- .../internal/playfield/StandardPlayfield.java | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java index 6d91ffd6..6846a512 100644 --- a/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java +++ b/ICGE-Simulation/src/main/java/de/unistuttgart/informatik/fius/icge/simulation/internal/playfield/StandardPlayfield.java @@ -97,7 +97,8 @@ public Simulation getSimulation() { } /** - * Queues a draw update to the playfield drawer. Draw updates are sent to the playfield drawer automatically every 32ms. + * Queues a draw update to the playfield drawer. Draw updates are sent to the playfield drawer automatically every + * 32ms. */ public void drawEntities() { this.awaitingEntityDraw = true; @@ -107,24 +108,26 @@ public void drawEntities() { * Converts all entities to drawables and sends them to the playfield drawer. */ private void drawEntitiesInternal() { - if (this.awaitingEntityDraw) { - final List drawables = new ArrayList<>(); - for (final Entity entity : this.getAllEntities()) { - try { - drawables.add(entity.getDrawInformation()); - } catch (@SuppressWarnings("unused") final EntityNotOnFieldException e) { - //Entity has been removed from the field while this loop was running. - //Just don't draw it and ignore the exception. - } - } + if (!this.awaitingEntityDraw) { //fast exit as default + return; // no updates to draw + } + final List drawables = new ArrayList<>(); + for (final Entity entity : this.getAllEntities()) { try { - if (this.drawablesChangedListener != null) { - this.drawablesChangedListener.accept(drawables); - } - } catch (@SuppressWarnings("unused") final IllegalStateException e) { - //If we are not attached to a simultion we do not need to draw anything + drawables.add(entity.getDrawInformation()); + } catch (@SuppressWarnings("unused") final EntityNotOnFieldException e) { + //Entity has been removed from the field while this loop was running. + //Just don't draw it and ignore the exception. } } + try { + if (this.drawablesChangedListener != null) { + this.drawablesChangedListener.accept(drawables); + } + } catch (@SuppressWarnings("unused") final IllegalStateException e) { + //If we are not attached to a simultion we do not need to draw anything + } + } @Override