Integrated thread implementation / Crash fix

This commit is contained in:
Anuken
2018-10-30 12:58:25 -04:00
parent 5aba065413
commit c02329e4b1
10 changed files with 43 additions and 129 deletions

View File

@@ -23,7 +23,6 @@ import io.anuke.kryonet.DefaultThreadImpl;
import io.anuke.kryonet.KryoClient; import io.anuke.kryonet.KryoClient;
import io.anuke.kryonet.KryoServer; import io.anuke.kryonet.KryoServer;
import io.anuke.mindustry.core.Platform; import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
import io.anuke.mindustry.game.Saves.SaveSlot; import io.anuke.mindustry.game.Saves.SaveSlot;
import io.anuke.mindustry.io.SaveIO; import io.anuke.mindustry.io.SaveIO;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
@@ -85,11 +84,6 @@ public class AndroidLauncher extends PatchedAndroidApplication{
showDonations(); showDonations();
} }
@Override
public ThreadProvider getThreadProvider(){
return new DefaultThreadImpl();
}
@Override @Override
public String getUUID(){ public String getUUID(){
try{ try{

View File

@@ -26,7 +26,7 @@ allprojects {
appName = 'Mindustry' appName = 'Mindustry'
gdxVersion = '1.9.8' gdxVersion = '1.9.8'
roboVMVersion = '2.3.0' roboVMVersion = '2.3.0'
uCoreVersion = '53571305f7e5b31dd07377756bb46c0f2ae2ef34' uCoreVersion = 'dec41336067c013f04f0e17db3b06e24d3c11f6a'
getVersionString = { getVersionString = {
String buildVersion = getBuildVersion() String buildVersion = getBuildVersion()

View File

@@ -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; mobile = Gdx.app.getType() == ApplicationType.Android || Gdx.app.getType() == ApplicationType.iOS || testMobile;
ios = Gdx.app.getType() == ApplicationType.iOS; ios = Gdx.app.getType() == ApplicationType.iOS;

View File

@@ -210,7 +210,7 @@ public class ContentLoader{
if(id < 0) id += 256; if(id < 0) id += 256;
if(temporaryMapper != null && temporaryMapper[type.ordinal()] != null && temporaryMapper[type.ordinal()].length != 0){ 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 getByID(type, 0); //default value is always ID 0
} }
return (T)temporaryMapper[type.ordinal()][id]; return (T)temporaryMapper[type.ordinal()][id];

View File

@@ -2,7 +2,6 @@ package io.anuke.mindustry.core;
import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Base64Coder; import com.badlogic.gdx.utils.Base64Coder;
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
import io.anuke.ucore.core.Settings; import io.anuke.ucore.core.Settings;
import io.anuke.ucore.function.Consumer; import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.scene.ui.TextField; import io.anuke.ucore.scene.ui.TextField;
@@ -67,17 +66,6 @@ public abstract class Platform {
* @param filetype File extension to filter * @param filetype File extension to filter
*/ */
public void showFileChooser(String text, String content, Consumer<FileHandle> cons, boolean open, String filetype){} public void showFileChooser(String text, String content, Consumer<FileHandle> 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.*/ /**Forces the app into landscape mode. Currently Android only.*/
public void beginForceLandscape(){} public void beginForceLandscape(){}

View File

@@ -6,13 +6,15 @@ import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.ucore.core.Settings; import io.anuke.ucore.core.Settings;
import io.anuke.ucore.core.Timers; import io.anuke.ucore.core.Timers;
import io.anuke.ucore.util.Log; 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.control;
import static io.anuke.mindustry.Vars.logic; import static io.anuke.mindustry.Vars.logic;
public class ThreadHandler{ public class ThreadHandler implements ThreadInfoProvider{
private final Queue<Runnable> toRun = new Queue<>(); private final Queue<Runnable> toRun = new Queue<>();
private final ThreadProvider impl; private Thread thread, graphicsThread;
private final Object updateLock = new Object(); private final Object updateLock = new Object();
private float delta = 1f; private float delta = 1f;
private float smoothDelta = 1f; private float smoothDelta = 1f;
@@ -22,11 +24,12 @@ public class ThreadHandler{
private boolean rendered = true; private boolean rendered = true;
private long lastFrameTime; private long lastFrameTime;
public ThreadHandler(ThreadProvider impl){ public ThreadHandler(){
this.impl = impl; Threads.setThreadInfoProvider(this);
graphicsThread = Thread.currentThread();
Timers.setDeltaProvider(() -> { 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); return Math.min(Float.isNaN(result) ? 1f : result, 15f);
}); });
} }
@@ -86,7 +89,7 @@ public class ThreadHandler{
long elapsed = TimeUtils.timeSinceMillis(lastFrameTime); long elapsed = TimeUtils.timeSinceMillis(lastFrameTime);
if(elapsed < target){ if(elapsed < target){
try{ try{
impl.sleep(target - elapsed); Thread.sleep(target - elapsed);
}catch(InterruptedException e){ }catch(InterruptedException e){
e.printStackTrace(); e.printStackTrace();
} }
@@ -99,7 +102,7 @@ public class ThreadHandler{
synchronized(updateLock){ synchronized(updateLock){
rendered = true; rendered = true;
impl.notify(updateLock); Threads.notify(updateLock);
} }
} }
@@ -111,12 +114,25 @@ public class ThreadHandler{
if(enabled){ if(enabled){
logic.doUpdate = false; logic.doUpdate = false;
Timers.runTask(2f, () -> { 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; this.enabled = true;
}); });
}else{ }else{
this.enabled = false; this.enabled = false;
impl.stop(); if(thread != null){
thread.interrupt();
thread = null;
}
Timers.runTask(2f, () -> { Timers.runTask(2f, () -> {
logic.doUpdate = true; logic.doUpdate = true;
}); });
@@ -128,7 +144,17 @@ public class ThreadHandler{
} }
public boolean isOnThread(){ 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(){ private void runLogic(){
@@ -157,12 +183,12 @@ public class ThreadHandler{
long target = (long) ((1000) / 60f); long target = (long) ((1000) / 60f);
if(elapsed < target){ if(elapsed < target){
impl.sleep(target - elapsed); Thread.sleep(target - elapsed);
} }
synchronized(updateLock){ synchronized(updateLock){
while(!rendered){ while(!rendered){
impl.wait(updateLock); Threads.wait(updateLock);
} }
rendered = false; rendered = false;
} }
@@ -184,18 +210,4 @@ public class ThreadHandler{
control.setError(ex); 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);
}
} }

View File

@@ -165,6 +165,7 @@ public class SaveIO{
stream.close(); stream.close();
}catch(Exception e){ }catch(Exception e){
content.setTemporaryMapper(null);
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }

View File

@@ -6,11 +6,9 @@ import club.minnced.discord.rpc.DiscordRichPresence;
import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Base64Coder; import com.badlogic.gdx.utils.Base64Coder;
import io.anuke.kryonet.DefaultThreadImpl;
import io.anuke.mindustry.Vars; import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.core.Platform; import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
import io.anuke.mindustry.game.GameMode; import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.ui.dialogs.FileChooser; import io.anuke.mindustry.ui.dialogs.FileChooser;
@@ -112,11 +110,6 @@ public class DesktopPlatform extends Platform{
if(useDiscord) DiscordRPC.INSTANCE.Discord_Shutdown(); if(useDiscord) DiscordRPC.INSTANCE.Discord_Shutdown();
} }
@Override
public ThreadProvider getThreadProvider(){
return new DefaultThreadImpl();
}
@Override @Override
public String getUUID(){ public String getUUID(){
try{ try{

View File

@@ -4,13 +4,11 @@ import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.iosrobovm.IOSApplication; import com.badlogic.gdx.backends.iosrobovm.IOSApplication;
import com.badlogic.gdx.backends.iosrobovm.IOSApplicationConfiguration; import com.badlogic.gdx.backends.iosrobovm.IOSApplicationConfiguration;
import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.files.FileHandle;
import io.anuke.kryonet.DefaultThreadImpl;
import io.anuke.kryonet.KryoClient; import io.anuke.kryonet.KryoClient;
import io.anuke.kryonet.KryoServer; import io.anuke.kryonet.KryoServer;
import io.anuke.mindustry.core.Platform; 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.game.Saves.SaveSlot;
import io.anuke.mindustry.io.SaveIO;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.ucore.scene.ui.TextField; import io.anuke.ucore.scene.ui.TextField;
import io.anuke.ucore.scene.ui.layout.Unit; import io.anuke.ucore.scene.ui.layout.Unit;
@@ -73,11 +71,6 @@ public class IOSLauncher extends IOSApplication.Delegate {
return locale.getDisplayName(locale); return locale.getDisplayName(locale);
} }
@Override
public ThreadHandler.ThreadProvider getThreadProvider() {
return new DefaultThreadImpl();
}
@Override @Override
public void shareFile(FileHandle file){ public void shareFile(FileHandle file){
FileHandle to = Gdx.files.absolute(getDocumentsDirectory()).child(file.name()); FileHandle to = Gdx.files.absolute(getDocumentsDirectory()).child(file.name());

View File

@@ -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();
}
}