Fixes to many multithreading crashes and freezes

This commit is contained in:
Anuken
2018-02-13 18:19:33 -05:00
parent 6b42525f8a
commit c03619c5de
12 changed files with 87 additions and 23 deletions

View File

@@ -24,7 +24,7 @@ allprojects {
appName = 'Mindustry' appName = 'Mindustry'
gdxVersion = '1.9.8' gdxVersion = '1.9.8'
aiVersion = '1.8.1' aiVersion = '1.8.1'
uCoreVersion = '91b310b' uCoreVersion = '1deab5e'
getVersionString = { getVersionString = {
String buildVersion = getBuildVersion() String buildVersion = getBuildVersion()

View File

@@ -1,7 +1,7 @@
#Autogenerated file. Do not modify. #Autogenerated file. Do not modify.
#Tue Feb 13 17:19:41 EST 2018 #Tue Feb 13 18:19:15 EST 2018
version=beta version=beta
androidBuildCode=183 androidBuildCode=190
name=Mindustry name=Mindustry
code=3.3 code=3.3
build=custom build build=custom build

View File

@@ -227,7 +227,7 @@ public class NetServer extends Module{
if(timer.get(timerEntitySync, serverSyncTime)){ if(timer.get(timerEntitySync, serverSyncTime)){
//scan through all groups with syncable entities //scan through all groups with syncable entities
for(EntityGroup<?> group : Entities.getAllGroups()) { for(EntityGroup<?> group : Entities.getAllGroups()) {
if(group.size() == 0 || !(group.all().first() instanceof SyncEntity)) continue; if(group.size() == 0 || !(group.all().iterator().next() instanceof SyncEntity)) continue;
//get write size for one entity (adding 4, as you need to write the ID as well) //get write size for one entity (adding 4, as you need to write the ID as well)
int writesize = SyncEntity.getWriteSize((Class<? extends SyncEntity>)group.getType()) + 4; int writesize = SyncEntity.getWriteSize((Class<? extends SyncEntity>)group.getType()) + 4;

View File

@@ -241,16 +241,16 @@ public class Renderer extends RendererModule{
Mathf.round(camera.position.y - ch/2, tilesize), Mathf.round(camera.position.y - ch/2, tilesize),
(cw - vw) /2, (cw - vw) /2,
ch + tilesize, ch + tilesize,
0, ch / tilesize + 1, 0, 0,
((cw - vw) / 2 / tilesize), 0); ((cw - vw) / 2 / tilesize), -ch / tilesize + 1);
batch.draw(background, batch.draw(background,
camera.position.x - vw/2, camera.position.x - vw/2,
Mathf.round(camera.position.y - ch/2, tilesize), Mathf.round(camera.position.y - ch/2, tilesize),
-(cw - vw) /2, -(cw - vw) /2,
ch + tilesize, ch + tilesize,
0, ch / tilesize + 1, 0, 0,
-((cw - vw) / 2 / tilesize), 0); -((cw - vw) / 2 / tilesize), -ch / tilesize + 1);
} }
} }
@@ -539,7 +539,7 @@ public class Renderer extends RendererModule{
} }
public void clampScale(){ public void clampScale(){
targetscale = Mathf.clamp(targetscale, Math.round(Unit.dp.scl(1)), Math.round(Unit.dp.scl((5)))); targetscale = Mathf.clamp(targetscale, Math.round(Unit.dp.scl(2)), Math.round(Unit.dp.scl((5))));
} }
} }

View File

