Smart Recipes

Smart Recipes

Mod

A Fabric mod that extends recipe format with conditions.

Server LibraryUtility

1,275 downloads
7 followers
Created3 years ago
Updated4 months ago

Follow Save
Host your Minecraft server on BisectHosting - get 25% off your first month with code MODRINTH.

Logo

Smart Recipes

GitHub Build Status Version Modrinth CurseForge License

Do you find the standard Minecraft recipe format boring? Or maybe you wish to make the game more event-based, like Terraria? If so, Smart Recipes is what you need! Craft your own unique experience with our new conditional recipe format!


Format

If you prefer a practical example over explanations, feel free to skip directly to the Example section. However, don't forget to revisit the Conditions and Reload Conditions sections later.

Conditions Format

The Smart Recipes mod extends the vanilla recipe format. It's crucial to understand how the vanilla format works; otherwise, the following descriptions may not make sense.

This mod introduces a new smart_recipes:conditions property to the recipe format. It's somewhat similar to the conditions in loot tables. Let's take a closer look it:

"smart_recipes:conditions": []

This property determines conditions for the recipe to be loaded. If multiple conditions are specified, all must pass.

"smart_recipes:conditions": [
  {
    "condition": "conditionName0",
    "args": [
      // Arguments to be passed to some condition named `conditionName0`.
      4,
      "2"
    ]
  },
  {
    "condition": "conditionName1",
    "args": [
      // Arguments to be passed to some condition named `conditionName1`.
      "foo"
    ]
  }
]

This example is identical to how conditions in loot tables are usually written. However, I find them too verbose. Let's explore how we can improve our conditions.

// Let's turn this condition declaration:
{
  "condition": "conditionName1",
  "args": [
    "foo"
  ]
}

// Into this one:
"conditionName1": ["foo"]

Much better, don't you think?

"smart_recipes:conditions": [
  {
    "conditionName0": [4, "2"]
  },
  {
    "conditionName1": ["foo"]
  }
]

This is even better than before, but there is still some room for imporvement. Let's consolidate our conditions into a single object:

"smart_recipes:conditions": [
  {
    "conditionName0": [4, "2"],
    "conditionName1": ["foo"]
  }
]

Finally, if an array contains only one object, the Smart Recipes mod allows you to omit its declaration. Here's the final result:

"smart_recipes:conditions": {
  "conditionName0": [4, "2"],
  "conditionName1": "foo"
}

I should note that Smart Recipes can parse every single one of the examples above, so you can choose the style you prefer.

Reload Conditions Format

Reload conditions allow recipe conditions to be re-evaluated on different occasions. It can be useful if your recipe relies on weather, time and/or other volatile entities.

This process is surprisingly straightforward. All you need to do is provide the names of the reload conditions that your recipe depends on:

"smart_recipes:reload_conditions": [
  "weather_changed",
  "time_changed"
]

Conditions

false

Doesn't require arguments, always returns false.

"smart_recipes:conditions": [
  "false"
]

true

Doesn't require arguments, always returns true.

"smart_recipes:conditions": [
  "true"
]

or and any

Return true if any of the specified conditions returns true.

"smart_recipes:conditions": {
  "or": [
    { "false": {} },
    false,
    "true"
  ]
}

and and all

Return true if all the specified conditions return true.

"smart_recipes:conditions": {
  "and": {
    "true": {},
    "false": null
  }
}

not and none

Return true if none of the specified conditions return true.

"smart_recipes:conditions": {
  "not": {
    "false": null
  }
}

is_hardcore

Doesn't require arguments, returns true if the server is in Hardcore mode.

"smart_recipes:conditions": {
  "not": "is_hardcore"
}

is_peaceful_difficulty

Doesn't require arguments, returns true if the current difficulty is Peaceful.

"smart_recipes:conditions": {
  "or": [
    "is_peaceful_difficulty",
    "is_hardcore"
  ]
}

is_easy_difficulty

Doesn't require arguments, returns true if the current difficulty is Easy.

"smart_recipes:conditions": {
  "not": ["is_easy_difficulty"]
}

is_normal_difficulty

Doesn't require arguments, returns true if the current difficulty is Normal.

"smart_recipes:conditions": "is_normal_difficulty"

is_hard_difficulty

Doesn't require arguments, returns true if the current difficulty is Hard.

"smart_recipes:conditions": {
  "is_hard_difficulty": null
}

difficulty_check

Returns true if one of the specified values matches the current difficulty.

