•
任务可以多个dman接? 一个人装不了
JobDeliverman.java
public IRequest<IDeliverymanRequestable> getCurrentTask()
{
// 只取不删
final IToken<?> request = getTaskQueueFromDataStore().peekFirst();
if (request == null)
{
return null;
}
return (IRequest<IDeliverymanRequestable>) getColony().getRequestManager().getRequestForToken(request);
}
decide (5S)
1.
获取第一个任务
2.
没任务就清背包或者歇着
3.
有任务就做
private IAIState decide()
{
worker.getCitizenData().setVisibleStatus(VisibleCitizenStatus.WORKING);
final IRequest<? extends IDeliverymanRequestable> currentTask = job.getCurrentTask();
if (currentTask == null)
{
// If there are no deliveries/pickups pending, just loiter around the warehouse.
if (!worker.isWorkerAtSiteWithMove(getAndCheckWareHouse().getPosition(), MIN_DISTANCE_TO_WAREHOUSE))
{
setDelay(WALK_DELAY);
return START_WORKING;
}
else
{
if (!worker.getInventoryCitizen().isEmpty())
{
return DUMPING;
}
else
{
return START_WORKING;
}
}
}
if (currentTask instanceof DeliveryRequest)
{
// Before a delivery can be made, the inventory first needs to be dumped.
if (!worker.getInventoryCitizen().isEmpty())
{
return DUMPING;
}
else
{
return PREPARE_DELIVERY;
}
}
else
{
return PICKUP;
}
}
准备运送 状态函数 (5Tick)
1.
找出同目的地的任务
2.
拿取尽可能多的任务物品
3.
跳到运送状态
private IAIState prepareDelivery()
{
final IRequest<? extends IRequestable> currentTask = job.getCurrentTask();
if (!(currentTask instanceof DeliveryRequest))
{
// The current task has changed since the Decision-state.
// Restart.
return START_WORKING;
}
// already put current task in the first location of the result list.
final List<IRequest<? extends Delivery>> taskList = job.getTaskListWithSameDestination((IRequest<? extends Delivery>) currentTask);
final List<ItemStack> alreadyInInv = new ArrayList<>();
IRequest<? extends Delivery> nextPickUp = null;
int parallelDeliveryCount = 0;
for (final IRequest<? extends Delivery> task : taskList)
{
parallelDeliveryCount++;
//背包里拥有任务物品的总数量,ignore stack size 是指比较的时候忽略数量,而不是求和的时候
int totalCount = InventoryUtils.getItemCountInItemHandler(worker.getInventoryCitizen(),
itemStack -> ItemStackUtils.compareItemStacksIgnoreStackSize(task.getRequest().getStack(), itemStack));
//减去先前任务已占用的物品.
int hasCount = 0;
for (final ItemStack stack : alreadyInInv)
{
if (ItemStackUtils.compareItemStacksIgnoreStackSize(stack, task.getRequest().getStack()))
{
hasCount += stack.getCount();
}
}
if (totalCount < hasCount + task.getRequest().getStack().getCount())
{
// 物品不足, 去 pick up,每次只pick up 一个task的items
nextPickUp = task;
break;
}
else
{
alreadyInInv.add(task.getRequest().getStack());
}
}
// 不需要pick up 或者 达到当前等级运送上限,直接运送
if (nextPickUp == null || parallelDeliveryCount > 1 + (getSecondarySkillLevel() / 5))
{
return DELIVERY;
}
// 下面是pick up
final ILocation location = nextPickUp.getRequest().getStart();
if (!location.isReachableFromLocation(worker.getLocation()))
{
job.finishRequest(false);
return START_WORKING;
}
// 正在赶路时直接返回,等待下一tick
// todo: 减小tick频率,以节省cpu资源
if (walkToBlock(location.getInDimensionLocation()))
{
return PREPARE_DELIVERY;
}
// 疑似 避免多人同时拿取逻辑
final TileEntity tileEntity = world.getTileEntity(location.getInDimensionLocation());
if (tileEntity instanceof ChestTileEntity && !(tileEntity instanceof TileEntityColonyBuilding))
{
if (((ChestTileEntity) tileEntity).numPlayersUsing == 0)
{
this.world.addBlockEvent(tileEntity.getPos(), tileEntity.getBlockState().getBlock(), 1, 1);
this.world.notifyNeighborsOfStateChange(tileEntity.getPos(), tileEntity.getBlockState().getBlock());
this.world.notifyNeighborsOfStateChange(tileEntity.getPos().down(), tileEntity.getBlockState().getBlock());
return PREPARE_DELIVERY;
}
this.world.addBlockEvent(tileEntity.getPos(), tileEntity.getBlockState().getBlock(), 1, 0);
this.world.notifyNeighborsOfStateChange(tileEntity.getPos(), tileEntity.getBlockState().getBlock());
this.world.notifyNeighborsOfStateChange(tileEntity.getPos().down(), tileEntity.getBlockState().getBlock());
}
job.addConcurrentDelivery(nextPickUp.getId());
// 直接拿取
if (gatherIfInTileEntity(tileEntity, nextPickUp.getRequest().getStack()))
{
return PREPARE_DELIVERY;
}
// 拿取失败,直接开始运送. 如果排在前面的是缺少的就会导致后面的无法运送,如果任务是计算过的就不会这样.
if (parallelDeliveryCount > 1)
{
job.removeConcurrentDelivery(nextPickUp.getId());
return DELIVERY;
}
// 拿取失败,一个任务也没, 退回前一个状态
job.finishRequest(false);
job.removeConcurrentDelivery(nextPickUp.getId());
return START_WORKING;
}
运送 状态函数 (5Tick)
1.
任务是否改变
2.
目的地是否可达
3.
是否已到达
4.
拿出物品
5.
放入
6.
检查放入结果
7.
经验值 饱食度 手持物
8.
失败就dump
dman 背包是满的会怎么样?
private IAIState deliver()
{
final IRequest<? extends IDeliverymanRequestable> currentTask = job.getCurrentTask();
if (!(currentTask instanceof DeliveryRequest))
{
// The current task has changed since the Decision-state.
// Since prepareDelivery() was called earlier, go dumping first and then restart.
return DUMPING;
}
worker.getCitizenData().setVisibleStatus(DELIVERING);
worker.getCitizenStatusHandler().setLatestStatus(new TranslationTextComponent("com.minecolonies.coremod.status.delivering"));
// get the target location
final ILocation targetBuildingLocation = ((Delivery) currentTask.getRequest()).getTarget();
if (!targetBuildingLocation.isReachableFromLocation(worker.getLocation()))
{
//todo: alter user when this happen;
Log.getLogger().info(worker.getCitizenColonyHandler().getColony().getName() + ": " + worker.getName() + ": Can't inter dimension yet: ");
return START_WORKING;
}
// delay ticks when is not at site
if (!worker.isWorkerAtSiteWithMove(targetBuildingLocation.getInDimensionLocation(), MIN_DISTANCE_TO_WAREHOUSE))
{
setDelay(WALK_DELAY);
return DELIVERY;
}
final TileEntity tileEntity = world.getTileEntity(targetBuildingLocation.getInDimensionLocation());
if (!(tileEntity instanceof TileEntityColonyBuilding))
{
// TODO: Non-Colony deliveries are unsupported yet. Fix that at some point in time.
job.finishRequest(true);
return START_WORKING;
}
final IBuildingContainer targetBuilding = ((AbstractTileEntityColonyBuilding) tileEntity).getBuilding();
boolean success = true;
// 是否操作过, 相当于背包是否是空
boolean extracted = false;
final IItemHandler workerInventory = worker.getInventoryCitizen();
for (int i = 0; i < workerInventory.getSlots(); i++)
{
if (workerInventory.getStackInSlot(i).isEmpty())
{
continue;
}
// 把物品取出来
final ItemStack stack = workerInventory.extractItem(i, Integer.MAX_VALUE, false);
if (ItemStackUtils.isEmpty(stack))
{
continue;
}
extracted = true;
final ItemStack insertionResultStack;
// TODO: Please only push items into the target that were actually requested.
if (targetBuilding instanceof AbstractBuildingWorker)
{
// 放物品,成功的话返回为空. 有判断 是否是需要的物品
insertionResultStack = InventoryUtils.forceItemStackToItemHandler(
targetBuilding.getCapability(ITEM_HANDLER_CAPABILITY, null).orElseGet(null), stack, ((IBuildingWorker) targetBuilding)::isItemStackInRequest);
}
else
{
// Buildings that are not inherently part of the request system, but just receive a delivery, cannot have their items replaced.
// Therefore, the keep-predicate always returns true.
insertionResultStack =
InventoryUtils.forceItemStackToItemHandler(targetBuilding.getCapability(ITEM_HANDLER_CAPABILITY, null).orElseGet(null),
stack,
itemStack -> true);
}
if (!ItemStackUtils.isEmpty(insertionResultStack))
{
// A stack was replaced (meaning the inventory didn't have enough space).
if (ItemStack.areItemStacksEqual(insertionResultStack, stack) && worker.getCitizenData() != null)
{
// The replaced stack is the same as the one we tried to put into the inventory.
// Meaning, replacing failed.
success = false;
if (targetBuilding instanceof AbstractBuildingWorker)
{
worker.getCitizenData()
.triggerInteraction(new PosBasedInteraction(new TranslationTextComponent(COM_MINECOLONIES_COREMOD_JOB_DELIVERYMAN_NAMEDCHESTFULL,
targetBuilding.getMainCitizen().getName()),
ChatPriority.IMPORTANT,
new TranslationTextComponent(COM_MINECOLONIES_COREMOD_JOB_DELIVERYMAN_CHESTFULL),
targetBuilding.getID()));
}
else
{
worker.getCitizenData()
.triggerInteraction(new PosBasedInteraction(new TranslationTextComponent(COM_MINECOLONIES_COREMOD_JOB_DELIVERYMAN_CHESTFULL,
new StringTextComponent(" :" + targetBuilding.getSchematicName())),
ChatPriority.IMPORTANT,
new TranslationTextComponent(COM_MINECOLONIES_COREMOD_JOB_DELIVERYMAN_CHESTFULL),
targetBuildingLocation.getInDimensionLocation()));
}
}
//Insert the result back into the inventory so we do not lose it.
workerInventory.insertItem(i, insertionResultStack, false);
}
}
if (!extracted)
{
// This can only happen if the dman's inventory was completely empty.
// Let the retry-system handle this case.
worker.decreaseSaturationForContinuousAction();
worker.getCitizenItemHandler().setHeldItem(Hand.MAIN_HAND, SLOT_HAND);
job.finishRequest(false);
// No need to go dumping in this case.
return START_WORKING;
}
// 经验 饱食度 等
worker.getCitizenExperienceHandler().addExperience(1.5D);
worker.decreaseSaturationForContinuousAction();
worker.getCitizenItemHandler().setHeldItem(Hand.MAIN_HAND, SLOT_HAND);
job.finishRequest(true);
return success ? START_WORKING : DUMPING;
}
评论区