package com.massivecraft.factions.entity; import com.google.gson.reflect.TypeToken; import com.massivecraft.factions.Factions; import com.massivecraft.factions.TerritoryAccess; import com.massivecraft.massivecore.ps.PS; import com.massivecraft.massivecore.store.Entity; import java.lang.reflect.Type; import java.util.Collections; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentSkipListMap; import java.util.function.Function; import java.util.stream.Collectors; public class Board extends Entity implements BoardInterface { public static final Type MAP_TYPE = new TypeToken>() { }.getType(); // -------------------------------------------- // // META // -------------------------------------------- // public static Board get(Object oid) { return BoardColl.get().get(oid); } // -------------------------------------------- // // OVERRIDE: ENTITY // -------------------------------------------- // @Override public Board load(Board that) { this.map = that.map; return this; } @Override public boolean isDefault() { if (this.map == null) { return true; } return this.map.isEmpty(); } // -------------------------------------------- // // FIELDS // -------------------------------------------- // private ConcurrentSkipListMap map; public Map getMap() { return Collections.unmodifiableMap(this.map); } public Map getMapRaw() { return this.map; } // -------------------------------------------- // // CONSTRUCT // -------------------------------------------- // public Board() { this.map = new ConcurrentSkipListMap<>(); } public Board(Map map) { this.map = new ConcurrentSkipListMap<>(map); } // -------------------------------------------- // // OVERRIDE: BOARD // -------------------------------------------- // // GET @Override public TerritoryAccess getTerritoryAccessAt(PS ps) { if (ps == null) { throw new NullPointerException("ps"); } ps = ps.getChunkCoords(true); TerritoryAccess ret = this.map.get(ps); if (ret == null || ret.getHostFaction() == null) { ret = TerritoryAccess.valueOf(Factions.ID_NONE); } return ret; } @Override public Faction getFactionAt(PS ps) { return this.getTerritoryAccessAt(ps).getHostFaction(); } // SET @Override public void setTerritoryAccessAt(PS ps, TerritoryAccess territoryAccess) { ps = ps.getChunkCoords(true); if (territoryAccess == null || (territoryAccess.getHostFactionId().equals(Factions.ID_NONE) && territoryAccess.isDefault())) { this.map.remove(ps); } else { this.map.put(ps, territoryAccess); } this.changed(); } @Override public void setFactionAt(PS ps, Faction faction) { TerritoryAccess territoryAccess = null; if (faction != null) { territoryAccess = TerritoryAccess.valueOf(faction.getId()); } this.setTerritoryAccessAt(ps, territoryAccess); } // REMOVE @Override public void removeAt(PS ps) { this.setTerritoryAccessAt(ps, null); } @Override public void removeAll(Faction faction) { this.getChunks(faction).forEach(this::removeAt); } // CHUNKS @Override public Set getChunks(Faction faction) { return this.getChunks(faction.getId()); } @Override public Set getChunks(String factionId) { return this.map.entrySet().stream() .filter(e -> e.getValue().getHostFactionId().equals(factionId)) .map(Entry::getKey) .map(ps -> ps.withWorld(this.getId())) .collect(Collectors.toSet()); } @Override @Deprecated public Map> getFactionToChunks() { return this.getFactionToChunks(true); } @Override public Map> getFactionToChunks(boolean withWorld) { Function, PS> mapper = Entry::getKey; if (withWorld) { mapper = mapper.andThen(ps -> ps.withWorld(this.getId())); } return map.entrySet().stream().collect(Collectors.groupingBy( entry -> entry.getValue().getHostFaction(), // This specifies how to get the key Collectors.mapping(mapper, Collectors.toSet()) // This maps the entries and puts them in the collection )); } @Override public Map>> getWorldToFactionToChunks(boolean withWorld) { return Collections.singletonMap(this.getId(), this.getFactionToChunks(withWorld)); } // COUNT @Override public int getCount(Faction faction) { if (faction == null) { throw new NullPointerException("faction"); } return this.getCount(faction.getId()); } @Override public int getCount(String factionId) { if (factionId == null) { throw new NullPointerException("factionId"); } return (int) this.map.values().stream() .map(TerritoryAccess::getHostFactionId) .filter(factionId::equals) .count(); } @Override public Map getFactionToCount() { return this.map.entrySet().stream() .collect(Collectors.groupingBy( e -> e.getValue().getHostFaction(), Collectors.counting() )); } // CLAIMED @Override public boolean hasClaimed(Faction faction) { return this.hasClaimed(faction.getId()); } @Override public boolean hasClaimed(String factionId) { return this.map.values().stream() .map(TerritoryAccess::getHostFactionId) .anyMatch(factionId::equals); } // NEARBY DETECTION // Is this coord NOT completely surrounded by coords claimed by the same faction? // Simpler: Is there any nearby coord with a faction other than the faction here? @Override public boolean isBorderPs(PS ps) { ps = ps.getChunk(true); PS nearby; Faction faction = this.getFactionAt(ps); nearby = ps.withChunkX(ps.getChunkX() + 1); if (faction != this.getFactionAt(nearby)) { return true; } nearby = ps.withChunkX(ps.getChunkX() - 1); if (faction != this.getFactionAt(nearby)) { return true; } nearby = ps.withChunkZ(ps.getChunkZ() + 1); if (faction != this.getFactionAt(nearby)) { return true; } nearby = ps.withChunkZ(ps.getChunkZ() - 1); return faction != this.getFactionAt(nearby); } @Override public boolean isAnyBorderPs(Set pss) { return pss.stream().anyMatch(this::isBorderPs); } // Is this coord connected to any coord claimed by the specified faction? @Override public boolean isConnectedPs(PS ps, Faction faction) { ps = ps.getChunk(true); PS nearby; nearby = ps.withChunkX(ps.getChunkX() + 1); if (faction == this.getFactionAt(nearby)) { return true; } nearby = ps.withChunkX(ps.getChunkX() - 1); if (faction == this.getFactionAt(nearby)) { return true; } nearby = ps.withChunkZ(ps.getChunkZ() + 1); if (faction == this.getFactionAt(nearby)) { return true; } nearby = ps.withChunkZ(ps.getChunkZ() - 1); return faction == this.getFactionAt(nearby); } @Override public boolean isAnyConnectedPs(Set pss, Faction faction) { return pss.stream().anyMatch(ps -> this.isConnectedPs(ps, faction)); } }