Skip to content

Commit

Permalink
Add more Curios docs
Browse files Browse the repository at this point in the history
  • Loading branch information
TheIllusiveC4 committed Sep 17, 2023
1 parent 898ca80 commit 116f24f
Show file tree
Hide file tree
Showing 12 changed files with 508 additions and 11 deletions.
88 changes: 88 additions & 0 deletions docs/curios/Developing with Curios/APIs/renderer-interface.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
sidebar_position: 1
---

# `ICurioRenderer`

## Methods

* [Reference](#reference)
* [render()](#render)
* [static translateIfSneaking()](#static-translateifsneaking)
* [static rotateIfSneaking()](#static-rotateifsneaking)
* [static followHeadRotations()](#static-followheadrotations)
* [static followBodyRotations()](#static-followbodyrotations)

## Reference

### `render()`
---
Runs the rendering code when an associated item is equipped in a curio slot and the visibility of the rendering is
enabled. An equipped cosmetic item will override the rendering of its related functional item.

**Parameters:**

|Name|Type|Description|
|-----------|-----------|-----------|
|`stack`|`ItemStack`|`ItemStack` being rendered|
|`slotContext`|`SlotContext`|`SlotContext` for the slot with the `ItemStack` being rendered|
|`poseStack`|`PoseStack`|`PoseStack` passed from the parent `RenderLayer`|
|`renderLayerParent`|`RenderLayerParent`|`RenderLayerParent` passed from the parent `RenderLayer`|
|`light`|integer|Light value|
|`limbSwing`|float|Limb swing value|
|`limbSwingAmount`|float|Limb swing amount value|
|`partialTicks`|float|Partial ticks value|
|`ageInTicks`|float|Age in ticks value|
|`netHeadYaw`|float|Net head yaw value|
|`headPitch`|float|Head pitch value|

### `static translateIfSneaking()`
---
Applies a translation to the given `PoseStack` if the given `LivingEntity` is crouching. This is called to have the
render appropriately adjust its positioning up or down based on the crouching status of the entity.

**Parameters:**

|Name|Type|Description|
|-----------|-----------|-----------|
|`poseStack`|`PoseStack`|`PoseStack` passed from the parent `RenderLayer`|
|`livingEntity`|`LivingEntity`|`LivingEntity` to check `isCrouching()`|

### `static rotateIfSneaking()`
---
Applies a rotation to the given `PoseStack` if the given `LivingEntity` is crouching. This is called to have the
render appropriately adjust its rotations based on the crouching status of the entity. Specifically, these rotations
are based on the body/torso rotations of the entity.

**Parameters:**

|Name|Type|Description|
|-----------|-----------|-----------|
|`poseStack`|`PoseStack`|`PoseStack` passed from the parent `RenderLayer`|
|`livingEntity`|`LivingEntity`|`LivingEntity` to check `isCrouching()` and rotate around|

### `static followHeadRotations()`
---
Applies rotations to the given `ModelPart`s based on the given `LivingEntity` and its head rotations. This is called to
render the model parts in alignment with the entity's head. This does nothing if the entity's renderer does not
implement `LivingEntityRenderer` or if the model does not have a head inherited from the `HumanoidModel` class.

**Parameters:**

|Name|Type|Description|
|-----------|-----------|-----------|
|`livingEntity`|`LivingEntity`|`LivingEntity` to align the rotations around|
|`modelParts`|`ModelPart...`|List of model parts to align to the head movement|

### `static followBodyRotations()`
---
Applies rotations to the given `HumanoidModel`s based on the given `LivingEntity` and its rotations. This is called to
render the model parts in alignment with the entity's movements, such as their leg and arm movements when walking or
interacting with objects.

**Parameters:**

|Name|Type|Description|
|-----------|-----------|-----------|
|`livingEntity`|`LivingEntity`|`LivingEntity` to align the rotations around|
|`models`|`HumanoidModel...`|List of model parts to align to the body movement|
142 changes: 142 additions & 0 deletions docs/curios/Developing with Curios/curio-creation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
---
sidebar_position: 2
---

# Creating a Curio

A tutorial on how to attach curio capabilities to your items.

## Overview
---
Curios comes with interfaces that you can attach to your items in order to define certain behaviors for those items when
interacting with curios slots. This includes events such as ticking while in a curio slot or triggering certain actions
when equipped or unequipped into a curio slot.

There are three main ways to implement the capability on your item: directly attaching an `ICurio` implementation as a
capability, extending the `ICurioItem` interface on your item, or registering an `ICurioItem` implementation to an item.

Only **one** of these methods needs to be implemented for the curio item to work.

## Attaching an `ICurio` capability
---
This is recommended for mods that are Forge-oriented, due to the use of capabilities, and want to attach the
capability optionally to their own items or another mod's items.

To attach the capability to your own items, override the `IForgeItem#initCapabilities` method:
```java
@Override
public ICapabilityProvider initCapabilities(ItemStack stack, CompoundTag unused) {
return CuriosApi.createCurioProvider(new ICurio() {

@Override
public ItemStack getStack() {
return stack;
}

@Override
public void curioTick(SlotContext slotContext) {
// ticking logic here
}
});
}
```
The `ICurio` implementation in the example can be replaced or extended by your own custom implementation. The
implementation can also exist in a separate class altogether as long as the instantiation is still done in the
`IForgeItem#initCapabilities` method.

To attach the capability to any item, including vanilla's and other mods', subscribe to the
`AttachCapabilitiesEvent<ItemStack>` and use its methods:
```java
@SubscribeEvent
public void attachCapabilities(AttachCapabilitiesEvent<ItemStack> evt) {
ItemStack stack = evt.getObject();
Item item = stack.getItem();
evt.addCapability(CuriosCapability.ID_ITEM, CuriosApi.createCurioProvider(new ICurio() {

@Override
public ItemStack getStack() {
return stack;
}

@Override
public void curioTick(SlotContext slotContext) {
// ticking logic here
}
}));
}
```

:::note
You will need to pass in the `ItemStack` from the `IForgeItem#initCapabilities` argument or the
`AttachCapabilitiesEvent#getObject` result to the return of `ICurio#getStack` as shown in the example. This makes sure
that the implementation receives the correct `ItemStack` for further curios logic. Technically, `ICurio#getStack` can
return any stack if proxies are needed, but the use-case for that is outside the scope of this documentation.
:::

## Implementing the `ICurioItem` interface
---
This is recommended for mods that want the simplest and most straightforward method, do not mind having Curios as a
required dependency, and are only working with their own items.

To implement the `ICurioItem` interface, simply implement it on your item class:
```java
public class CurioItem extends Item implements ICurioItem {

public CurioItem() {
super(new Item.Properties().stacksTo(1).defaultDurability(0));
}

@Override
public void curioTick(SlotContext slotContext, ItemStack stack) {
// ticking logic here
}
}
```

## Registering an `ICurioItem` implementation
---
This is recommended for multi-loader mods as a platform-agnostic method of registering Curios behavior to their own
items or another mod's items that can be loaded optionally.

To register an `ICurioItem` implementation, first create the implementation:
```java
public class CurioItem implements ICurioItem {

@Override
public void curioTick(SlotContext slotContext, ItemStack stack) {
// ticking logic here
}
}
```

And then register it by using `CurioApi#registerCurio`:
```java
CuriosApi.registerCurio(CurioModItems.MY_ITEM, new CurioItem());
```

Registration can occur at any time, but for simplicity can be called during the `FMLCommonSetupEvent` phase during mod
loading:

```java
@Mod("CurioMod")
public class CurioMod {

public CurioMod() {
final IEventBus eventBus = FMLJavaModLoadingContext.get().getModEventBus();
eventBus.addListener(this::setup);
}

private void setup(final FMLCommonSetupEvent evt) {
CuriosApi.registerCurio(CurioModItems.MY_ITEM, new CurioItem());
}
}
```

## Priority
---
In situations where multiple implementations are registered to the same item, there a few things to take note of:
* Only one implementation will be used on any one item, any other implementations found will be ignored.
* `ICurio` capabilities initialized through `IForgeItem#initCapabilities` will always be prioritized and other
implementations will be ignored.
* `ICurioItem` implementations registered through `CuriosApi#registerCurio` will be prioritized over `ICurioItem`
implementations directly on the item class.
84 changes: 84 additions & 0 deletions docs/curios/Developing with Curios/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
sidebar_position: 1
---

# Setting Up the Development Environment

A tutorial on how to set up your development workspace to work with Curios API interfaces and methods.

## Set up your build script
---
### Add repository

First, add the repository hosting the Curios API files by adding the following to your build script's
`repositories` block:

```gradle
repositories {
maven {
name = "Illusive Soulworks maven"
url = "https://maven.theillusivec4.top/"
}
}
```

### Add dependencies

Secondly, add the Curios API dependencies to your build script's `dependencies` block:

```gradle
dependencies {
// Compile against only the API artifact
compileOnly(fg.deobf("top.theillusivec4.curios:curios-forge:${curios_version}:api"))
// Use the full Curios API jar at runtime
runtimeOnly(fg.deobf("top.theillusivec4.curios:curios-forge:${curios_version}"))
}
```

:::note
**Why compile against only the API artifact?**

Compiling against only the API artifact is recommended because the artifact only contains the public API packages,
interfaces, and methods. These are all intended to be stable and will not break within the same major version if used.
The same cannot be said about internal packages and methods, which may accidentally be used if the full jar is included
during compile time. Including the full jar at runtime still means that testing can occur normally in development.

If there is an internal package and or method you would like to use, please make a suggestion on the [issue tracker](https://github.com/TheIllusiveC4/Curios/issues)
so that it may potentially be included in the public API.
:::

### Configure runs for mixin

Finally, since Curios uses mixins, your run configurations will need to ensure that the remapping functions correctly:

```gradle
property 'mixin.env.remapRefMap', 'true'
property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
```

Add the above code block into each of the run configurations that you plan on using, for example:

```gradle
runs {
client {
property 'mixin.env.remapRefMap', 'true'
property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
}
}
```

Remember to regenerate the run configurations after changing the settings.

## Select a version
---
If you followed the steps above, `${curios_version}` should be defined so that it is replaced by the specific Curios API
version that you want to use. This property can be set up by including a mapping in the `gradle.properties` file located
in the same directory as the `build.gradle` file.

Please see [CurseForge](https://www.curseforge.com/minecraft/mc-mods/curios/files), [Modrinth](https://modrinth.com/mod/curios/versions),
or the [maven](https://maven.theillusivec4.top/top/theillusivec4/curios/curios-forge/) for possible versions.

Example in `gradle.properties`:
```
curios_version=5.3.1+1.20.1
```
64 changes: 64 additions & 0 deletions docs/curios/Developing with Curios/rendering-registry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
sidebar_position: 8
---

# Rendering a Curio

A tutorial on how to run rendering code when a specific curio item is equipped on an entity.

## Create an `ICurioRenderer`
---
In the `top.theillusivec4.curios.api.client` package, you'll find an interface called `ICurioRenderer`. This interface
needs to be implemented on an object of your choice, as its `render` method is what will be called to run your rendering
code later.

For the full guide on the interface, see [here](APIs/renderer-interface.md).

### Example
```java
public class MyCurioRenderer implements ICurioRenderer {

@Override
public <T extends LivingEntity, M extends EntityModel<T>> void render(ItemStack stack,
SlotContext slotContext,
PoseStack matrixStack,
RenderLayerParent<T, M> renderLayerParent,
MultiBufferSource renderTypeBuffer,
int light, float limbSwing,
float limbSwingAmount,
float partialTicks,
float ageInTicks,
float netHeadYaw,
float headPitch) {
// Render code goes here
}
}
```

## Register your renderer
---
Once you have an implementation of `ICurioRenderer`, you need to register an instance of that to an item. This is done
by calling the `register` method in `top.theillusivec4.curios.api.client.CuriosRendererRegistry` during the
`FMLClientSetupEvent` in mod loading.

### Example
```java
@Mod("CurioMod")
public class CurioMod {

public CurioMod() {
final IEventBus eventBus = FMLJavaModLoadingContext.get().getModEventBus();
eventBus.addListener(this::clientSetup);
}

private void clientSetup(final FMLClientSetupEvent evt) {
CuriosRendererRegistry.register(CurioModItems.MY_ITEM, () -> new MyCurioRenderer());
}
}
```

:::tip
Multiple items are allowed to share a renderer instance or type. This can be handy if your `ICurioRenderer`
implementation shares a lot of common code or if your items have very similar renders, in which case you may find it
advantageous to simply register those items with a single renderer rather than multiple.
:::
Loading

0 comments on commit 116f24f

Please sign in to comment.