Skip to content

Instantly share code, notes, and snippets.

@FireController1847
Last active November 21, 2021 05:34
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FireController1847/c7a50144f45806a996d13efcff468d1b to your computer and use it in GitHub Desktop.
Save FireController1847/c7a50144f45806a996d13efcff468d1b to your computer and use it in GitHub Desktop.
Minecraft Forge 1.14.4 ~ LevelHearts Capability
package com.firecontroller1847.levelhearts.capabilities;
public interface IMoreHealth {
byte getHeartContainers();
byte getDefaultHealth();
double getModifier();
short getLevelRampPosition();
void setHeartContainers(byte heartContainers);
void setDefaultHealth(byte defaultHealth);
void setModifier(double modifier);
void setLevelRampPosition(short levelRampPosition);
}
package com.firecontroller1847.levelhearts;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.firecontroller1847.levelhearts.capabilities.IMoreHealth;
import com.firecontroller1847.levelhearts.capabilities.MoreHealth;
import com.firecontroller1847.levelhearts.capabilities.MoreHealthProvider;
import com.firecontroller1847.levelhearts.capabilities.MoreHealthStorage;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
@Mod(LevelHearts.MOD_ID)
@Mod.EventBusSubscriber(modid = LevelHearts.MOD_ID)
public class LevelHearts {
public static final String MOD_ID = "levelhearts";
public static final String MOD_NAME = "LevelHearts";
public static final String MOD_VERSION = "2.0.0";
public static Logger logger = LogManager.getLogger(LevelHearts.MOD_ID);
public LevelHearts() {
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, LevelHeartsConfig.COMMON, "levelhearts.toml");
FMLJavaModLoadingContext.get().getModEventBus().addListener(LevelHearts::onCommonSetup);
}
@SubscribeEvent
public static void onCommonSetup(FMLCommonSetupEvent event) {
CapabilityManager.INSTANCE.register(IMoreHealth.class, new MoreHealthStorage(), MoreHealth::new);
}
@SubscribeEvent
public static void onAttachCapabilities(AttachCapabilitiesEvent<Entity> event) {
if (event.getObject() instanceof PlayerEntity) {
event.addCapability(new ResourceLocation(LevelHearts.MOD_ID, "morehealth"), new MoreHealthProvider());
}
}
public static void debug(String message) {
if (LevelHeartsConfig.GENERAL.debug.get()) {
logger.info(message);
}
}
}
package com.firecontroller1847.levelhearts.capabilities;
import com.firecontroller1847.levelhearts.LevelHeartsConfig;
import net.minecraft.entity.SharedMonsterAttributes;
public class MoreHealth implements IMoreHealth {
private byte heartContainers;
private byte defaultHealth;
private double modifier;
private short levelRampPosition;
public MoreHealth() {
this.heartContainers = 0;
this.defaultHealth = LevelHeartsConfig.HEALTH.defHealth.get().byteValue();
this.modifier = this.defaultHealth - SharedMonsterAttributes.MAX_HEALTH.getDefaultValue();
this.levelRampPosition = 0;
}
@Override
public byte getHeartContainers() {
return this.heartContainers;
}
@Override
public byte getDefaultHealth() {
return this.defaultHealth;
}
@Override
public double getModifier() {
return this.modifier;
}
@Override
public short getLevelRampPosition() {
return this.levelRampPosition;
}
@Override
public void setHeartContainers(byte heartContainers) {
this.heartContainers = heartContainers;
}
@Override
public void setDefaultHealth(byte defaultHealth) {
this.defaultHealth = defaultHealth;
}
@Override
public void setModifier(double modifier) {
this.modifier = modifier;
}
@Override
public void setLevelRampPosition(short levelRampPosition) {
this.levelRampPosition = levelRampPosition;
}
}
package com.firecontroller1847.levelhearts.capabilities;
import net.minecraft.nbt.INBT;
import net.minecraft.util.Direction;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.LazyOptional;
public class MoreHealthProvider implements ICapabilitySerializable<INBT> {
@CapabilityInject(IMoreHealth.class)
public static final Capability<IMoreHealth> MORE_HEALTH_CAPABILITY = null;
private LazyOptional<IMoreHealth> instance = LazyOptional.of(MORE_HEALTH_CAPABILITY::getDefaultInstance);
@Override
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) {
return cap == MORE_HEALTH_CAPABILITY ? instance.cast() : LazyOptional.empty();
}
@Override
public INBT serializeNBT() {
// @formatter:off
return MORE_HEALTH_CAPABILITY.getStorage().writeNBT(MORE_HEALTH_CAPABILITY, this.instance.orElseThrow(() -> new IllegalArgumentException("LazyOptional must not be empty!")), null);
// @formatter:on
}
@Override
public void deserializeNBT(INBT nbt) {
// @formatter:off
MORE_HEALTH_CAPABILITY.getStorage().readNBT(MORE_HEALTH_CAPABILITY, this.instance.orElseThrow(() -> new IllegalArgumentException("LazyOptional must not be empty!")), null, nbt);
// @formatter:on
}
}
package com.firecontroller1847.levelhearts.capabilities;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.INBT;
import net.minecraft.util.Direction;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.Capability.IStorage;
public class MoreHealthStorage implements IStorage<IMoreHealth> {
@Override
public INBT writeNBT(Capability<IMoreHealth> capability, IMoreHealth instance, Direction side) {
CompoundNBT tag = new CompoundNBT();
tag.putByte("heartContainers", instance.getHeartContainers());
tag.putByte("minHealth", instance.getDefaultHealth());
tag.putDouble("modifier", instance.getModifier());
tag.putShort("levelRampPosition", instance.getLevelRampPosition());
return tag;
}
@Override
public void readNBT(Capability<IMoreHealth> capability, IMoreHealth instance, Direction side, INBT nbt) {
CompoundNBT tag = (CompoundNBT) nbt;
instance.setHeartContainers(tag.getByte("heartContainers"));
instance.setDefaultHealth(tag.getByte("minHealth"));
instance.setModifier(tag.getDouble("modifier"));
instance.setLevelRampPosition(tag.getShort("levelRampPosition"));
}
}
@sinhlt58
Copy link

sinhlt58 commented Apr 3, 2020

:))

@thejacobexpress
Copy link

Thanks for putting this on GitHub, this is really helping me understand capabilities better. Forges documents on this kinda suck.

@FireController1847
Copy link
Author

Thanks for putting this on GitHub, this is really helping me understand capabilities better. Forges documents on this kinda suck.

Glad I was able to be of help. Forge documentation relies heavily on a "trial-and-error" and a "figure it out" mentality which, in my opinion, is a terrible way to go about things. I'm very much so more of a "learn by example" type of guy, and so I wanted to share this so that there'd be at least one public example of capabilities working for 1.14. They've changed a little in 1.17 but not by much, so hopefully this example is still helpful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment