Massively improved thread safety
This commit is contained in:
@@ -27,7 +27,7 @@ allprojects {
|
|||||||
appName = 'Mindustry'
|
appName = 'Mindustry'
|
||||||
gdxVersion = '1.9.8'
|
gdxVersion = '1.9.8'
|
||||||
roboVMVersion = '2.3.0'
|
roboVMVersion = '2.3.0'
|
||||||
uCoreVersion = '03c4093f724e63069e097393991592db308728e0'
|
uCoreVersion = '89250a4ec499609329c52e7742a251b9f4c6bd5b'
|
||||||
|
|
||||||
getVersionString = {
|
getVersionString = {
|
||||||
String buildVersion = getBuildVersion()
|
String buildVersion = getBuildVersion()
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import io.anuke.mindustry.type.ItemStack;
|
|||||||
import io.anuke.mindustry.type.Recipe;
|
import io.anuke.mindustry.type.Recipe;
|
||||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||||
import io.anuke.ucore.core.*;
|
import io.anuke.ucore.core.*;
|
||||||
import io.anuke.ucore.entities.Entities;
|
|
||||||
import io.anuke.ucore.entities.EntityQuery;
|
import io.anuke.ucore.entities.EntityQuery;
|
||||||
import io.anuke.ucore.modules.Module;
|
import io.anuke.ucore.modules.Module;
|
||||||
import io.anuke.ucore.util.Atlas;
|
import io.anuke.ucore.util.Atlas;
|
||||||
@@ -382,10 +381,6 @@ public class Control extends Module{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!state.is(State.paused) || Net.active()){
|
|
||||||
Entities.update(effectGroup);
|
|
||||||
Entities.update(groundEffectGroup);
|
|
||||||
}
|
|
||||||
}else{
|
}else{
|
||||||
if(!state.is(State.paused) || Net.active()){
|
if(!state.is(State.paused) || Net.active()){
|
||||||
Timers.update();
|
Timers.update();
|
||||||
|
|||||||
@@ -147,6 +147,10 @@ public class Logic extends Module{
|
|||||||
if(!Entities.defaultGroup().isEmpty())
|
if(!Entities.defaultGroup().isEmpty())
|
||||||
throw new RuntimeException("Do not add anything to the default group!");
|
throw new RuntimeException("Do not add anything to the default group!");
|
||||||
|
|
||||||
|
if(!headless){
|
||||||
|
Entities.update(effectGroup);
|
||||||
|
Entities.update(groundEffectGroup);
|
||||||
|
}
|
||||||
|
|
||||||
for(EntityGroup group : unitGroups){
|
for(EntityGroup group : unitGroups){
|
||||||
Entities.update(group);
|
Entities.update(group);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import io.anuke.ucore.entities.EntityGroup;
|
|||||||
import io.anuke.ucore.entities.EntityQuery;
|
import io.anuke.ucore.entities.EntityQuery;
|
||||||
import io.anuke.ucore.function.Consumer;
|
import io.anuke.ucore.function.Consumer;
|
||||||
import io.anuke.ucore.function.Predicate;
|
import io.anuke.ucore.function.Predicate;
|
||||||
|
import io.anuke.ucore.util.Threads;
|
||||||
import io.anuke.ucore.util.EnumSet;
|
import io.anuke.ucore.util.EnumSet;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
@@ -20,10 +21,11 @@ import static io.anuke.mindustry.Vars.*;
|
|||||||
*/
|
*/
|
||||||
public class Units{
|
public class Units{
|
||||||
private static Rectangle rect = new Rectangle();
|
private static Rectangle rect = new Rectangle();
|
||||||
|
private static Rectangle rectGraphics = new Rectangle();
|
||||||
private static Rectangle hitrect = new Rectangle();
|
private static Rectangle hitrect = new Rectangle();
|
||||||
private static Unit result;
|
private static Unit result;
|
||||||
private static float cdist;
|
private static float cdist;
|
||||||
private static boolean boolResult;
|
private static boolean boolResult, boolResultGraphics;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates a target.
|
* Validates a target.
|
||||||
@@ -63,22 +65,43 @@ public class Units{
|
|||||||
return anyEntities(rect);
|
return anyEntities(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**Can be called from any thread.*/
|
||||||
public static boolean anyEntities(Rectangle rect){
|
public static boolean anyEntities(Rectangle rect){
|
||||||
|
if(Threads.isLogic()){
|
||||||
|
boolResult = false;
|
||||||
|
|
||||||
boolResult = false;
|
Units.getNearby(rect, unit -> {
|
||||||
|
if(boolResult) return;
|
||||||
|
if(!unit.isFlying()){
|
||||||
|
unit.getHitbox(hitrect);
|
||||||
|
|
||||||
Units.getNearby(rect, unit -> {
|
if(hitrect.overlaps(rect)){
|
||||||
if(boolResult) return;
|
boolResult = true;
|
||||||
if(!unit.isFlying()){
|
}
|
||||||
unit.getHitbox(hitrect);
|
|
||||||
|
|
||||||
if(hitrect.overlaps(rect)){
|
|
||||||
boolResult = true;
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
return boolResult;
|
return boolResult;
|
||||||
|
}else{
|
||||||
|
for(EntityGroup<? extends BaseUnit> g : unitGroups){
|
||||||
|
g.forEach(u -> {
|
||||||
|
u.getHitbox(rectGraphics);
|
||||||
|
if(rectGraphics.overlaps(rect)){
|
||||||
|
boolResultGraphics = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(boolResultGraphics) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
playerGroup.forEach(u -> {
|
||||||
|
u.getHitbox(rectGraphics);
|
||||||
|
if(rectGraphics.overlaps(rect)){
|
||||||
|
boolResultGraphics = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return boolResultGraphics;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns whether there are any entities on this tile, with the hitbox expanded.*/
|
/**Returns whether there are any entities on this tile, with the hitbox expanded.*/
|
||||||
|
|||||||
@@ -254,7 +254,6 @@ public abstract class InputHandler extends InputAdapter{
|
|||||||
&& tile.floor().drops != null && tile.floor().drops.item.hardness <= player.mech.drillPower
|
&& tile.floor().drops != null && tile.floor().drops.item.hardness <= player.mech.drillPower
|
||||||
&& !tile.floor().playerUnmineable
|
&& !tile.floor().playerUnmineable
|
||||||
&& player.inventory.canAcceptItem(tile.floor().drops.item)
|
&& player.inventory.canAcceptItem(tile.floor().drops.item)
|
||||||
&& Units.getClosestEnemy(player.getTeam(), tile.worldx(), tile.worldy(), 40f, e -> true) == null //don't being mining when an enemy is near
|
|
||||||
&& tile.block() == Blocks.air && player.distanceTo(tile.worldx(), tile.worldy()) <= Player.mineDistance;
|
&& tile.block() == Blocks.air && player.distanceTo(tile.worldx(), tile.worldy()) <= Player.mineDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,12 +329,8 @@ public abstract class InputHandler extends InputAdapter{
|
|||||||
public boolean validPlace(int x, int y, Block type, int rotation){
|
public boolean validPlace(int x, int y, Block type, int rotation){
|
||||||
for(Tile tile : state.teams.get(player.getTeam()).cores){
|
for(Tile tile : state.teams.get(player.getTeam()).cores){
|
||||||
if(tile.distanceTo(x * tilesize, y * tilesize) < coreBuildRange){
|
if(tile.distanceTo(x * tilesize, y * tilesize) < coreBuildRange){
|
||||||
//TODO terrible hack
|
return Build.validPlace(player.getTeam(), x, y, type, rotation) &&
|
||||||
//this might actually screw things up on the logic thread.
|
Vector2.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance;
|
||||||
try{
|
|
||||||
return Build.validPlace(player.getTeam(), x, y, type, rotation) &&
|
|
||||||
Vector2.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance;
|
|
||||||
}catch(Exception e){return false;}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package io.anuke.mindustry.ui.dialogs;
|
package io.anuke.mindustry.ui.dialogs;
|
||||||
|
|
||||||
import io.anuke.mindustry.entities.Player;
|
|
||||||
import io.anuke.mindustry.net.Administration.PlayerInfo;
|
import io.anuke.mindustry.net.Administration.PlayerInfo;
|
||||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||||
import io.anuke.ucore.scene.ui.layout.Table;
|
import io.anuke.ucore.scene.ui.layout.Table;
|
||||||
@@ -43,12 +42,18 @@ public class AdminsDialog extends FloatingDialog{
|
|||||||
res.addImageButton("icon-cancel", 14 * 3, () -> {
|
res.addImageButton("icon-cancel", 14 * 3, () -> {
|
||||||
ui.showConfirm("$text.confirm", "$text.confirmunadmin", () -> {
|
ui.showConfirm("$text.confirm", "$text.confirmunadmin", () -> {
|
||||||
netServer.admins.unAdminPlayer(info.id);
|
netServer.admins.unAdminPlayer(info.id);
|
||||||
|
playerGroup.forEach(player -> {
|
||||||
|
if(player.uuid.equals(info.id)){
|
||||||
|
player.isAdmin = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/*
|
||||||
for(Player player : playerGroup.all()){
|
for(Player player : playerGroup.all()){
|
||||||
if(player.con != null){
|
if(player.con != null){
|
||||||
player.isAdmin = false;
|
player.isAdmin = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
setup();
|
setup();
|
||||||
});
|
});
|
||||||
}).size(h).pad(-14f);
|
}).size(h).pad(-14f);
|
||||||
|
|||||||
@@ -66,10 +66,10 @@ public class PlayerListFragment extends Fragment{
|
|||||||
|
|
||||||
float h = 74f;
|
float h = 74f;
|
||||||
|
|
||||||
for(Player player : playerGroup.all()){
|
playerGroup.forEach(player -> {
|
||||||
NetConnection connection = gwt ? null : player.con;
|
NetConnection connection = gwt ? null : player.con;
|
||||||
|
|
||||||
if(connection == null && Net.server() && !player.isLocal) continue;
|
if(connection == null && Net.server() && !player.isLocal) return;
|
||||||
|
|
||||||
Table button = new Table("button");
|
Table button = new Table("button");
|
||||||
button.left();
|
button.left();
|
||||||
@@ -134,7 +134,7 @@ public class PlayerListFragment extends Fragment{
|
|||||||
|
|
||||||
content.add(button).padBottom(-6).width(350f).maxHeight(h + 14);
|
content.add(button).padBottom(-6).width(350f).maxHeight(h + 14);
|
||||||
content.row();
|
content.row();
|
||||||
}
|
});
|
||||||
|
|
||||||
content.marginBottom(5);
|
content.marginBottom(5);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,27 @@
|
|||||||
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.util.Threads;
|
||||||
|
import io.anuke.ucore.util.Threads.ThreadInfoProvider;
|
||||||
import io.anuke.ucore.util.Log;
|
import io.anuke.ucore.util.Log;
|
||||||
|
|
||||||
public class DefaultThreadImpl implements ThreadProvider {
|
public class DefaultThreadImpl implements ThreadProvider, ThreadInfoProvider{
|
||||||
private Thread thread;
|
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
|
@Override
|
||||||
public boolean isOnThread() {
|
public boolean isOnThread() {
|
||||||
return Thread.currentThread() == thread;
|
return Thread.currentThread() == thread;
|
||||||
|
|||||||
Reference in New Issue
Block a user