@@ -4,6 +4,10 @@ import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.TimeUtils; import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.ucore.core.Timers; import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.EntityGroup.ArrayContainer;
import io.anuke.ucore.util.Log; import io.anuke.ucore.util.Log;
import static io.anuke.mindustry.Vars.logic; import static io.anuke.mindustry.Vars.logic;
@@ -57,6 +61,9 @@ public class ThreadHandler {
public void setEnabled(boolean enabled){ public void setEnabled(boolean enabled){
if(enabled){ if(enabled){
logic.doUpdate = false; logic.doUpdate = false;
for(EntityGroup<?> group : Entities.getAllGroups()){
impl.switchContainer(group);
}
Timers.runTask(2f, () -> { Timers.runTask(2f, () -> {
impl.start(this::runLogic); impl.start(this::runLogic);
this.enabled = true; this.enabled = true;
@@ -64,6 +71,9 @@ public class ThreadHandler {
}else{ }else{
this.enabled = false; this.enabled = false;
impl.stop(); impl.stop();
for(EntityGroup<?> group : Entities.getAllGroups()){
group.setContainer(new ArrayContainer<>());
}
Timers.runTask(2f, () -> { Timers.runTask(2f, () -> {
logic.doUpdate = true; logic.doUpdate = true;
}); });
@@ -110,7 +120,7 @@ public class ThreadHandler {
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
Log.info("Stopping logic thread."); Log.info("Stopping logic thread.");
} catch (Exception ex) { } catch (Exception ex) {
Gdx.app.postRunnable(() -> { Timers.run(0f, () -> {
throw new RuntimeException(ex); throw new RuntimeException(ex);
}); });
} }
@@ -123,5 +133,6 @@ public class ThreadHandler {
void stop(); void stop();
void wait(Object object) throws InterruptedException; void wait(Object object) throws InterruptedException;
void notify(Object object); void notify(Object object);
<T extends Entity> void switchContainer(EntityGroup<T> group);
} }
} }

View File

@@ -1,6 +1,8 @@
package io.anuke.mindustry.io; package io.anuke.mindustry.io;
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider; import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.scene.ui.TextField; import io.anuke.ucore.scene.ui.TextField;
import java.util.Date; import java.util.Date;
@@ -36,6 +38,7 @@ public abstract class Platform {
@Override public void stop() {} @Override public void stop() {}
@Override public void notify(Object object) {} @Override public void notify(Object object) {}
@Override public void wait(Object object) {} @Override public void wait(Object object) {}
@Override public <T extends Entity> void switchContainer(EntityGroup<T> group) {}
}; };
} }
} }

View File

@@ -15,6 +15,7 @@ import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Blocks; import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.ucore.core.Core; import io.anuke.ucore.core.Core;
import io.anuke.ucore.entities.Entities; import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityGroup.EntityContainer;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
@@ -216,11 +217,11 @@ public class Save12 extends SaveFileVersion {
//--ENEMIES-- //--ENEMIES--
Array<Enemy> enemies = enemyGroup.all(); EntityContainer<Enemy> enemies = enemyGroup.all();
stream.writeInt(enemies.size); //enemy amount stream.writeInt(enemies.size()); //enemy amount
for(int i = 0; i < enemies.size; i ++){ for(int i = 0; i < enemies.size(); i ++){
Enemy enemy = enemies.get(i); Enemy enemy = enemies.get(i);
stream.writeByte(enemy.type.id); //type stream.writeByte(enemy.type.id); //type
stream.writeByte(enemy.lane); //lane stream.writeByte(enemy.lane); //lane

View File

@@ -19,6 +19,7 @@ import io.anuke.mindustry.world.blocks.types.BlockPart;
import io.anuke.mindustry.world.blocks.types.Rock; import io.anuke.mindustry.world.blocks.types.Rock;
import io.anuke.ucore.core.Core; import io.anuke.ucore.core.Core;
import io.anuke.ucore.entities.Entities; import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityGroup.EntityContainer;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
@@ -229,11 +230,11 @@ public class Save13 extends SaveFileVersion {
} }
//--ENEMIES-- //--ENEMIES--
Array<Enemy> enemies = enemyGroup.all(); EntityContainer<Enemy> enemies = enemyGroup.all();
stream.writeInt(enemies.size); //enemy amount stream.writeInt(enemies.size()); //enemy amount
for(int i = 0; i < enemies.size; i ++){ for(int i = 0; i < enemies.size(); i ++){
Enemy enemy = enemies.get(i); Enemy enemy = enemies.get(i);
stream.writeByte(enemy.type.id); //type stream.writeByte(enemy.type.id); //type
stream.writeByte(enemy.lane); //lane stream.writeByte(enemy.lane); //lane

View File

@@ -19,6 +19,7 @@ import io.anuke.mindustry.world.blocks.types.BlockPart;
import io.anuke.mindustry.world.blocks.types.Rock; import io.anuke.mindustry.world.blocks.types.Rock;
import io.anuke.ucore.core.Core; import io.anuke.ucore.core.Core;
import io.anuke.ucore.entities.Entities; import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityGroup.EntityContainer;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
@@ -255,11 +256,11 @@ public class Save14 extends SaveFileVersion{
//--ENEMIES-- //--ENEMIES--
Array<Enemy> enemies = enemyGroup.all(); EntityContainer<Enemy> enemies = enemyGroup.all();
stream.writeInt(enemies.size); //enemy amount stream.writeInt(enemies.size()); //enemy amount
for(int i = 0; i < enemies.size; i ++){ for(int i = 0; i < enemies.size(); i ++){
Enemy enemy = enemies.get(i); Enemy enemy = enemies.get(i);
stream.writeByte(enemy.type.id); //type stream.writeByte(enemy.type.id); //type
stream.writeByte(enemy.lane); //lane stream.writeByte(enemy.lane); //lane

View File

@@ -19,6 +19,7 @@ import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.mindustry.world.blocks.types.BlockPart; import io.anuke.mindustry.world.blocks.types.BlockPart;
import io.anuke.mindustry.world.blocks.types.Rock; import io.anuke.mindustry.world.blocks.types.Rock;
import io.anuke.ucore.core.Core; import io.anuke.ucore.core.Core;
import io.anuke.ucore.entities.EntityGroup.EntityContainer;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
@@ -280,11 +281,11 @@ public class Save15 extends SaveFileVersion {
//--ENEMIES-- //--ENEMIES--
Array<Enemy> enemies = enemyGroup.all(); EntityContainer<Enemy> enemies = enemyGroup.all();
stream.writeInt(enemies.size); //enemy amount stream.writeInt(enemies.size()); //enemy amount
for(int i = 0; i < enemies.size; i ++){ for(int i = 0; i < enemies.size(); i ++){
Enemy enemy = enemies.get(i); Enemy enemy = enemies.get(i);
stream.writeByte(enemy.type.id); //type stream.writeByte(enemy.type.id); //type
stream.writeByte(enemy.lane); //lane stream.writeByte(enemy.lane); //lane

View File

@@ -1,8 +1,14 @@
package io.anuke.kryonet; package io.anuke.kryonet;
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider; import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.EntityGroup.EntityContainer;
import io.anuke.ucore.util.Log; import io.anuke.ucore.util.Log;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
public class DefaultThreadImpl implements ThreadProvider { public class DefaultThreadImpl implements ThreadProvider {
private Thread thread; private Thread thread;
@@ -47,4 +53,43 @@ public class DefaultThreadImpl implements ThreadProvider {
public void notify(Object object) { public void notify(Object object) {
object.notify(); object.notify();
} }
@Override
public <T extends Entity> void switchContainer(EntityGroup<T> group) {
group.setContainer(new ConcurrentContainer<>());
}
static class ConcurrentContainer<T> implements EntityContainer<T>{
private CopyOnWriteArrayList<T> list = new CopyOnWriteArrayList<>();
@Override
public int size() {
return list.size();
}
@Override
public void add(T item) {
list.add(item);
}
@Override
public void clear() {
list.clear();
}
@Override
public void remove(T item) {
list.remove(item);
}
@Override
public T get(int index) {
return list.get(index);
}
@Override
public Iterator<T> iterator() {
return list.iterator();
}
}
} }

View File

@@ -23,6 +23,7 @@ import io.anuke.mindustry.net.Streamable;
import io.anuke.mindustry.net.Streamable.StreamBegin; import io.anuke.mindustry.net.Streamable.StreamBegin;
import io.anuke.mindustry.net.Streamable.StreamChunk; import io.anuke.mindustry.net.Streamable.StreamChunk;
import io.anuke.ucore.UCore; import io.anuke.ucore.UCore;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.util.Log; import io.anuke.ucore.util.Log;
import org.java_websocket.WebSocket; import org.java_websocket.WebSocket;
import org.java_websocket.exceptions.WebsocketNotConnectedException; import org.java_websocket.exceptions.WebsocketNotConnectedException;
@@ -296,7 +297,7 @@ public class KryoServer implements ServerProvider {
} }
private void handleException(Throwable e){ private void handleException(Throwable e){
Gdx.app.postRunnable(() -> { throw new RuntimeException(e);}); Timers.run(0f, () -> { throw new RuntimeException(e);});
} }
KryoConnection getByKryoID(int id){ KryoConnection getByKryoID(int id){