Extra Hard Mode

Extra Hard Mode

63.1k Downloads

Crops death

SlimeDog opened this issue ยท 16 comments

commented

Spigot 1.13.2 latest
EHM 3.13.beta (second release)

I have three farm plots near the world spawn. Until recently, the crops never died, but at least once since 3.13.alpha3, crops died and changed to dead bushes (I do not know the release in which it occurred).

Test method: I have a skript that replaces dirt with farmland, and replaces dead bushes with appropriate crops. Since running the skript, I have waited IRL hours for more crop death. No crops have been replaced. I have been logged on the entire period, in the relevant chunks, although occasionally I slipped into AFK.

What is the algorithm and cycle for crop death?

config.yml (business bits)

ExtraHardMode:
...
  Farming:
    Weak Crops:
      Enable: true
      Loss Rate: 25
 ...
commented

It checks every time a block grows from what I recall

commented

Hmmm. Within what radius? Since all of these crops are fully mature, there will be no local growth. It might be better on an occasional timer.

I'll set some to a lesser maturity and report back.

commented

It's for that specific block. It determines if it should die when that block grows.

Before it used to do it ~data value 7, which is about when crops would mature. But since other crops mature a lot sooner (data value 3) I moved it to greater than or equal to 2.

commented

The growing crops were affected. Adjacent fully-mature crops were not (consistent with ^^^).

IIRC, in 1.12.2 versions, fully-mature crops were affected.

commented

As for the original issue - what is the expected result? It seems your skript is replacing the dead bushes or something...? Not sure what the result should be.

commented

My skript is replacing the dead bushes on demand, for testing purposes. In production, they are left to player manipulation.

The desired result (for me) is that fully-matured crops are targeted for death. So I guess that is a feature request.

commented

Feature request... as in for crops that are fully matured, continually test if they should die over time?

Not sure of a good way to do this other than scan each chunk for crop blocks on chunk load.

commented

public void onBlockGrow(BlockGrowEvent event)
{
World world = event.getBlock().getWorld();
final boolean weakCropsEnabled = CFG.getBoolean(RootNode.WEAK_FOOD_CROPS, world.getName());
// FEATURE:
if (weakCropsEnabled && plugin.getModuleForClass(BlockModule.class).plantDies(event.getBlock(), event.getNewState().getData()))
{
event.setCancelled(true);
//shrub gets removed on farmland
event.getBlock().getRelative(BlockFace.DOWN).setType(Material.DIRT);
event.getBlock().setType(Material.DEAD_BUSH); // dead shrub
}
}

Which calls

/**
* Check if the given plant at the block should die.
*
* @param block - Block to check.
* @param newDataValue - Data value to replace.
*
* @return True if plant should die, else false.
*/
public boolean plantDies(Block block, MaterialData newDataValue)
{
World world = block.getWorld();
final boolean weakFoodCropsEnabled = CFG.getBoolean(RootNode.WEAK_FOOD_CROPS, world.getName());
final int lossRate = CFG.getInt(RootNode.WEAK_FOOD_CROPS_LOSS_RATE, world.getName());
final boolean aridDesertsEnabled = CFG.getBoolean(RootNode.ARID_DESSERTS, world.getName());
if (weakFoodCropsEnabled)
{
// not evaluated until the plant is nearly full grown
//For some plants (netherwart, beetroot), this is at data value 3.
//TODO: 1.13
if (newDataValue.getData() >= 2)
{
Material material = block.getType();
if (material == Material.WHEAT || material == Material.CARROTS || material == Material.POTATOES || material == Material.BEETROOTS)
{
int deathProbability = lossRate;
// plants in the dark always die
if (block.getLightFromSky() < 10)
{
deathProbability = 100;
} else
{
Biome biome = block.getBiome();
// the desert environment is very rough on crops
if ((biome == Biome.DESERT || biome == Biome.DESERT_HILLS) && aridDesertsEnabled)
{
deathProbability += 50;
}
// unwatered crops are more likely to die
Block belowBlock = block.getRelative(BlockFace.DOWN);
byte moistureLevel = 0;
if (belowBlock.getType() == Material.FARMLAND)
{
moistureLevel = belowBlock.getData();
}
if (moistureLevel == 0)
{
deathProbability += 25;
}
}
if (plugin.random(deathProbability))
{
return true;
}
}
}
}
return false;
}

