Skip to content

Commit

Permalink
Merge branch 'main' into fix-message_id-damagetype
Browse files Browse the repository at this point in the history
  • Loading branch information
starforcraft authored Nov 16, 2024
2 parents 8df8097 + 7fe01bd commit c9dfac2
Show file tree
Hide file tree
Showing 159 changed files with 19,798 additions and 2,563 deletions.
4 changes: 2 additions & 2 deletions docs/advanced/_category_.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"label": "Advanced Topics",
"position": 12
"label": "Advanced Topics",
"position": 12
}
18 changes: 9 additions & 9 deletions docs/advanced/accesstransformers.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ Access Transformers need to be declared in `build.gradle`. AT files can be speci
// In build.gradle:
// This block is where your mappings version is also specified
minecraft {
accessTransformers {
file('src/main/resources/META-INF/accesstransformer.cfg')
}
accessTransformers {
file('src/main/resources/META-INF/accesstransformer.cfg')
}
}
```

Expand All @@ -35,10 +35,10 @@ Additionally, multiple AT files can be specified and will be applied in order. T
```groovy
// In build.gradle:
minecraft {
accessTransformers {
file('src/main/resources/accesstransformer_main.cfg')
file('src/additions/resources/accesstransformer_additions.cfg')
}
accessTransformers {
file('src/main/resources/accesstransformer_main.cfg')
file('src/additions/resources/accesstransformer_additions.cfg')
}
}
```

Expand Down Expand Up @@ -135,8 +135,8 @@ public net.minecraft.util.Crypt$ByteArrayToKeyFunction
protected-f net.minecraft.server.MinecraftServer random
# Makes public the 'makeExecutor' method in Util,
# accepting a String and returns an ExecutorService
public net.minecraft.Util makeExecutor(Ljava/lang/String;)Ljava/util/concurrent/ExecutorService;
# accepting a String and returns a TracingExecutor
public net.minecraft.Util makeExecutor(Ljava/lang/String;)Lnet/minecraft/TracingExecutor;
# Makes public the 'leastMostToIntArray' method in UUIDUtil,
# accepting two longs and returning an int[]
Expand Down
5 changes: 2 additions & 3 deletions docs/advanced/extensibleenums.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ The parameters can be specified in three ways with limitations depending on the

- Inline in the JSON file as an array of constants (only allowed for primitive values, Strings and for passing null to any reference type)
- As a reference to a field of type `EnumProxy<TheEnum>` in a class from the mod (see `EnumProxy` example above)
- The first parameter specifies the target enum and the subsequent parameters are the ones to be passed to the enum constructor
- The first parameter specifies the target enum and the subsequent parameters are the ones to be passed to the enum constructor
- As a reference to a method returning `Object`, where the return value is the parameter value to use. The method must have exactly two parameters of type `int` (index of the parameter) and `Class<?>` (expected type of the parameter)
- The `Class<?>` object should be used to cast (`Class#cast()`) the return value in order to keep `ClassCastException`s in mod code.
- The `Class<?>` object should be used to cast (`Class#cast()`) the return value in order to keep `ClassCastException`s in mod code.

:::warning
The fields and/or methods used as sources for parameter values should be in a separate class to avoid unintentionally loading mod classes too early.
Expand All @@ -117,7 +117,6 @@ Further action is required depending on specific details about the enum:
- If the enum has an int ID parameter which should match the entry's ordinal, then the enum should be annotated with `@NumberedEnum` with the ID's parameter index as the annotation's value if it's not the first parameter
- If the enum has a String name parameter which is used for serialization and should therefore be namespaced, then the enum should be annotated with `@NamedEnum` with the name's parameter index as the annotation's value if it's not the first parameter
- If the enum is sent over the network, then it should be annotated with `@NetworkedEnum` with the annotation's parameter specifying in which direction the values may be sent (clientbound, serverbound or bidirectional)
- Warning: networked enums will require additional steps once network checks for enums are implemented in NeoForge
- If the enum has constructors which are not usable by mods (i.e. because they require registry objects on an enum that may be initialized before modded registration runs), then they should be annotated with `@ReservedConstructor`

