package mcjty.rftools.blocks.teleporter;
import mcjty.lib.varia.Coordinate;
import mcjty.lib.varia.GlobalCoordinate;
import mcjty.lib.varia.Logging;
import mcjty.rftools.dimension.DimensionInformation;
import mcjty.rftools.dimension.RfToolsDimensionManager;
import mcjty.rftools.playerprops.PlayerExtendedProperties;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.server.MinecraftServer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraft.world.WorldSavedData;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.util.Constants;
import java.util.*;
public class TeleportDestinations extends WorldSavedData {
public static final String TPDESTINATIONS_NAME = "TPDestinations";
private static TeleportDestinations instance = null;
private final Map<GlobalCoordinate,TeleportDestination> destinations = new HashMap<GlobalCoordinate,TeleportDestination>();
private final Map<Integer,GlobalCoordinate> destinationById = new HashMap<Integer, GlobalCoordinate>();
private final Map<GlobalCoordinate,Integer> destinationIdByCoordinate = new HashMap<GlobalCoordinate, Integer>();
private int lastId = 0;
public TeleportDestinations(String identifier) {
super(identifier);
}
public void save(World world) {
world.mapStorage.setData(TPDESTINATIONS_NAME, this);
markDirty();
}
public static void clearInstance() {
if (instance != null) {
instance.destinations.clear();
instance.destinationById.clear();
instance.destinationIdByCoordinate.clear();
instance = null;
}
}
public void cleanupInvalid(World world) {
Set<GlobalCoordinate> keys = new HashSet<GlobalCoordinate>(destinations.keySet());
for (GlobalCoordinate key : keys) {
World transWorld = RfToolsDimensionManager.getDimensionManager(world).getWorldForDimension(key.getDimension());
boolean removed = false;
if (transWorld == null) {
Logging.log("Receiver on dimension " + key.getDimension() + " removed because world can't be loaded!");
removed = true;
} else {
Coordinate c = key.getCoordinate();
TileEntity te;
try {
te = transWorld.getTileEntity(c.getX(), c.getY(), c.getZ());
} catch (Exception e) {
te = null;
}
if (!(te instanceof MatterReceiverTileEntity)) {
Logging.log("Receiver at " + c + " on dimension " + key.getDimension() + " removed because there is no receiver there!");
removed = true;
}
}
if (removed) {
destinations.remove(key);
}
}
}
public static TeleportDestinations getDestinations(World world) {
if (world.isRemote) {
return null;
}
if (instance != null) {
return instance;
}
instance = (TeleportDestinations) world.mapStorage.loadData(TeleportDestinations.class, TPDESTINATIONS_NAME);
if (instance == null) {
instance = new TeleportDestinations(TPDESTINATIONS_NAME);
}
return instance;
}
// Server side only
public Collection<TeleportDestinationClientInfo> getValidDestinations(World worldObj, String playerName) {
PlayerExtendedProperties properties = null;
if (playerName != null) {
List list = MinecraftServer.getServer().getConfigurationManager().playerEntityList;
for (Object player : list) {
EntityPlayerMP entityplayermp = (EntityPlayerMP) player;
if (playerName.equals(entityplayermp.getDisplayName())) {
properties = PlayerExtendedProperties.getProperties(entityplayermp);
break;
}
}
}
List<TeleportDestinationClientInfo> result = new ArrayList<TeleportDestinationClientInfo>();
for (TeleportDestination destination : destinations.values()) {
TeleportDestinationClientInfo destinationClientInfo = new TeleportDestinationClientInfo(destination);
Coordinate c = destination.getCoordinate();
World world = DimensionManager.getWorld(destination.getDimension());
String dimName = null;
if (world != null) {
dimName = DimensionManager.getProvider(destination.getDimension()).getDimensionName();
}
DimensionInformation information = RfToolsDimensionManager.getDimensionManager(worldObj).getDimensionInformation(destination.getDimension());
if (information != null) {
dimName = information.getName();
}
if (dimName == null || dimName.trim().isEmpty()) {
dimName = "Id " + destination.getDimension();
} else {
dimName = dimName + " (" + destination.getDimension() + ")";
}
destinationClientInfo.setDimensionName(dimName);
if (world != null) {
TileEntity te = world.getTileEntity(c.getX(), c.getY(), c.getZ());
if (te instanceof MatterReceiverTileEntity) {
MatterReceiverTileEntity matterReceiverTileEntity = (MatterReceiverTileEntity) te;
if (playerName != null && !matterReceiverTileEntity.checkAccess(playerName)) {
// No access.
continue;
}
}
}
if (properties != null) {
destinationClientInfo.setFavorite(properties.getFavoriteDestinationsProperties().isDestinationFavorite(new GlobalCoordinate(c, destination.getDimension())));
}
result.add(destinationClientInfo);
}
Collections.sort(result);
return result;
}
/**
* Check if the teleport destination is still valid.
* @param destination
* @return
*/
public boolean isDestinationValid(TeleportDestination destination) {
GlobalCoordinate key = new GlobalCoordinate(destination.getCoordinate(), destination.getDimension());
return destinations.containsKey(key);
}
// Set an old id to a new position (after moving a receiver).
public void assignId(GlobalCoordinate key, int id) {
destinationById.put(id, key);
destinationIdByCoordinate.put(key, id);
}
public int getNewId(GlobalCoordinate key) {
if (destinationIdByCoordinate.containsKey(key)) {
return destinationIdByCoordinate.get(key);
}
lastId++;
destinationById.put(lastId, key);
destinationIdByCoordinate.put(key, lastId);
return lastId;
}
// Get the id from a coordinate.
public Integer getIdForCoordinate(GlobalCoordinate key) {
return destinationIdByCoordinate.get(key);
}
public GlobalCoordinate getCoordinateForId(int id) {
return destinationById.get(id);
}
public TeleportDestination addDestination(GlobalCoordinate key) {
if (!destinations.containsKey(key)) {
TeleportDestination teleportDestination = new TeleportDestination(key.getCoordinate(), key.getDimension());
destinations.put(key, teleportDestination);
}
return destinations.get(key);
}
public void removeDestinationsInDimension(int dimension) {
Set<GlobalCoordinate> keysToRemove = new HashSet<GlobalCoordinate>();
for (Map.Entry<GlobalCoordinate, TeleportDestination> entry : destinations.entrySet()) {
if (entry.getKey().getDimension() == dimension) {
keysToRemove.add(entry.getKey());
}
}
for (GlobalCoordinate key : keysToRemove) {
removeDestination(key.getCoordinate(), key.getDimension());
}
}
public void removeDestination(Coordinate coordinate, int dimension) {
GlobalCoordinate key = new GlobalCoordinate(coordinate, dimension);
destinations.remove(key);
Integer id = destinationIdByCoordinate.get(key);
if (id != null) {
destinationById.remove(id);
destinationIdByCoordinate.remove(key);
}
}
public TeleportDestination getDestination(GlobalCoordinate coordinate) {
return destinations.get(coordinate);
}
public TeleportDestination getDestination(Coordinate coordinate, int dimension) {
return destinations.get(new GlobalCoordinate(coordinate, dimension));
}
@Override
public void readFromNBT(NBTTagCompound tagCompound) {
destinations.clear();
destinationById.clear();
destinationIdByCoordinate.clear();
lastId = tagCompound.getInteger("lastId");
readDestinationsFromNBT(tagCompound);
}
private void readDestinationsFromNBT(NBTTagCompound tagCompound) {
NBTTagList lst = tagCompound.getTagList("destinations", Constants.NBT.TAG_COMPOUND);
for (int i = 0 ; i < lst.tagCount() ; i++) {
NBTTagCompound tc = lst.getCompoundTagAt(i);
Coordinate c = new Coordinate(tc.getInteger("x"), tc.getInteger("y"), tc.getInteger("z"));
int dim = tc.getInteger("dim");
String name = tc.getString("name");
TeleportDestination destination = new TeleportDestination(c, dim);
destination.setName(name);
GlobalCoordinate gc = new GlobalCoordinate(c, dim);
destinations.put(gc, destination);
int id;
if (tc.hasKey("id")) {
id = tc.getInteger("id");
destinationById.put(id, gc);
destinationIdByCoordinate.put(gc, id);
}
}
}
@Override
public void writeToNBT(NBTTagCompound tagCompound) {
writeDestinationsToNBT(tagCompound, destinations.values(), destinationIdByCoordinate);
tagCompound.setInteger("lastId", lastId);
}
private static void writeDestinationsToNBT(NBTTagCompound tagCompound, Collection<TeleportDestination> destinations,
Map<GlobalCoordinate, Integer> coordinateToInteger) {
NBTTagList lst = new NBTTagList();
for (TeleportDestination destination : destinations) {
NBTTagCompound tc = new NBTTagCompound();
Coordinate c = destination.getCoordinate();
tc.setInteger("x", c.getX());
tc.setInteger("y", c.getY());
tc.setInteger("z", c.getZ());
tc.setInteger("dim", destination.getDimension());
tc.setString("name", destination.getName());
if (coordinateToInteger != null) {
Integer id = coordinateToInteger.get(new GlobalCoordinate(c, destination.getDimension()));
if (id != null) {
tc.setInteger("id", id);
}
}
lst.appendTag(tc);
}
tagCompound.setTag("destinations", lst);
}
}