[Feedback] Testing 224 - Crop growth times

I guess my point is that the system would have to know the current state of the crop, regardless of linear growth or ‘chanced based’ growth.

If the crop is at stage 5, why do you need to keep the data for stage 1-4?

Or if each day has a 50% chance to go to the next stage, why would the system require more information if it has 100% chance?

I’m not arguing for or against using a chance based crop progression here, I’m just saying the the reason stated above doesn’t seem logical.

The data cannot be the same because Luca explained there is something else needed. I myself don’t understand the specifics so in some way it might not sound logical but I trust that it IS logical because of what they put in place.

I’d lean to @Kirinvar and the explanation he provided. The additional counter is needed and that extends the data you are tracking. While this isn’t a big deal it means somewhere at some other time you have to account for that data and space that you used up earlier.

So if you do this and make the executive decision that just to give people a consistent growth signal and things people are asking for here at some point another game feature will have to be limited because you used up all your bits.

There is a set amount of data that can be stored. The developers have the huge task of trying to manage this limitation and only add data where it is absolutely needed. That means putting in systems that might not be as ideal as they want but they cannot risk running out of this limited space or the game development stops.

As an example - this is why we only have a few rotations and a few patterns that deco blocks can make. They can’t go too far or they will use up their limited space.

This is an area where the community needs to understand and make a compromise to protect the game instead of putting their interests ahead of the game. Luca isn’t stupid… so he put a system in that could work decently as best as it could considering the constraints they have.

2 Likes

OK, I think I’m starting to get it.

Rather than each plant having its own individual growth ‘stages’ (as had been my thinking), there is a set of universal growth stages that all plants follow, the only difference being the visuals.

And to create variation in growing times using the universal rules, each type of crop has a different percent chance to advance to the next stage each ‘day’.

@Xaldafax I’d kindly ask if you are quoting me again, to please make sure you contextualise correctly, the quote you used makes it seem like I was making a statement, rather than asking a question, as you lifted part of the question and not the whole thing, which changes the tone of my post significantly. Thanks

1 Like

Yeah sorry about that… I was trying to address a specific thing and didn’t want to confuse that, but I can see how it might confuse the other side!

I’m thinking that universal stuff is more inline with what is happening. They must not have had an easy way to do the tracking of day 1, 2, 3, etc without taking up more bits. And since the bit space is like one of the most important thing to manage they have to just make concessions and make a simpler system in one way.

I’m not sure I like the variance either… I think I will just focus on planting and coming back X amount of time later and just accepting the return after I play with optimization. Instead of trying to micromanage a RNG game mechanic… probably give me way too much grey hair.

1 Like

Generally speaking, anything block-based has 8 bits to play with for encoding extra state, eg chiselling blocks uses “all” of those bits to encode the different shape/orientiations of the shapes.

In some cases, we use extra block-ids where those bits aren’t sufficient, eg texture-rotation (because chiselling already uses all the 8 extra bits) uses 3 extra block-ids instead.

For crops, that means that as a base, we have 8 bits to play with.

3 bits are used for fertilizing. There are 3 types of fertilizer (including the “none” type for when not fertilized at a ll) (2 bits) and also a skill that makes fertilizing “better” (1 bit).

That leaves 5 bits for other things, which we use to store the stage of the crop growth for a maximum of 32 stages. Currently we only use up to 8 stages (so 3 bits), but @james is playing with having in-between stages of growth for more visual variance; and noting that more stages means less variance in the growth process (will “act” less randomnly).

Now, crops tick once per day, and say we have a crop which we want to be fully grown in 225 days (fuel crops have this expected growth time); how would you do that? either you need to store the day that the crop was planted so that you can evaulate “current day - day crop was planted” to know how longs its been… but storing that “day” would need a “lot” more than just 5 bits, it would need more like 5 bytes since servers can live for a long time; so it would make more sense to store “how old is the crop (in days)” which involves much smaller numbers, and then each game-day when the crop is ticked, it will just increment that value. For 225 days, that requires 8 bits… but we already used 3 of them for fertilizer. Also note that the (not yet released) prestige crops have an expected-growth time as it stands of 420 game-days + a wither expected time of 1260 game-days which would mean storing a counter up to 1680 needing 11 bits… but lets ignore that for now.

