New team system / Prototype dedicated PvP gamemode

This commit is contained in:
Anuken
2018-08-20 23:45:27 -04:00
parent 7a5e61fd2e
commit 2e958d8d8f
25 changed files with 255 additions and 312 deletions
@@ -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<>();
+15 -13
View File
@@ -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();