Minecolonies & The Progress Manager

in #utopian-io6 years ago (edited)

Minecolonies & The Progress Manager

Hey everyone, one thing we had noticed was that one of the main issues we have with our userbase is user retention. This means that we got a ton of people playing our modification but a lot of people give up early on because they don't get how it works.

To improve this we created a 3 phase work plan.

  • Guidance System
  • Achievement System
  • Ingame Books

In this post, I will cover the first of the 3. I also call it:

The Progress Manager:

The progress Manager basically tracks the progress of a colony and prints useful tips on the way to guide the player to develop a healthy colony.

Examples are as the above screenshot shows the placement of the colony but also placement of other buildings, spawning of colonists, the building of buildings etc.

How it is Implemented:

The first thing I did was creating an Enum for all progress types.

And then following that I designed the interface of all methods I am going to need.
For that, I took the enum and tried to figure out which events they have in common to figure out which events we're going to need to support.

Following that I added the principal methods of it:

Trigger:

To trigger the progress type to notify the player.

TogglePrintProgress:

To make sure the player can turn these messages on and off.

Read and Write from and to NBT

Methods to persist the data.

IsPrintingProgress

To check if it is turned on or off.

The progress methods in general divide then into the right subevents.
As the progress build building message which will then trigger the right enum value.

And reading and writing stores and reads it from NBT to persist it over a longer period of time.

The trigger method on the other hand checks if progress should be printed and if so it checks if it triggered it already.
If not it will print the progress and store it as triggered.

After that, I had to add the progress handler hooks into the respective classes and add a button to the town hall to turn it on and off.
For that, I also needed a message to synch this to the server.

Builder improvements

Besides, that people were complaining about the builder not being very efficient so I gave him an overhaul.

In this sense I changed two principal parts:

#1 Improve his positioning to be more realistic
#2 Picking up all blocks he will need for the building.

For the first one, I update the walk to construction site method to be more specific for the builder. So he updates the position if he is too far or too close to the block is building at.


    @Override
    public boolean walkToConstructionSite(final BlockPos targetPos)
    {
        if (workFrom == null || MathUtils.twoDimDistance(targetPos, workFrom) < MIN_DISTANCE || MathUtils.twoDimDistance(targetPos, workFrom) > ACCEPTANCE_DISTANCE)
        {
            workFrom = getWorkingPosition(targetPos);
        }
         return worker.isWorkerAtSiteWithMove(workFrom, MAX_DISTANCE) || MathUtils.twoDimDistance(worker.getPosition(), workFrom) < ACCEPTANCE_DISTANCE;
    }
    

And then I update the position finding the code to calculate a block in distance to the block he is trying to place on a block where he can stand.
So I get the general location of the building.
I use this to find a reasonable y level to start checking and a useable y level to stop checking.
Then I calculate the direction from which the worker will approach it.

After that, I'd do a range search around these variables.

The second was a bit more complicated.

For it, I created a new state for the builder which would be picking up.
And I created two new methods which define what he should do after certain actions.

So, after a requested pickup he would start dumping all blocks he won't need.

And after the dumping he would pick up all the blocks he is going to need.
To define the block he is going to need we query the list of required items in his building and then go into a pickup stage for each of them if we don't have a similar item in the inventory already or if our inventory is not full.

/**
 * State to pick up material before going back to work.
 * @return the next state to go to.
 */
public AIState pickUpMaterial()
{
    final BuildingBuilder building = getOwnBuilding();
    final List<Predicate<ItemStack>> neededItemsList = new ArrayList<>(building.getRequiredItemsAndAmount().keySet());
    if (neededItemsList.size() <= pickUpCount || InventoryUtils.openSlotCount(new InvWrapper(worker.getInventoryCitizen())) < MIN_OPEN_SLOTS)
    {
        pickUpCount = 0;
        return START_WORKING;
    }
     needsCurrently = neededItemsList.get(pickUpCount);
    pickUpCount++;
    return GATHERING_REQUIRED_MATERIALS;
}