"smart_recipes:conditions": {
  "difficulty_check": [
    0, // Ordinal number of the Peaceful difficulty
    1, // Ordinal number of the Easy difficulty
    2, // Ordinal number of the Normal difficulty
    3, // Ordinal number of the Hard difficulty
    "peaceful",
    "easy",
    "normal",
    "HarD" // Case doesn't matter
  ]
}

is_survival

Doesn't require arguments, returns true if the default gamemode is Survival.

"smart_recipes:conditions": "is_survival"

is_creative

Doesn't require arguments, returns true if the default gamemode is Creative.

"smart_recipes:conditions": ["is_creative"]

is_adventure

Doesn't require arguments, returns true if the default gamemode is Adventure.

"smart_recipes:conditions": {
  "is_adventure": {}
}

is_spectator

Doesn't require arguments, returns true if the default gamemode is Spectator.

"smart_recipes:conditions": {
  "not": "is_spectator"
}

gamemode_check

Returns true if one of the specified values matches the default gamemode.

"smart_recipes:conditions": {
  "gamemode_check": [
    0, // Ordinal number of the Survival gamemode
    1, // Ordinal number of the Creative gamemode
    2, // Ordinal number of the Adventure gamemode
    3, // Ordinal number of the Spectator gamemode
    "survival",
    "creative",
    "adventure",
    "SpEcTaToR" // Case doesn't matter
  ]
}

weather_check

Returns true if one of the specified strings matches the current weather in the Overworld dimension.

"smart_recipes:conditions": {
  "weather_check": [
    "clear",    // Weather is clear
    "rain",     // It's raining or thundering
    "thunder"   // It's thundering
  ]
}

time_check

Returns true if one of the specified strings matches the current time in the Overworld dimension.

"smart_recipes:conditions": {
  "time_check": [
    "day",      // from 1000  to 12999 ticks
    "noon",     // from 5000  to 6999  ticks
    "sunset",   // from 11000 to 12999 ticks
    "midnight", // from 17000 to 18999 ticks
    "sunrise",  // from 22000 to 23999 ticks
    "night"     // from 13000 to 23999 ticks, from 0 to 999 ticks
  ]
}

players_online

Returns true if all the specified players are online.

"smart_recipes:conditions": {
  "players_online": [
    "Notch",
    "Dinnerbone",
    "jeb_"
  ]
}

blocks_registered

Returns true if all the specified blocks are registered.

"smart_recipes:conditions": {
  "blocks_registered": [
    "stone",
    "minecraft:dirt",
    "aether:aether_dirt"
  ]
}

items_registered

Returns true if all the specified items are registered.

"smart_recipes:conditions": {
  "items_registered": [
    "stone",
    "minecraft:dirt",
    "aether:aether_dirt"
  ]
}

block_entities_registered

Returns true if all the specified block entities are registered.

"smart_recipes:conditions": {
  "block_entities_registered": [
    "furnance",
    "minecraft:chest",
    "aether:incubator"
  ]
}

entries_registered

Returns true if all the specified registry entries are registered.

"smart_recipes:conditions": {
  "entries_registered": [
    {
      "registry": "block",
      "entry": "stone"
    },
    "minecraft:dirt", // `registry`'s default value is "block",
    {
      "registry": "item",
      "entry": "aether:incubator"
    },
    {
      "entry": "air"  // `registry`'s default value is "block",
    }
  ]
}

fabric:mods_loaded

Returns true if all the specified mods are loaded.

"smart_recipes:conditions": {
  "fabric:mods_loaded": [
    {
      "id": "smart-recipes",
      "version": "1.0"
    },
    "fabric-transfer-api-v1",       // `version`'s default value is "*"
    {
      "id": "fabric-command-api-v1" // `version`'s default value is "*"
    }
  ]
}

Reload Conditions

player_joined and player_disconnected

Reload recipes when player joins to/disconnects from the server.

"smart_recipes:conditions": {
  "not": {
    "players_online": "Nickname"
  }
},
"smart_recipes:reload_conditions": [
  "player_joined",
  "player_disconnected"
]

difficulty_changed

Reloads recipes when the current difficulty changes.

"smart_recipes:conditions": "is_easy_difficulty",
"smart_recipes:reload_conditions": "difficulty_changed"

gamemode_changed

Reloads recipes when the default gamemode changes.

"smart_recipes:conditions": {
  "gamemode_check": [
    "survival",
    "creative"
  ]
},
"smart_recipes:reload_conditions": ["gamemode_changed"]

weather_changed