where newDataValue.getData() >= 7 in EHM 3.12.1

Not sure what you mean by in 1.12.2 that fully-mature crops (assuming we're talking about wheat crops) were affected - it only occurred to crops growing to full maturity (if they were already mature, no BlockGrowEvent is called on them).

commented

Hmmm. Checking 1.12.2 test server...

So perhaps my memory is faulty. I cannot get any dead bushes on my 1.12.2 server. :(

In any event, I trust your reading of the code.

commented

Yes, although that raises a few issues:

  • Growth-tick level: Since beetroot matures at age=3, but the other crops at age=7, beetroot is much less likely than the others to die, when checked for age>=2 at growth-ticks. The check should really be crop dependent, for example at age>=(maturityAge-2).
  • Growth-tick loss rate: With the default loss rate (25 percent), the cumulative probability of death for carrots, potatoes, and wheat is a near certainty by maturity. So the default growth-tick loss rate may need to be adjusted.
  • Mature crop check frequency and loss rate: The frequency and loss rate of mature crops checks should be separately configurable, so that everything doesn't die too quickly.
commented

Ok I'm not sure what you're asking for now.

Do you want the crop death check to occur on the respective block's final growth phase (so each crop has an equal chance of dying no matter its type) or all the time based on a fixed time interval for all crops in loaded chunks?

commented

I apologize for being unclear. I was exploring/considering the consequences of the various options, not deciding on one, assuming we were in a conversation.

My preference would be to provide three options:

  1. Check at only the final growth change. That gives each plant one change to die through its growth cycle. It is equivalent to the 1.12.x behavior with the exception of beetroot, which never died since it never made the transition from age=6 to age=7. Consequently, beetroot must be implemented as an exception, to account for its different maturity age.
  2. Check at every growth change. This means that carrots, potatoes, and wheat are more likely to die than beetroot, which is not ideal. It is a little harder to explain, but (probably) easiest to implement.
  3. Check periodically. The negative of the first two options is that crops never die once mature. The beauty of this option is that crops are always at hazard, regardless of their growth status.

I suppose (1) should be the default, since it is consistent with the 1.12.behavior. Personally, I would configure a combination of (2) and (3), so that seedings are at some risk, but mature plants are also at risk.

The configuration to allow all three would look something like:

  Farming:
    # Convert crops to dead bushes and farmland to dirt, based on growth stage or a periodic timer.
    Weak Crops:
      # Final growth stage only
      # If this check is enabled, each seedling will have one chance to die.
      # Mature plants will never die.
      # This is the default.
      Kill Plants At Final Growth Stage:
        Enable: true
        Loss Rate Percentage: 21
      # If this check is enabled, seedlings will have 7 chances to die before maturity,
      # except beetroot seedlings will have only 3 chances to die before maturity.
      # The loss rate should be 1/7 of the final stage loss rate.
      # Mature plants will never die.
      Kill Plants At Any Growth Stage:
        Enable: false
        Loss Rate Percentage: 3
      # If this check is enabled, each plant will have many chances to die, even after maturity.
      # Consequently, the period should be infrequent and the loss rate should be very small.
      Kill Plants Periodically:
        Enable: false
        Period In Minutes: 10
        Loss Rate Percentage: 1
commented

Yea, it's fine to discuss the consequences too. Just didn't know which one you preferred c:

I think it'll be easiest if I provide a config option to specify which "mode" since it wouldn't make too much sense (IMO) to have all three or any combination enabled. Could be something like mode 1, 2 or 3 or could be a string identifier such as crop death occurs at: "maturity" "growth" "anytime". Thoughts?

commented

Considering ^^ further, I think you are right, and that I would just use (3), which puts seedlings, young plants, and mature plants at risk. So please give it a go. Note that "anytime" will require a period specification, while the others will not.

I look forward to it.

commented

Well anytime would require a lot of work, since it can't just listen to an event, but has to be a task continually checking blocks in loaded chunks.

If you want you can add an issue for that 3rd option. (And another for the 2nd, if you'd like.) In the meantime I'll fix properly for original behavior (evaluation on block growth).

commented

Pe that code, we have check on maturity (6->7 except 2->3 for beetroot). I will open a ticket for (2). (3) I can live without.