In the gather stage, it would then search this item in all chests which are connected to his building and following that path to it and pick the item up.

Structure Progress:

The new walking around made him a bit less efficient though, that's why I had the idea to store his progress.
Unfortunately, until now, reloading the world would make the builder start over which is a bit stupid (also because just teleporting away would cause that as well).

So I created three new variables in the building of the builder.
a) The last progress position
b) The stage he was at
c) A counter.

So, on each progress, he would add the progress position, make sure to save this every 50 progress positions (to avoid spending too much CPU time on saving) and resetting it also when the building would be ready.

In the structure AI he would then retrieve this position and set it on structure loading:

I also made sure to reset it on structure cancellation.

And, finally, I needed to get this information from and to the structure.
So, I had to add getters and setters there as well.

Other fixes:

Besides that, I fixed a bug where the deliveryman would try to gather from the warehouse (players didn't like that one too much).
By excluding it from the gather calc.

final List<AbstractBuilding> buildings = worker.getCitizenColonyHandler().getColony().getBuildingManager().getBuildings().values().stream()
                                                   .filter(building -> !(building instanceof BuildingWareHouse || building instanceof BuildingTownHall || building.isBeingGathered()))
                                                   .collect(Collectors.toList());

Besides that, I fixed that blocks get always registered to the required blocks list when the builder notices he needs them (Because else he would dump them right back after picking them up).

So always when he requests a block he will check if he has it in his list, and if not would request it.

I hope this will make our builder a bit more stable and as well more interesting to watch, at the same time it should help binding players to us as well.

See you the next time!

Pull Requests:
https://github.com/ldtteam/minecolonies/pull/2781
https://github.com/ldtteam/minecolonies/pull/2801
https://github.com/ldtteam/minecolonies/pull/2807
https://github.com/ldtteam/minecolonies/pull/2812

Sort:  
  • Great job on the post. You are talking us on your journey of development and I find that fascinating.
  • Also, who's the man?

Besides that, I fixed a bug where the man would try to gather from the warehouse (players didn't like that one too much).

  • You have a bot that seems to not like literals in conditions, is that a real issue?

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Oh, I meant the deliveryman =D I gotta fix that in the text.
About the literals. I feel this always depends on the case.
Random literals in the code should always have a constant which explains it.

But in this particular case, we're counting up the amount of citizens spawned, so creating a literal for each of it would just be a hastle.

Thank you for your review, @helo!

So far this week you've reviewed 2 contributions. Keep up the good work!

Hi @raycoms! We are @steem-ua, a new Steem dApp, computing UserAuthority for all accounts on Steem. Starting from the witnesses, UA propagates from user to user based on its followers until equilibirum is reached. We are currently in test modus upvoting quality contributions with a high UA value (UA_author + UA_post)! Your UA_post value is 8.327.

Interesting idea but misleading name as authorities are used as a name for key permissions.

hi @reggaemuffin, how are you? I am from Venezuela I am starting in this community I would like your support very much, I do not ask upvote just that if some publication of my blog you like to support me you would be helping me and my family thank you and apologize for the inconvenience.

Hey @raycoms
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

User guides made by the users themselves are very important in any community, because more than you or anyone who's just "just" a user, they know what troubles are ran into the most.

I suggest a guide creation guide contest with good prizes, maybe money. Not only you will end up with really good YouTube tutorials, but it will help raise brand awareness.

I'm actually at the moment running a youtube series about how to get started with minecolonies, I'm 10 episodes in already.
Thanks =)

I thought so, but I still find the community involvement to be very important, so do consider something that involves the players. I'm glad development is running smoothly. :)

yeah, we actually even have some contests planned. More info we'll probably publish in the next weeks

Coin Marketplace

STEEM 0.27
TRX 0.12
JST 0.031
BTC 68526.92
ETH 3726.80
USDT 1.00
SBD 3.73