:::note
Expand Down
282 changes: 282 additions & 0 deletions docs/advanced/featureflags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
# Feature Flags

Feature flags are a system that allows developers to gate a set of features behind some set of required flags, that being registered elements, gameplay mechanics, data pack entries or some other unique system to your mod.

A common use case would be gating experimental features/elements behind a experimental flag, allowing users to easily switch them on and play around with them before they are finalized.

:::tip
You are not forced to add your own flags. If you find a vanilla flag which would fit your use case, feel free to flag your blocks/items/entities/etc. with said flag.

For example in `1.21.3` if you were to add to the set of Pale Oak wood blocks, you'd only want those to show up if the `WINTER_DROP` flag is enabled.
:::

## Creating a Feature Flag

To create new Feature flags, a JSON file needs to be created and referenced in your `neoforge.mods.toml` file with the `featureFlags` entry inside of your `[[mods]]` block. The specified path must be relative to the `resources` directory:

```toml
# In neoforge.mods.toml:
[[mods]]
# The file is relative to the output directory of the resources, or the root path inside the jar when compiled
# The 'resources' directory represents the root output directory of the resources
featureFlags="META-INF/feature_flags.json"
```

The definition of the entry consists of a list of Feature flag names, which will be loaded and registered during game initialization.

```json5
{
"flags": [
// Identifier of a Feature flag to be registered
"examplemod:experimental"
]
}
```

## Retrieving the Feature Flag

The registered Feature flag can be retrieved via `FeatureFlagRegistry.getFlag(ResourceLocation)`. This can be done at any time during your mod's initialization and is recommended to be stored somewhere for future use, rather than looking up the registry each time you require your flag.

```java
// Look up the 'examplemod:experimental' Feature flag
public static final FeatureFlag EXPERIMENTAL = FeatureFlags.REGISTRY.getFlag(ResourceLocation.fromNamespaceAndPath("examplemod", "experimental"));
```

## Feature Elements

`FeatureElement`s are registry values which can be given a set of required flags. These values are only made available to players when the respective required flags match the flags enabled in the level.

When a feature element is disabled, it is fully hidden from the player's view, and all interactions will be skipped. Do note that these disabled elements will still exist in the registry and are merely functionally unusable.

The following is a complete list of all registries which directly implement the `FeatureElement` system:

- Item
- Block
- EntityType
- MenuType
- Potion
- MobEffect

### Flagging Elements

In order to flag a given `FeatureElement` as requiring your Feature flag, you simply pass it and any other desired flags into the respective registration method:

- `Item`: `Item.Properties#requiredFeatures`
- `Block`: `BlockBehaviour.Properties#requiredFeatures`
- `EntityType`: `EntityType.Builder#requiredFeatures`
- `MenuType`: `MenuType#new`
- `Potion`: `Potion#requiredFeatures`
- `MobEffect`: `MobEffect#requiredFeatures`

