New team system / Prototype dedicated PvP gamemode
This commit is contained in:
@@ -1,17 +1,14 @@
|
||||
package io.anuke.mindustry.ai;
|
||||
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Bits;
|
||||
import com.badlogic.gdx.utils.IntMap;
|
||||
import com.badlogic.gdx.utils.ObjectMap;
|
||||
import com.badlogic.gdx.utils.ObjectSet;
|
||||
import com.badlogic.gdx.utils.*;
|
||||
import io.anuke.mindustry.content.Items;
|
||||
import io.anuke.mindustry.content.blocks.Blocks;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.game.EventType.TileChangeEvent;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.TeamInfo.TeamData;
|
||||
import io.anuke.mindustry.game.Teams.TeamData;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.meta.BlockFlag;
|
||||
@@ -21,66 +18,43 @@ import io.anuke.ucore.function.Predicate;
|
||||
import io.anuke.ucore.util.EnumSet;
|
||||
import io.anuke.ucore.util.Geometry;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.ucore.util.ThreadArray;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
//TODO consider using quadtrees for finding specific types of blocks within an area
|
||||
//TODO maybe use Arrays instead of ObjectSets?
|
||||
|
||||
/**
|
||||
* Class used for indexing special target blocks for AI.
|
||||
*/
|
||||
/**Class used for indexing special target blocks for AI.*/
|
||||
public class BlockIndexer{
|
||||
/**
|
||||
* Size of one ore quadrant.
|
||||
*/
|
||||
/**Size of one ore quadrant.*/
|
||||
private final static int oreQuadrantSize = 20;
|
||||
/**
|
||||
* Size of one structure quadrant.
|
||||
*/
|
||||
/**Size of one structure quadrant.*/
|
||||
private final static int structQuadrantSize = 12;
|
||||
|
||||
/**
|
||||
* Set of all ores that are being scanned.
|
||||
*/
|
||||
/**Set of all ores that are being scanned.*/
|
||||
private final ObjectSet<Item> scanOres = ObjectSet.with(Items.copper, Items.coal, Items.lead, Items.thorium, Items.titanium);
|
||||
private final ObjectSet<Item> itemSet = new ObjectSet<>();
|
||||
/**
|
||||
* Stores all ore quadtrants on the map.
|
||||
*/
|
||||
/**Stores all ore quadtrants on the map.*/
|
||||
private ObjectMap<Item, ObjectSet<Tile>> ores;
|
||||
/**
|
||||
* Tags all quadrants.
|
||||
*/
|
||||
/**Tags all quadrants.*/
|
||||
private Bits[] structQuadrants;
|
||||
|
||||
/**
|
||||
* Maps teams to a map of flagged tiles by type.
|
||||
*/
|
||||
private ObjectMap<BlockFlag, ObjectSet<Tile>> enemyMap = new ObjectMap<>();
|
||||
/**
|
||||
* Maps teams to a map of flagged tiles by type.
|
||||
*/
|
||||
private ObjectMap<BlockFlag, ObjectSet<Tile>> allyMap = new ObjectMap<>();
|
||||
/**
|
||||
* Empty map for invalid teams.
|
||||
*/
|
||||
private ObjectMap<BlockFlag, ObjectSet<Tile>> emptyMap = new ObjectMap<>();
|
||||
/**
|
||||
* Maps tile positions to their last known tile index data.
|
||||
*/
|
||||
/**Maps teams to a map of flagged tiles by type.*/
|
||||
private ObjectSet<Tile>[][] flagMap = new ObjectSet[Team.all.length][BlockFlag.all.length];
|
||||
/**Maps tile positions to their last known tile index data.*/
|
||||
private IntMap<TileIndex> typeMap = new IntMap<>();
|
||||
/**
|
||||
* Empty array used for returning.
|
||||
*/
|
||||
private ObjectSet<Tile> emptyArray = new ObjectSet<>();
|
||||
/**Empty set used for returning.*/
|
||||
private ObjectSet<Tile> emptySet = new ObjectSet<>();
|
||||
/**Array used for returning and reusing.*/
|
||||
private Array<Tile> returnArray = new ThreadArray<>();
|
||||
|
||||
public BlockIndexer(){
|
||||
Events.on(TileChangeEvent.class, tile -> {
|
||||
if(typeMap.get(tile.packedPosition()) != null){
|
||||
TileIndex index = typeMap.get(tile.packedPosition());
|
||||
for(BlockFlag flag : index.flags){
|
||||
getMap(index.team).get(flag).remove(tile);
|
||||
getFlagged(index.team)[flag.ordinal()].remove(tile);
|
||||
}
|
||||
}
|
||||
process(tile);
|
||||
@@ -88,8 +62,12 @@ public class BlockIndexer{
|
||||
});
|
||||
|
||||
Events.on(WorldLoadEvent.class, () -> {
|
||||
enemyMap.clear();
|
||||
allyMap.clear();
|
||||
flagMap = new ObjectSet[Team.all.length][BlockFlag.all.length];
|
||||
for(int i = 0; i < flagMap.length; i++){
|
||||
for(int j = 0; j < BlockFlag.all.length; j++){
|
||||
flagMap[i][j] = new ObjectSet<>();
|
||||
}
|
||||
}
|
||||
typeMap.clear();
|
||||
ores = null;
|
||||
|
||||
@@ -115,18 +93,26 @@ public class BlockIndexer{
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all allied blocks with a flag.
|
||||
*/
|
||||
public ObjectSet<Tile> getAllied(Team team, BlockFlag type){
|
||||
return state.teams.has(team) ? (state.teams.get(team).ally ? allyMap : enemyMap).get(type, emptyArray) : emptyArray;
|
||||
private ObjectSet<Tile>[] getFlagged(Team team){
|
||||
return flagMap[team.ordinal()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all enemy blocks with a flag.
|
||||
*/
|
||||
public ObjectSet<Tile> getEnemy(Team team, BlockFlag type){
|
||||
return (!state.teams.get(team).ally ? allyMap : enemyMap).get(type, emptyArray);
|
||||
/**Get all allied blocks with a flag.*/
|
||||
public ObjectSet<Tile> getAllied(Team team, BlockFlag type){
|
||||
return flagMap[team.ordinal()][type.ordinal()];
|
||||
}
|
||||
|
||||
/**Get all enemy blocks with a flag.*/
|
||||
public Array<Tile> getEnemy(Team team, BlockFlag type){
|
||||
returnArray.clear();
|
||||
for(Team enemy : state.teams.enemiesOf(team)){
|
||||
if(state.teams.isActive(enemy)){
|
||||
for(Tile tile : getFlagged(enemy)[type.ordinal()]){
|
||||
returnArray.add(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
public TileEntity findTile(Team team, float x, float y, float range, Predicate<Tile> pred){
|
||||
@@ -166,7 +152,7 @@ public class BlockIndexer{
|
||||
* Only specific ore types are scanned. See {@link #scanOres}.
|
||||
*/
|
||||
public ObjectSet<Tile> getOrePositions(Item item){
|
||||
return ores.get(item, emptyArray);
|
||||
return ores.get(item, emptySet);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,19 +178,15 @@ public class BlockIndexer{
|
||||
private void process(Tile tile){
|
||||
if(tile.block().flags != null &&
|
||||
tile.getTeam() != Team.none){
|
||||
ObjectMap<BlockFlag, ObjectSet<Tile>> map = getMap(tile.getTeam());
|
||||
ObjectSet<Tile>[] map = getFlagged(tile.getTeam());
|
||||
|
||||
for(BlockFlag flag : tile.block().flags){
|
||||
|
||||
ObjectSet<Tile> arr = map.get(flag);
|
||||
if(arr == null){
|
||||
arr = new ObjectSet<>();
|
||||
map.put(flag, arr);
|
||||
}
|
||||
ObjectSet<Tile> arr = map[flag.ordinal()];
|
||||
|
||||
arr.add(tile);
|
||||
|
||||
map.put(flag, arr);
|
||||
map[flag.ordinal()] = arr;
|
||||
}
|
||||
typeMap.put(tile.packedPosition(), new TileIndex(tile.block().flags, tile.getTeam()));
|
||||
}
|
||||
@@ -247,7 +229,8 @@ public class BlockIndexer{
|
||||
int quadrantY = tile.y / structQuadrantSize;
|
||||
int index = quadrantX + quadrantY * quadWidth();
|
||||
|
||||
for(TeamData data : state.teams.getTeams()){
|
||||
for(Team team : Team.all){
|
||||
TeamData data = state.teams.get(team);
|
||||
|
||||
//fast-set this quadrant to 'occupied' if the tile just placed is already of this team
|
||||
if(tile.getTeam() == data.team && tile.entity != null){
|
||||
@@ -284,11 +267,6 @@ public class BlockIndexer{
|
||||
return Mathf.ceil(world.height() / (float) structQuadrantSize);
|
||||
}
|
||||
|
||||
private ObjectMap<BlockFlag, ObjectSet<Tile>> getMap(Team team){
|
||||
if(!state.teams.has(team)) return emptyMap;
|
||||
return state.teams.get(team).ally ? allyMap : enemyMap;
|
||||
}
|
||||
|
||||
private void scanOres(){
|
||||
ores = new ObjectMap<>();
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package io.anuke.mindustry.ai;
|
||||
|
||||
import com.badlogic.gdx.math.GridPoint2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.IntArray;
|
||||
import com.badlogic.gdx.utils.ObjectSet;
|
||||
import com.badlogic.gdx.utils.ObjectSet.ObjectSetIterator;
|
||||
import com.badlogic.gdx.utils.Queue;
|
||||
import com.badlogic.gdx.utils.TimeUtils;
|
||||
import io.anuke.mindustry.game.EventType.TileChangeEvent;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.TeamInfo.TeamData;
|
||||
import io.anuke.mindustry.game.Teams.TeamData;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.meta.BlockFlag;
|
||||
@@ -30,8 +29,9 @@ public class Pathfinder{
|
||||
Events.on(TileChangeEvent.class, tile -> {
|
||||
if(Net.client()) return;
|
||||
|
||||
for(TeamData data : state.teams.getTeams()){
|
||||
if(data.team != tile.getTeam() && paths[data.team.ordinal()].weights[tile.x][tile.y] >= Float.MAX_VALUE){
|
||||
for(Team team : Team.all){
|
||||
TeamData data = state.teams.get(team);
|
||||
if(state.teams.isActive(team) && data.team != tile.getTeam() && paths[data.team.ordinal()].weights[tile.x][tile.y] >= Float.MAX_VALUE){
|
||||
update(tile, data.team);
|
||||
}
|
||||
}
|
||||
@@ -43,10 +43,10 @@ public class Pathfinder{
|
||||
public void update(){
|
||||
if(Net.client()) return;
|
||||
|
||||
ObjectSetIterator<TeamData> iterator = new ObjectSetIterator<>(state.teams.getTeams());
|
||||
|
||||
for(TeamData team : iterator){
|
||||
updateFrontier(team.team, maxUpdate);
|
||||
for(Team team : Team.all){
|
||||
if(state.teams.isActive(team)){
|
||||
updateFrontier(team, maxUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ public class Pathfinder{
|
||||
|
||||
path.lastSearchTime = TimeUtils.millis();
|
||||
|
||||
ObjectSet<Tile> set = world.indexer().getEnemy(team, BlockFlag.target);
|
||||
Array<Tile> set = world.indexer().getEnemy(team, BlockFlag.target);
|
||||
for(Tile other : set){
|
||||
path.weights[other.x][other.y] = 0;
|
||||
path.searches[other.x][other.y] = path.search;
|
||||
@@ -173,11 +173,13 @@ public class Pathfinder{
|
||||
paths = new PathData[Team.all.length];
|
||||
blocked.clear();
|
||||
|
||||
for(TeamData data : state.teams.getTeams()){
|
||||
for(Team team : Team.all){
|
||||
PathData path = new PathData();
|
||||
paths[data.team.ordinal()] = path;
|
||||
paths[team.ordinal()] = path;
|
||||
|
||||
createFor(data.team);
|
||||
if(state.teams.isActive(team)){
|
||||
createFor(team);
|
||||
}
|
||||
}
|
||||
|
||||
state.spawner.checkAllQuadrants();
|
||||
|
||||
Reference in New Issue
Block a user