Integrated thread implementation / Crash fix
This commit is contained in:
@@ -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{
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
@@ -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(){}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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{
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user