Hey everyone, in my last post here I added the ability to move certain buildings.
While this is a great feature it has some missing pieces to it.
Mainly: The builder will rebuild the building at another place but will leave the old structure in place.
Therefore, it would be better to tell the builder to deconstruct the old building first and then reconstruct it at the new location/rotation.
For this, I had to adapt two central parts of our code.
First of all, I had to add a destroy stage in the structure handling code which will destroy the structure independently of the world block at that location.
Second, I had to adapt our workOrder handling to accept these kind of requests.
WorkOrders are requests for structure manipulation which are handled by the colony and can be assigned to certainw orkers.
I'll break this down into 3 main tasks:
- Additional WorkOrders
- Destroy Stage
- Refactoring
Additional WorkOrders:
First of all, I created a bunch of new WorkOrders for the more specific cases.
I created 3 new types of orders.
- One for removal
- One for building
- One for the miner (will be explained in step 3)
In Object Oriented Programming it is considered bad style to create instances of super classes.
An example would be, we have animal classes like "Lion" or "Dog" of which we can create objects, but it would be weird to create an object of "Animal" which is too generic.
That's why I also created an explicit Build workorder.
The workOrder to destroy a building is called "WorkOrderBuildRemoval".
This means, the order is never cleared (it has to clear the building always) and it is always valid (even if the building doesn't exist anymore).
It receives the building details and level details of the building it is supposed to clear.
The next one is the explicit building order which is only a clone of the super class.
The last one is a miner workOrder. Its orders are handled like decoration but require the building of the miner as an additional parameter.
Last but not least I created an utility method in the WorkManager to be able to query orders of specific types.
To be able to do that I created a generic "W" which the method receives and which it uses to check the instance and to cast the object it will return.
Then I create a stream of all orders and filter them.
In this case, we only want unassigned orders which are of the certain type.
Last but not least we sort the list by priority.
Destroy Stage:
The destroy stage is a quite simple part.
For this to work I have to add code at a few different locations.
- In the Structure AI class
- In the Structure class
- In the Builder class
For that, I had to add a new AIStage to our stages file and
then I had to add an additional target in the structure AI class to connect it.
I connected it directly with the clear step since the clear step already removes any block it finds. How exactly this will work I'll explain a bit later on.
In the next step, I added the removal step also in the switching stage method so the structure stage gets added correctly.
As you can see we store the stage in the AI and in the structure.
We do this since the AI stages do not persist, they are temporary. Therefore, when the worker has to restart the structure he is working on will remember the stage it was in.
if (isAlreadyCleared() || (!currentStructure.getStage().equals(Structure.Stage.CLEAR) && !currentStructure.getStage().equals(Structure.Stage.REMOVE)))
{
return true;
}
Additionally, I had to a way to make sure that if the structure stage is removal we never pull over the removal step.
In the next step, I added to the builder that he does not automatically stop constructing if the order has no building since it might be a removal request.
public AIState switchStage(final AIState state)
{
if (job.getWorkOrder() instanceof WorkOrderBuildRemoval && state.equals(BUILDING_STEP))
{
return COMPLETE_BUILD;
}
return super.switchStage(state);
}
Then, I overrode the switch stage method so he always completes the order after the removal request and does not start constructing yet.
Then, inside the Structure code, I had to add some additional code.
First of all, I added the new stage to the structure.
And then I created the method which will iterate through the blocks.
The clear stage will compare the world block with the structure block and only clear blocks which are not equal to the structure.
The removal step will want to remove all blocks which aren't air.
This way we're able to reuse the clearing code just giving it a different input
And last but not least, on the creation of a build request after moving a building we first create a removal order and then the actual order.
While debugging this I found a fix for our duplicated workers:
On recall, we now check if the citizen really exists in the world and if not we assign the correct worker to it and do not duplicate one by creating a new one with the same abilities.
Refactoring:
Now, to get all of the above to work correctly I had to rework the workOrder code quite strongly.
First of all, I enabled the miner to use workOrders as well, this way he will now work stateful in his mines and will remember what shaft he was working on.
Additionally, he will know which structure he is actually working on which enables him to request the full amount of materials for each structure.
For this, to work I extracted the order code of the builder building, job and AI into generic AI, building and job classes.
Therefore I called the AI class:
public abstract class AbstractEntityAIStructureWithWorkOrder<J extends AbstractJobStructure> extends AbstractEntityAIStructure<J>
The job:
and the building:
And moved their code out of the builder specific classes in the abstract classes.
After that, I had to change the builder and miner classes to extend these specific classes.
Not to forget the window class to be able to serialize the data over to the client for the all potentially using workers as well.
In the next step, due to these additional work orders, I moved the assignment code from the colony assigning the workers to orders to each worker assigning a order to himself.
This will allow us in the future to let a player decide individually on each worker which tasks he want to allow the worker to assign to itself.
For that, I created this abstract method in the building class.
Which, first of all, the miner will implement and assign all work orders which are connected to his building to himself.
And in the next step the builder.
The builder will get all building and removal as well as decoration orders.
And then compare its distance to other workers in the colony.
If he detects that another builder which is able to do the job is unoccupied and closer to the building site, he will deny to accept it (since the other builder will probably accept it in a few seconds).
This also means that one builder can work on the removal job while the other starts to reconstruct the building.
This third step was a lot of work since I had to move a lot of code around and adapt a lot of code at a bunch of locations to make sure the integration will work for the new workers as well as for the old ones.
I hope you liked our new update. This fixes a whole bunch of problems we had with the miner since he forgot what he is working on and didn't know how many he needed of each material as well as it allows the players to move buildings without having to deconstruct the old building manually.
Posted on Utopian.io - Rewarding Open Source Contributors
Thank you for the contribution. It has been approved
Need help? Write a ticket on https://support.utopian.io.
Chat with us on Discord.
[utopian-moderator]
I’d love to be able to program Minecraft Mods or Plugins. Where did you learn to apply programming to Minecraft and how has it helped your skills as a developer? @raycoms
That's a nice question. I actually found this mod in an extremely early stage of development 4-5 years during my Bachelor. I already knew a bit of java so I just started contributing and became now the main contributor of the mod. I think developing it has seriously shaped my skills as a developer, on the one side due to programming in java and using tools like gradle, teamcity, sonar, git, etc but as well due to working in a team, and within the team working my way up to the maintainer up to being the responsible for development.
Sorry to ask more but I really am interested. Were the other programmers experienced when you just started and did they help you learn how to program more efficiently and effectively? I currently program a little myself, but I’m just wondering if you have others there’s to help you through problems it can help.
Yes, during the project we had a whole bunch of experienced programmers. Some of the game industry, some with general industry experience for over 20 years and some which were just more actively developing things than me at the time.
Additionally, people always have different experiences, therefore, a project like that helps to bundle those experiences of several people and everyone can learn from everyone in the end.
I would say that this post is awesome !! nice piece of code and nice feature !! would really love to see it in action !! keep it up !!
Drear @raycoms excellent post. Thank you very much.
Hey @raycoms! Thank you for the great work you've done!
We're already looking forward to your next contribution!
Fully Decentralized Rewards
We hope you will take the time to share your expertise and knowledge by rating contributions made by others on Utopian.io to help us reward the best contributions together.
Utopian Witness!
Vote for Utopian Witness! We are made of developers, system administrators, entrepreneurs, artists, content creators, thinkers. We embrace every nationality, mindset and belief.
Want to chat? Join us on Discord https://discord.me/utopian-io
Cuando veo éstas cosas solo sé que no sé nada.