Skip to content

Conversation

@exefer
Copy link
Contributor

@exefer exefer commented Apr 17, 2025

This pull request introduces a script that can automatically generate ores, dusts, nuggets, blocks, ingots, and their associated recipes from a single configuration object.

It also adds the first custom ore: Akite. Akite is configured with loot tables and a very rare spawn rate, it only spawns in ancient cities and can only be mined with a netherite pickaxe.
This ore could be used for some end-game recipes, due to it's rarity(the amount of ancient cities in a world is limited, that's why). Right now it doesn't have any usage.

Currently, all custom ores are blacklisted from the Digital Miner by default, and this behavior isn't configurable yet.

The OreProcessing.js script automatically creates Mekanism and Occultism crushing/enriching recipes to convert raw materials or ores into dusts. It also generates smelting recipes to convert ores, dusts, or raw materials into ingots. This applies to all ore variants (stone, deepslate, nether, and end).

Adding a new ore is straightforward. It requires a configured feature, a placed feature, a loot table, textures for at least the ore, ingot, dust(for ore processing), and an entry in the customOres global object. This object defines the ore’s name, which variants to generate, what derivates to generate(e.g. nugget, smelted ore block), and the required harvest level to mine it.

Some functionality is still missing, for example, recipes for converting nuggets to and from ingots (e.g., 9 nuggets → 1 ingot) haven’t been implemented yet. I didn’t consider it essential at this stage, but it can be added easily when needed.

Added a HarvestLevel enum now used across all global scripts

EDIT: Forgot to mention. This method, using configured features, placed features, and biome modifiers all in JSON files (datapack), is currently the only way to generate custom ores in KubeJS for 1.21. There's no WorldgenEvents like in 1.20.1 or similar yet, though Lat plans to create an addon for it afaik.

@exefer
Copy link
Contributor Author

exefer commented Apr 17, 2025

For checking out the current ore spawn rates I recommend using the Advanced XRay mod.

@WhitePhant0m
Copy link
Member

EDIT: Forgot to mention. This method, using configured features, placed features, and biome modifiers all in JSON files (datapack), is currently the only way to generate custom ores in KubeJS for 1.21. There's no WorldgenEvents like in 1.20.1 or similar yet, though Lat plans to create an addon for it afaik.

All of that could use ServerEvents.generateData() for automating most of the process.

@exefer
Copy link
Contributor Author

exefer commented Apr 17, 2025

EDIT: Forgot to mention. This method, using configured features, placed features, and biome modifiers all in JSON files (datapack), is currently the only way to generate custom ores in KubeJS for 1.21. There's no WorldgenEvents like in 1.20.1 or similar yet, though Lat plans to create an addon for it afaik.

All of that could use ServerEvents.generateData() for automating most of the process.

Automating in what way?

@WhitePhant0m
Copy link
Member

WhitePhant0m commented Apr 17, 2025

Example:
You could take the configured_feature/ore_deepslate_akite.json, and replace it with something like this.

ServerEvents.generateData('before_mods', event => {
  for (const [entry, ore] of Object.entries(global.customOres)) {
    let oreVariants = {
      stone: `${entry}_ore`,
      deepslate: `deepslate_${entry}_ore`,
      nether: `nether_${entry}_ore`,
      end: `end_${entry}_ore`,
    };

    for (const [variant, oreId] of Object.entries(oreVariants)) {
      if (!ore.worldGen[variant]) continue; // Skip if the variant is not present

      let size = ore.worldGen.size ?? 2;
      let discardChance = ore.worldGen.discardChance ?? 0.1;

      createOreGen(oreId, size, discardChance);
    }
  }

  function createOreGen(oreId, size, discardChance) {
    event.json(`craftoria:worldgen/configured_feature/${oreId}`, {
      type: 'minecraft:ore',
      config: {
        targets: [
          {
            target: {
              predicate_type: 'minecraft:tag_match',
              tag: 'minecraft:stone_ore_replaceables',
            },
            state: {
              Name: `craftoria:${oreId}`,
            },
          },
        ],
        size: size,
        discard_chance_on_air_exposure: discardChance,
      },
    });
  }
});

@exefer
Copy link
Contributor Author

exefer commented Apr 17, 2025

Oh nice aa34246, I was a bit scared of using LootJS because I haven't use it in a bit. Way nicer than loot tables with JSON

@exefer
Copy link
Contributor Author

exefer commented Apr 17, 2025

Example: You could take the configured_feature/ore_deepslate_akite.json, and replace it with something like this.

ServerEvents.generateData('before_mods', event => {
  for (const [entry, ore] of Object.entries(global.customOres)) {
    let oreVariants = {
      stone: `${entry}_ore`,
      deepslate: `deepslate_${entry}_ore`,
      nether: `nether_${entry}_ore`,
      end: `end_${entry}_ore`,
    };

    for (const [variant, oreId] of Object.entries(oreVariants)) {
      if (!ore.worldGen[variant]) continue; // Skip if the variant is not present

      let size = ore.worldGen.size ?? 2;
      let discardChance = ore.worldGen.discardChance ?? 0.1;

      createOreGen(oreId, size, discardChance);
    }
  }

  function createOreGen(oreId, size, discardChance) {
    event.json(`craftoria:worldgen/configured_feature/${oreId}`, {
      type: 'minecraft:ore',
      config: {
        targets: [
          {
            target: {
              predicate_type: 'minecraft:tag_match',
              tag: 'minecraft:stone_ore_replaceables',
            },
            state: {
              Name: `craftoria:${oreId}`,
            },
          },
        ],
        size: size,
        discard_chance_on_air_exposure: discardChance,
      },
    });
  }
});

The current configured feature is as simple as it can get, for akite. For more complex configured features this wouldn't cut it, and especially with ores with multiple block states(you used the stone replaceables instead of deepslate, and for all the other ore variants :P). If this could be expanded on that'd be alright imo

@WhitePhant0m
Copy link
Member

WhitePhant0m commented Apr 17, 2025

Definetely could be expanded, but also, it's just nicer to not have to make a json file for each thing that gets added.
(Also that was just a quick example, didn't really try to make it perfect :P)

@exefer
Copy link
Contributor Author

exefer commented Apr 18, 2025

We can squash to reduce the amount of commits if needed😌

@exefer exefer force-pushed the feat/custom-ores branch 3 times, most recently from 2cf251a to 3e1943b Compare April 18, 2025 17:30
@exefer exefer force-pushed the feat/custom-ores branch from 3e1943b to 0d7b30a Compare April 19, 2025 07:18
Add dynamic ore/dust/nugget/block/ingot generation with recipes
Implement loot table auto-generation with silk touch/fortune support
Add `HarvestLevel` enum and use it across global scripts
Blacklist Akite ore from AA's vertical digger

Co-authored-by: Phantom <33400200+WhitePhant0m@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants