侧边栏壁纸
  • 累计撰写 781 篇文章
  • 累计创建 1 个标签
  • 累计收到 1 条评论
标签搜索
MC

运送员 AI

Dettan
2021-07-10 / 0 评论 / 0 点赞 / 91 阅读 / 8,458 字
温馨提示:
本文最后更新于 2022-04-30,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。
任务可以多个dman接? 一个人装不了
JobDeliverman.java
public IRequest<IDeliverymanRequestable> getCurrentTask()
{
		// 只取不删
    final IToken<?> request = getTaskQueueFromDataStore().peekFirst();
    if (request == null)
    {
        return null;
    }
return (IRequest&lt;IDeliverymanRequestable&gt;) 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&lt;IRequest&lt;? extends Delivery&gt;&gt; taskList = job.getTaskListWithSameDestination((IRequest&lt;? extends Delivery&gt;) currentTask);
final List&lt;ItemStack&gt; alreadyInInv = new ArrayList&lt;&gt;();
IRequest&lt;? extends Delivery&gt; nextPickUp = null;

int parallelDeliveryCount = 0;
for (final IRequest&lt;? extends Delivery&gt; task : taskList)
{
    parallelDeliveryCount++;
    //背包里拥有任务物品的总数量,ignore stack size 是指比较的时候忽略数量,而不是求和的时候
    int totalCount = InventoryUtils.getItemCountInItemHandler(worker.getInventoryCitizen(),
      itemStack -&gt; 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 &lt; 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 &gt; 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 &gt; 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(&quot;com.minecolonies.coremod.status.delivering&quot;));

// 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() + &quot;: &quot; + worker.getName() + &quot;: Can't inter dimension yet: &quot;);
    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 &lt; 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 -&gt; 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(&quot; :&quot; + 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;

}





0

评论区