```java
// These elements will only become available once the 'EXPERIMENTAL' flag is enabled

// Item
DeferredRegister.Items ITEMS = DeferredRegister.createItems("examplemod");
DeferredItem<Item> EXPERIMENTAL_ITEM = ITEMS.registerSimpleItem("experimental", new Item.Properties()
.requiredFeatures(EXPERIMENTAL) // mark as requiring the 'EXPERIMENTAL' flag
);

// Block
DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks("examplemod");
// Do note that BlockBehaviour.Properties#ofFullCopy and BlockBehaviour.Properties#ofLegacyCopy will copy over the required features.
// This means that in 1.21.3, using BlockBehaviour.Properties.ofFullCopy(Blocks.PALE_OAK_WOOD) would have your block require the 'WINTER_DROP' flag.
DeferredBlock<Block> EXPERIMENTAL_BLOCK = BLOCKS.registerSimpleBlock("experimental", BlockBehaviour.Properties.of()
.requiredFeatures(EXPERIMENTAL) // mark as requiring the 'EXPERIMENTAL' flag
);

// BlockItems are special in that the required features are inherited from their respective Blocks.
// The same is also true for spawn eggs and their respective EntityTypes.
DeferredItem<BlockItem> EXPERIMENTAL_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(EXPERIMENTAL_BLOCK);

// EntityType
DeferredRegister<EntityType<?>> ENTITY_TYPES = DeferredRegister.create(Registries.ENTITY_TYPE, "examplemod");
DeferredHolder<EntityType<?>, EntityType<ExperimentalEntity>> EXPERIMENTAL_ENTITY = ENTITY_TYPES.register("experimental", registryName -> EntityType.Builder.of(ExperimentalEntity::new, MobCategory.AMBIENT)
.requiredFeatures(EXPERIMENTAL) // mark as requiring the 'EXPERIMENTAL' flag
.build(ResourceKey.create(Registries.ENTITY_TYPE, registryName))
);

// MenuType
DeferredRegister<MenuType<?>> MENU_TYPES = DeferredRegister.create(Registries.MENU, "examplemod");
DeferredHolder<MenuType<?>, MenuType<ExperimentalMenu>> EXPERIMENTAL_MENU = MENU_TYPES.register("experimental", () -> new MenuType<>(
// Using vanilla's MenuSupplier:
// This is used when your menu is not encoding complex data during `player.openMenu`. Example:
// (windowId, inventory) -> new ExperimentalMenu(windowId, inventory),

// Using NeoForge's IContainerFactory:
// This is used when you wish to read complex data encoded during `player.openMenu`.
// Casting is important here, as `MenuType` specifically expects a `MenuSupplier`.
(IContainerFactory<ExperimentalMenu>) (windowId, inventory, buffer) -> new ExperimentalMenu(windowId, inventory, buffer),

FeatureFlagSet.of(EXPERIMENTAL) // mark as requiring the 'EXPERIMENTAL' flag
));

// MobEffect
DeferredRegister<MobEffect> MOB_EFFECTS = DeferredRegister.create(Registries.MOB_EFFECT, "examplemod");
DeferredHolder<MobEffect, ExperimentalMobEffect> EXPERIMENTAL_MOB_EEFECT = MOB_EFFECTS.register("experimental", registryName -> new ExperimentalMobEffect(MobEffectCategory.NEUTRAL, CommonColors.WHITE)
.requiredFeatures(EXPERIMENTAL) // mark as requiring the 'EXPERIMENTAL' flag
);

// Potion
DeferredRegister<Potion> POTIONS = DeferredRegister.create(Registries.POTION, "examplemod");
DeferredHolder<Potion, ExperimentalPotion> EXPERIMENTAL_POTION = POTIONS.register("experimental", registryName -> new ExperimentalPotion(registryName.toString(), new MobEffectInstance(EXPERIMENTAL_MOB_EEFECT))
.requiredFeatures(EXPERIMENTAL) // mark as requiring the 'EXPERIMENTAL' flag
);
```

### Validating Enabled Status

In order to validate if features should be enabled or not, you must first acquire the set of enabled features. This can be done in a variety of ways, but the common and recommended method is `LevelReader#enabledFeatures`.

```java
level.enabledFeatures(); // from a 'LevelReader' instance
entity.level().enabledFeatures(); // from a 'Entity' instance

// Client Side
minecraft.getConnection().enabledFeatures();

// Server Side
server.getWorldData().enabledFeatures();
```

To validate if any `FeatureFlagSet` is enabled, you can pass the enabled features to `FeatureFlagSet#isSubsetOf`, and for validating if a specific `FeatureElement` is enabled, you can invoke `FeatureElement#isEnabled`.

