From c02329e4b1b160f19e80eb7b132c50fa5686e8e0 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 30 Oct 2018 12:58:25 -0400 Subject: [PATCH] Integrated thread implementation / Crash fix --- .../io/anuke/mindustry/AndroidLauncher.java | 6 -- build.gradle | 2 +- core/src/io/anuke/mindustry/Vars.java | 2 +- .../anuke/mindustry/core/ContentLoader.java | 2 +- .../src/io/anuke/mindustry/core/Platform.java | 12 ---- .../anuke/mindustry/core/ThreadHandler.java | 64 +++++++++++------- core/src/io/anuke/mindustry/io/SaveIO.java | 1 + .../mindustry/desktop/DesktopPlatform.java | 7 -- ios/src/io/anuke/mindustry/IOSLauncher.java | 9 +-- .../io/anuke/kryonet/DefaultThreadImpl.java | 67 ------------------- 10 files changed, 43 insertions(+), 129 deletions(-) delete mode 100644 kryonet/src/io/anuke/kryonet/DefaultThreadImpl.java diff --git a/android/src/io/anuke/mindustry/AndroidLauncher.java b/android/src/io/anuke/mindustry/AndroidLauncher.java index 44fa1e6363..31fa3fe03b 100644 --- a/android/src/io/anuke/mindustry/AndroidLauncher.java +++ b/android/src/io/anuke/mindustry/AndroidLauncher.java @@ -23,7 +23,6 @@ import io.anuke.kryonet.DefaultThreadImpl; import io.anuke.kryonet.KryoClient; import io.anuke.kryonet.KryoServer; import io.anuke.mindustry.core.Platform; -import io.anuke.mindustry.core.ThreadHandler.ThreadProvider; import io.anuke.mindustry.game.Saves.SaveSlot; import io.anuke.mindustry.io.SaveIO; import io.anuke.mindustry.net.Net; @@ -85,11 +84,6 @@ public class AndroidLauncher extends PatchedAndroidApplication{ showDonations(); } - @Override - public ThreadProvider getThreadProvider(){ - return new DefaultThreadImpl(); - } - @Override public String getUUID(){ try{ diff --git a/build.gradle b/build.gradle index 67b55f03c5..c5f82b6b0b 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ allprojects { appName = 'Mindustry' gdxVersion = '1.9.8' roboVMVersion = '2.3.0' - uCoreVersion = '53571305f7e5b31dd07377756bb46c0f2ae2ef34' + uCoreVersion = 'dec41336067c013f04f0e17db3b06e24d3c11f6a' getVersionString = { String buildVersion = getBuildVersion() diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index a51431a503..286f022c0d 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -166,7 +166,7 @@ public class Vars{ }); } - threads = new ThreadHandler(Platform.instance.getThreadProvider()); + threads = new ThreadHandler(); mobile = Gdx.app.getType() == ApplicationType.Android || Gdx.app.getType() == ApplicationType.iOS || testMobile; ios = Gdx.app.getType() == ApplicationType.iOS; diff --git a/core/src/io/anuke/mindustry/core/ContentLoader.java b/core/src/io/anuke/mindustry/core/ContentLoader.java index e5dac901e1..9f32f06c27 100644 --- a/core/src/io/anuke/mindustry/core/ContentLoader.java +++ b/core/src/io/anuke/mindustry/core/ContentLoader.java @@ -210,7 +210,7 @@ public class ContentLoader{ if(id < 0) id += 256; if(temporaryMapper != null && temporaryMapper[type.ordinal()] != null && temporaryMapper[type.ordinal()].length != 0){ - if(temporaryMapper[type.ordinal()][id] == null){ + if(temporaryMapper[type.ordinal()].length <= id || temporaryMapper[type.ordinal()][id] == null){ return getByID(type, 0); //default value is always ID 0 } return (T)temporaryMapper[type.ordinal()][id]; diff --git a/core/src/io/anuke/mindustry/core/Platform.java b/core/src/io/anuke/mindustry/core/Platform.java index 16291b2bfa..c6d038cdb8 100644 --- a/core/src/io/anuke/mindustry/core/Platform.java +++ b/core/src/io/anuke/mindustry/core/Platform.java @@ -2,7 +2,6 @@ package io.anuke.mindustry.core; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.utils.Base64Coder; -import io.anuke.mindustry.core.ThreadHandler.ThreadProvider; import io.anuke.ucore.core.Settings; import io.anuke.ucore.function.Consumer; import io.anuke.ucore.scene.ui.TextField; @@ -67,17 +66,6 @@ public abstract class Platform { * @param filetype File extension to filter */ public void showFileChooser(String text, String content, Consumer cons, boolean open, String filetype){} - /**Use the default thread provider from the kryonet module for this.*/ - public ThreadProvider getThreadProvider(){ - return new ThreadProvider() { - @Override public boolean isOnThread() {return true;} - @Override public void sleep(long ms) {} - @Override public void start(Runnable run) {} - @Override public void stop() {} - @Override public void notify(Object object) {} - @Override public void wait(Object object) {} - }; - } /**Forces the app into landscape mode. Currently Android only.*/ public void beginForceLandscape(){} diff --git a/core/src/io/anuke/mindustry/core/ThreadHandler.java b/core/src/io/anuke/mindustry/core/ThreadHandler.java index 66522df150..e64bfde8e1 100644 --- a/core/src/io/anuke/mindustry/core/ThreadHandler.java +++ b/core/src/io/anuke/mindustry/core/ThreadHandler.java @@ -6,13 +6,15 @@ import com.badlogic.gdx.utils.TimeUtils; import io.anuke.ucore.core.Settings; import io.anuke.ucore.core.Timers; import io.anuke.ucore.util.Log; +import io.anuke.ucore.util.Threads; +import io.anuke.ucore.util.Threads.ThreadInfoProvider; import static io.anuke.mindustry.Vars.control; import static io.anuke.mindustry.Vars.logic; -public class ThreadHandler{ +public class ThreadHandler implements ThreadInfoProvider{ private final Queue toRun = new Queue<>(); - private final ThreadProvider impl; + private Thread thread, graphicsThread; private final Object updateLock = new Object(); private float delta = 1f; private float smoothDelta = 1f; @@ -22,11 +24,12 @@ public class ThreadHandler{ private boolean rendered = true; private long lastFrameTime; - public ThreadHandler(ThreadProvider impl){ - this.impl = impl; + public ThreadHandler(){ + Threads.setThreadInfoProvider(this); + graphicsThread = Thread.currentThread(); Timers.setDeltaProvider(() -> { - float result = impl.isOnThread() ? delta : Gdx.graphics.getDeltaTime() * 60f; + float result = isOnThread() ? delta : Gdx.graphics.getDeltaTime() * 60f; return Math.min(Float.isNaN(result) ? 1f : result, 15f); }); } @@ -86,7 +89,7 @@ public class ThreadHandler{ long elapsed = TimeUtils.timeSinceMillis(lastFrameTime); if(elapsed < target){ try{ - impl.sleep(target - elapsed); + Thread.sleep(target - elapsed); }catch(InterruptedException e){ e.printStackTrace(); } @@ -99,7 +102,7 @@ public class ThreadHandler{ synchronized(updateLock){ rendered = true; - impl.notify(updateLock); + Threads.notify(updateLock); } } @@ -111,12 +114,25 @@ public class ThreadHandler{ if(enabled){ logic.doUpdate = false; Timers.runTask(2f, () -> { - impl.start(this::runLogic); + if(thread != null){ + thread.interrupt(); + thread = null; + } + + thread = new Thread(this::runLogic); + thread.setDaemon(true); + thread.setName("Update Thread"); + thread.start(); + Log.info("Starting logic thread."); + this.enabled = true; }); }else{ this.enabled = false; - impl.stop(); + if(thread != null){ + thread.interrupt(); + thread = null; + } Timers.runTask(2f, () -> { logic.doUpdate = true; }); @@ -128,7 +144,17 @@ public class ThreadHandler{ } public boolean isOnThread(){ - return impl.isOnThread(); + return Thread.currentThread() == thread; + } + + @Override + public boolean isOnLogicThread() { + return !enabled || Thread.currentThread() == thread; + } + + @Override + public boolean isOnGraphicsThread() { + return !enabled || Thread.currentThread() == graphicsThread; } private void runLogic(){ @@ -157,12 +183,12 @@ public class ThreadHandler{ long target = (long) ((1000) / 60f); if(elapsed < target){ - impl.sleep(target - elapsed); + Thread.sleep(target - elapsed); } synchronized(updateLock){ while(!rendered){ - impl.wait(updateLock); + Threads.wait(updateLock); } rendered = false; } @@ -184,18 +210,4 @@ public class ThreadHandler{ control.setError(ex); } } - - public interface ThreadProvider{ - boolean isOnThread(); - - void sleep(long ms) throws InterruptedException; - - void start(Runnable run); - - void stop(); - - void wait(Object object) throws InterruptedException; - - void notify(Object object); - } } diff --git a/core/src/io/anuke/mindustry/io/SaveIO.java b/core/src/io/anuke/mindustry/io/SaveIO.java index 51120ce987..0c24f2357d 100644 --- a/core/src/io/anuke/mindustry/io/SaveIO.java +++ b/core/src/io/anuke/mindustry/io/SaveIO.java @@ -165,6 +165,7 @@ public class SaveIO{ stream.close(); }catch(Exception e){ + content.setTemporaryMapper(null); throw new RuntimeException(e); } } diff --git a/desktop/src/io/anuke/mindustry/desktop/DesktopPlatform.java b/desktop/src/io/anuke/mindustry/desktop/DesktopPlatform.java index b942d7b1a5..dd6f09a967 100644 --- a/desktop/src/io/anuke/mindustry/desktop/DesktopPlatform.java +++ b/desktop/src/io/anuke/mindustry/desktop/DesktopPlatform.java @@ -6,11 +6,9 @@ import club.minnced.discord.rpc.DiscordRichPresence; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Base64Coder; -import io.anuke.kryonet.DefaultThreadImpl; import io.anuke.mindustry.Vars; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.Platform; -import io.anuke.mindustry.core.ThreadHandler.ThreadProvider; import io.anuke.mindustry.game.GameMode; import io.anuke.mindustry.net.Net; import io.anuke.mindustry.ui.dialogs.FileChooser; @@ -112,11 +110,6 @@ public class DesktopPlatform extends Platform{ if(useDiscord) DiscordRPC.INSTANCE.Discord_Shutdown(); } - @Override - public ThreadProvider getThreadProvider(){ - return new DefaultThreadImpl(); - } - @Override public String getUUID(){ try{ diff --git a/ios/src/io/anuke/mindustry/IOSLauncher.java b/ios/src/io/anuke/mindustry/IOSLauncher.java index afc17656a4..576a84a96f 100644 --- a/ios/src/io/anuke/mindustry/IOSLauncher.java +++ b/ios/src/io/anuke/mindustry/IOSLauncher.java @@ -4,13 +4,11 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.backends.iosrobovm.IOSApplication; import com.badlogic.gdx.backends.iosrobovm.IOSApplicationConfiguration; import com.badlogic.gdx.files.FileHandle; -import io.anuke.kryonet.DefaultThreadImpl; import io.anuke.kryonet.KryoClient; import io.anuke.kryonet.KryoServer; import io.anuke.mindustry.core.Platform; -import io.anuke.mindustry.core.ThreadHandler; -import io.anuke.mindustry.io.SaveIO; import io.anuke.mindustry.game.Saves.SaveSlot; +import io.anuke.mindustry.io.SaveIO; import io.anuke.mindustry.net.Net; import io.anuke.ucore.scene.ui.TextField; import io.anuke.ucore.scene.ui.layout.Unit; @@ -73,11 +71,6 @@ public class IOSLauncher extends IOSApplication.Delegate { return locale.getDisplayName(locale); } - @Override - public ThreadHandler.ThreadProvider getThreadProvider() { - return new DefaultThreadImpl(); - } - @Override public void shareFile(FileHandle file){ FileHandle to = Gdx.files.absolute(getDocumentsDirectory()).child(file.name()); diff --git a/kryonet/src/io/anuke/kryonet/DefaultThreadImpl.java b/kryonet/src/io/anuke/kryonet/DefaultThreadImpl.java deleted file mode 100644 index 9a50a4f51e..0000000000 --- a/kryonet/src/io/anuke/kryonet/DefaultThreadImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -package io.anuke.kryonet; - -import io.anuke.mindustry.core.ThreadHandler.ThreadProvider; -import io.anuke.ucore.util.Threads; -import io.anuke.ucore.util.Threads.ThreadInfoProvider; -import io.anuke.ucore.util.Log; - -public class DefaultThreadImpl implements ThreadProvider, ThreadInfoProvider{ - private Thread thread; - - public DefaultThreadImpl(){ - Threads.setThreadInfoProvider(this); - } - - @Override - public boolean isOnLogicThread(){ - return thread == null || isOnThread(); - } - - @Override - public boolean isOnGraphicsThread(){ - return thread == null || !isOnThread(); - } - - @Override - public boolean isOnThread() { - return Thread.currentThread() == thread; - } - - @Override - public void sleep(long ms) throws InterruptedException{ - Thread.sleep(ms); - } - - @Override - public void start(Runnable run) { - if(thread != null){ - thread.interrupt(); - thread = null; - } - - thread = new Thread(run); - thread.setDaemon(true); - thread.setName("Update Thread"); - thread.start(); - Log.info("Starting logic thread."); - } - - @Override - public void stop() { - if(thread != null){ - thread.interrupt(); - thread = null; - } - } - - @Override - public void wait(Object object) throws InterruptedException{ - object.wait(); - } - - @Override - public void notify(Object object) { - object.notify(); - } - -}