Step 1. Add the JitPack repository to your build file
Add it in your root settings.gradle at the end of repositories:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
Add it in your settings.gradle.kts at the end of repositories:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
Add to pom.xml
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
Add it in your build.sbt at the end of resolvers:
resolvers += "jitpack" at "https://jitpack.io"
Add it in your project.clj at the end of repositories:
:repositories [["jitpack" "https://jitpack.io"]]
Step 2. Add the dependency
dependencies {
implementation 'com.github.pyrofab:cardinal-components-api:2.0.1-pre'
}
dependencies {
implementation("com.github.pyrofab:cardinal-components-api:2.0.1-pre")
}
<dependency>
<groupId>com.github.pyrofab</groupId>
<artifactId>cardinal-components-api</artifactId>
<version>2.0.1-pre</version>
</dependency>
libraryDependencies += "com.github.pyrofab" % "cardinal-components-api" % "2.0.1-pre"
:dependencies [[com.github.pyrofab/cardinal-components-api "2.0.1-pre"]]
A components API for Fabric that is easy, modular, and fast.
Note: as no 2.0 version of Cardinal Components API is available on the main maven, this fork offers an alternative using Jitpack
repositories {
maven {
name = "JitPack"
url "https://jitpack.io"
}
}
dependencies {
// Replace modImplementation with modApi if you expose components in your own API
modImplementation "com.github.Pyrofab:Cardinal-Components-API:<VERSION>"
}
The include configuration will not work with JitPack and the master jar! See how to include individual modules below.
You can find the current version of the API in the releases tab of the repository on Github.
Cardinal Components API is split into several modules. The main artifact bundles every module, but often all
are not required for a project. To depend on a specific module, use the dependency string
com.github.Pyrofab.Cardinal-Components-API:<MODULE>:<VERSION>
. Module names can be found below.
Example:
// Adds an API dependency on the base cardinal components module
modApi "com.github.Pyrofab.Cardinal-Components-API:cardinal-components-base:<VERSION>"
// Includes the base module as a Jar-in-Jar dependency (optional)
include "com.github.Pyrofab.Cardinal-Components-API:cardinal-components-base:<VERSION>"
To get started, you only need 2 things: an interface extending Component
, and a class implementing this interface.
Minimal code example:
interface IntComponent extends Component {
int getValue();
}
class RandomIntComponent implements IntComponent {
private int value = (int) (Math.random() * 20);
@Override public int getValue() { return this.value; }
@Override public void fromTag(CompoundTag tag) { this.value = tag.getInt("value"); }
@Override public CompoundTag toTag(CompoundTag tag) { tag.putInt("value", this.value); return tag; }
}
All that is left is to actually use that component.
Components are provided by various objects through the ComponentProvider
interface.
To interact with those, you need to register your component type, using ComponentRegistry.registerIfAbsent
;
the resulting ComponentType
instance is used as a key for component providers.
public static final ComponentType<IntComponent> MAGIK =
ComponentRegistry.INSTANCE.registerIfAbsent(new Identifier("mymod:magik"), IntComponent.class);
public static void useMagik(ComponentProvider provider) {
// Retrieve a provided component
int magik = MAGIK.get(provider).getValue();
// Or, if the provider is not guaranteed to provide that component:
int magik = MAGIK.maybeGet(provider).map(IntComponent::getValue).orElse(0);
// ...
}
Note: a component class can be reused for several component types
Cardinal Components API offers component provider implementations for a few vanilla types, each in its own module:
Components can be added to entities of any type (modded or vanilla) by registering an EntityComponentCallback
.
Entity components are saved automatically with the entity. Synchronization must be done either manually or with
help of the SyncedComponent
and EntitySyncedComponent
interfaces.
Cardinal Components also provides mechanisms for handling player respawns. By default, components get copied when
players return from the End, but mods can customize that behaviour through RespawnCopyStrategy
and PlayerCopyCallback
to copy all or part of the component data.
Example:
// Add the component to every instance of PlayerEntity
EntityComponentCallback.event(PlayerEntity.class).register((player, components) -> components.put(MAGIK, new RandomIntComponent()));
// Ensure the component's data is copied when keepInventory is enabled (Optional)
EntityComponents.registerRespawnCopyStrat(MAGIK, RespawnCopyStrategy.INVENTORY);
module: cardinal-components-entity
Components can be added to stacks of any item (modded or vanilla) by registering an ItemComponentCallback
.
Item stack components are saved and synchronized automatically.
Notes:
ItemStack
equality: stack equality methods areTagsEqual
and isEqualIgnoreDamage
are modified to check component equality.
If you have issues when attaching components to item stacks, it usually means you forgot to implement a proper
equals
check on your component.ItemStack
: empty item stacks never expose any components, no matter what was originally attached to them.Example:
// Add the component to every stack of wasted diamonds
ItemComponentCallback.event(Items.DIAMOND_HOE).register((stack, components) -> components.put(MAGIK, new RandomIntComponent()));
module: cardinal-components-item
Components can be added to any world by registering a WorldComponentCallback
.
World components are saved automatically with the world. Synchronization must be done either manually or with
help of the SyncedComponent
and WorldSyncedComponent
interfaces.
Example:
// Add the component to every world
WorldComponentCallback.EVENT.register((world, components) -> components.put(MAGIK, new RandomIntComponent()));
module: cardinal-components-world
Components can be added to LevelProperties
objects by registering a LevelComponentCallback
.
Level properties are shared between every world in a server, making them useful to store global data.
Level components are saved automatically with the global state. Synchronization must be done either manually or with
help of the SyncedComponent
and LevelSyncedComponent
interfaces.
Example:
// Add the component to level properties
LevelComponentCallback.EVENT.register((levelProperties, components) -> components.put(MAGIK, new RandomIntComponent()));
module: cardinal-components-level
Components can be added to chunks by registering a ChunkComponentCallback
.
Chunk components are saved automatically with the chunk. Synchronization must be done either manually or with
help of the SyncedComponent
and ChunkSyncedComponent
interfaces.
Notes:
EmptyChunk
: empty chunks never expose any components, no matter what was originally attached to them.
As such, when chunk components are queried on the client, one should make sure the chunk is loaded, or use
ComponentType#maybeGet
to retrieve a component.Example:
// Add the component to every chunk in every world
ChunkComponentCallback.EVENT.register((chunk, components) -> components.put(MAGIK, new RandomIntComponent()));
module: cardinal-components-chunk
Blocks actually implement the BlockComponentProvider
interface instead of the regular ComponentProvider
.
Custom blocks may re-implement that interface themselves to provide components independently of the presence of
a BlockEntity. Usually the block simply proxies its Block Entity, however the Block Entity does not need to
implement BlockComponentProvider
if the block already has a custom implementation. Block components can be
slightly less convenient to provide as they require their own implementations, but several utility classes
are available to help.
Components are entirely compatible with LibBlockAttributes' attributes.
Since Component
is an interface, any attribute instance can easily implement it. Conversely, making an Attribute
for an existing Component
is as simple as calling Attributes.create(MyComponent.class)
.
module: cardinal-components-block
A test mod for the API is available in this repository, under src/testmod
. It makes uses of most features from the API.
Its code is outlined in a secondary readme.