Minecolonies & Automatic Warehouse Sorting

in #utopian-io6 years ago

Hi everyone, I almost forgot to write about this update I merged 11 days ago.
Players have been asking for a long time for a way to automatically sort the warehouse.

Now, sorting the warehouse, in general, can be approached from different points. We could sort chest by chest or we could sort the complete warehosue and distribute things to the right chests.
Now, the first one is rather uninteresting since if the things are not very well distributed they will continue not very well distributed.
While the second one is rather complex since we don't have the same "information" the player has to distribute things evenly.

Based on that I wrote a small greedy algorithm which sorts the chests based on best effort and tries to evenly distributed all the load between all the chests.

Preparation:

First of all, I enhanced the ItemStorage class (our custom item storage which overrides equal and hash correctly and has an unlimited amount) with the creative tab index.

For non Minecraft players: The creative tab index is the tab of items when you are in unlimited item mode where you can find the item.

Since this value is protected within the minecraft classes I used forge reflection to make it public.

Adding it into the src/main/resources/META-INF/minecolonies_at.cfg and rebuilding the project then does the trick.

Then, I added a sort button to the warehouse GUI.

Where I added it first to the XML.

Afterward, I registered the button handler.

Made sure it wouldn't show for low level warehouses.

and then I send a custom message to the server side.

GUI action happens on the client side.

I had to create and register this message then.

The message itself then would search the building in the colony (deny the message if the colony or building are not existent or the player didn't have permission)
then again check if the warehouse is sortable and then query the combined inventory to hand it to the sorting utils.

To make it as generic as possible the sorting utils sorts any kind of combined inventory handler and doesn't care if it is a colony building, a warehouse or something else.

Finally, I had to improved our implementation of the combined inventory handler so I am able to tell where the chest I am currently iterating in ends. (So I can separate between the different inventories).

Before coming to the sorting, I had to fix one small thing in the racks to make sure the combined inventories are handled correct there.

Making sure that the rack always has an inventory handler.

Sorting:

The main method of the sorting process is the static sort method which receives the inventory.

First of all, if the inventory exists, it will iterate through all the slots and extracts the items into a map.

Removing the items from the inventories and sorting the reference.

In the next step it would calculate some stats we will need for the sorting.

The method calculates some stats based on the previously collected map.

The method will basically iterate over all itemStorages, calculate how many total stacks we have (considering that there is a max stack size per item for inventories) and then also return information how many items from how many different creative tabs we have.

final Map<Integer, Integer> creativeTabs = new HashMap<>();
int sum = 0;
for (final Map.Entry<ItemStorage, Integer> entry : map.entrySet())
{
    sum += Math.ceil((double) entry.getValue() / entry.getKey().getItemStack().getMaxStackSize());

    creativeTabs.put(entry.getKey().getCreativeTabIndex(), creativeTabs.getOrDefault(entry.getKey().getCreativeTabIndex(), 0) + (int) Math.ceil((double) entry.getValue() / entry.getKey().getItemStack().getMaxStackSize()));
}

Based on that information we would then order the map and then iterate again over the map and push the items to the inventory.

For that, I wrote a compare function returning, clasically, an integer.
Which receives two itemstorage map entries and then first sorts them by creative tab, then by item id and then by damage value.

Which brings us to the core part, the iterating over the inventories to push it.

The method would receive all information we previously gathered plus information regarding the inventory (as in current slot and max slots).

There we would set a slotLimit variable. Retrieve the stack and retrieve the total size of the item type.

Then, we'd iterate over the item until we inserted all items of this type. (While making sure not to dump into the same slot again since then we'd lose items).

Consequently, we would increase the temporary size, decrement the required slots and decrease the creative tab information.

Finally, after we finished inserting an item we would check if this was the last item of this creative tab. If this is the case we would check on some metric how well we distributed the item over all inventories we have (comparing on how many slots we filled until now compared to how many items we have and how many slots we have available).

And based on that calculate where the next inventory would start.

The End:

I hoped you liked the more technical post today. I can promise you that the next post is going to be a bit more exciting and less backend.

Nevertheless, I had a lot of fun coding this and I bet it's going to make the players lives a lot easier.

See you the next time!

Repository:

https://github.com/ldtteam/minecolonies

Pull Request:

https://github.com/ldtteam/minecolonies/pull/2999

Sort:  

Thanks for the contribution, @raycoms! Cool to see you have implemented a feature that people have been waiting for for a long time!

The quality of the code is really high and the post is very interesting to read as usual, so I don't really have any feedback to give other than: keep up the great work!


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]

Thank you for your review, @amosbastian! Keep up the good work!

Hey @raycoms! Nice to come across a fellow coder here on steemit! I started following you to see more things going on. I have never personally even played minecraft, but the whole ecosystem seems very interesting... :)

Welcome on Steem then =) Coders are always good to have around in these lands

Hello! Your post has been resteemed and upvoted by @ilovecoding because we love coding! Keep up good work! Consider upvoting this comment to support the @ilovecoding and increase your future rewards! ^_^ Steem On!

Reply !stop to disable the comment. Thanks!

Hi @raycoms!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Hey, @raycoms!

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

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

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

Vote for Utopian Witness!

Hi, @raycoms!

You just got a 10.59% upvote from SteemPlus!
To get higher upvotes, earn more SteemPlus Points (SPP). On your Steemit wallet, check your SPP balance and click on "How to earn SPP?" to find out all the ways to earn.
If you're not using SteemPlus yet, please check our last posts in here to see the many ways in which SteemPlus can improve your Steem experience on Steemit and Busy.

Coin Marketplace

STEEM 0.19
TRX 0.13
JST 0.029
BTC 58728.31
ETH 3185.59
USDT 1.00
SBD 2.43