Reloads recipes when the current weather changes.

"smart_recipes:conditions": {
  "weather_check": "thunder"
},
"smart_recipes:reload_conditions": "weather_changed"

time_changed

Reloads recipes when the current time changes.

"smart_recipes:conditions": {
  "time_check": [
    "noon",
    "midnight"
  ]
},
"smart_recipes:reload_conditions": [
  "time_changed"
]

Example

Consider a scenario where we want to add a simplified TNT recipe:

{
  "type": "minecraft:crafting_shaped",
  "pattern": [
    "# X",
    "   ",
    "X #"
  ],
  "key": {
    "#": {
      "item": "minecraft:sand"
    },
    "X": {
      "item": "minecraft:gunpowder"
    }
  },
  "result": {
    "item": "minecraft:tnt"
  }
}

Now, let's add some conditions. Here are our objectives:

  1. This recipe should only be available at midnight and sunrise, because nobody crafts explosives in the light of day.
  2. The recipe should only be available when the weather is clear, to prevent the gunpowder from getting damp.
  3. The recipe should not be available when Vladimir is online, as we don't trust Vladimir with deadly weapons.
  4. The recipe should only be available on the hard difficulty, because... why not?

Time to put our plan into action:

{
  // The same part as above, nothing interesting to see here
  "type": "minecraft:crafting_shaped",
  "pattern": [
    "# X",
    "   ",
    "X #"
  ],
  "key": {
    "#": {
      "item": "minecraft:sand"
    },
    "X": {
      "item": "minecraft:gunpowder"
    }
  },
  "result": {
    "item": "minecraft:tnt"
  },

  // Here's where the fun begins.
  // We need to describe our conditions for this recipe to be loaded in the
  // `conditions` section. If multiple conditions are specified, all must pass.
  "smart_recipes:conditions": {
    // #1
    "time_check": [
      "midnight",
      "sunrise"
    ],

    // #2
    // Note that `weather_check` usually consumes an array (just like `time_check` does),
    // but since we need to pass only one value, it can be omitted.
    "weather_check": "clear",

    // #3
    "not": {
      // We can omit an array declaration here too, but
      // I left it just to show that it's not necessary.
      "players_online": ["Vladimir"]
    },

    // #4
    // Can be replaced with:
    // - `"is_hard_difficulty": null`
    // - `"is_hard_difficulty"` (in arrays)
    // - `{ "condition": "is_hard_difficulty" }` (in arrays)
    // - `{ "condition": "difficulty_check", "args": ["hard"] }` (in arrays)
    "difficulty_check": "hard"
  },

  // By default, conditions are evaluated only when the server starts.
  // So, if we want to keep our recipes up-to-date with the actual
  // state of the game, we need to add `reload_conditions`.
  "smart_recipes:reload_conditions": [
    // #1
    // Reloads the recipe when time changes.
    "time_changed",

    // #2
    // Reloads the recipe when weather changes.
    "weather_changed",

    // #3
    // These reload the recipe when a player joins or disconnects from the server.
    // I may combine these two into a single one in the future.
    "player_joined",
    "player_disconnected",

    // #4
    // Reloads the recipe when difficulty changes.
    // To be honest, I don't think you really need it,
    // because difficulty is locked on most servers,
    // so it's fine to evaluate difficulty-based conditions
    // only on server start.
    "difficulty_changed"
  ]
}

Installation

Requirements:

  • Minecraft >=1.17.x
  • Fabric Loader >=0.11.3
  • Fabric API >=0.35.0

You can download the mod from:

Using as a Dependency

You can include Smart Recipes in your mod to use the new conditional format without requiring players to download it separately.

build.gradle:

repositories {
  maven {
    name = "Modrinth"
    url = "https://api.modrinth.com/maven"
    content {
      includeGroup "maven.modrinth"
    }
  }
}

dependencies {
  modImplementation "maven.modrinth:smart-recipes:${project.smart_recipes_version}"
}

gradle.properties:

smart_recipes_version=/* latest version goes here */

Building from sources

Requirements:

  • JDK 17

Linux/MacOS

git clone https://github.com/Kir-Antipov/smart-recipes.git
cd smart-recipes

chmod +x ./gradlew
./gradlew build
cd build/libs

Windows

git clone https://github.com/Kir-Antipov/smart-recipes.git
cd smart-recipes

gradlew build
cd build/libs

External resources



Project members

Kir_Antipov

Owner


Technical information

License
MIT
Client side
unsupported
Server side
required
Project ID