Now, we might be able to use block-ids to get those 8 bits, we need 3 more bits, which means using 8 block-ids instead of 1, but there’s another problem, which is that there are things like lighting/liquid/block conditions/fertilizer that can effect the growth rate, speeding it up or slowing it down, and if we wanted no RNG, then we actually need much more precision in that tick value than “1 day”… we would need something more like “1/32th of a day” meaning another 5 bits for extra precision, and now suddenly instead of an extra 8 block ids, we actually need 256 block-ids… and if we go back to the unreleaed prestige crop, we would need 2048 block-ids which I hope you can agree is a bit much… but there is “another” problem… which is that fertilizer also has a life time (currently 12 hours = 30 game-days) so need another 5bits, and now instead we need 8192 block ids, or 65536 block ids for the unreleased prestige crops… which is more than the entire range of the block-id datatype to begin with… aka this is just not feasible to “not” have rng with a block-data based system… so what else is there? Well we could make it an entity-based system so that there is an entire entity for every single crop… but then we would have to severely limit how many crops can be placed as it would be far too expensive to have huge fields of crops where every crop has entity data to be stored and maintained (and sent to clients! eek bandwidth…)

So instead, introduce RNG, and instead of storing “days since planted” we just store a much smaller value that can fit, which is the “growth stage”, and there is a probability of advancing to the next stage each day based on the desired average growth time, this is a poisson process which gives an accurate “expected” growth time for all the crops without worrying about precision, but as with any RNG is a law of large numbers and sometimes you get very good RNG rolls and the crop will mature “much faster” than its expected growth time (yay!) and sometimes much slower (boo!).

(There is also an entirely non-technical side to the RNG of crops… which is that it just looks better (visually; opinion) to see a field of crops grow somewhat stochastically instead of advancing exactly like a machine, and also gives a reason to be more pro-active in maintaining your crops, checking for those whose fertilizer has run out quicker than expected to fertilize again and get the best rng rolls on growth, or checking for those that have matured more quickly for an early harvest etc.)

17 Likes

i get the system would be nuts without it but you can also see why we are panicking. the forge rng is the thing of nightmares and keeps alot of people away form doing it and now we got to deal with that for mats that we would need for pies and such depending on how bad it is we could see a noticeable drop in the food usage form people just not wanting to have to deal with even 1 season of bad rng and now all of a sudden sometihing super common like teaching pies goes the way of forged tools where only a select few that have the patience to make them do.

its a question of scale here though. If you were just planting a single crop and then sat there waiting for it to grow… then yeh I agree rng is horrific. but when you have a small field full of crops, it doesnt really matter if 1 or 2 crops continuously hit a cycle of bad rng and dont mature for longer, when the reset of the field fully matured (and parts of it matured even more quickly), especially when you can “plant and forget” if you want and you arent consuming valuable resources in the process of growing crops like with forging too.

yea and thats the thing with it when i was runing it tho my head i was thinking like a backyard garden 1 maybe 2 plots big cuz if you are a builder starting out leveling is brutal(my main was only 42 when i quit after 5 months or so of playing) even more so if you are solo player(due to the fact that some professions like mineing makeing next to no xp till you hit end game and no longer really need it) i did not start getting any buffer cubits till my late 20’s mid 30’s and for sure would not have had any to spare to build a 10-25 plot big farm so a lot of mid tier players are going to only have 3 or 4 crop farm.

1 Like

even with 1 plot you can have hundreds of crops, I dont even see the point in doing farming at all if you only have 3 or 4 crops…

4 Likes

1 plot gets you less than 64 plants. Unless you ignore optimization, then you get exactly 64 with a greatly reduced yield. For a single smart stack of mats you are look at 8 plots with room for optimizing blocks.

2 Likes

ok i was messing up bad then the little test i ran i only got 30 on 1 plot i guess i was thinking minecraft logic and did not try to see how many i could shove in there

No, you are right. With optimizing blocks you are looking at about 30 blocks of actual plants. Tho you can get crazy with ramp planting to make the most use of the 8 by 8 cube.

How are fields ticking in their planting order, are you storing some kind of timestamp when it was last ticked, or planting time? I don’t think the ticking always happens at midnight.

I did some tests and I’m not sure what to think of the data, the number of ready crops doesn’t follow the poisson distribution as well as I had thought.

