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

AbstractEntityAICrafting

Dettan
2021-07-10 / 0 评论 / 0 点赞 / 86 阅读 / 8,665 字
温馨提示:
本文最后更新于 2022-04-30,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。
package com.minecolonies.coremod.entity.ai.basic;

public abstract class AbstractEntityAICrafting
<J extends AbstractJobCrafter<?, J>, B extends AbstractBuildingWorker>
extends AbstractEntityAIInteract<J, B>
{
/**
* Time the worker delays until the next hit.
*/
protected static final int HIT_DELAY = 20;

/**
 * Increase this value to make the product creation progress way slower.
 */
public static final int PROGRESS_MULTIPLIER = 10;

/**
 * Max level which should have an effect on the speed of the worker.
 */
protected static final int MAX_LEVEL = 50;

/**
 * Times the product needs to be hit.
 */
private static final int HITTING_TIME = 3;

//当前制作中的请求
public IRequest&lt;? extends PublicCrafting&gt; currentRequest;

//当前制作中的配方
protected IRecipeStorage currentRecipeStorage;

/**
 * The number of actions a crafting &quot;success&quot; is worth.
 * By default, that's 1 action for 1 crafting success.
 * Override this in your subclass to make crafting recipes worth more actions :-)
 *
 * @return The number of actions a crafting &quot;success&quot; is worth.
 */
protected int getActionRewardForCraftingSuccess()
{
    return 1;
}

<span style="background:rgb(244,223,235);">//状态机初始化</span>
public AbstractEntityAICrafting(@NotNull final J job)
{
    super(job);
    super.registerTargets(
      /*
       * Check if tasks should be executed.
       */
      new AITarget(IDLE, () -&gt; START_WORKING, 1),
      new AITarget(START_WORKING, this::decide, STANDARD_DELAY),
      new AITarget(QUERY_ITEMS, this::queryItems, STANDARD_DELAY),
      new AITarget(GET_RECIPE, this::getRecipe, STANDARD_DELAY),
      new AITarget(CRAFT, this::craft, HIT_DELAY)
    );
    worker.setCanPickUpLoot(true);
}

//START_WORKING的状态装换函数, 决定做什么.
protected IAIState decide()
{
    if (job.getTaskQueue().isEmpty())
    {
        return START_WORKING;
    }

    if (job.getCurrentTask() == null)
    {
        return START_WORKING;
    }

    if (walkToBuilding())
    {
        return START_WORKING;
    }

    <span style="background:rgb(244,223,235);">if (job.getActionsDone() &gt; 0)
    {
        // Wait to dump before continuing.
        return getState();
    }</span>
			//有请求,有配方,开始请求物品.
    if (currentRequest != null && currentRecipeStorage != null)
    {
        return QUERY_ITEMS;
    }
			//有请求,没配方
    return GET_RECIPE;
}

//GET_RECIPE的状态转换函数 , Query the IRecipeStorage of the first request in the queue.
protected IAIState getRecipe()
{
    final IRequest&lt;? extends PublicCrafting&gt; currentTask = job.getCurrentTask();

    if (currentTask == null)
    {
        return START_WORKING;
    }
    final IBuildingWorker buildingWorker = getOwnBuilding();
    currentRecipeStorage = buildingWorker.getFirstFullFillableRecipe(stack -&gt; stack.isItemEqual(currentTask.getRequest().getStack()), 1);
    if (currentRecipeStorage == null)
    {
        job.finishRequest(false);
        incrementActionsDone(getActionRewardForCraftingSuccess());
        return START_WORKING;
    }

    currentRequest = currentTask;
			//
    job.setMaxCraftingCount(currentRequest.getRequest().getCount());
    //当前有的数量
			final int currentCount = InventoryUtils.getItemCountInItemHandler(worker.getInventoryCitizen(), stack -&gt; stack.isItemEqual(currentRecipeStorage.getPrimaryOutput()));
    //制作中的数量
			final int inProgressCount = getExtendedOutputCount(currentRecipeStorage.getPrimaryOutput());
			//每轮做出几个
    final int countPerIteration = currentRecipeStorage.getPrimaryOutput().getCount();
    //需要制作几次
			final int doneOpsCount = currentCount / countPerIteration;
    //制作中的次数
			final int progressOpsCount = inProgressCount / countPerIteration;
			//还需要制作多少次
    final int remainingOpsCount = currentRequest.getRequest().getCount() - doneOpsCount - progressOpsCount;
			//检测数量是否够制作
    final List&lt;ItemStorage&gt; input = currentRecipeStorage.getCleanedInput();
    for (final ItemStorage inputStorage : input)
    {
        if (InventoryUtils.getItemCountInProvider(getOwnBuilding(), itemStack -&gt; itemStack.isItemEqual(inputStorage.getItemStack()))
              + InventoryUtils.getItemCountInItemHandler(worker.getInventoryCitizen(), itemStack -&gt; itemStack.isItemEqual(inputStorage.getItemStack()))
              &lt; inputStorage.getAmount() * remainingOpsCount)
        {
							<span style="background:rgb(244,223,235);">//</span>
            job.finishRequest(false);
            incrementActionsDone(getActionRewardForCraftingSuccess());
            return START_WORKING;
        }
    }

    job.setCraftCounter(doneOpsCount);
    return QUERY_ITEMS;
}

/**
 * Get an extended output count that can be overriden.
 * @param primaryOutput the type of output.
 * @return the output count that should be added too.
 */
protected int getExtendedOutputCount(final ItemStack primaryOutput)
{
    return 0;
}

@Override
public IAIState getStateAfterPickUp()
{
    return GET_RECIPE;
}</code></pre></div>            <div style="width:100%;max-width:996px;margin-top:4px;margin-bottom:4px;">
/**
     * Query the required items to take them in the inventory to craft.
     *
     * @return the next state to go to.
     */
    private IAIState queryItems()
    {
        if (currentRecipeStorage == null)
        {
            return START_WORKING;
        }

        return checkForItems(currentRecipeStorage);
    }

    /**
     * Check for all items of the required recipe.
     *
     * @param storage the recipe storage.
     * @return the next state to go to.
     */
    protected IAIState checkForItems(@NotNull final IRecipeStorage storage)
    {
        final int inProgressCount = getExtendedOutputCount(currentRecipeStorage.getPrimaryOutput());
        final int countPerIteration = currentRecipeStorage.getPrimaryOutput().getCount();
        final int progressOpsCount = inProgressCount / countPerIteration;

        final List<ItemStorage> input = storage.getCleanedInput();
        for (final ItemStorage inputStorage : input)
        {
            final Predicate<ItemStack> predicate = stack -> !ItemStackUtils.isEmpty(stack) && new Stack(stack).matches(inputStorage.getItemStack());
            if (InventoryUtils.getItemCountInItemHandler(worker.getInventoryCitizen(), predicate) + ((job.getCraftCounter() + progressOpsCount ) * inputStorage.getAmount())
                  < inputStorage.getAmount() * job.getMaxCraftingCount())
            {
                if (InventoryUtils.hasItemInProvider(getOwnBuilding(), predicate))
                {
                    needsCurrently = new Tuple<>(predicate, inputStorage.getAmount() * job.getMaxCraftingCount());
                    return GATHERING_REQUIRED_MATERIALS;
                }
                currentRecipeStorage = null;
                currentRequest = null;
                return GET_RECIPE;
            }
        }

        return CRAFT;
    }

    /**
     * The actual crafting logic.
     *
     * @return the next state to go to.
     */
    protected IAIState craft()
    {
        if (currentRecipeStorage == null || job.getCurrentTask() == null)
        {
            return START_WORKING;
        }

        if (currentRequest == null && job.getCurrentTask() != null)
        {
            return GET_RECIPE;
        }

        if (walkToBuilding())
        {
            return getState();
        }

        job.setProgress(job.getProgress() + 1);

        worker.setHeldItem(Hand.MAIN_HAND,
          currentRecipeStorage.getCleanedInput().get(worker.getRandom().nextInt(currentRecipeStorage.getCleanedInput().size())).getItemStack().copy());
        worker.setHeldItem(Hand.OFF_HAND, currentRecipeStorage.getPrimaryOutput().copy());
        worker.getCitizenItemHandler().hitBlockWithToolInHand(getOwnBuilding().getPosition());

        currentRequest = job.getCurrentTask();

        if (currentRequest != null && (currentRequest.getState() == RequestState.CANCELLED || currentRequest.getState() == RequestState.FAILED))
        {
            currentRequest = null;
            incrementActionsDone(getActionRewardForCraftingSuccess());
            currentRecipeStorage = null;
            return START_WORKING;
        }

        if (job.getProgress() >= getRequiredProgressForMakingRawMaterial())
        {
            final IAIState check = checkForItems(currentRecipeStorage);
            if (check == CRAFT)
            {
                if (!currentRecipeStorage.fullFillRecipe(worker.getItemHandlerCitizen()))
                {
                    currentRequest = null;
                    incrementActionsDone(getActionRewardForCraftingSuccess());
                    job.finishRequest(false);
                    resetValues();
                    return START_WORKING;
                }

                currentRequest.addDelivery(currentRecipeStorage.getPrimaryOutput());
                job.setCraftCounter(job.getCraftCounter() + 1);

                if (job.getCraftCounter() >= job.getMaxCraftingCount())
                {
                    incrementActionsDone(getActionRewardForCraftingSuccess());
                    currentRecipeStorage = null;
                    resetValues();

                    if (inventoryNeedsDump())
                    {
                        if (job.getMaxCraftingCount() == 0 && job.getProgress() == 0 && job.getCraftCounter() == 0 && currentRequest != null)
                        {
                            job.finishRequest(true);
                            worker.getCitizenExperienceHandler().addExperience(currentRequest.getRequest().getCount() / 2.0);
                        }
                    }
                }
                else
                {
                    job.setProgress(0);
                    return GET_RECIPE;
                }
            }
            else
            {
                currentRequest = null;
                job.finishRequest(false);
                incrementActionsDoneAndDecSaturation();
                resetValues();
            }
            return START_WORKING;
        }

        return getState();
    }

    /**
     * Reset all the values.
     */
    public void resetValues()
    {
        job.setMaxCraftingCount(0);
        job.setProgress(0);
        job.setCraftCounter(0);
        worker.setHeldItem(Hand.MAIN_HAND, ItemStackUtils.EMPTY);
        worker.setHeldItem(Hand.OFF_HAND, ItemStackUtils.EMPTY);
    }

    @Override
    public IAIState afterDump()
    {
        if (job.getMaxCraftingCount() == 0 && job.getProgress() == 0 && job.getCraftCounter() == 0 && currentRequest != null)
        {
            // Fallback security blanket. Normally, the craft() method should have dealt with the request.
            if (currentRequest.getState() == RequestState.IN_PROGRESS)
            {
                job.finishRequest(true);
            }
            currentRequest = null;
        }

        resetValues();
        return super.afterDump();
    }

    @Override
    protected int getActionsDoneUntilDumping()
    {
        return 1;
    }

    /**
     * Get the required progress to execute a recipe.
     *
     * @return the amount of hits required.
     */
    private int getRequiredProgressForMakingRawMaterial()
    {
        return PROGRESS_MULTIPLIER / Math.min(worker.getCitizenData().getJobModifier() + 1, MAX_LEVEL) * HITTING_TIME;
    }

    @Override
    public boolean isAfterDumpPickupAllowed()
    {
        return currentRequest == null;
    }
}
            <div style="color: inherit; fill: inherit;">
                <div style="display: flex;">

0

评论区