Skip to content

Commit

Permalink
Changes per review
Browse files Browse the repository at this point in the history
  • Loading branch information
legobmw99 committed Jan 15, 2024
1 parent d0dfc1c commit dfe4fc6
Showing 1 changed file with 32 additions and 28 deletions.
60 changes: 32 additions & 28 deletions docs/resources/server/advancements.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ A list of criteria triggers defined by vanilla can be found in `CriteriaTriggers

### Custom Criteria Triggers

Custom criteria triggers can be created by creating a class which implements `SimpleCriterionTrigger<T>` for a class `T` which implements `SimpleCriterionTrigger.SimpleInstance`. Typically, the `SimpleInstance` implementor is a subclass of the class which implements `SimpleCriterionTrigger`.
Custom criteria triggers are made up of two parts: the trigger, which is activated in code at some point you specify by calling `#trigger`, and the instance which defines the conditions under which the trigger should award the criterion. The trigger extends `SimpleCriterionTrigger<T>` while the instance implements `SimpleCriterionTrigger.SimpleInstance`. The generic value `T` represents the trigger instance type.

### SimpleCriterionTrigger.SimpleInstance Subclass
### The SimpleCriterionTrigger.SimpleInstance Implementation

The `SimpleCriterionTrigger.SimpleInstance` represents a single criteria defined in the `criteria` object. Trigger instances are responsible for holding the defined conditions, and returning whether the inputs match the condition.

Conditions are usually passed in through the constructor. The `SimpleCriterionTrigger.SimpleInstance` interface requires only one function, called `player()`, which returns the conditions the player must meet as an `Optional<ContextAwarePredicate>`. If the subclass is a Java record, the automatically generated `player()` method will suffice.
Conditions are usually passed in through the constructor. The `SimpleCriterionTrigger.SimpleInstance` interface requires only one function, called `#player`, which returns the conditions the player must meet as an `Optional<ContextAwarePredicate>`. If the subclass is a Java record with a `player` parameter of this type (as below), the automatically generated `#player` method will suffice.

```java
public record ExampleTriggerInstance(Optional<ContextAwarePredicate> player, ItemPredicate item) implements SimpleCriterionTrigger.SimpleInstance {
Expand All @@ -61,22 +61,13 @@ public record ExampleTriggerInstance(Optional<ContextAwarePredicate> player, Ite
Typically, trigger instances have static helper methods which construct the full `Criterion<T>` object from the arguments to the instance. This allows these instances to be easily created during data generation, but are optional.

```java
// In this example, EXAMPLE_TRIGGER is a DeferredHolder<CriterionTrigger<?>>
public static Criterion<ExampleTriggerInstance> instance(ContextAwarePredicate player, ItemPredicate item) {
return EXAMPLE_TRIGGER.get().createCriterion(new ExampleTriggerInstance(Optional.of(player), item));
}
```
:::

While it could be defined elsewhere, it is also typical to define a [`Codec`][codec] which can serialize this class as a constant in the class.
A codec which can serialize this class must be defined somewhere, as it is required to implement `SimpleCriterionTrigger#codec` and is used to serialize criteria to JSON during data generation and deserialize them during loading.

```java
public static final Codec<ExampleTriggerInstance> CODEC = RecordCodecBuilder.create(instance -> instance.group(
ContextAwarePredicate.CODEC.optionalFieldOf("player").forGetter(ExampleTriggerInstance::player),
ItemPredicate.CODEC.fieldOf("item").forGetter(ExampleTriggerInstance::item)
).apply(instance, ExampleTriggerInstance::new));
```

Finally, a method should be added which takes in the current data state and returns whether the user has met the necessary conditions. The conditions of the player are already checked through `SimpleCriterionTrigger#trigger(ServerPlayer, Predicate)`. Most trigger instances call this method `#matches`.

