Minecolonies & PvP System Part #2
Hey everyone as announced previously, due to our planned PvP functionalities one of the core parts of this had to be reworked as well. In this case the guards.
For part 1 of our pvp rework [here].
Now, I actually reworked 3 core parts of the Guard which should make handling them way easier and more efficient to use in combat.
- Rework how guards handle GUIs
- Create a mobile GUI for guard handling.
- Render Patrol/Guard Points
Let's start with the easiest part first.
Rendering Patrol/Guard Points
Our guard can be assigned to patrol or guard a certain position. Previously, there only existed a list of the points in the GUI of the guard.
To do this we added to our client-side render class a new part of the method which detects if the player is holding the guard scepter.
If the player holds it we would use it to get the information of the colony and guard tower from it.
And if the colony exists and at the position, we found a guard tower we can extract all the points from the guard-tower and hand it with a template to the render manager.
if (partolPointTemplate == null)
{
partolPointTemplate = new Structure(null, "schematics/infrastructure/PatrolPoint",
new PlacementSettings().setRotation(BlockUtils.getRotation(Settings.instance.getRotation())).setMirror(Settings.instance.getMirror())).getTemplate();
}
if (hut instanceof AbstractBuildingGuards.View)
{
TemplateRenderHandler.getInstance().drawTemplateAtListOfPositions(((AbstractBuildingGuards.View) hut).getPatrolTargets().stream().map(BlockPos::up).collect(Collectors.toList()), event.getPartialTicks(),
}
The Template renderer will calculate the relative position of the player to calculate the position it has to calculate the blocks at. Then it will calculate the relative position of the block and hand each of these with the template to the draw method.
Previously, the draw method was unable to handle banners so I had to add some additional code. First of all, I have to construct the TileEntity of the Banner from the blockInfo.
Then I can call this method in a stream which goes through all blockInfo blocks, filter them and tries to construct the tileEntity on them. If it is unable to do so it will filter the created null entities and finally call the render method for the TileEntity.
template.blocks.stream().filter(blockInfo -> blockInfo.tileentityData != null).map(b -> constructTileEntities(b, pos)).filter(Objects::nonNull).forEach(tileEntity -> TileEntityRendererDispatcher.instance.render(tileEntity, partialTicks, 0));
GUI:
Then, I created a fancy new GUI which can be accessed from the guard scepter when shift-right-clicking.
This tool can be obtained on the last page of the guard GUI
The first thing I did was generalizing our current code which is responsible for drawing hearts so I can call it from any GUI and add the hearts to any GUI.
For this reason, I made it static and gave it all the necessary data it would need for the job.
This way I can give it any citizenData and any view it should append the generated image to.
Then I created the window class of the new GUI including an adapted version of the GUI XML.
Both the GUI and the window class are almost copies from the Guard GUI with some small changes as extracting not needed methods related to changing the Guard type and the mob attack list as well as some adaptions to make it fit the other window.
Additionally, I added a way to render the data of the worker.
For this, I had to synch the worker id to the building view.
So, serializing it, add the list to the view, add a getter.
And deserializing it.
Additionally, I had to synch the position of the worker over.
Finally, I had to create a data provider for the list which would take the length of the list as the length of the list and then update each element with the data from the citizen creating the health bar.
Additionally, I had to make sure that the tool which previously got the colony data from the position of the player would get the colony data from the tool directly now.
For this reason, I stored this additional information in the tool.
(To be able to control the guards with this stick in other colonies for example.)
In the end, I only had to make sure we open the GUI only if we got all the necessary info in the tool.
Extracting the data from the tool and only opening it when the player right clicks and sneaks.
Armor Requesting:
Finally, the most complicated part. Our guard requesting had a few issues:
a) It was running too often and lagging the clients
b) Not taking the best armor he had
c) Taking all armor he found
d) Not stopping to request the armor at the warehouse.
e) Shield requests didn't have a symbol in the GUI.
The first one was easily solved by only checking it averagely every 60s.
Similarly easy was the last one.
First I had to register it as a tool so it gets detected as a tool.
And second I had to give it a tool-type which we can find if necessary.
Then, for the other 3, I simplified our armor request class to accept a range of levels for the building level and worker level.
Then, I had it extend predicate so we could test on it.
Basically, we would test if the itemStack is of the type we're searching and of the armor level we're searching or if not armor is of the shield type and requested for the main hand (for which we request the shield for).
@Override
public boolean test(final ItemStack stack)
{
return (ItemStackUtils.hasToolLevel(stack, itemNeeded, armorLevel, armorLevel) && stack.getItem() instanceof ItemArmor && ((ItemArmor) stack.getItem()).armorType == getType()) || (stack.getItem() instanceof ItemShield && getType() == EntityEquipmentSlot.MAINHAND);
}
Then I created a helper class which builds requests so we wouldn't have to build several requests manually if we would like the same for all armor pieces.
Which would reduce the code where we previously had 30 lines to build the request. down to 1 line per gear level.
Then, I created some helper methods to find all viable slots for a given request in an inventory.
For that, we need one method to go through all inventory providers (like entities and buildings).
And the second one would actually build the list for each slot in the itemhandler.
Then I created some methods which enable us to cancel certain request types if we notice we got the item already.
Now, let's go to the central part of the rework.
Guard now, on prepare will go first through all items they might need and build a list based on their level and based on the building level including all possible armor parts they might wear.
Then, for each type of tool, they would do a bunch of checks.
First, they'd search for the best tool they have in their inventory matching the specifications.
Then they'd do the same thing for all chests connected to their building.
And finally, they'd compare the results, move the item from the chest to their inventory if they found anything better, put it in the list to wear and transfer all not needed items of this type back to the building chest.
Now, every 60s in average the guard would reset his armor, check if the armor he should wear is still there if so, it would cancel all requests for this armor type and wear the armor.
If it didn't find it it would request all armor it couldn't find.
Also, to make the code nicer I moved archer specific code from the abstract guard to the archer and knight specific code to the knight class.
Previously, the abstract class was very cluttered with specialized code.
Conclusion:
This new update should make our guard handling in war situations way more efficient and at the same time make sure that the guards always receive the armor they need and do not overload the system with unnecessary requests.
I hope you are liking our progress. Until the next time!
Pull Requests:
https://github.com/ldtteam/minecolonies/pull/2770
https://github.com/ldtteam/minecolonies/pull/2764
https://github.com/ldtteam/minecolonies/pull/2779
Thank you for your contribution. A lot of work has been done and a very good contribution.
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, @codingdefined!
So far this week you've reviewed 6 contributions. Keep up the good work!
well done my friend, very nice.
Hi @raycoms! We are @steem-ua, a new Steem dApp, computing UserAuthority for all accounts on Steem. We are currently in test modus upvoting quality Utopian-io contributions! Nice work!
Very interesting project, keep up the good work!
Posted using Partiko Android
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!
Thanks a lot, this is very informative. There are humans in this platform pretending to provide information and click on-baiting customers. But this put up honestly packs a punch with all this information. well played sir.