-
-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Entity docs #171
base: main
Are you sure you want to change the base?
Entity docs #171
Changes from all commits
312442d
aafbf1b
a748304
4b2d021
c49ff55
242abf0
a4971bd
9950d51
f64b8fe
a1bd87d
31b5bf2
ff5d5b1
965be16
2e65131
1ed292c
e2fbc31
40c17a9
7a24414
55873a1
cdf58f2
380db40
2a369a7
b1e1966
b5a78bb
b6dcbb9
8d54466
90c3b4a
1d17916
99dd0e6
a9b38d5
41f583b
a9937e3
4dd1142
f615ade
773ce6a
ec869d5
12392bc
461206c
859d031
8963971
d4466af
25cc2c1
0bcad78
3f53b81
87938c6
54600a4
930fca6
e0e8020
6316767
83436ba
d1120f5
74eef1c
6c4cd53
7c12eff
84d7574
551bac0
ca9bc33
79bb313
44951b9
2986514
e7ca864
79078a2
7b35abe
110be93
56eef02
6652351
362280b
a1746fe
887ed98
8e8774d
77247ba
fbc75e4
bf4efbe
6dc07d5
aa35a02
2948e60
97bb02e
a6eb49c
71106de
5db64db
8a0900f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,8 +25,8 @@ After registering the block, all references to the new `my_block` should use thi | |
|
||
```java | ||
level.getBlockState(position) // returns the blockstate placed in the given level (world) at the given position | ||
//highlight-next-line | ||
.is(MyBlockRegistrationClass.MY_BLOCK); | ||
//highlight-next-line | ||
.is(MyBlockRegistrationClass.MY_BLOCK); | ||
``` | ||
|
||
This approach also has the convenient effect that `block1 == block2` works and can be used instead of Java's `equals` method (using `equals` still works, of course, but is pointless since it compares by reference anyway). | ||
|
@@ -69,16 +69,16 @@ So for example, a simple implementation would look something like this: | |
```java | ||
//BLOCKS is a DeferredRegister.Blocks | ||
public static final DeferredBlock<Block> MY_BETTER_BLOCK = BLOCKS.register( | ||
"my_better_block", | ||
registryName -> new Block(BlockBehaviour.Properties.of() | ||
//highlight-start | ||
.setId(ResourceKey.create(Registries.BLOCK, registryName)) | ||
.destroyTime(2.0f) | ||
.explosionResistance(10.0f) | ||
.sound(SoundType.GRAVEL) | ||
.lightLevel(state -> 7) | ||
//highlight-end | ||
)); | ||
"my_better_block", | ||
registryName -> new Block(BlockBehaviour.Properties.of() | ||
//highlight-start | ||
.setId(ResourceKey.create(Registries.BLOCK, registryName)) | ||
.destroyTime(2.0f) | ||
.explosionResistance(10.0f) | ||
.sound(SoundType.GRAVEL) | ||
.lightLevel(state -> 7) | ||
//highlight-end | ||
)); | ||
``` | ||
|
||
For further documentation, see the source code of `BlockBehaviour.Properties`. For more examples, or to look at the values used by Minecraft, have a look at the `Blocks` class. | ||
|
@@ -104,7 +104,6 @@ If the block subclass only takes in the `BlockBehaviour.Properties`, then `Block | |
```java | ||
// For some block subclass | ||
public class SimpleBlock extends Block { | ||
|
||
public SimpleBlock(BlockBehavior.Properties properties) { | ||
// ... | ||
} | ||
|
@@ -129,7 +128,6 @@ If the block subclass contains more parameters, then [`RecordCodecBuilder#mapCod | |
```java | ||
// For some block subclass | ||
public class ComplexBlock extends Block { | ||
|
||
public ComplexBlock(int value, BlockBehavior.Properties properties) { | ||
// ... | ||
} | ||
|
@@ -170,28 +168,28 @@ We already discussed how to create a `DeferredRegister.Blocks` [above], as well | |
public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks("yourmodid"); | ||
|
||
public static final DeferredBlock<Block> EXAMPLE_BLOCK = BLOCKS.register( | ||
"example_block", registryName -> new Block( | ||
BlockBehaviour.Properties.of() | ||
// The ID must be set on the block | ||
.setId(ResourceKey.create(Registries.BLOCK, registryName)) | ||
) | ||
"example_block", registryName -> new Block( | ||
BlockBehaviour.Properties.of() | ||
// The ID must be set on the block | ||
.setId(ResourceKey.create(Registries.BLOCK, registryName)) | ||
) | ||
); | ||
|
||
// Same as above, except that the block properties are constructed eagerly. | ||
// setId is also called internally on the properties object. | ||
public static final DeferredBlock<Block> EXAMPLE_BLOCK = BLOCKS.registerBlock( | ||
"example_block", | ||
Block::new, // The factory that the properties will be passed into. | ||
BlockBehaviour.Properties.of() // The properties to use. | ||
"example_block", | ||
Block::new, // The factory that the properties will be passed into. | ||
BlockBehaviour.Properties.of() // The properties to use. | ||
); | ||
``` | ||
|
||
If you want to use `Block::new`, you can leave out the factory entirely: | ||
|
||
```java | ||
public static final DeferredBlock<Block> EXAMPLE_BLOCK = BLOCKS.registerSimpleBlock( | ||
"example_block", | ||
BlockBehaviour.Properties.of() // The properties to use. | ||
"example_block", | ||
BlockBehaviour.Properties.of() // The properties to use. | ||
); | ||
``` | ||
|
||
|
@@ -209,7 +207,7 @@ In several situations, multiple methods of `Block` are used at different times. | |
|
||
### Placing a Block | ||
|
||
Block placement logic is called from `BlockItem#useOn` (or some subclass's implementation thereof, such as in `PlaceOnWaterBlockItem`, which is used for lily pads). For more information on how the game gets there, see the [Interaction Pipeline][interactionpipeline]. In practice, this means that as soon as a `BlockItem` is right-clicked (for example a cobblestone item), this behavior is called. | ||
Block placement logic is called from `BlockItem#useOn` (or some subclass's implementation thereof, such as in `PlaceOnWaterBlockItem`, which is used for lily pads). For more information on how the game gets there, see [Right-Clicking Items][rightclick]. In practice, this means that as soon as a `BlockItem` is right-clicked (for example a cobblestone item), this behavior is called. | ||
|
||
- Several prerequisites are checked, for example that you are not in spectator mode, that all required feature flags for the block are enabled or that the target position is not outside the world border. If at least one of these checks fails, the pipeline ends. | ||
- `BlockBehaviour#canBeReplaced` is called for the block currently at the position where the block is attempted to be placed. If it returns `false`, the pipeline ends. Prominent cases that return `true` here are tall grass or snow layers. | ||
|
@@ -241,11 +239,10 @@ while (leftClickIsBeingHeld()) { | |
} | ||
``` | ||
|
||
The following subsections further break down these stages into actual method calls. | ||
The following subsections further break down these stages into actual method calls. For information about how the game gets from left-clicking to this pipeline, see [Left-Clicking an Item][leftclick]. | ||
|
||
#### The "Initiating" Stage | ||
|
||
- Client-only: `InputEvent.InteractionKeyMappingTriggered` is fired with the left mouse button and the main hand. If the event is canceled, the pipeline ends. | ||
- Several prerequisites are checked, for example that you are not in spectator mode, that all required feature flags for the `ItemStack` in your main hand are enabled or that the block in question is not outside the world border. If at least one of these checks fails, the pipeline ends. | ||
- `PlayerInteractEvent.LeftClickBlock` is fired. If the event is canceled, the pipeline ends. | ||
- Note that when the event is canceled on the client, no packets are sent to the server and thus no logic runs on the server. | ||
|
@@ -281,6 +278,38 @@ The following subsections further break down these stages into actual method cal | |
- Server-only: `BlockDropsEvent` is fired. If the event is canceled, then nothing is dropped when the block breaks. Otherwise, every `ItemEntity` in `BlockDropsEvent#getDrops` is added to the current level. | ||
- Server-only: `Block#popExperience` is called with the result of the previous `IBlockExtension#getExpDrop` call, if that call returned a value greater than 0. | ||
|
||
#### Mining Speed | ||
|
||
The mining speed is calculated from the block's hardness, the used [tool]'s speed, and several entity [attributes] according to the following rules: | ||
|
||
```java | ||
// This will return the tool's mining speed, or 1 if the held item is either empty, not a tool, | ||
// or not applicable for the block being broken. | ||
float destroySpeed = item.getDestroySpeed(); | ||
// If we have an applicable tool, add the minecraft:mining_efficiency attribute as an additive modifier. | ||
if (destroySpeed > 1) { | ||
destroySpeed += player.getAttributeValue(Attributes.MINING_EFFICIENCY); | ||
} | ||
// Apply effects from haste, conduit power, and slowness multiplicatively. | ||
if (player.hasEffect(MobEffects.DIG_SPEED)) { destroySpeed *= ...; } | ||
if (player.hasEffect(MobEffects.CONDUIT_POWER)) { destroySpeed *= ...; } | ||
Comment on lines
+294
to
+295
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is partially wrong. It applies the maximum amplifier from dig speed and conduit power before doing some math stuff. |
||
if (player.hasEffect(MobEffects.DIG_SLOWDOWN)) { destroySpeed *= ...; } | ||
// Add the minecraft:block_break_speed attribute as a multiplicative modifier. | ||
destroySpeed *= player.getAttributeValue(Attributes.BLOCK_BREAK_SPEED); | ||
// If the player is underwater, apply the underwater mining speed penalty multiplicatively. | ||
if (player.isEyeInFluid(FluidTags.WATER)) { | ||
destroySpeed *= player.getAttributeValue(Attributes.SUBMERGED_MINING_SPEED); | ||
} | ||
// If the player is trying to break a block in mid-air, make the player mine 5 times slower. | ||
if (!player.onGround()) { | ||
destroySpeed /= 5; | ||
} | ||
destroySpeed = /* The PlayerEvent.BreakSpeed event is fired here, allowing modders to further modify this value. */; | ||
return destroySpeed; | ||
``` | ||
|
||
The exact code for this can be found in `Player#getDestroySpeed` for reference. | ||
|
||
### Ticking | ||
|
||
Ticking is a mechanism that updates (ticks) parts of the game every 1 / 20 seconds, or 50 milliseconds ("one tick"). Blocks provide different ticking methods that are called in different ways. | ||
|
@@ -306,19 +335,21 @@ Random ticks occur every tick for a set amount of blocks in a chunk. That set am | |
Random ticking is used by a wide range of mechanics in Minecraft, such as plant growth, ice and snow melting, or copper oxidizing. | ||
|
||
[above]: #one-block-to-rule-them-all | ||
[attributes]: ../entities/attributes.md | ||
[below]: #deferredregisterblocks-helpers | ||
[blockentities]: ../blockentities/index.md | ||
[blockstates]: states.md | ||
[bsfile]: ../resources/client/models/index.md#blockstate-files | ||
[codec]: ../datastorage/codecs.md#records | ||
[events]: ../concepts/events.md | ||
[interactionpipeline]: ../items/interactionpipeline.md | ||
[item]: ../items/index.md | ||
[leftclick]: ../items/interactions.md#left-clicking-an-item | ||
[model]: ../resources/client/models/index.md | ||
[randomtick]: #random-ticking | ||
[registration]: ../concepts/registries.md#methods-for-registering | ||
[resources]: ../resources/index.md#assets | ||
[rightclick]: ../items/interactions.md#right-clicking-an-item | ||
[sounds]: ../resources/client/sounds.md | ||
[textures]: ../resources/client/textures.md | ||
[tool]: ../items/tools.md | ||
[usingblocks]: #using-blocks | ||
[usingblockstates]: states.md#using-blockstates |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -120,6 +120,7 @@ graph TD; | |
PlayerEvent-->CanPlayerSleepEvent; | ||
|
||
class Event,BlockEvent,EntityEvent,LivingEvent,PlayerEvent red; | ||
class BlockDropsEvent,CanPlayerSleepEvent blue; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a reason for this in an entity docs PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mainly because this is the first PR that really makes use of Mermaid diagrams. I adopted the style guide of red -> abstract, blue -> non-abstract, and applied it to the only other diagram we had while I was at it. |
||
``` | ||
|
||
### Cancellable Events | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"label": "Entities", | ||
"position": 5 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, this takes in the
BlockState
to determine the destroy speed.