Implemented toggling of multithreading
This commit is contained in:
@@ -9,8 +9,10 @@ import android.os.Bundle;
|
||||
import android.telephony.TelephonyManager;
|
||||
import com.badlogic.gdx.backends.android.AndroidApplication;
|
||||
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
|
||||
import io.anuke.kryonet.DefaultThreadImpl;
|
||||
import io.anuke.kryonet.KryoClient;
|
||||
import io.anuke.kryonet.KryoServer;
|
||||
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.scene.ui.TextField;
|
||||
@@ -85,6 +87,11 @@ public class AndroidLauncher extends AndroidApplication{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreadProvider getThreadProvider() {
|
||||
return new DefaultThreadImpl();
|
||||
}
|
||||
};
|
||||
|
||||
if(doubleScaleTablets && isTablet(this.getContext())){
|
||||
|
||||
@@ -217,6 +217,7 @@ setting.sensitivity.name=Controller Sensitivity
|
||||
setting.saveinterval.name=Autosave Interval
|
||||
setting.seconds={0} Seconds
|
||||
setting.fullscreen.name=Fullscreen
|
||||
setting.multithread.name=Multithreading [scarlet](unstable!)
|
||||
setting.fps.name=Show FPS
|
||||
setting.vsync.name=VSync
|
||||
setting.lasers.name=Show Power Lasers
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
package io.anuke.mindustry;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.utils.TimeUtils;
|
||||
import io.anuke.mindustry.core.*;
|
||||
import io.anuke.mindustry.io.BlockLoader;
|
||||
import io.anuke.mindustry.io.BundleLoader;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.modules.ModuleCore;
|
||||
import io.anuke.ucore.util.Log;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Mindustry extends ModuleCore {
|
||||
boolean multithread = true;
|
||||
Thread thread;
|
||||
float delta = 1f;
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
@@ -25,10 +19,7 @@ public class Mindustry extends ModuleCore {
|
||||
BundleLoader.load();
|
||||
BlockLoader.load();
|
||||
|
||||
logic = new Logic();
|
||||
|
||||
if(!multithread) module(logic);
|
||||
|
||||
module(logic = new Logic());
|
||||
module(world = new World());
|
||||
module(control = new Control());
|
||||
module(renderer = new Renderer());
|
||||
@@ -36,49 +27,12 @@ public class Mindustry extends ModuleCore {
|
||||
module(netServer = new NetServer());
|
||||
module(netClient = new NetClient());
|
||||
module(netCommon = new NetCommon());
|
||||
|
||||
Timers.setDeltaProvider(() ->
|
||||
Math.min(Thread.currentThread() == thread ? delta : Gdx.graphics.getDeltaTime()*60f, 20f)
|
||||
);
|
||||
|
||||
if(multithread) {
|
||||
|
||||
logic.init();
|
||||
|
||||
thread = new Thread(() -> {
|
||||
try {
|
||||
while (true) {
|
||||
long time = TimeUtils.millis();
|
||||
logic.update();
|
||||
long elapsed = TimeUtils.timeSinceMillis(time);
|
||||
long target = (long) (1000 / 60f);
|
||||
|
||||
delta = Math.max(elapsed, target) / 1000f * 60f;
|
||||
|
||||
if (elapsed < target) {
|
||||
Thread.sleep(target - elapsed);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Gdx.app.postRunnable(() -> {
|
||||
throw new RuntimeException(ex);
|
||||
});
|
||||
}
|
||||
});
|
||||
thread.setDaemon(true);
|
||||
thread.setName("Update Thread");
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(){
|
||||
super.render();
|
||||
|
||||
try {
|
||||
//Thread.sleep(40);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
threads.handleRender();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.effect.Shield;
|
||||
import io.anuke.mindustry.entities.enemies.Enemy;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.net.ClientDebug;
|
||||
import io.anuke.mindustry.net.ServerDebug;
|
||||
import io.anuke.ucore.UCore;
|
||||
@@ -112,6 +113,7 @@ public class Vars{
|
||||
public static final int webPort = 6568;
|
||||
|
||||
public static final GameState state = new GameState();
|
||||
public static final ThreadHandler threads = new ThreadHandler(Platform.instance.getThreadProvider());
|
||||
|
||||
public static final ServerDebug serverDebug = new ServerDebug();
|
||||
public static final ClientDebug clientDebug = new ClientDebug();
|
||||
|
||||
@@ -268,6 +268,13 @@ public class Control extends Module{
|
||||
Entities.collisions().setCollider(tilesize, world::solid);
|
||||
|
||||
Platform.instance.updateRPC();
|
||||
|
||||
//TODO remove
|
||||
/*
|
||||
Timers.runTask(2, () -> {
|
||||
state.set(State.playing);
|
||||
SaveIO.loadFromSlot(0);
|
||||
});*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.anuke.mindustry.core;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
@@ -35,10 +34,6 @@ import static io.anuke.mindustry.Vars.*;
|
||||
public class Logic extends Module {
|
||||
private final Array<EnemySpawn> spawns = WaveCreator.getSpawns();
|
||||
|
||||
public Logic(){
|
||||
Timers.setDeltaProvider(() -> Math.min(Gdx.graphics.getDeltaTime()*60f, 60));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
Entities.initPhysics();
|
||||
@@ -111,6 +106,7 @@ public class Logic extends Module {
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
|
||||
if(!state.is(State.paused) || Net.active()){
|
||||
Timers.update();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package io.anuke.mindustry.core;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.utils.TimeUtils;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.util.Log;
|
||||
|
||||
import static io.anuke.mindustry.Vars.logic;
|
||||
|
||||
public class ThreadHandler {
|
||||
private final ThreadProvider impl;
|
||||
private final Object lock = new Object();
|
||||
private float delta = 1f;
|
||||
private boolean finished;
|
||||
private boolean enabled;
|
||||
|
||||
public ThreadHandler(ThreadProvider impl){
|
||||
this.impl = impl;
|
||||
|
||||
Timers.setDeltaProvider(() -> impl.isOnThread() ? delta : Gdx.graphics.getDeltaTime()*60f);
|
||||
}
|
||||
|
||||
public void handleRender(){
|
||||
synchronized(lock) {
|
||||
finished = true;
|
||||
lock.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled){
|
||||
if(enabled){
|
||||
logic.doUpdate = false;
|
||||
Timers.runTask(2f, () -> impl.start(this::runLogic));
|
||||
}else{
|
||||
impl.stop();
|
||||
Timers.runTask(2f, () -> logic.doUpdate = true);
|
||||
}
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isEnabled(){
|
||||
return enabled;
|
||||
}
|
||||
|
||||
private void runLogic(){
|
||||
try {
|
||||
while (true) {
|
||||
long time = TimeUtils.millis();
|
||||
logic.update();
|
||||
|
||||
long elapsed = TimeUtils.timeSinceMillis(time);
|
||||
long target = (long) (1000 / 60f);
|
||||
|
||||
delta = Math.max(elapsed, target) / 1000f * 60f;
|
||||
|
||||
if (elapsed < target) {
|
||||
impl.sleep(target - elapsed);
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
while(!finished) {
|
||||
lock.wait();
|
||||
}
|
||||
finished = false;
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
Log.info("Stopping logic thread.");
|
||||
} catch (Exception ex) {
|
||||
Gdx.app.postRunnable(() -> {
|
||||
throw new RuntimeException(ex);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public interface ThreadProvider {
|
||||
boolean isOnThread();
|
||||
void sleep(long ms) throws InterruptedException;
|
||||
void start(Runnable run);
|
||||
void stop();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.anuke.mindustry.io;
|
||||
|
||||
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
|
||||
import io.anuke.ucore.scene.ui.TextField;
|
||||
|
||||
import java.util.Date;
|
||||
@@ -27,4 +28,27 @@ public abstract class Platform {
|
||||
return true;
|
||||
}
|
||||
public boolean isDebug(){return false;}
|
||||
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() {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +113,14 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
game.sliderPref("sensitivity", 100, 10, 300, i -> i + "%");
|
||||
game.sliderPref("saveinterval", 90, 10, 5*120, i -> Bundles.format("setting.seconds", i));
|
||||
|
||||
if(!gwt){
|
||||
graphics.checkPref("multithread", false, threads::setEnabled);
|
||||
|
||||
if(Settings.getBool("multithread")){
|
||||
threads.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
if(!android && !gwt) {
|
||||
graphics.checkPref("vsync", true, b -> Gdx.graphics.setVSync(b));
|
||||
graphics.checkPref("fullscreen", false, b -> {
|
||||
@@ -128,6 +136,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode());
|
||||
}
|
||||
}
|
||||
|
||||
graphics.checkPref("fps", false);
|
||||
graphics.checkPref("lasers", true);
|
||||
graphics.checkPref("indicators", true);
|
||||
|
||||
@@ -28,6 +28,7 @@ public class Conveyor extends Block{
|
||||
private static final float itemSpace = 0.135f;
|
||||
private static final float offsetScl = 128f*3f;
|
||||
private static final float itemSize = 4f;
|
||||
private static final float minmove = 1f / (Short.MAX_VALUE - 2);
|
||||
|
||||
private final Translator tr1 = new Translator();
|
||||
private final Translator tr2 = new Translator();
|
||||
@@ -57,7 +58,7 @@ public class Conveyor extends Block{
|
||||
byte rotation = tile.getRotation();
|
||||
|
||||
Draw.rect(name() +
|
||||
(Timers.time() % ((20 / 100f) / speed) < (10 / 100f) / speed && acceptItem(Item.stone, tile, null) ? "" : "move"),
|
||||
(Timers.time() % ((20 / 100f) / speed) < (10 / 100f) / speed && acceptItem(Item.stone, tile, null) ? "" : "move"),
|
||||
tile.worldx(), tile.worldy(), rotation * 90);
|
||||
}
|
||||
|
||||
@@ -67,7 +68,7 @@ public class Conveyor extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawLayer(Tile tile){
|
||||
public synchronized void drawLayer(Tile tile){
|
||||
ConveyorEntity entity = tile.entity();
|
||||
|
||||
byte rotation = tile.getRotation();
|
||||
@@ -87,7 +88,7 @@ public class Conveyor extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Tile tile){
|
||||
public synchronized void update(Tile tile){
|
||||
|
||||
ConveyorEntity entity = tile.entity();
|
||||
entity.minitem = 1f;
|
||||
@@ -107,13 +108,11 @@ public class Conveyor extends Block{
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean canmove = i == entity.convey.size - 1 ||
|
||||
!(pos2.set(entity.convey.get(i + 1)).y - pos.y < itemSpace * Math.max(Timers.delta(), 1f));
|
||||
float nextpos = (i == entity.convey.size - 1 ? 100f : pos2.set(entity.convey.get(i + 1)).y) - itemSpace;
|
||||
float maxmove = Math.min(nextpos - pos.y, speed * Timers.delta());
|
||||
|
||||
float minmove = 1f / (Short.MAX_VALUE - 2);
|
||||
|
||||
if(canmove){
|
||||
pos.y += Math.max(speed * Timers.delta(), minmove); //TODO fix precision issues when at high FPS?
|
||||
if(maxmove > minmove){
|
||||
pos.y += maxmove;
|
||||
pos.x = Mathf.lerpDelta(pos.x, 0, 0.06f);
|
||||
}else{
|
||||
pos.x = Mathf.lerpDelta(pos.x, pos.seed/offsetScl, 0.1f);
|
||||
@@ -224,25 +223,25 @@ public class Conveyor extends Block{
|
||||
private static void sort(long[] elements, int length){
|
||||
List<Long> wrapper = new AbstractList<Long>() {
|
||||
|
||||
@Override
|
||||
public Long get(int index) {
|
||||
return elements[index];
|
||||
}
|
||||
@Override
|
||||
public Long get(int index) {
|
||||
return elements[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return length;
|
||||
}
|
||||
@Override
|
||||
public int size() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long set(int index, Long element) {
|
||||
long v = elements[index];
|
||||
elements[index] = element;
|
||||
return v;
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public Long set(int index, Long element) {
|
||||
long v = elements[index];
|
||||
elements[index] = element;
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
Collections.sort(wrapper, Conveyor::compareItems);
|
||||
Collections.sort(wrapper, Conveyor::compareItems);
|
||||
}
|
||||
|
||||
private static int compareItems(Long a, Long b){
|
||||
|
||||
@@ -3,7 +3,9 @@ package io.anuke.mindustry.desktop;
|
||||
import club.minnced.discord.rpc.DiscordEventHandlers;
|
||||
import club.minnced.discord.rpc.DiscordRPC;
|
||||
import club.minnced.discord.rpc.DiscordRichPresence;
|
||||
import io.anuke.kryonet.DefaultThreadImpl;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.util.Strings;
|
||||
@@ -85,4 +87,9 @@ public class DesktopPlatform extends Platform {
|
||||
public boolean isDebug() {
|
||||
return args.length > 0 && args[0].equalsIgnoreCase("-debug");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreadProvider getThreadProvider() {
|
||||
return new DefaultThreadImpl();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package io.anuke.kryonet;
|
||||
|
||||
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
|
||||
import io.anuke.ucore.util.Log;
|
||||
|
||||
public class DefaultThreadImpl implements ThreadProvider {
|
||||
private Thread thread;
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user