Skip to content

Instantly share code, notes, and snippets.

@GizmoTheMoonPig
Last active June 16, 2023 02:20
Show Gist options
  • Save GizmoTheMoonPig/06f6a1be8c68c246beb97bc207f01ab7 to your computer and use it in GitHub Desktop.
Save GizmoTheMoonPig/06f6a1be8c68c246beb97bc207f01ab7 to your computer and use it in GitHub Desktop.
DamageType Conversion

DamageSource changes:

Starting in 1.19.4, damage sources have been removed and replaced with a new system called DamageTypes. Damage Types are now a datapack registry, meaning they are no longer hardcoded. There are now also DamageType tags. To fetch DamageTypes, you will need to be able to use RegistryAccess. There are 2 ways to fetch vanilla DamageTypes: use level.damageSources() or entity.damageSources(). Theres a method for each vanilla type, such as .fall() for fall damage, .mobAttack() for mob attacks, and so on. You can find all the ones you can use in DamageSources. Here's how to call vanilla sources: https://github.com/TeamTwilight/twilightforest/blob/1.19.x/src/main/java/twilightforest/entity/projectile/SlimeProjectile.java#L66

Registering your own DamageTypes and calling them:

As an example, I will be walking through how to register a DamageType called thrown_block.

First, create a ResourceKey for the damage like so:

public static final ResourceKey<DamageType> THROWN_BLOCK = ResourceKey.create(Registries.DAMAGE_TYPE, new ResourceLocation("modid", "thrown_block"));

Next, you'll need to register it via a datapack. You can either add the file to a datapack manually or datagen it. I'll run through datagen, but will also show how the file is supposed to look if you want to manually add it. The method below will be called from datagen, so you can throw it wherever. I normally store it in the same class my ResourceKeys are in.

public static void bootstrap(BootstapContext<DamageType> context) {
    context.register(THROWN_BLOCK, new DamageType("modid.thrownBlock", 0.0F));
}

This will tie a DamageType to your ResourceKey. DamageType has a few different constructors. I used the one that uses the most defaults, but you can define a lot. I'll go over what each parameter does. (The entries in parenthesis are how theyre formatted in the json file)

msgId (message_id): the string identifier for the localized string. Death messages are localized as follows: death.attack.msgId. I definitely recommend adding your modid into this message to avoid conflicts.

scaling (scaling): a reference to a new enum called DamageScaling. There are 3 available options.

  • NEVER: damage always stays the same.
  • WHEN_CAUSED_BY_LIVING_NON_PLAYER: damage scales based on difficulty when a mob causes the damage.
  • ALWAYS: damage always scales with difficulty regardless of origin.

exhaustion (exhaustion): a float that defines the amount of exhaustion to cause after damage is dealt. Vanilla typically uses anywhere from 0.0F to 0.1F.

effects (effects): a reference to a new enum called DamageEffects. Defines what sound should play after a player is hurt. There are 6 available options, each should speak for itself:

  • HURT: the generic hurt sound
  • THORNS: the sound that plays when thorns activates
  • DROWNING: the bubbling sound that plays when a player drowns
  • BURNING: the scorching sound that plays when a player takes damage while on fire
  • POKING: plays a pricking sound, used when stepping through a sweet berry bush
  • FREEZING: plays a crackling sound, used when freezing in powder snow

deathMessageType (death_message_type): a reference to a new enum called DeathMessageType. Defines how the unlocalized death message is formatted. There are 3 available options:

  • DEFAULT: the default formatting, as defined in the msgId
  • FALL_VARIANTS: handles the fall variants of death messages. Its a bit complex to explain, but the logic is found in CombatTracker.getDeathMessage
  • INTENTIONAL_GAME_DESIGN: appends a link to bug report seen in the nether bed death message

All of minecraft's damage types are defined here if you would like the json examples: https://github.com/InventivetalentDev/minecraft-assets/tree/1.19.4/data/minecraft/damage_type

Datagen time!

Youll need to set up a new class to call from the GatherDataEvent. If you have a class that already extends DatapackBuiltinEntriesProvider because you have worldgen stuff, you can simply append the DamageType call to the rest of the registries you have defined. Otherwise you can use the below class for reference.

public class RegistryDataGenerator extends DatapackBuiltinEntriesProvider {

    public static final RegistrySetBuilder BUILDER = new RegistrySetBuilder()
            .add(Registries.DAMAGE_TYPE, YourDamageTypeClass::bootstrap);

    private RegistryDataGenerator(PackOutput output, CompletableFuture<HolderLookup.Provider> provider) {
        super(output, provider, BUILDER, Set.of("minecraft", "modid"));
    }

    public static void addProviders(boolean isServer, DataGenerator generator, PackOutput output, CompletableFuture<HolderLookup.Provider> provider, ExistingFileHelper helper) {
        generator.addProvider(isServer, new RegistryDataGenerator(output, provider));
        generator.addProvider(isServer, new DamageTypeTagGenerator(output, provider.thenApply(r -> append(r, BUILDER)), helper));
    }

    private static HolderLookup.Provider append(HolderLookup.Provider original, RegistrySetBuilder builder) {
        return builder.buildPatch(RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY), original);
    }
}

You'll notice this class also calls DamageTypeTagGenerator which doesnt exist quite yet. This is so you can tag your sources as needed. All tags are stored in DamageTypeTags. I assume you know how this part works, so I wont explain it unless asked. These tags essentially replace the old modifiers DamageSources used to have. If youre using the tags, make sure to call addProviders from the event. This is important as the tags wont properly parse otherwise!

Calling your DamageType: As mentioned before, you will need to be able to use RegistryAccess to fetch your DamageType. I made a few custom methods to do this in TF, but you can also unprivate the various source methods in vanilla's DamageSources class. https://github.com/TeamTwilight/twilightforest/blob/1.19.x/src/main/java/twilightforest/init/TFDamageTypes.java#L56-L66. Heres an example of how to call a DamageType: https://github.com/TeamTwilight/twilightforest/blob/1.19.x/src/main/java/twilightforest/entity/monster/GiantMiner.java#L93

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