```java
Expand All @@ -89,22 +80,12 @@ public boolean matches(ItemStack stack) {

### SimpleCriterionTrigger

The `SimpleCriterionTrigger<T>` subclass, where `T` is the type of the trigger instance, is responsible for specifying a codec to serialize `T`s, and supplying a method to check trigger instances and run attached listeners on success.
The `SimpleCriterionTrigger<T>` subclass is responsible for specifying a codec to [serialize] the trigger instance `T` and supplying a method to check trigger instances and run attached listeners on success.

The codec is typically defined as a constant of the inner `SimpleCriterionTrigger.SimpleInstance` class, and simply returned by the trigger's `codec()` method.
The later is done by defining a method to check all trigger instances and run the listeners if their condition is met. This method takes in the `ServerPlayer` and whatever other data defined by the matching method in the `SimpleCriterionTrigger.SimpleInstance` subclass. This method should internally call `SimpleCriterionTrigger#trigger` to properly handle checking all listeners. Most trigger instances call this method `#trigger`.

```java
// in ExampleTrigger
@Override
public Codec<ExampleTriggerInstance> codec() {
return ExampleTriggerInstance.CODEC;
}
```
Finally, a method is defined to check all trigger instances and run the listeners if their condition is met. This method takes in the `ServerPlayer` and whatever other data defined by the matching method in the `SimpleCriterionTrigger.SimpleInstance` subclass. This method should internally call `SimpleCriterionTrigger#trigger` to properly handle checking all listeners. Most trigger instances call this method `#trigger`.
```java
// This method is unique for each trigger and is as such not an override
// This method is unique for each trigger and is as such not a method to override
public void trigger(ServerPlayer player, ItemStack stack) {
this.trigger(player,
// The condition checker method within the SimpleCriterionTrigger.SimpleInstance subclass
Expand All @@ -113,15 +94,37 @@ public void trigger(ServerPlayer player, ItemStack stack) {
}
```

Instances must be registered on the `Registries.TRIGGER_TYPE` registry. Techniques for doing so can be found under [Registries][registration].
Finally, instances must be registered on the `Registries.TRIGGER_TYPE` registry. Techniques for doing so can be found under [Registries][registration].

### Serialization

A [codec] must be defined to serialize and deserialize the trigger instance. Vanilla typically creates this codec as a constant within the instance implementation.

```java
// in ExampleTriggerInstance
public static final Codec<ExampleTriggerInstance> CODEC = RecordCodecBuilder.create(instance -> instance.group(
ExtraCodecs.strictOptionalField(EntityPredicate.ADVANCEMENT_CODEC, "player").forGetter(ExampleTriggerInstance::player),
ItemPredicate.CODEC.fieldOf("item").forGetter(ExampleTriggerInstance::item)
).apply(instance, ExampleTriggerInstance::new));
```

This is then returned by the trigger's `#codec` method.
```java
// in ExampleTrigger
@Override
public Codec<ExampleTriggerInstance> codec() {
return ExampleTriggerInstance.CODEC;
}
```
### Calling the Trigger
Whenever the action being checked is performed, the `#trigger` method defined by the `SimpleCriterionTrigger` subclass should be called.
```java
// In some piece of code where the action is being performed
// Where EXAMPLE_TRIGGER is a supplier for the registered instance of the custom criteria trigger
// Again, EXAMPLE_TRIGGER is a supplier for the registered instance of the custom criteria trigger
public void performExampleAction(ServerPlayer player, ItemStack stack) {
// Run code to perform action
EXAMPLE_TRIGGER.get().trigger(player, stack);
Expand Down Expand Up @@ -159,3 +162,4 @@ When an advancement is completed, rewards may be given out. These can be a combi
[datagen]: ../../datagen/server/advancements.md#advancement-generation
[codec]: ../../datastorage/codecs.md
[registration]: ../../concepts/registries.md#methods-for-registering
[serialize]: #serialization

1 comment on commit dfe4fc6

@neoforged-pages-deployments
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploying with Cloudflare Pages

Name Result
Last commit: dfe4fc6d975b6c00d904f6f7a33ac84087004ecc
Status: ✅ Deploy successful!
Preview URL: https://b7c13c59.neoforged-docs-previews.pages.dev
PR Preview URL: https://pr-45.neoforged-docs-previews.pages.dev

Please sign in to comment.