Number of crops ready as time goes on

expectedDays = 80
cropStages = 8
success = Math.random() < expectedDays / cropStages / 100;
image
Field fully grown in 211 ticks

Multiple runs

Field fully grown, took 211 ticks to complete
Field fully grown, took 194 ticks to complete
Field fully grown, took 211 ticks to complete
Field fully grown, took 193 ticks to complete
Field fully grown, took 183 ticks to complete
Field fully grown, took 180 ticks to complete
Field fully grown, took 203 ticks to complete

Just to confirm it’s not a design issue, but a programming one? Showing the players the worst case scenarios in the tooltips would also make less frustrated players. If it says 18 hours and it’s not ready after 3 days I wouldn’t like it.

If you keep count of failed growth attempts (this growth stage only, in the case of a 10 day/stage crop it’s taking up 5 bits), cutting that tail is possible. Probably you can come up with a more intricate one, if you store some kind of a time stamp it’d become a lot easier.

success = Math.random() < expectedDays / cropStages / 600 + expectedDays / cropStages / 300 * failedAttempts;
image

All graphs made with Boundless Grow Simulator

edit: I know storing the failed count isn’t realistic as the size can be much larger, I was just trying to see how it’d affect the curve. There should be a more efficient way of achieving the same.

2 Likes

You can squeeze a lot more than 30 optimal plants into a plot if you utilize the space better… but where is the fun in single plot farms? I want to build towering hydroponic stacks and sprawling fields of flooded rice paddies. Dozens, maybe hundreds of plots. It would be silly if plant’s code was so complex that I was restricted to farms that were dwarfed by the average workshop.

1 Like

I want to say thank you for this very in depth and informative response, I really appreciate that you took the time.

Especially as it probably feels like telling a 5 year old how electricity works!

4 Likes

Each simulation cell (16x16x16) has a timestamp of when it was last updated for crops, and there are 24 buckets the crops are sorted into based on placement time (modulo crop cycle) so that crops placed within 1 minute of eachother will update at the same time, then the crops placed in the next minute and so forth; mostly this is about reducing the amount of work done per-frame since its unlikely “every crop” in the cell is placed into the same bucket, but also means that you never have a case of placing a crop and then it “instantly” ticking, it’ll always tick 23-24minutes later and then every 24th minute from then on.

cant see the code of your simulator, but based on your “Math.random()” line, that is only the case of 1 tick, its possible for the crop to go any number of ticks in a single update (just much less likely), the tick is more like:

L = deltaTime * growthStages / timeToMature;
u = random();
p = s = exp(-L);
for (i = 0; stage < growthStages && u > s; ++stage)
{
  p *= L / ++i;
  s += p;
}
2 Likes

That will be improved in the next update; no crop-simulation time was being lost, but the fast-forwarding functioned so that some crops may not have done their fast-forward for nearly 24 minutes in the worst-case; all crops will tick once to fast-forward when revisting within roughly 12 seconds in the next update.

3 Likes

Not sure I implemented it correctly but it didn’t change much. The code is in https://boundless.mayumi.fi/farming/simulator/javascript.js tickArray()

I wasn’t sure what your deltaTime contains, I’m assuming it’s for retroactively ticking multiple times?

js code
let stage = arr[x][y]; // current growth stage
let growthStages = cropStages.length; // crop total growth stage count
let L = growthStages / expectedDays;
let u = Math.random();
let p = s = Math.exp(-L);
for(let i = 0; stage < growthStages && u > s; ++stage)
{
    p *= L / ++i;
    s += p;
    arr[x][y]++; // stage is not a reference for some javascript reason
}

The curve didn’t change much, but I’d presume the average number of ticks went down. Sample size is too small to say really.

image

Field fully grown, took 200 ticks to complete
Field fully grown, took 193 ticks to complete
Field fully grown, took 192 ticks to complete
Field fully grown, took 249 ticks to complete
Field fully grown, took 195 ticks to complete
Field fully grown, took 207 ticks to complete
Field fully grown, took 191 ticks to complete
Field fully grown, took 212 ticks to complete

1 Like

well what do you mean by it doesnt follow poisson? that by definition is poisson; the loop is generating a stage increment according to the poisson distribution with parameter L.

yes the deltaTime is for fast-forwarding.