419 lines
11 KiB
Java
Executable file
419 lines
11 KiB
Java
Executable file
/**
|
|
* Copyright (c) 2011-2017, SpaceToad and the BuildCraft Team
|
|
* http://www.mod-buildcraft.com
|
|
* <p/>
|
|
* BuildCraft is distributed under the terms of the Minecraft Mod Public
|
|
* License 1.0, or MMPL. Please check the contents of the license located in
|
|
* http://www.mod-buildcraft.com/MMPL-1.0.txt
|
|
*/
|
|
package buildcraft.robotics;
|
|
|
|
import java.security.InvalidParameterException;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.Map;
|
|
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
import net.minecraft.nbt.NBTTagList;
|
|
import net.minecraft.util.LongHashMap;
|
|
import net.minecraft.world.World;
|
|
import net.minecraft.world.WorldSavedData;
|
|
|
|
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
|
import net.minecraftforge.common.util.Constants;
|
|
import net.minecraftforge.common.util.ForgeDirection;
|
|
import net.minecraftforge.event.world.ChunkEvent;
|
|
|
|
import buildcraft.api.core.BCLog;
|
|
import buildcraft.api.robots.DockingStation;
|
|
import buildcraft.api.robots.EntityRobotBase;
|
|
import buildcraft.api.robots.IRobotRegistry;
|
|
import buildcraft.api.robots.ResourceId;
|
|
import buildcraft.api.robots.RobotManager;
|
|
|
|
public class RobotRegistry extends WorldSavedData implements IRobotRegistry {
|
|
|
|
protected World world;
|
|
protected final HashMap<StationIndex, DockingStation> stations = new HashMap<StationIndex, DockingStation>();
|
|
|
|
private long nextRobotID = Long.MIN_VALUE;
|
|
|
|
private final LongHashMap robotsLoaded = new LongHashMap();
|
|
private final HashSet<EntityRobot> robotsLoadedSet = new HashSet<EntityRobot>();
|
|
private final HashMap<ResourceId, Long> resourcesTaken = new HashMap<ResourceId, Long>();
|
|
private final LongHashMap resourcesTakenByRobot = new LongHashMap();
|
|
private final LongHashMap stationsTakenByRobot = new LongHashMap();
|
|
|
|
public RobotRegistry(String id) {
|
|
super(id);
|
|
}
|
|
|
|
@Override
|
|
public long getNextRobotId() {
|
|
long result = nextRobotID;
|
|
|
|
nextRobotID = nextRobotID + 1;
|
|
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public void registerRobot(EntityRobotBase robot) {
|
|
markDirty();
|
|
|
|
if (robot.getRobotId() == EntityRobotBase.NULL_ROBOT_ID) {
|
|
((EntityRobot) robot).setUniqueRobotId(getNextRobotId());
|
|
}
|
|
if (robotsLoaded.containsItem(robot.getRobotId())) {
|
|
BCLog.logger.warn("Robot with id %d was not unregistered properly", robot.getRobotId());
|
|
}
|
|
|
|
addRobotLoaded((EntityRobot) robot);
|
|
}
|
|
|
|
private HashSet<ResourceId> getResourcesTakenByRobot(long robotId) {
|
|
return (HashSet<ResourceId>) resourcesTakenByRobot.getValueByKey(robotId);
|
|
}
|
|
|
|
private HashSet<StationIndex> getStationsTakenByRobot(long robotId) {
|
|
return (HashSet<StationIndex>) stationsTakenByRobot.getValueByKey(robotId);
|
|
}
|
|
|
|
|
|
private void addRobotLoaded(EntityRobot robot) {
|
|
robotsLoaded.add(robot.getRobotId(), robot);
|
|
robotsLoadedSet.add(robot);
|
|
}
|
|
|
|
private void removeRobotLoaded(EntityRobot robot) {
|
|
robotsLoaded.remove(robot.getRobotId());
|
|
robotsLoadedSet.remove(robot);
|
|
}
|
|
|
|
@Override
|
|
public void killRobot(EntityRobotBase robot) {
|
|
markDirty();
|
|
|
|
releaseResources(robot, true);
|
|
removeRobotLoaded((EntityRobot) robot);
|
|
}
|
|
|
|
@Override
|
|
public void unloadRobot(EntityRobotBase robot) {
|
|
markDirty();
|
|
|
|
releaseResources(robot, false, true);
|
|
removeRobotLoaded((EntityRobot) robot);
|
|
}
|
|
|
|
@Override
|
|
public EntityRobot getLoadedRobot(long id) {
|
|
if (robotsLoaded.containsItem(id)) {
|
|
return (EntityRobot) robotsLoaded.getValueByKey(id);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized boolean isTaken(ResourceId resourceId) {
|
|
return robotIdTaking(resourceId) != EntityRobotBase.NULL_ROBOT_ID;
|
|
}
|
|
|
|
@Override
|
|
public synchronized long robotIdTaking(ResourceId resourceId) {
|
|
if (!resourcesTaken.containsKey(resourceId)) {
|
|
return EntityRobotBase.NULL_ROBOT_ID;
|
|
}
|
|
|
|
long robotId = resourcesTaken.get(resourceId);
|
|
|
|
if (robotsLoaded.containsItem(robotId) && !((EntityRobot) robotsLoaded.getValueByKey(robotId)).isDead) {
|
|
return robotId;
|
|
} else {
|
|
// If the robot is either not loaded or dead, the resource is not
|
|
// actively used anymore. Release it.
|
|
release(resourceId);
|
|
return EntityRobotBase.NULL_ROBOT_ID;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized EntityRobot robotTaking(ResourceId resourceId) {
|
|
long robotId = robotIdTaking(resourceId);
|
|
|
|
if (robotId == EntityRobotBase.NULL_ROBOT_ID || !robotsLoaded.containsItem(robotId)) {
|
|
return null;
|
|
} else {
|
|
return (EntityRobot) robotsLoaded.getValueByKey(robotId);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized boolean take(ResourceId resourceId, EntityRobotBase robot) {
|
|
markDirty();
|
|
|
|
return take(resourceId, robot.getRobotId());
|
|
}
|
|
|
|
@Override
|
|
public synchronized boolean take(ResourceId resourceId, long robotId) {
|
|
if (resourceId == null) {
|
|
return false;
|
|
}
|
|
|
|
markDirty();
|
|
|
|
if (!resourcesTaken.containsKey(resourceId)) {
|
|
resourcesTaken.put(resourceId, robotId);
|
|
|
|
if (!resourcesTakenByRobot.containsItem(robotId)) {
|
|
resourcesTakenByRobot.add(robotId, new HashSet<ResourceId>());
|
|
}
|
|
|
|
getResourcesTakenByRobot(robotId).add(resourceId);
|
|
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized void release(ResourceId resourceId) {
|
|
if (resourceId == null) {
|
|
return;
|
|
}
|
|
|
|
markDirty();
|
|
|
|
if (resourcesTaken.containsKey(resourceId)) {
|
|
long robotId = resourcesTaken.get(resourceId);
|
|
|
|
getResourcesTakenByRobot(robotId).remove(resourceId);
|
|
resourcesTaken.remove(resourceId);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized void releaseResources(EntityRobotBase robot) {
|
|
releaseResources(robot, false);
|
|
}
|
|
|
|
private synchronized void releaseResources(EntityRobotBase robot, boolean forceAll) {
|
|
releaseResources(robot, forceAll, false);
|
|
}
|
|
|
|
private synchronized void releaseResources(EntityRobotBase robot, boolean forceAll, boolean resetEntities) {
|
|
markDirty();
|
|
|
|
if (resourcesTakenByRobot.containsItem(robot.getRobotId())) {
|
|
HashSet<ResourceId> resourceSet = (HashSet<ResourceId>) getResourcesTakenByRobot(robot.getRobotId())
|
|
.clone();
|
|
|
|
for (ResourceId id : resourceSet) {
|
|
release(id);
|
|
}
|
|
|
|
resourcesTakenByRobot.remove(robot.getRobotId());
|
|
}
|
|
|
|
if (stationsTakenByRobot.containsItem(robot.getRobotId())) {
|
|
HashSet<StationIndex> stationSet = (HashSet<StationIndex>) getStationsTakenByRobot(robot.getRobotId())
|
|
.clone();
|
|
|
|
for (StationIndex s : stationSet) {
|
|
DockingStation d = stations.get(s);
|
|
|
|
if (d != null) {
|
|
if (!d.canRelease()) {
|
|
if (forceAll) {
|
|
d.unsafeRelease(robot);
|
|
} else if (resetEntities && d.robotIdTaking() == robot.getRobotId()) {
|
|
d.invalidateRobotTakingEntity();
|
|
}
|
|
} else {
|
|
d.unsafeRelease(robot);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (forceAll) {
|
|
stationsTakenByRobot.remove(robot.getRobotId());
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized DockingStation getStation(int x, int y, int z, ForgeDirection side) {
|
|
StationIndex index = new StationIndex(side, x, y, z);
|
|
|
|
if (stations.containsKey(index)) {
|
|
return stations.get(index);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized Collection<DockingStation> getStations() {
|
|
return stations.values();
|
|
}
|
|
|
|
@Override
|
|
public synchronized void registerStation(DockingStation station) {
|
|
markDirty();
|
|
|
|
StationIndex index = new StationIndex(station);
|
|
|
|
if (stations.containsKey(index)) {
|
|
throw new InvalidParameterException("Station " + index + " already registered");
|
|
} else {
|
|
stations.put(index, station);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized void removeStation(DockingStation station) {
|
|
markDirty();
|
|
|
|
StationIndex index = new StationIndex(station);
|
|
|
|
if (stations.containsKey(index)) {
|
|
if (station.robotTaking() != null) {
|
|
if (!station.isMainStation()) {
|
|
station.robotTaking().undock();
|
|
} else {
|
|
station.robotTaking().setMainStation(null);
|
|
}
|
|
} else if (station.robotIdTaking() != EntityRobotBase.NULL_ROBOT_ID) {
|
|
if (stationsTakenByRobot.containsItem(station.robotIdTaking())) {
|
|
getStationsTakenByRobot(station.robotIdTaking()).remove(index);
|
|
}
|
|
}
|
|
|
|
stations.remove(index);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized void take(DockingStation station, long robotId) {
|
|
if (!stationsTakenByRobot.containsItem(robotId)) {
|
|
stationsTakenByRobot.add(robotId, new HashSet<StationIndex>());
|
|
}
|
|
|
|
getStationsTakenByRobot(robotId).add(new StationIndex(station));
|
|
}
|
|
|
|
@Override
|
|
public synchronized void release(DockingStation station, long robotId) {
|
|
if (stationsTakenByRobot.containsItem(robotId)) {
|
|
getStationsTakenByRobot(robotId).remove(new StationIndex(station));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized void writeToNBT(NBTTagCompound nbt) {
|
|
nbt.setLong("nextRobotID", nextRobotID);
|
|
|
|
NBTTagList resourceList = new NBTTagList();
|
|
|
|
for (Map.Entry<ResourceId, Long> e : resourcesTaken.entrySet()) {
|
|
NBTTagCompound cpt = new NBTTagCompound();
|
|
NBTTagCompound resourceId = new NBTTagCompound();
|
|
e.getKey().writeToNBT(resourceId);
|
|
cpt.setTag("resourceId", resourceId);
|
|
cpt.setLong("robotId", e.getValue());
|
|
|
|
resourceList.appendTag(cpt);
|
|
}
|
|
|
|
nbt.setTag("resourceList", resourceList);
|
|
|
|
NBTTagList stationList = new NBTTagList();
|
|
|
|
for (Map.Entry<StationIndex, DockingStation> e : stations.entrySet()) {
|
|
NBTTagCompound cpt = new NBTTagCompound();
|
|
e.getValue().writeToNBT(cpt);
|
|
cpt.setString("stationType", RobotManager.getDockingStationName(e.getValue().getClass()));
|
|
stationList.appendTag(cpt);
|
|
}
|
|
|
|
nbt.setTag("stationList", stationList);
|
|
}
|
|
|
|
@Override
|
|
public synchronized void readFromNBT(NBTTagCompound nbt) {
|
|
nextRobotID = nbt.getLong("nextRobotID");
|
|
|
|
NBTTagList resourceList = nbt.getTagList("resourceList", Constants.NBT.TAG_COMPOUND);
|
|
|
|
for (int i = 0; i < resourceList.tagCount(); ++i) {
|
|
NBTTagCompound cpt = resourceList.getCompoundTagAt(i);
|
|
ResourceId resourceId = ResourceId.load(cpt.getCompoundTag("resourceId"));
|
|
long robotId = cpt.getLong("robotId");
|
|
|
|
take(resourceId, robotId);
|
|
}
|
|
|
|
NBTTagList stationList = nbt.getTagList("stationList", Constants.NBT.TAG_COMPOUND);
|
|
|
|
for (int i = 0; i < stationList.tagCount(); ++i) {
|
|
NBTTagCompound cpt = stationList.getCompoundTagAt(i);
|
|
|
|
Class<? extends DockingStation> cls;
|
|
|
|
if (!cpt.hasKey("stationType")) {
|
|
cls = DockingStationPipe.class;
|
|
} else {
|
|
cls = RobotManager.getDockingStationByName(cpt.getString("stationType"));
|
|
if (cls == null) {
|
|
BCLog.logger.error("Could not load docking station of type "
|
|
+ nbt.getString("stationType"));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
try {
|
|
DockingStation station = cls.newInstance();
|
|
station.readFromNBT(cpt);
|
|
|
|
registerStation(station);
|
|
|
|
if (station.linkedId() != EntityRobotBase.NULL_ROBOT_ID) {
|
|
take(station, station.linkedId());
|
|
}
|
|
} catch (Exception e) {
|
|
BCLog.logger.error("Could not load docking station", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public void onChunkUnload(ChunkEvent.Unload e) {
|
|
if (e.world == this.world) {
|
|
for (EntityRobot robot : new ArrayList<EntityRobot>(robotsLoadedSet)) {
|
|
if (!e.world.loadedEntityList.contains(robot)) {
|
|
robot.onChunkUnload();
|
|
}
|
|
}
|
|
for (DockingStation station : new ArrayList<DockingStation>(stations.values())) {
|
|
if (!world.blockExists(station.x(), station.y(), station.z())) {
|
|
station.onChunkUnload();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function is a wrapper for markDirty(), done this way due to
|
|
* obfuscation issues.
|
|
*/
|
|
@Override
|
|
public void registryMarkDirty() {
|
|
markDirty();
|
|
}
|
|
}
|