:::note
`ItemStack` has a special `isItemEnabled(FeatureFlagSet)` method. This is so that empty stacks are treated as enabled even if the required features for the backing `Item` do not match the enabled features. It is recommended to prefer this method over `Item#isEnabled` where possible.
:::

```java
requiredFeatures.isSubsetOf(enabledFeatures);
featureElement.isEnabled(enabledFeatures);
itemStack.isItemEnabled(enabledFeatures);
```

## Feature Packs

_See also: [Resource Packs](../resources/index.md#assets), [Data Packs](../resources/index.md#data) and [Pack.mcmeta](../resources/index.md#packmcmeta)_

Feature packs are a type of pack that not only loads resources and/or data, but also has the ability to toggle on a given set of feature flags. These flags are defined in the `pack.mcmeta` JSON file at the root of this pack, which follows the below format:

```json5
{
"features": [
"enabled": [
// Identifier of a Feature flag to be enabled
// Must be a valid registered flag
"examplemod:experimental"
]
]
}
```

There are a couple of ways for users to obtain a feature pack, namely installing them from an external source as a datapack, or downloading a mod that has a built-in feature pack. Both of these then need to be installed differently depending on the [physical side](../concepts/sides.md).

### Built-In

Built-in packs are bundled with your mod and are made available to the game using the `AddPackFindersEvent` event.

```java
@SubscribeEvent
public static void addFeaturePacks(final AddPackFindersEvent event) {
event.addPackFinders(
// Path relative to your mods 'resources' pointing towards this pack
// Take note this also defines your packs id using the following format
// mod/<namespace>:<path>`, e.g. `mod/examplemod:data/examplemod/datapacks/experimental`
ResourceLocation.fromNamespaceAndPath("examplemod", "data/examplemod/datapacks/experimental"),

// What kind of resources are contained within this pack
// 'CLIENT_RESOURCES' for packs with client assets (resource packs)
// 'SERVER_DATA' for packs with server data (data packs)
PackType.SERVER_DATA,

// Display name shown in the Experiments screen
Component.literal("ExampleMod: Experiments"),

// In order for this pack to load and enable feature flags, this MUST be 'FEATURE',
// any other PackSource type is invalid here
PackSource.FEATURE,

// If this is true, the pack is always active and cannot be disabled, should always be false for feature packs
false,

// Priority to load resources from this pack in
// 'TOP' this pack will be prioritized over other packs
// 'BOTTOM' other packs will be prioritized over this pack
Pack.Position.TOP
);
}
```

#### Enabling in Singleplayer

1. Create a new world.
2. Navigate to the Experiments screen.
3. Toggle on the desired packs.
4. Confirm changes by clicking `Done`.

#### Enabling in Multiplayer

1. Open your server's `server.properties` file.
2. Add the feature pack id to `initial-enabled-packs`, separating each pack by a `,`. The pack id is defined during registering your pack finder, as seen above.

### External

External packs are provided to your users in datapack form.

#### Installation in Singleplayer

1. Create a new world.
2. Navigate to the datapack selection screen.
3. Drag and drop the datapack zip file onto the game window.
4. Move the newly available datapack over to the `Selected` packs list.
5. Confirm changes by clicking `Done`.

The game will now warn you about any newly selected experimental features, potential bugs, issues and crashes. You can confirm these changes by clicking `Proceed` or `Details` to see an extensive list of all selected packs and which features they would enable.

:::note
External feature packs do not show up in the Experiments screen. The Experiments screen will only show built-in feature packs.

To disable external feature packs after enabling them, navigate back into the datapacks screen and move the external packs back into `Available` from `Selected`.
:::

#### Installation in Multiplayer

Enabling Feature Packs can only be done during initial world creation, and they cannot be disabled once enabled.

1. Create the directory `./world/datapacks`
2. Upload the datapack zip file into the newly created directory
3. Open your server's `server.properties` file
4. Add the datapack zip file name (excluding `.zip`) to `initial-enabled-packs` (separating each pack by a `,`)
- Example: The zip `examplemod-experimental.zip` would be added like so `initial-enabled-packs=vanilla,examplemod-experimental`

### Data Generation

_See also: [Datagen](../resources/index.md#data-generation)_

Feature packs can be generated during regular mod datagen. This is best used in combination with built-in packs, but it is also possible to zip up the generated result and share it as an external pack. Just choose one, i.e. don't provide it as an external pack and also bundle it as a built-in pack.
```java
@SubscribeEvent
public static void gatherData(final GatherDataEvent event) {
DataGenerator generator = event.getGenerator();
// To generate a feature pack, you must first obtain a pack generator instance for the desired pack.
// generator.getBuiltinDatapack(<shouldGenerate>, <namespace>, <path>);
// This will generate the feature pack into the following path:
// ./data/<namespace>/datapacks/<path>
PackGenerator featurePack = generator.getBuiltinDatapack(true, "examplemod", "experimental");
// Register a provider to generate the `pack.mcmeta` file.
featurePack.addProvider(output -> PackMetadataGenerator.forFeaturePack(
output,
// Description displayed in the Experiments screen
Component.literal("Enabled experimental features for ExampleMod"),
// Set of Feature flags this pack should enable
FeatureFlagSet.of(EXPERIMENTAL)
));
// Register additional providers (recipes, loot tables) to `featurePack` to write any generated resources into this pack, rather than the root pack.
}
```
4 changes: 2 additions & 2 deletions docs/blockentities/_category_.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"label": "Block Entities",
"position": 6
"label": "Block Entities",
"position": 6
}
10 changes: 10 additions & 0 deletions docs/blockentities/ber.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,16 @@ public static void registerClientExtensions(RegisterClientExtensionsEvent event)
`IClientItemExtensions` are generally expected to be treated as singletons. Do not construct them outside `RegisterClientExtensionsEvent`!
:::
Finally, the item has to know that it should use the BEWLR for its rendering. This is done by having the final [`BakedModel`][bakedmodel] return true for `#isCustomRenderer`. The easiest way to do this is to have the [item model JSON][model] with a `parent` of `minecraft:builtin/entity`:
```json5
// In some item model file assets/<mod_id>/models/item/<registry_name>.json
{
"parent": "minecraft: builtin/entity",
// ...
}
```
[block]: ../blocks/index.md
[blockentity]: index.md
[event]: ../concepts/events.md#registering-an-event-handler
Expand Down
4 changes: 2 additions & 2 deletions docs/blockentities/container.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ public class MyBackpackContainer extends SimpleContainer {
And voilà, you have created an item-backed container! Call `new MyBackpackContainer(stack)` to create a container for a menu or other use case.

:::warning
Be aware that `Menu`s that directly interface with `Container`s must `#copy()` their `ItemStack`s when modifying them, as otherwise the immutability contract on data components is broken. To do this, NeoForge provides the `StackCopySlot` class for you.
Be aware that menus that directly interface with `Container`s must `#copy()` their `ItemStack`s when modifying them, as otherwise the immutability contract on data components is broken. To do this, NeoForge provides the `StackCopySlot` class for you.
:::

## `Container`s on `Entity`s
Expand Down Expand Up @@ -306,7 +306,7 @@ When iterating over the inventory contents, it is recommended to iterate over `i
[block]: ../blocks/index.md
[blockentity]: index.md
[component]: ../resources/client/i18n.md#components
[datacomponent]: ../items/datacomponents.mdx
[datacomponent]: ../items/datacomponents.md
[item]: ../items/index.md
[itemstack]: ../items/index.md#itemstacks
[menu]: ../gui/menus.md
Loading

0 comments on commit c9dfac2

Please sign in to comment.