pmmp / PocketMine-MP

A server software for Minecraft: Bedrock Edition in PHP
https://pmmp.io
GNU Lesser General Public License v3.0
3.28k stars 1.55k forks source link

Verification of the placement in the worlds #4856

Closed ShockedPlot7560 closed 2 years ago

ShockedPlot7560 commented 2 years ago

Introduction

Many blocks (most as Flowable) cannot be placed on certain types of blocks. We don't currently have a way for each block to give the surface type for each side.
With this in mind, I would like to know your position after mine to refine this system and potentially move on to a PR. As you can see on the block placement wiki (not necessarily up to date but gives an overview) some blocks only allow some blocks on one side, while they accept others on others. This has the disadvantage that you can't really find a generic placement solution for each of them.

The concept

The system I imagine would be based on 2 functions in particular which would allow each one to provide the size of the surface of the given side. There are two types of notion to understand for the continuation:

With these notions in mind, there would be a function handling each case. Each one would return a float representing the (abstract) size of its face, where 0 represents a non-placable/attachable face and 1 the maximum obtainable. First, getSurfaceSize(int $face) will provide the size of its surfaces with the desired face as parameters. Second, getAttachSize(int $face, ?int $tempFacing = null) will reference the minimum size needed for this block to be placed. Let's imagine a torch with an attachment size of 0.5, a block of earth (1 in surface), can be placed but cannot be placed on a block with 0 or 0.1 area.

So, when we place a block, a check will be made looking at the size of the clicked surface, and the attachment size of the opposite of the current block and will compare them. If the surface is larger than or equal to the attachment, the placement is ok, otherwise the placement is impossible. A dedicated function is most likely to be considered.

Abstract sizes

The difficulty is going to reside there in the definition of constant growing represents a hierarchy of placement. Several manage to distinguish themselves:

  • The signs / banners are placed on the same types of blocks and appear to be the minimum for each side.
  • The torches / lanterns / pressure plates will also behave similarly.
  • ...

All blocks can be grouped according to different criteria

The best would be to start from 0 (zero sizes) and go to 1 (full sizes). With this in mind, torches and other blocks with similar behavior would have a size of 0.5, this size would allow better flexibility.

It would also be correct and simpler, for blocks with hit boxes different than normal, to provide a way to convert it to a float from 0 to 1 to automate the placements and improve backwards compatibility.

Exemple

Taking into account the fact that currently the torches cannot be placed on all possible blocks, here is an example of this possibility.

With these constants in mind, if we set the bottom face of the torch, the face opposite its current facing (or supplied) to 0.5, the rest to 0. This way we can easily place the torch on the fence and the slab but not on the side of the fence for example.

Alternative method

There is no real alternative method to this at present, except to hardcode all possible solutions before placement.

Linked issue :

dktapps commented 2 years ago

This sounds overcomplicated but the basic concept makes sense.

ShockedPlot7560 commented 2 years ago

After some time of reflection, it is true that setting arbitrary values for a certain type of block is not necessarily the right solution.

The principle of having two more dedicated functions in the Block class should be kept because it allows any plugin to modify the behavior of its block. The values should be dynamic according to the collisionboxes (getCollisionBoxes). Thus, from these values, it would be possible to generate a variant between 0 and 1 representing the size of the block surface.

A problem arises for the flowables which are currently the major source of this corective, they have no collision with the players and yet it should be possible to express them. However, we can observe that flowables, for the most part, only need to have their bottom side fully expressed. For example, the repeater can only be placed on top of the blocks. So an override of the basic function would probably be considered to provide only this behavior and this would continue case by case. Torches would add the fact of placement on walls etc...

dktapps commented 2 years ago

I don't think the sizes of the collision box has any meaning in this context. You can place stuff like skulls on top of fences for example.

ShockedPlot7560 commented 2 years ago

That would make it possible to solve many cases, would come over for certain cases, a modification to in particular solve this problem of head on the fence ?

ShockedPlot7560 commented 2 years ago

For all solid blocks in particular

dktapps commented 2 years ago

My analysis of JE suggests that this is handled with 3 types of support:

Name Description
Full The blockface doesn't have any restrictions on support it can provide
Center The blockface may support elements placed in the center (e.g. torch on top of fence)
Edge The blockface may support elements which reach the edges of the block (e.g. rails/repeaters/comparators on top of hoppers, composters and other bucket-shaped blocks)

JE calculates this per block using some complex cross-section AABB logic. For PM I think it would be sufficient to have a getSupportType(Facing) : SupportType method for each block which provides the correct logic, since most blocks don't have complex shapes.

NB: Bedrock is not the same as JE on this, and appears to use some simplified logic. For example, torches may be placed on top of hoppers in Bedrock, but not in JE.

PocketMiner92 commented 2 years ago

You should learn the Logic of BDS and not JE.

dktapps commented 2 years ago

You should learn the Logic of BDS and not JE.

Maybe you should do that instead of making unhelpful comments.

ShockedPlot7560 commented 2 years ago

After starting the implementation to observe the problems that could be caused by this type of logic. This is indeed the three main categories that I could observe. However, as in minecraft actually, the signs, banners can be placed on a larger number of support than the torches or other like lantern. To name a few: anvils, end portals, can only place signs, banners while torches cannot.

This being the case, it would be necessary to add a type that would correspond to torches, banners, with the same principle as the center, but smaller.

dktapps commented 2 years ago

The support-type logic is not the only logic influencing the placeability of blocks.

ShockedPlot7560 commented 2 years ago

Providing a function that allows the blocks to define their support type is necessary. As said before, there would be 3 types that come out (potentially more). However, it is also necessary that the blocks can provide the type of surface needed to place it? Basically, we have a fence, and we want to place a repeter on it. The fence, with its pillar surface type, will not be able to accommodate this repeater, as it requires a solid surface.

dktapps commented 2 years ago

Repeater can only be placed on "full" or "edge" support-type faces. This can be checked in place() like all other placement requirements.

ShockedPlot7560 commented 2 years ago

Indeed, I had not explored this track there