Add the modules Truly Modular is missing, and two more materials
Platinum (Create Propulsion: Simulated) and aviation alloy (AeroEngine) were the only materials left in the pack; Pastel's gem fragments now count as an eighth of a gem, and Create: Wizardry's arcane sheet, arcane block and mithril nugget feed the metals they are made of, through extensions in its own pack so they cost nothing to anyone without it. Four modules of our own, in packs gated on the addon whose slots they use: - A khopesh blade for any sword blade slot - axe damage, a point of knockback, an axe's mining level, fast, and short-reached and fragile to pay for it. Nothing in the ecosystem ships one, so it is drawn here. - Socketed pommels. Arsenal's own socket pommel takes a small gem, and no module anywhere in Arsenal, Armory, Archery or MIAPI offers a gem_melee_large slot, so the large gemstone had nowhere to go. Now it does. - A sealed helmet and a life support pack. Cosmonautics suffocates you in space through LivingBreatheEvent and exempts only items that *are* a Create diving helmet, which a modular helmet cannot be, so VacuumSeal.java answers the same event last. Half a seal each: it takes the suit, not the hat. Arcane alloy is what it is called in game - Create: Wizardry renames the ingot - and cutting spell cooldowns is now the reason to build out of it: 10% held per module, less on armour, on Iron's Spells' cooldown * (2 - value), so a weapon made of it beats the mod's best staff and a full kit still stays inside the formula. Two bugs found on the way: the Ice and Fire amethyst extension named an item that does not exist (the mod spells it amythest_gem) in a shape MIAPI's codec does not read, so it had never done anything - extensions are item-checked like materials now. And the generator handed a namespace to whichever jar sorted first, which is an addon as often as the mod that owns it; it goes to the jar with the most of it now. A mod whose jar is missing is skipped with its files left alone rather than failing the run, and only material folders are cleared, since the module packs are hand-written. Module art is placeholder-grade and meant to be repainted: it lives in textures/items and textures/equipment, with blank templates and a guide sheet giving the palette stops and every region a model samples. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>modules-and-missing-materials
128
README.md
|
|
@ -1,13 +1,17 @@
|
||||||
# Create/Mekanism Modular
|
# Create/Mekanism Modular
|
||||||
|
|
||||||
A [Truly Modular](https://modrinth.com/mod/modular-item-api) addon for Minecraft
|
A [Truly Modular](https://modrinth.com/mod/modular-item-api) addon for Minecraft
|
||||||
1.21.1 / NeoForge. It adds 124 materials drawn from 20 mods - Create, Mekanism, Ice
|
1.21.1 / NeoForge. It adds 126 materials drawn from 22 mods - Create, Mekanism, Ice
|
||||||
and Fire, Immersive Engineering, Ender IO, Applied Energistics, Occultism,
|
and Fire, Immersive Engineering, Ender IO, Applied Energistics, Occultism,
|
||||||
Ars Nouveau, Iron's Spells, Pastel, Crystal Chronicles, NauTec, Superb Warfare,
|
Ars Nouveau, Iron's Spells, Pastel, Crystal Chronicles, NauTec, Superb Warfare,
|
||||||
Industrial Foregoing, RFTools, Create Deco, Steampunk Dimension and the three
|
Industrial Foregoing, RFTools, Create Deco, Steampunk Dimension and the Create
|
||||||
Create aerospace addons - so their metals, gems, scales and essences can all be
|
aerospace addons - so their metals, gems, scales and essences can all be
|
||||||
used to build modular tools and armour.
|
used to build modular tools and armour.
|
||||||
|
|
||||||
|
On top of the materials it adds a few modules of its own: a khopesh blade for
|
||||||
|
Arsenal, and a sealed helmet and life support pack for Armory that between them
|
||||||
|
let you breathe in the vacuum Create: Cosmonautics puts above the atmosphere.
|
||||||
|
|
||||||
Every source mod is optional. Install any subset - the materials for mods you do
|
Every source mod is optional. Install any subset - the materials for mods you do
|
||||||
not have are never registered.
|
not have are never registered.
|
||||||
|
|
||||||
|
|
@ -52,6 +56,51 @@ MIAPI's internals, `FireImmunity.java` registers a `cmmodular:fire_immunity`
|
||||||
attribute, the material grants it like any other attribute, and a damage handler
|
attribute, the material grants it like any other attribute, and a damage handler
|
||||||
watches for it. Neither side knows about the other.
|
watches for it. Neither side knows about the other.
|
||||||
|
|
||||||
|
**Breathing in a vacuum.** The same trick, for the space set - see below.
|
||||||
|
|
||||||
|
## Modules
|
||||||
|
|
||||||
|
Three of the packs hold modules rather than materials. They are hand-written
|
||||||
|
rather than generated, and gated on the Truly Modular addon whose slots they use.
|
||||||
|
|
||||||
|
**Khopesh blade** (`packs/arsenal`) fits any `sword_blade` slot, so it is an
|
||||||
|
option wherever the plain sword blade is. It is the chopping sword it looks
|
||||||
|
like: axe damage off hardness *and* density, a full point of knockback, an axe's
|
||||||
|
mining level so it fells trees and strips logs, and a fast swing. The cost is
|
||||||
|
everything a hook gives up - shorter reach than a sword, no sweep, and a quarter
|
||||||
|
less durability than the blade it replaces.
|
||||||
|
|
||||||
|
There was no khopesh to borrow. Nothing in the Truly Modular ecosystem ships
|
||||||
|
one, and the khopesh art that exists elsewhere is either another mod's item or a
|
||||||
|
retexture of a vanilla sword - neither is a MIAPI module and neither is ours to
|
||||||
|
ship, so the blade is drawn here.
|
||||||
|
|
||||||
|
**Socketed pommels** (`packs/arsenal`) give the bigger gems somewhere to sit.
|
||||||
|
Arsenal does ship a socket pommel, but it takes a small gem, and a sweep of
|
||||||
|
Arsenal, Armory, Archery and MIAPI turns up no module anywhere that offers a
|
||||||
|
`gem_melee_large` slot - the large gemstone is defined and then has nowhere to
|
||||||
|
go. So there are two here: a medium socket, and a great socket for the large
|
||||||
|
gem. Each is a heavier counterweight than the last, paid for in swing speed.
|
||||||
|
|
||||||
|
**The space set** (`packs/armory`) is Create: Cosmonautics' answer to vacuum,
|
||||||
|
rebuilt as modules. Cosmonautics suffocates you above the atmosphere by
|
||||||
|
answering NeoForge's `LivingBreatheEvent` with "no", and exempts its own space
|
||||||
|
helmet through Create's diving code, which asks whether the worn helmet *is a*
|
||||||
|
`DivingHelmetItem`. A modular helmet cannot be one, so the exemption is
|
||||||
|
unreachable and the set brings its own: `VacuumSeal.java` registers a
|
||||||
|
`cmmodular:vacuum_seal` attribute and answers the same event last.
|
||||||
|
|
||||||
|
It takes two modules to reach the seal. The sealed helmet grants 0.5 and the
|
||||||
|
life support pack on the chest grants 0.5, and only at 1 does the wearer
|
||||||
|
breathe - so it is a suit, not a hat, which is the same trade Cosmonautics makes
|
||||||
|
by pairing its helmet with a jetpack. Both come in a socketed version that
|
||||||
|
trades 5% armour for a medium gem slot, exactly as Armory's own socket pieces
|
||||||
|
do, and each socketed version has its own model and texture with the setting
|
||||||
|
drawn in, rather than wearing the plain piece's art.
|
||||||
|
|
||||||
|
All of the art here is placeholder-grade and meant to be repainted - see
|
||||||
|
Textures below.
|
||||||
|
|
||||||
## Stats
|
## Stats
|
||||||
|
|
||||||
Tinkers' Construct 3 is the reference, re-scaled onto MIAPI's vanilla-derived
|
Tinkers' Construct 3 is the reference, re-scaled onto MIAPI's vanilla-derived
|
||||||
|
|
@ -98,6 +147,28 @@ which is what MIAPI's own palettes do.
|
||||||
The sample points were tuned against MIAPI's hand-authored copper palette and
|
The sample points were tuned against MIAPI's hand-authored copper palette and
|
||||||
reproduce it to within about 2% per channel.
|
reproduce it to within about 2% per channel.
|
||||||
|
|
||||||
|
## Textures
|
||||||
|
|
||||||
|
The modules' own art is hand-drawn and lives where it can be found and changed:
|
||||||
|
|
||||||
|
```
|
||||||
|
assets/cmmodular/textures/items/ flat 16x16 art - gui icons, the khopesh blade
|
||||||
|
assets/cmmodular/textures/equipment/ 32x32 cube nets for the worn armour models
|
||||||
|
assets/cmmodular/textures/templates_guide.png
|
||||||
|
```
|
||||||
|
|
||||||
|
Everything is greyscale, because MIAPI recolours a module's texture through the
|
||||||
|
material's palette: the seven shades a texture may use are the brightness stops
|
||||||
|
of that palette (24, 68, 107, 150, 190, 216, 255), and a pixel drawn between two
|
||||||
|
of them lands somewhere interpolated and muddy.
|
||||||
|
|
||||||
|
`textures/*/templates/` holds blanks to draw over - the same size as the real
|
||||||
|
thing, with every region a model samples outlined and the seven shades parked in
|
||||||
|
a corner no model reads, so they can be picked straight out of the file.
|
||||||
|
`templates_guide.png` is a single sheet showing the shades with their values,
|
||||||
|
the cube net with each face labelled, and the vanilla armour layout, for when a
|
||||||
|
new piece is wanted rather than a repaint of an existing one.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|
@ -116,12 +187,24 @@ textures. The generated JSON is committed, so a plain build does not need this.
|
||||||
python3 tools/generate_materials.py --jars ~/path/to/mod/jars
|
python3 tools/generate_materials.py --jars ~/path/to/mod/jars
|
||||||
```
|
```
|
||||||
|
|
||||||
The folder needs one jar per source mod. Every item id in `materials.py` is
|
Point it at the pack's `mods` folder. Every item id in `materials.py` is checked
|
||||||
checked against those jars and the run fails on a typo, rather than shipping a
|
against those jars and the run fails on a typo, rather than shipping a material
|
||||||
material that silently refuses to load.
|
that silently refuses to load.
|
||||||
|
|
||||||
|
A mod whose jar is not there is skipped instead, with a line saying so, and its
|
||||||
|
committed files are left untouched - the pack this follows adds and drops mods,
|
||||||
|
and neither losing the materials of a mod you no longer have nor being unable to
|
||||||
|
regenerate anything without a complete set of jars is useful. Nothing else is
|
||||||
|
relaxed: a typo in a mod you *do* have still fails the run. Where several jars
|
||||||
|
claim the same asset namespace - Applied Mekanistics writes into `ae2`, half the
|
||||||
|
Create addons into `create` - the one with the most files in it wins, which is
|
||||||
|
the mod that owns the namespace rather than whichever sorted first.
|
||||||
|
|
||||||
Requires `pillow` and `numpy`.
|
Requires `pillow` and `numpy`.
|
||||||
|
|
||||||
|
Module JSON and textures are not generated. A run only clears the material
|
||||||
|
folders, so the hand-written packs survive it.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- Titanium's palette comes from Cosmonautics' ingot, which is violet. Air War's
|
- Titanium's palette comes from Cosmonautics' ingot, which is violet. Air War's
|
||||||
|
|
@ -161,3 +244,36 @@ Requires `pillow` and `numpy`.
|
||||||
material properties they accept and list only `default` plus their own gem
|
material properties they accept and list only `default` plus their own gem
|
||||||
tags. Anything filed under `armor`/`handheld` silently never applies to a
|
tags. Anything filed under `armor`/`handheld` silently never applies to a
|
||||||
socketed gem. The attribute's own slot is what decides where it counts.
|
socketed gem. The attribute's own slot is what decides where it counts.
|
||||||
|
- Arcane alloy shortens Iron's Spells cooldowns, and that is the point of it:
|
||||||
|
0.10 held, 0.05 on a helmet, 0.03 on the lower armour, filed under `default`
|
||||||
|
so a suit plated in it counts as well as a staff made of it. Iron's Spells
|
||||||
|
reads the attribute as a factor on a base of 1 and spends it as
|
||||||
|
`cooldown * (2 - value)`, so the operation is `*` - a flat `+` would be added
|
||||||
|
to a base of zero and do nothing - and 0.10 means 10% off the wait. It stacks
|
||||||
|
per module, so a weapon built entirely of arcane alloy is around 40%, against
|
||||||
|
25% for Iron's Spells' own best staff; a full set adds roughly another 45%,
|
||||||
|
which keeps even an all-arcane player under the 100% where the formula
|
||||||
|
bottoms out. The material
|
||||||
|
is called Arcane Alloy rather than Arcane Steel because Create: Wizardry
|
||||||
|
renames the ingot that way, and Create: Wizardry's arcane sheet and block are
|
||||||
|
the same metal - they arrive as a material extension in that mod's own pack,
|
||||||
|
since naming them directly would break the material for anyone without it.
|
||||||
|
- Platinum comes from Create Propulsion: Simulated, the only platinum in the
|
||||||
|
pack. It is soft for its density, so it swings slowly and hits like steel; it
|
||||||
|
is worth mining for gold-grade enchantability that does not fall apart, and it
|
||||||
|
is heat proof because platinum melts at 1768C.
|
||||||
|
- Aviation alloy is AeroEngine's, iron superheated with netherite powder. A
|
||||||
|
turbine superalloy: light and heat proof like titanium, harder, worse to
|
||||||
|
enchant. It sits between titanium and titanium alloy, which is where its
|
||||||
|
recipe sits too.
|
||||||
|
- Extensions are material files with a different shape - `parent` naming the
|
||||||
|
material to edit and `data` merged onto a copy of it, the same form MIAPI's
|
||||||
|
stained glass uses to vary plain glass. The merge replaces a field rather than
|
||||||
|
appending to it, so an extension that adds an ingredient repeats the ones it
|
||||||
|
keeps; `_extend_with_extra_forms` builds those lists from the material itself.
|
||||||
|
- Ice and Fire's amethyst gem is spelled `amythest_gem` in Ice and Fire. The
|
||||||
|
extension named the correct spelling, which is an item that does not exist, so
|
||||||
|
it did nothing. Extensions are item-checked like materials now.
|
||||||
|
- Pastel's paltaeria and stratine gems break into eight fragments on an anvil,
|
||||||
|
so a fragment counts as an eighth of a gem, the way a nugget counts as a ninth
|
||||||
|
of an ingot.
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ neo_version=21.1.248
|
||||||
|
|
||||||
mod_id=cmmodular
|
mod_id=cmmodular
|
||||||
mod_name=Create/Mekanism Modular
|
mod_name=Create/Mekanism Modular
|
||||||
mod_version=1.1.0
|
mod_version=1.2.0
|
||||||
mod_group_id=eu.abdelbaki.cmmodular
|
mod_group_id=eu.abdelbaki.cmmodular
|
||||||
mod_authors=themiro
|
mod_authors=themiro
|
||||||
mod_description=Materials from Create, Mekanism, Ice and Fire, Iron's Spells and the Create aerospace addons, for Truly Modular.
|
mod_description=Materials from Create, Mekanism, Ice and Fire, Iron's Spells and the Create aerospace addons, for Truly Modular - plus a khopesh blade and a sealed space suit.
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ import net.neoforged.neoforge.event.AddPackFindersEvent;
|
||||||
public class CMModular {
|
public class CMModular {
|
||||||
public static final String MOD_ID = "cmmodular";
|
public static final String MOD_ID = "cmmodular";
|
||||||
|
|
||||||
/** A set of materials, and the mod it needs in order to load. */
|
/** A built-in datapack - materials or modules - and the mod it needs. */
|
||||||
private record MaterialPack(String id, String name, String requires) {
|
private record MaterialPack(String id, String name, String requires) {
|
||||||
boolean present() {
|
boolean present() {
|
||||||
return ModList.get().isLoaded(requires);
|
return ModList.get().isLoaded(requires);
|
||||||
|
|
@ -61,10 +61,18 @@ public class CMModular {
|
||||||
new MaterialPack("rftoolsbase", "RFTools Materials", "rftoolsbase"),
|
new MaterialPack("rftoolsbase", "RFTools Materials", "rftoolsbase"),
|
||||||
new MaterialPack("createdeco", "Create Deco Materials", "createdeco"),
|
new MaterialPack("createdeco", "Create Deco Materials", "createdeco"),
|
||||||
new MaterialPack("crystal_chronicles", "Crystal Chronicles Materials", "crystal_chronicles"),
|
new MaterialPack("crystal_chronicles", "Crystal Chronicles Materials", "crystal_chronicles"),
|
||||||
new MaterialPack("pastel", "Pastel Materials", "pastel"));
|
new MaterialPack("pastel", "Pastel Materials", "pastel"),
|
||||||
|
new MaterialPack("createpropulsion", "Create Propulsion Materials", "createpropulsion"),
|
||||||
|
new MaterialPack("aeroengineering", "AeroEngine Materials", "aeroengineering"),
|
||||||
|
new MaterialPack("create_wizardry", "Create Wizardry Materials", "create_wizardry"),
|
||||||
|
// Modules, not materials, and gated for the same reason: they name
|
||||||
|
// slots - and inherit modules - that only exist with these installed.
|
||||||
|
new MaterialPack("arsenal", "Arsenal Modules", "tm_arsenal"),
|
||||||
|
new MaterialPack("armory", "Armory Modules", "tm_armory"));
|
||||||
|
|
||||||
public CMModular(IEventBus modBus) {
|
public CMModular(IEventBus modBus) {
|
||||||
FireImmunity.register(modBus);
|
FireImmunity.register(modBus);
|
||||||
|
VacuumSeal.register(modBus);
|
||||||
modBus.addListener(this::addMaterialPacks);
|
modBus.addListener(this::addMaterialPacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
package eu.abdelbaki.cmmodular;
|
||||||
|
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.Attribute;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.RangedAttribute;
|
||||||
|
import net.neoforged.bus.api.EventPriority;
|
||||||
|
import net.neoforged.bus.api.IEventBus;
|
||||||
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
|
import net.neoforged.neoforge.event.entity.EntityAttributeModificationEvent;
|
||||||
|
import net.neoforged.neoforge.event.entity.living.LivingBreatheEvent;
|
||||||
|
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||||
|
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The space set: a sealed helmet and a life support pack that together let the
|
||||||
|
* wearer breathe where there is nothing to breathe.
|
||||||
|
*
|
||||||
|
* <p>Create: Cosmonautics suffocates you in space by answering
|
||||||
|
* {@link LivingBreatheEvent} with "no", the same event vanilla uses underwater,
|
||||||
|
* and Create decides who is exempt by asking whether the helmet
|
||||||
|
* <em>is a</em> {@code DivingHelmetItem}. A modular helmet never can be, so
|
||||||
|
* neither mod's own answer can be reused - hence an attribute of this mod's own
|
||||||
|
* and a listener for it, exactly as {@link FireImmunity} does for fire.
|
||||||
|
*
|
||||||
|
* <p>Half a seal per piece is the point: one module is never enough, so a
|
||||||
|
* player wanting to breathe in a vacuum has to build both halves of the suit,
|
||||||
|
* which is the trade Cosmonautics itself makes with its helmet and jetpack.
|
||||||
|
*/
|
||||||
|
public final class VacuumSeal {
|
||||||
|
private static final DeferredRegister<Attribute> ATTRIBUTES =
|
||||||
|
DeferredRegister.create(Registries.ATTRIBUTE, CMModular.MOD_ID);
|
||||||
|
|
||||||
|
/** At or above 1 the wearer always has air; each piece of the set is 0.5. */
|
||||||
|
public static final DeferredHolder<Attribute, Attribute> VACUUM_SEAL =
|
||||||
|
ATTRIBUTES.register("vacuum_seal", id -> new RangedAttribute(
|
||||||
|
"attribute.cmmodular.vacuum_seal", 0.0D, 0.0D, 1.0D).setSyncable(true));
|
||||||
|
|
||||||
|
private VacuumSeal() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register(IEventBus modBus) {
|
||||||
|
ATTRIBUTES.register(modBus);
|
||||||
|
modBus.addListener(VacuumSeal::attachToEntities);
|
||||||
|
// Last, so it answers after whatever said there was no air - Cosmonautics
|
||||||
|
// in space, vanilla underwater.
|
||||||
|
NeoForge.EVENT_BUS.addListener(EventPriority.LOWEST, VacuumSeal::onBreathe);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Attributes only exist on an entity if they were added to its type. */
|
||||||
|
private static void attachToEntities(EntityAttributeModificationEvent event) {
|
||||||
|
event.getTypes().forEach(type -> event.add(type, VACUUM_SEAL));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void onBreathe(LivingBreatheEvent event) {
|
||||||
|
if (event.canBreathe()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AttributeInstance instance = event.getEntity().getAttribute(VACUUM_SEAL);
|
||||||
|
if (instance != null && instance.getValue() >= 1.0D) {
|
||||||
|
event.setCanBreathe(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -182,3 +182,41 @@ type = "optional"
|
||||||
versionRange = "[0,)"
|
versionRange = "[0,)"
|
||||||
ordering = "AFTER"
|
ordering = "AFTER"
|
||||||
side = "BOTH"
|
side = "BOTH"
|
||||||
|
|
||||||
|
[[dependencies.${mod_id}]]
|
||||||
|
modId = "createpropulsion"
|
||||||
|
type = "optional"
|
||||||
|
versionRange = "[0,)"
|
||||||
|
ordering = "AFTER"
|
||||||
|
side = "BOTH"
|
||||||
|
|
||||||
|
[[dependencies.${mod_id}]]
|
||||||
|
modId = "aeroengineering"
|
||||||
|
type = "optional"
|
||||||
|
versionRange = "[0,)"
|
||||||
|
ordering = "AFTER"
|
||||||
|
side = "BOTH"
|
||||||
|
|
||||||
|
[[dependencies.${mod_id}]]
|
||||||
|
modId = "create_wizardry"
|
||||||
|
type = "optional"
|
||||||
|
versionRange = "[0,)"
|
||||||
|
ordering = "AFTER"
|
||||||
|
side = "BOTH"
|
||||||
|
|
||||||
|
# The two Truly Modular addons that own the slots this mod's modules go in, and
|
||||||
|
# the modules they inherit from. Optional like everything else - without them
|
||||||
|
# the module packs are simply never registered.
|
||||||
|
[[dependencies.${mod_id}]]
|
||||||
|
modId = "tm_arsenal"
|
||||||
|
type = "optional"
|
||||||
|
versionRange = "[0,)"
|
||||||
|
ordering = "AFTER"
|
||||||
|
side = "BOTH"
|
||||||
|
|
||||||
|
[[dependencies.${mod_id}]]
|
||||||
|
modId = "tm_armory"
|
||||||
|
type = "optional"
|
||||||
|
versionRange = "[0,)"
|
||||||
|
ordering = "AFTER"
|
||||||
|
side = "BOTH"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,13 @@
|
||||||
{
|
{
|
||||||
"attribute.cmmodular.fire_immunity": "Fire Immunity"
|
"attribute.cmmodular.fire_immunity": "Fire Immunity",
|
||||||
|
"attribute.cmmodular.vacuum_seal": "Vacuum Seal",
|
||||||
|
|
||||||
|
"miapi.module.cmmodular.blade.khopesh.name": "Khopesh Blade",
|
||||||
|
"miapi.module.cmmodular.pommel.gem_socket.name": "Socketed Pommel",
|
||||||
|
"miapi.module.cmmodular.pommel.great_socket.name": "Great Socketed Pommel",
|
||||||
|
|
||||||
|
"miapi.module.cmmodular.armor.space.helmet.name": "Sealed Helmet",
|
||||||
|
"miapi.module.cmmodular.armor.space.helmet_socket.name": "Sealed Helmet with Socket",
|
||||||
|
"miapi.module.cmmodular.armor.space.life_support.name": "Life Support Pack",
|
||||||
|
"miapi.module.cmmodular.armor.space.life_support_socket.name": "Life Support Pack with Socket"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "cmmodular:items/space_helmet"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "cmmodular:items/space_helmet_socket"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"comment": "Life support pack, worn. Twin tanks sitting on the back plate; the same 32x32 cube net as the helmet, so both are edited the same way.",
|
||||||
|
"texture_size": [32, 32],
|
||||||
|
"textures": {
|
||||||
|
"1": "cmmodular:equipment/life_support_pack",
|
||||||
|
"particle": "cmmodular:equipment/life_support_pack"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"name": "tanks",
|
||||||
|
"from": [-3.5, -6.5, 2],
|
||||||
|
"to": [3.5, 1.5, 5],
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [8, 8, 16, 16], "texture": "#1"},
|
||||||
|
"east": {"uv": [16, 8, 24, 16], "texture": "#1"},
|
||||||
|
"south": {"uv": [24, 8, 32, 16], "texture": "#1"},
|
||||||
|
"west": {"uv": [0, 8, 8, 16], "texture": "#1"},
|
||||||
|
"up": {"uv": [8, 0, 16, 8], "texture": "#1"},
|
||||||
|
"down": {"uv": [16, 0, 24, 8], "texture": "#1"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "Life Support Pack",
|
||||||
|
"origin": [0, 0, 0],
|
||||||
|
"color": 0,
|
||||||
|
"children": [0]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
{
|
||||||
|
"comment": "Life support pack with a gem setting between the tanks, worn. Same box as the plain pack, socket stamped into the back face of the net.",
|
||||||
|
"texture_size": [
|
||||||
|
32,
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"textures": {
|
||||||
|
"1": "cmmodular:equipment/life_support_pack_socket",
|
||||||
|
"particle": "cmmodular:equipment/life_support_pack_socket"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"name": "tanks",
|
||||||
|
"from": [
|
||||||
|
-3.5,
|
||||||
|
-6.5,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"to": [
|
||||||
|
3.5,
|
||||||
|
1.5,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"faces": {
|
||||||
|
"north": {
|
||||||
|
"uv": [
|
||||||
|
8,
|
||||||
|
8,
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"texture": "#1"
|
||||||
|
},
|
||||||
|
"east": {
|
||||||
|
"uv": [
|
||||||
|
16,
|
||||||
|
8,
|
||||||
|
24,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"texture": "#1"
|
||||||
|
},
|
||||||
|
"south": {
|
||||||
|
"uv": [
|
||||||
|
24,
|
||||||
|
8,
|
||||||
|
32,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"texture": "#1"
|
||||||
|
},
|
||||||
|
"west": {
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
8,
|
||||||
|
8,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"texture": "#1"
|
||||||
|
},
|
||||||
|
"up": {
|
||||||
|
"uv": [
|
||||||
|
8,
|
||||||
|
0,
|
||||||
|
16,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"texture": "#1"
|
||||||
|
},
|
||||||
|
"down": {
|
||||||
|
"uv": [
|
||||||
|
16,
|
||||||
|
0,
|
||||||
|
24,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"texture": "#1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "Life Support Pack, socketed",
|
||||||
|
"origin": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"color": 0,
|
||||||
|
"children": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"comment": "Sealed helmet, worn. One cube around the head, textured from a 32x32 cube net so the faces can be edited without touching a vanilla armour atlas.",
|
||||||
|
"texture_size": [32, 32],
|
||||||
|
"textures": {
|
||||||
|
"1": "cmmodular:equipment/space_helmet",
|
||||||
|
"particle": "cmmodular:equipment/space_helmet"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"name": "dome",
|
||||||
|
"from": [-4.25, -4.25, -4.25],
|
||||||
|
"to": [4.25, 4.25, 4.25],
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [8, 8, 16, 16], "texture": "#1"},
|
||||||
|
"east": {"uv": [16, 8, 24, 16], "texture": "#1"},
|
||||||
|
"south": {"uv": [24, 8, 32, 16], "texture": "#1"},
|
||||||
|
"west": {"uv": [0, 8, 8, 16], "texture": "#1"},
|
||||||
|
"up": {"uv": [8, 0, 16, 8], "texture": "#1"},
|
||||||
|
"down": {"uv": [16, 0, 24, 8], "texture": "#1"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "Space Helmet",
|
||||||
|
"origin": [0, 0, 0],
|
||||||
|
"color": 0,
|
||||||
|
"children": [0]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
{
|
||||||
|
"comment": "Sealed helmet with a gem setting on the crown, worn. Same cube as the plain helmet, socket stamped into the top face of the net.",
|
||||||
|
"texture_size": [
|
||||||
|
32,
|
||||||
|
32
|
||||||
|
],
|
||||||
|
"textures": {
|
||||||
|
"1": "cmmodular:equipment/space_helmet_socket",
|
||||||
|
"particle": "cmmodular:equipment/space_helmet_socket"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"name": "dome",
|
||||||
|
"from": [
|
||||||
|
-4.25,
|
||||||
|
-4.25,
|
||||||
|
-4.25
|
||||||
|
],
|
||||||
|
"to": [
|
||||||
|
4.25,
|
||||||
|
4.25,
|
||||||
|
4.25
|
||||||
|
],
|
||||||
|
"faces": {
|
||||||
|
"north": {
|
||||||
|
"uv": [
|
||||||
|
8,
|
||||||
|
8,
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"texture": "#1"
|
||||||
|
},
|
||||||
|
"east": {
|
||||||
|
"uv": [
|
||||||
|
16,
|
||||||
|
8,
|
||||||
|
24,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"texture": "#1"
|
||||||
|
},
|
||||||
|
"south": {
|
||||||
|
"uv": [
|
||||||
|
24,
|
||||||
|
8,
|
||||||
|
32,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"texture": "#1"
|
||||||
|
},
|
||||||
|
"west": {
|
||||||
|
"uv": [
|
||||||
|
0,
|
||||||
|
8,
|
||||||
|
8,
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"texture": "#1"
|
||||||
|
},
|
||||||
|
"up": {
|
||||||
|
"uv": [
|
||||||
|
8,
|
||||||
|
0,
|
||||||
|
16,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"texture": "#1"
|
||||||
|
},
|
||||||
|
"down": {
|
||||||
|
"uv": [
|
||||||
|
16,
|
||||||
|
0,
|
||||||
|
24,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"texture": "#1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "Space Helmet, socketed",
|
||||||
|
"origin": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"color": 0,
|
||||||
|
"children": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "cmmodular:items/khopesh_blade"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "cmmodular:items/pommel_gem_socket"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "cmmodular:items/pommel_great_socket"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 175 B |
|
After Width: | Height: | Size: 235 B |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 272 B |
|
After Width: | Height: | Size: 257 B |
|
After Width: | Height: | Size: 168 B |
|
After Width: | Height: | Size: 128 B |
|
After Width: | Height: | Size: 128 B |
|
After Width: | Height: | Size: 152 B |
|
After Width: | Height: | Size: 219 B |
|
After Width: | Height: | Size: 257 B |
|
After Width: | Height: | Size: 85 B |
|
After Width: | Height: | Size: 7.5 KiB |
|
|
@ -0,0 +1,64 @@
|
||||||
|
{
|
||||||
|
"translation": "Aviation Alloy ",
|
||||||
|
"groups": [
|
||||||
|
"metal"
|
||||||
|
],
|
||||||
|
"icon": {
|
||||||
|
"type": "item",
|
||||||
|
"item": "aeroengineering:aviation_alloy_ingot"
|
||||||
|
},
|
||||||
|
"hardness": 6.6,
|
||||||
|
"density": 2.4,
|
||||||
|
"flexibility": 4,
|
||||||
|
"durability": 1650,
|
||||||
|
"enchantability": 14,
|
||||||
|
"toughness": 3,
|
||||||
|
"tier": 5,
|
||||||
|
"mining_speed": 10,
|
||||||
|
"mining_level": "minecraft:incorrect_for_netherite_tool",
|
||||||
|
"armor_durability": 35,
|
||||||
|
"armor_toughness": 2.0,
|
||||||
|
"color": "889295",
|
||||||
|
"color_palette": {
|
||||||
|
"type": "grayscale_map",
|
||||||
|
"colors": {
|
||||||
|
"24": "1f2122",
|
||||||
|
"68": "3b4041",
|
||||||
|
"107": "4f575a",
|
||||||
|
"150": "575e60",
|
||||||
|
"190": "666f72",
|
||||||
|
"216": "889295",
|
||||||
|
"255": "a5aeb0"
|
||||||
|
},
|
||||||
|
"filler": "interpolate"
|
||||||
|
},
|
||||||
|
"textures": [
|
||||||
|
"metallic",
|
||||||
|
"bright"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"default": {
|
||||||
|
"fire_proof": true
|
||||||
|
},
|
||||||
|
"handheld": {
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"attribute": "generic.attack_speed",
|
||||||
|
"value": "0.08",
|
||||||
|
"operation": "+",
|
||||||
|
"slot": "mainhand"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"item": "aeroengineering:aviation_alloy_ingot",
|
||||||
|
"value": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "aeroengineering:aviation_alloy_sheet",
|
||||||
|
"value": 1.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"description": "AeroEngine Materials for Truly Modular",
|
||||||
|
"pack_format": 48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
{
|
||||||
|
"parent": "tm_armory:armor/default/helmet",
|
||||||
|
"data": {
|
||||||
|
"merge": {
|
||||||
|
"module_tag": [
|
||||||
|
"space",
|
||||||
|
"sealed"
|
||||||
|
],
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"attribute": "cmmodular:vacuum_seal",
|
||||||
|
"value": "0.5",
|
||||||
|
"operation": "+",
|
||||||
|
"slot": "head"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"replace": {
|
||||||
|
"model": [
|
||||||
|
{
|
||||||
|
"path": "cmmodular:models/item/armor/model/helmet/space/[material.texture].json",
|
||||||
|
"trim_mode": "ARMOR_LAYER_ONE",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"scale": {"x": 1, "y": 1, "z": 1},
|
||||||
|
"origin": "head"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "cmmodular:models/item/armor/gui/space/helmet/[material.texture].json",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"scale": {"x": 1, "y": 1, "z": 1},
|
||||||
|
"origin": "item"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"priority": 4,
|
||||||
|
"display_name": "miapi.module.cmmodular.armor.space.helmet.name",
|
||||||
|
"allowed_material": {
|
||||||
|
"allowedMaterials": [
|
||||||
|
"metal",
|
||||||
|
"crystal",
|
||||||
|
"glass"
|
||||||
|
],
|
||||||
|
"cost": 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
{
|
||||||
|
"parent": "cmmodular:armor/space/helmet",
|
||||||
|
"data": {
|
||||||
|
"merge": {
|
||||||
|
"module_tag": [
|
||||||
|
"socket_armor"
|
||||||
|
],
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"attribute": "minecraft:generic.armor",
|
||||||
|
"value": "-0.05",
|
||||||
|
"operation": "*",
|
||||||
|
"slot": "head"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"replace": {
|
||||||
|
"model": [
|
||||||
|
{
|
||||||
|
"path": "cmmodular:models/item/armor/model/helmet/space_socket/[material.texture].json",
|
||||||
|
"trim_mode": "ARMOR_LAYER_ONE",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"scale": {"x": 1, "y": 1, "z": 1},
|
||||||
|
"origin": "head"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "cmmodular:models/item/armor/gui/space/helmet_socket/[material.texture].json",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"scale": {"x": 1, "y": 1, "z": 1},
|
||||||
|
"origin": "item"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"slots": {
|
||||||
|
"hat": {
|
||||||
|
"allowed": [
|
||||||
|
"hat",
|
||||||
|
"sub_hat"
|
||||||
|
],
|
||||||
|
"translationKey": "miapi.slot.hat.name",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": 0, "y": -1, "z": 0},
|
||||||
|
"scale": {"x": 1.1, "y": 1.1, "z": 1.1},
|
||||||
|
"origin": "head"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gem": {
|
||||||
|
"allowed": [
|
||||||
|
"gem_armor_medium"
|
||||||
|
],
|
||||||
|
"translationKey": "miapi.slot.gemstone.medium",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": 0, "y": 3, "z": 0},
|
||||||
|
"scale": {"x": 1, "y": 1, "z": 1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"display_name": "miapi.module.cmmodular.armor.space.helmet_socket.name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"parent": "tm_armory:armor/default/back_chest",
|
||||||
|
"data": {
|
||||||
|
"merge": {
|
||||||
|
"module_tag": [
|
||||||
|
"space",
|
||||||
|
"sealed"
|
||||||
|
],
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"attribute": "cmmodular:vacuum_seal",
|
||||||
|
"value": "0.5",
|
||||||
|
"operation": "+",
|
||||||
|
"slot": "chest"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"replace": {
|
||||||
|
"model": [
|
||||||
|
{
|
||||||
|
"path": "cmmodular:models/item/armor/model/chest_back/space/[material.texture].json",
|
||||||
|
"trim_mode": "ARMOR_LAYER_ONE",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"scale": {"x": 1, "y": 1, "z": 1},
|
||||||
|
"origin": "body"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"display_name": "miapi.module.cmmodular.armor.space.life_support.name",
|
||||||
|
"allowed_material": {
|
||||||
|
"allowedMaterials": [
|
||||||
|
"metal",
|
||||||
|
"crystal",
|
||||||
|
"glass"
|
||||||
|
],
|
||||||
|
"cost": 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
{
|
||||||
|
"parent": "cmmodular:armor/space/life_support",
|
||||||
|
"data": {
|
||||||
|
"merge": {
|
||||||
|
"module_tag": [
|
||||||
|
"socket_armor"
|
||||||
|
],
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"attribute": "minecraft:generic.armor",
|
||||||
|
"value": "-0.05",
|
||||||
|
"operation": "*",
|
||||||
|
"slot": "chest"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"replace": {
|
||||||
|
"model": [
|
||||||
|
{
|
||||||
|
"path": "cmmodular:models/item/armor/model/chest_back/space_socket/[material.texture].json",
|
||||||
|
"trim_mode": "ARMOR_LAYER_ONE",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"scale": {"x": 1, "y": 1, "z": 1},
|
||||||
|
"origin": "body"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"slots": {
|
||||||
|
"banner-back": {
|
||||||
|
"allowed": [
|
||||||
|
"cosmetic_4x8",
|
||||||
|
"banner_4x8"
|
||||||
|
],
|
||||||
|
"slotType": "cosmetic",
|
||||||
|
"translationKey": "miapi.slot.chest_back_center.name",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 180, "y": 0, "z": 180},
|
||||||
|
"translation": {"x": 0, "y": 1.7, "z": 2.35},
|
||||||
|
"scale": {"x": 1, "y": 0.775, "z": 1.1},
|
||||||
|
"origin": "body"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gem": {
|
||||||
|
"allowed": [
|
||||||
|
"gem_armor_medium"
|
||||||
|
],
|
||||||
|
"translationKey": "miapi.slot.gemstone.medium",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": 0, "y": -1, "z": 0},
|
||||||
|
"scale": {"x": 1.1, "y": 1.1, "z": 1.1},
|
||||||
|
"origin": "body"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"display_name": "miapi.module.cmmodular.armor.space.life_support_socket.name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"description": "Armory Modules for Truly Modular",
|
||||||
|
"pack_format": 48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
{
|
||||||
|
"display_name": "miapi.module.cmmodular.blade.khopesh.name",
|
||||||
|
"model": [
|
||||||
|
{
|
||||||
|
"path": "cmmodular:models/item/sword/blade/khopesh/[material.texture].json",
|
||||||
|
"color": "[material.color]",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": -1, "y": -1, "z": -0.001},
|
||||||
|
"scale": {"x": 1, "y": 1, "z": 1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"is_weapon": "true",
|
||||||
|
"priority": 3,
|
||||||
|
"repair_priority": -1,
|
||||||
|
"allowed_in_slots": [
|
||||||
|
"sword_blade"
|
||||||
|
],
|
||||||
|
"module_stats": {
|
||||||
|
"blade_size": 1
|
||||||
|
},
|
||||||
|
"allowed_material": {
|
||||||
|
"allowedMaterials": [
|
||||||
|
"wood",
|
||||||
|
"metal",
|
||||||
|
"flint",
|
||||||
|
"bone",
|
||||||
|
"stone",
|
||||||
|
"crystal",
|
||||||
|
"glass"
|
||||||
|
],
|
||||||
|
"cost": 2
|
||||||
|
},
|
||||||
|
"material_indication": {
|
||||||
|
"durability": 1,
|
||||||
|
"hardness": {
|
||||||
|
"strength": 3,
|
||||||
|
"info": {
|
||||||
|
"type": "translatable",
|
||||||
|
"translate": "tm_arsenal.material_indication.blade.damage",
|
||||||
|
"color": "dark_gray"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"density": {
|
||||||
|
"strength": 2,
|
||||||
|
"info": {
|
||||||
|
"type": "translatable",
|
||||||
|
"translate": "tm_arsenal.material_indication.blade.damage",
|
||||||
|
"color": "dark_gray"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mining_speed": {
|
||||||
|
"strength": 1,
|
||||||
|
"info": {
|
||||||
|
"type": "translatable",
|
||||||
|
"translate": "tm_arsenal.material_indication.default.mining_speed",
|
||||||
|
"color": "dark_gray"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enchantments": {
|
||||||
|
"allowed": [
|
||||||
|
"minecraft:enchantable/sword",
|
||||||
|
"minecraft:enchantable/fire_aspect",
|
||||||
|
"minecraft:enchantable/sharp_weapon",
|
||||||
|
"minecraft:enchantable/weapon",
|
||||||
|
"minecraft:enchantable/mining",
|
||||||
|
"minecraft:enchantable/mining_loot"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mining_level": {
|
||||||
|
"axe": {
|
||||||
|
"allowed": [
|
||||||
|
"#minecraft:mineable/axe"
|
||||||
|
],
|
||||||
|
"use_material": true,
|
||||||
|
"speed": "[material.mining_speed] * 0.75"
|
||||||
|
},
|
||||||
|
"sword": {
|
||||||
|
"allowed": [
|
||||||
|
"#minecraft:sword_efficient"
|
||||||
|
],
|
||||||
|
"use_material": false,
|
||||||
|
"speed": "1.5"
|
||||||
|
},
|
||||||
|
"cobweb": {
|
||||||
|
"allowed": [
|
||||||
|
[
|
||||||
|
"minecraft:cobweb"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"use_material": false,
|
||||||
|
"correct_for_drops": true,
|
||||||
|
"speed": "15"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ability_context": {
|
||||||
|
"axe_ability": {}
|
||||||
|
},
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"attribute": "generic.attack_damage",
|
||||||
|
"value": "[material.hardness]*0.9 + [material.density]*0.5",
|
||||||
|
"operation": "+",
|
||||||
|
"slot": "mainhand"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attribute": "generic.attack_speed",
|
||||||
|
"value": "0.15",
|
||||||
|
"operation": "+",
|
||||||
|
"slot": "mainhand"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attribute": "generic.attack_knockback",
|
||||||
|
"value": "1",
|
||||||
|
"operation": "+",
|
||||||
|
"slot": "mainhand"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attribute": "miapi:generic.attack_range",
|
||||||
|
"value": "-0.4",
|
||||||
|
"operation": "+",
|
||||||
|
"slot": "mainhand"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attribute": "miapi:generic.shield_break",
|
||||||
|
"value": "4",
|
||||||
|
"operation": "+",
|
||||||
|
"slot": "mainhand"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"durability": "[material.durability] * 0.2",
|
||||||
|
"better_combat_config": "bettercombat:axe",
|
||||||
|
"item_id": "miapi:modular_sword",
|
||||||
|
"fake_item_tag": [
|
||||||
|
"minecraft:swords",
|
||||||
|
"c:swords",
|
||||||
|
"minecraft:axes",
|
||||||
|
"c:axes",
|
||||||
|
"c:tools",
|
||||||
|
"c:tool/axe"
|
||||||
|
],
|
||||||
|
"module_tag": [
|
||||||
|
"default",
|
||||||
|
"handheld",
|
||||||
|
"blade",
|
||||||
|
"head",
|
||||||
|
"blade",
|
||||||
|
"blade_medium",
|
||||||
|
"axe",
|
||||||
|
"polearm_glaive",
|
||||||
|
"sharp"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
{
|
||||||
|
"display_name": "miapi.module.cmmodular.pommel.gem_socket.name",
|
||||||
|
"model": {
|
||||||
|
"path": "cmmodular:models/item/sword/pommel/gem_socket/[material.texture].json",
|
||||||
|
"color": "[material.color]",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": -4, "y": -5, "z": 0.001},
|
||||||
|
"scale": {"x": 1, "y": 1, "z": 1}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allowed_in_slots": [
|
||||||
|
"sword_pommel"
|
||||||
|
],
|
||||||
|
"slots": {
|
||||||
|
"socket_medium": {
|
||||||
|
"allowed": [
|
||||||
|
"gem_melee_medium"
|
||||||
|
],
|
||||||
|
"translationKey": "miapi.slot.gem.name",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": -5, "y": -5, "z": 0},
|
||||||
|
"scale": {"x": 1, "y": 1, "z": 1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"attribute": "generic.attack_speed",
|
||||||
|
"value": "-0.06",
|
||||||
|
"operation": "*",
|
||||||
|
"slot": "mainhand"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"priority": 0,
|
||||||
|
"repair_priority": 0,
|
||||||
|
"durability": "[material.durability]* 0.25",
|
||||||
|
"material_indication": {
|
||||||
|
"durability": 1
|
||||||
|
},
|
||||||
|
"allowed_material": {
|
||||||
|
"allowedMaterials": [
|
||||||
|
"wood",
|
||||||
|
"metal",
|
||||||
|
"flint",
|
||||||
|
"bone",
|
||||||
|
"stone",
|
||||||
|
"rod",
|
||||||
|
"crystal",
|
||||||
|
"glass"
|
||||||
|
],
|
||||||
|
"cost": 2
|
||||||
|
},
|
||||||
|
"module_tag": [
|
||||||
|
"default",
|
||||||
|
"handheld"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
{
|
||||||
|
"display_name": "miapi.module.cmmodular.pommel.great_socket.name",
|
||||||
|
"model": {
|
||||||
|
"path": "cmmodular:models/item/sword/pommel/great_socket/[material.texture].json",
|
||||||
|
"color": "[material.color]",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": -4, "y": -5, "z": 0.001},
|
||||||
|
"scale": {"x": 1, "y": 1, "z": 1}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allowed_in_slots": [
|
||||||
|
"sword_pommel"
|
||||||
|
],
|
||||||
|
"slots": {
|
||||||
|
"socket_large": {
|
||||||
|
"allowed": [
|
||||||
|
"gem_melee_large"
|
||||||
|
],
|
||||||
|
"translationKey": "miapi.slot.gem.name",
|
||||||
|
"transform": {
|
||||||
|
"rotation": {"x": 0, "y": 0, "z": 0},
|
||||||
|
"translation": {"x": -5, "y": -5, "z": 0},
|
||||||
|
"scale": {"x": 1, "y": 1, "z": 1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"attribute": "generic.attack_speed",
|
||||||
|
"value": "-0.12",
|
||||||
|
"operation": "*",
|
||||||
|
"slot": "mainhand"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"priority": 0,
|
||||||
|
"repair_priority": 0,
|
||||||
|
"durability": "[material.durability]* 0.3",
|
||||||
|
"material_indication": {
|
||||||
|
"durability": 1
|
||||||
|
},
|
||||||
|
"allowed_material": {
|
||||||
|
"allowedMaterials": [
|
||||||
|
"metal",
|
||||||
|
"flint",
|
||||||
|
"bone",
|
||||||
|
"stone",
|
||||||
|
"crystal",
|
||||||
|
"glass"
|
||||||
|
],
|
||||||
|
"cost": 3
|
||||||
|
},
|
||||||
|
"module_tag": [
|
||||||
|
"default",
|
||||||
|
"handheld"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"description": "Arsenal Modules for Truly Modular",
|
||||||
|
"pack_format": 48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"parent": "cmmodular:metal/arcane_metal",
|
||||||
|
"data": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"item": "irons_spellbooks:arcane_ingot",
|
||||||
|
"value": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "create_wizardry:arcane_sheet",
|
||||||
|
"value": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "create_wizardry:arcane_block",
|
||||||
|
"value": 9.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"parent": "cmmodular:metal/mithril",
|
||||||
|
"data": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"item": "irons_spellbooks:mithril_ingot",
|
||||||
|
"value": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "c:ingots/mithril",
|
||||||
|
"value": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "c:nuggets/mithril",
|
||||||
|
"value": 0.11112
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "c:storage_blocks/mithril",
|
||||||
|
"value": 9.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "create_wizardry:mithril_nugget",
|
||||||
|
"value": 0.11112
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"description": "Create Wizardry Materials for Truly Modular",
|
||||||
|
"pack_format": 48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
{
|
||||||
|
"translation": "Platinum ",
|
||||||
|
"groups": [
|
||||||
|
"metal"
|
||||||
|
],
|
||||||
|
"icon": {
|
||||||
|
"type": "item",
|
||||||
|
"item": "createpropulsion:platinum_ingot"
|
||||||
|
},
|
||||||
|
"hardness": 5.0,
|
||||||
|
"density": 5.7,
|
||||||
|
"flexibility": 3,
|
||||||
|
"durability": 680,
|
||||||
|
"enchantability": 24,
|
||||||
|
"toughness": 2,
|
||||||
|
"tier": 4,
|
||||||
|
"mining_speed": 7,
|
||||||
|
"mining_level": "minecraft:incorrect_for_diamond_tool",
|
||||||
|
"armor_durability": 24,
|
||||||
|
"armor_toughness": 1.0,
|
||||||
|
"color": "ADCCDE",
|
||||||
|
"color_palette": {
|
||||||
|
"type": "grayscale_map",
|
||||||
|
"colors": {
|
||||||
|
"24": "1b2731",
|
||||||
|
"68": "334b5e",
|
||||||
|
"107": "547086",
|
||||||
|
"150": "6896a4",
|
||||||
|
"190": "8dabc2",
|
||||||
|
"216": "adccde",
|
||||||
|
"255": "dbf5e9"
|
||||||
|
},
|
||||||
|
"filler": "interpolate"
|
||||||
|
},
|
||||||
|
"textures": [
|
||||||
|
"metallic",
|
||||||
|
"shiny"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"default": {
|
||||||
|
"fire_proof": true
|
||||||
|
},
|
||||||
|
"handheld": {
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"attribute": "generic.attack_speed",
|
||||||
|
"value": "-0.08",
|
||||||
|
"operation": "+",
|
||||||
|
"slot": "mainhand"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"item": "createpropulsion:platinum_ingot",
|
||||||
|
"value": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "createpropulsion:platinum_nugget",
|
||||||
|
"value": 0.11112
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "createpropulsion:platinum_sheet",
|
||||||
|
"value": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "createpropulsion:platinum_block",
|
||||||
|
"value": 9.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "c:ingots/platinum",
|
||||||
|
"value": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "c:nuggets/platinum",
|
||||||
|
"value": 0.11112
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "c:storage_blocks/platinum",
|
||||||
|
"value": 9.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"description": "Create Propulsion Materials for Truly Modular",
|
||||||
|
"pack_format": 48
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,23 @@
|
||||||
{
|
{
|
||||||
"key": "miapi:crystal/amethyst",
|
"parent": "miapi:crystal/amethyst",
|
||||||
|
"data": {
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"item": "iceandfire:amethyst_gem",
|
"item": "minecraft:amethyst_shard",
|
||||||
|
"value": 0.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "minecraft:amethyst_cluster",
|
||||||
|
"value": 0.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "minecraft:amethyst_block",
|
||||||
"value": 1.0
|
"value": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "iceandfire:amythest_gem",
|
||||||
|
"value": 0.25
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"translation": "Arcane Steel ",
|
"translation": "Arcane Alloy ",
|
||||||
"groups": [
|
"groups": [
|
||||||
"metal"
|
"metal"
|
||||||
],
|
],
|
||||||
|
|
@ -36,8 +36,44 @@
|
||||||
"metallic"
|
"metallic"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"handheld": {
|
"default": {
|
||||||
"attributes": [
|
"attributes": [
|
||||||
|
{
|
||||||
|
"attribute": "irons_spellbooks:cooldown_reduction",
|
||||||
|
"value": "0.1",
|
||||||
|
"operation": "*",
|
||||||
|
"slot": "mainhand"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attribute": "irons_spellbooks:cooldown_reduction",
|
||||||
|
"value": "0.05",
|
||||||
|
"operation": "*",
|
||||||
|
"slot": "head"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attribute": "irons_spellbooks:cooldown_reduction",
|
||||||
|
"value": "0.04",
|
||||||
|
"operation": "*",
|
||||||
|
"slot": "chest"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attribute": "irons_spellbooks:cooldown_reduction",
|
||||||
|
"value": "0.03",
|
||||||
|
"operation": "*",
|
||||||
|
"slot": "legs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attribute": "irons_spellbooks:cooldown_reduction",
|
||||||
|
"value": "0.03",
|
||||||
|
"operation": "*",
|
||||||
|
"slot": "feet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attribute": "irons_spellbooks:cooldown_reduction",
|
||||||
|
"value": "0.03",
|
||||||
|
"operation": "*",
|
||||||
|
"slot": "offhand"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"attribute": "irons_spellbooks:spell_power",
|
"attribute": "irons_spellbooks:spell_power",
|
||||||
"value": "0.05",
|
"value": "0.05",
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,10 @@
|
||||||
{
|
{
|
||||||
"item": "pastel:paltaeria_gem",
|
"item": "pastel:paltaeria_gem",
|
||||||
"value": 1.0
|
"value": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "pastel:paltaeria_fragments",
|
||||||
|
"value": 0.125
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,10 @@
|
||||||
{
|
{
|
||||||
"item": "pastel:stratine_gem",
|
"item": "pastel:stratine_gem",
|
||||||
"value": 1.0
|
"value": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item": "pastel:stratine_fragments",
|
||||||
|
"value": 0.125
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,21 @@ the mod that adds it, so a material always looks like the thing it is made of.
|
||||||
|
|
||||||
python3 tools/generate_materials.py --jars ~/mods
|
python3 tools/generate_materials.py --jars ~/mods
|
||||||
|
|
||||||
The jar directory needs one jar per source mod (Mekanism, Create, Create: The
|
Point --jars at the pack's mods folder. Generated files are committed, so this
|
||||||
Air War, Create: Cosmonautics, Ice and Fire). Generated files are committed, so
|
only needs re-running when a material definition or a source texture changes.
|
||||||
this only needs re-running when a material definition or a source texture
|
|
||||||
changes.
|
|
||||||
|
|
||||||
Every item id in materials.py is checked against the jars; a typo fails the run
|
Every item id in materials.py is checked against the jars; a typo fails the run
|
||||||
rather than shipping a material that silently refuses to load.
|
rather than shipping a material that silently refuses to load. A mod whose jar
|
||||||
|
is not in the folder is skipped instead, keeping its committed files, so the set
|
||||||
|
of jars does not have to be complete to regenerate the rest.
|
||||||
|
|
||||||
|
Only the material folders are rewritten. The hand-written module JSON that lives
|
||||||
|
in the same packs is left alone.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import shutil
|
|
||||||
import sys
|
import sys
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
|
|
@ -31,6 +33,7 @@ sys.path.insert(0, str(Path(__file__).parent))
|
||||||
from materials import EXTENSIONS, MATERIALS, PACKS # noqa: E402
|
from materials import EXTENSIONS, MATERIALS, PACKS # noqa: E402
|
||||||
|
|
||||||
NAMESPACE = "cmmodular"
|
NAMESPACE = "cmmodular"
|
||||||
|
VANILLA = "minecraft:"
|
||||||
PACK_FORMAT = 48 # 1.21.1
|
PACK_FORMAT = 48 # 1.21.1
|
||||||
|
|
||||||
# Brightness levels of MIAPI's grayscale templates. Each gets a colour; values
|
# Brightness levels of MIAPI's grayscale templates. Each gets a colour; values
|
||||||
|
|
@ -56,14 +59,24 @@ class Jars:
|
||||||
def __init__(self, folder: Path):
|
def __init__(self, folder: Path):
|
||||||
self.zips = []
|
self.zips = []
|
||||||
self.by_namespace = {}
|
self.by_namespace = {}
|
||||||
|
# Addons ship a handful of files under the namespace of the mod they add
|
||||||
|
# to - Applied Mekanistics into ae2, half the Create addons into create -
|
||||||
|
# so a namespace goes to whichever jar has the most of it, which is the
|
||||||
|
# mod that actually owns it rather than whichever sorted first.
|
||||||
|
counts = {}
|
||||||
for path in sorted(folder.glob("*.jar")):
|
for path in sorted(folder.glob("*.jar")):
|
||||||
zf = zipfile.ZipFile(path)
|
zf = zipfile.ZipFile(path)
|
||||||
names = zf.namelist()
|
names = zf.namelist()
|
||||||
self.zips.append((path.name, zf, set(names)))
|
self.zips.append((path.name, zf, set(names)))
|
||||||
|
here = {}
|
||||||
for name in names:
|
for name in names:
|
||||||
m = re.match(r"assets/([^/]+)/", name)
|
m = re.match(r"assets/([^/]+)/", name)
|
||||||
if m:
|
if m:
|
||||||
self.by_namespace.setdefault(m.group(1), (path.name, zf, set(names)))
|
here[m.group(1)] = here.get(m.group(1), 0) + 1
|
||||||
|
for namespace, count in here.items():
|
||||||
|
if count > counts.get(namespace, 0):
|
||||||
|
counts[namespace] = count
|
||||||
|
self.by_namespace[namespace] = (path.name, zf, set(names))
|
||||||
|
|
||||||
def _for(self, namespace):
|
def _for(self, namespace):
|
||||||
hit = self.by_namespace.get(namespace)
|
hit = self.by_namespace.get(namespace)
|
||||||
|
|
@ -199,6 +212,38 @@ def check_items(spec, jars: Jars):
|
||||||
return problems
|
return problems
|
||||||
|
|
||||||
|
|
||||||
|
def check_extension_items(ext, jars: Jars):
|
||||||
|
"""Same check for extensions - they name items too, and used to escape it."""
|
||||||
|
problems = []
|
||||||
|
for entry in ext["data"].get("data", {}).get("items", []):
|
||||||
|
item = entry.get("item", "")
|
||||||
|
if item.startswith(VANILLA):
|
||||||
|
continue
|
||||||
|
if item and not jars.has_item(item):
|
||||||
|
problems.append(f"{ext['path']}: no such item {item}")
|
||||||
|
return problems
|
||||||
|
|
||||||
|
|
||||||
|
def materials_path(out: Path, spec) -> Path:
|
||||||
|
"""Where a material or extension is written."""
|
||||||
|
path = spec["path"] if "path" in spec else f"{spec['group']}/{spec['name']}"
|
||||||
|
return out / spec["pack"] / "data" / NAMESPACE / "miapi" / "materials" / f"{path}.json"
|
||||||
|
|
||||||
|
|
||||||
|
def namespaces_of(spec):
|
||||||
|
"""Every namespace a material or extension needs a jar for.
|
||||||
|
|
||||||
|
Vanilla is not one of them - there is no Minecraft jar in the folder, and
|
||||||
|
the `minecraft` namespace a mod's resource overrides create is not it.
|
||||||
|
"""
|
||||||
|
entries = (spec["items"] if "items" in spec
|
||||||
|
else spec["data"].get("data", {}).get("items", []))
|
||||||
|
names = {entry["item"].split(":", 1)[0] for entry in entries if "item" in entry}
|
||||||
|
if "palette_from" in spec:
|
||||||
|
names.add(spec["palette_from"].split(":", 1)[0])
|
||||||
|
return names - {VANILLA.rstrip(":")}
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description=__doc__,
|
parser = argparse.ArgumentParser(description=__doc__,
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
|
@ -212,20 +257,45 @@ def main():
|
||||||
jars = Jars(args.jars)
|
jars = Jars(args.jars)
|
||||||
print(f"namespaces found: {', '.join(sorted(jars.by_namespace))}\n")
|
print(f"namespaces found: {', '.join(sorted(jars.by_namespace))}\n")
|
||||||
|
|
||||||
|
# A mod whose jar is not in the folder is skipped rather than fatal, and its
|
||||||
|
# committed file is left alone: the pack this addon follows drops and adds
|
||||||
|
# mods, and losing every material of a mod you no longer have - or being
|
||||||
|
# unable to regenerate anything without a complete set of jars - is worse
|
||||||
|
# than regenerating what you can. Anything the jars *can* be checked against
|
||||||
|
# is still checked, so a typo in a mod you do have still fails the run.
|
||||||
|
def present(spec):
|
||||||
|
return namespaces_of(spec) <= set(jars.by_namespace)
|
||||||
|
|
||||||
|
materials = [spec for spec in MATERIALS if present(spec)]
|
||||||
|
extensions = [ext for ext in EXTENSIONS if present(ext)]
|
||||||
|
skipped = [spec for spec in MATERIALS if not present(spec)]
|
||||||
|
skipped += [ext for ext in EXTENSIONS if not present(ext)]
|
||||||
|
if skipped:
|
||||||
|
missing = sorted({ns for spec in skipped for ns in namespaces_of(spec)
|
||||||
|
if ns not in jars.by_namespace})
|
||||||
|
print(f"no jar for {', '.join(missing)} - leaving "
|
||||||
|
f"{len(skipped)} committed file(s) as they are\n")
|
||||||
|
|
||||||
problems = []
|
problems = []
|
||||||
for spec in MATERIALS:
|
for spec in materials:
|
||||||
problems += check_items(spec, jars)
|
problems += check_items(spec, jars)
|
||||||
|
for ext in extensions:
|
||||||
|
problems += check_extension_items(ext, jars)
|
||||||
if problems:
|
if problems:
|
||||||
print("aborting, item ids do not check out:", file=sys.stderr)
|
print("aborting, item ids do not check out:", file=sys.stderr)
|
||||||
for p in problems:
|
for p in problems:
|
||||||
print(" " + p, file=sys.stderr)
|
print(" " + p, file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Wipe first. A material that moves between packs would otherwise leave a
|
# Clear out the material files first. A material that moves between packs
|
||||||
# stale copy behind, and two files claiming the same material id is a silent
|
# would otherwise leave a stale copy behind, and two files claiming the same
|
||||||
# mess to debug.
|
# material id is a silent mess to debug. Only the generated material folders
|
||||||
if args.out.exists():
|
# go: the packs also hold hand-written module JSON, and the files of the
|
||||||
shutil.rmtree(args.out)
|
# skipped mods above have to survive a run that cannot rebuild them.
|
||||||
|
keep = {materials_path(args.out, spec) for spec in skipped}
|
||||||
|
for stale in sorted(args.out.glob(f"*/data/{NAMESPACE}/miapi/materials/**/*.json")):
|
||||||
|
if stale not in keep:
|
||||||
|
stale.unlink()
|
||||||
|
|
||||||
written = 0
|
written = 0
|
||||||
for pack_id, pack in PACKS.items():
|
for pack_id, pack in PACKS.items():
|
||||||
|
|
@ -239,23 +309,21 @@ def main():
|
||||||
root.mkdir(parents=True, exist_ok=True)
|
root.mkdir(parents=True, exist_ok=True)
|
||||||
(root / "pack.mcmeta").write_text(json.dumps(mcmeta, indent=2) + "\n")
|
(root / "pack.mcmeta").write_text(json.dumps(mcmeta, indent=2) + "\n")
|
||||||
|
|
||||||
for spec in MATERIALS:
|
for spec in materials:
|
||||||
material = build_material(spec, jars)
|
material = build_material(spec, jars)
|
||||||
path = (args.out / spec["pack"] / "data" / NAMESPACE / "miapi" / "materials"
|
path = materials_path(args.out, spec)
|
||||||
/ spec["group"] / f"{spec['name']}.json")
|
|
||||||
path.parent.mkdir(parents=True, exist_ok=True)
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
path.write_text(json.dumps(material, indent=2) + "\n")
|
path.write_text(json.dumps(material, indent=2) + "\n")
|
||||||
written += 1
|
written += 1
|
||||||
swatch = " ".join(material["color_palette"]["colors"][str(s)] for s in STOPS)
|
swatch = " ".join(material["color_palette"]["colors"][str(s)] for s in STOPS)
|
||||||
print(f" {spec['pack']:<13} {NAMESPACE}:{spec['group']}/{spec['name']:<28} {swatch}")
|
print(f" {spec['pack']:<16} {NAMESPACE}:{spec['group']}/{spec['name']:<28} {swatch}")
|
||||||
|
|
||||||
for ext in EXTENSIONS:
|
for ext in extensions:
|
||||||
path = (args.out / ext["pack"] / "data" / NAMESPACE / "miapi" / "materials"
|
path = materials_path(args.out, ext)
|
||||||
/ f"{ext['path']}.json")
|
|
||||||
path.parent.mkdir(parents=True, exist_ok=True)
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
path.write_text(json.dumps(ext["data"], indent=2) + "\n")
|
path.write_text(json.dumps(ext["data"], indent=2) + "\n")
|
||||||
written += 1
|
written += 1
|
||||||
print(f" {ext['pack']:<13} extends {ext['data']['key']}")
|
print(f" {ext['pack']:<16} extends {ext['data']['parent']}")
|
||||||
|
|
||||||
print(f"\n{written} files written to {args.out}")
|
print(f"\n{written} files written to {args.out}")
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,17 @@ PACKS = {
|
||||||
"crystal_chronicles": {"mod": "crystal_chronicles",
|
"crystal_chronicles": {"mod": "crystal_chronicles",
|
||||||
"name": "Crystal Chronicles Materials"},
|
"name": "Crystal Chronicles Materials"},
|
||||||
"pastel": {"mod": "pastel", "name": "Pastel Materials"},
|
"pastel": {"mod": "pastel", "name": "Pastel Materials"},
|
||||||
|
"createpropulsion": {"mod": "createpropulsion",
|
||||||
|
"name": "Create Propulsion Materials"},
|
||||||
|
"aeroengineering": {"mod": "aeroengineering", "name": "AeroEngine Materials"},
|
||||||
|
"create_wizardry": {"mod": "create_wizardry", "name": "Create Wizardry Materials"},
|
||||||
|
# Modules rather than materials, but the same problem: a module that names
|
||||||
|
# Arsenal's or Armory's slots - or inherits one of their modules - is only
|
||||||
|
# useful when that mod is installed. Nothing is generated into these two;
|
||||||
|
# they hold the hand-written module JSON under packs/arsenal and
|
||||||
|
# packs/armory, and are listed here so their pack.mcmeta is written.
|
||||||
|
"arsenal": {"mod": "tm_arsenal", "name": "Arsenal Modules"},
|
||||||
|
"armory": {"mod": "tm_armory", "name": "Armory Modules"},
|
||||||
}
|
}
|
||||||
|
|
||||||
# Attribute this mod registers itself, so a material can grant something the
|
# Attribute this mod registers itself, so a material can grant something the
|
||||||
|
|
@ -341,6 +352,38 @@ MATERIALS = [
|
||||||
enchantability=12, mining_speed=10, toughness=3, armor_durability=36,
|
enchantability=12, mining_speed=10, toughness=3, armor_durability=36,
|
||||||
armor_toughness=2.0, properties={"default": {"fire_proof": True}}),
|
armor_toughness=2.0, properties={"default": {"fire_proof": True}}),
|
||||||
|
|
||||||
|
# Create Propulsion: Simulated's own ore, and the only platinum in the pack.
|
||||||
|
M("platinum", "createpropulsion", "metal", "Platinum",
|
||||||
|
"createpropulsion:platinum_ingot",
|
||||||
|
[{"item": "createpropulsion:platinum_ingot", "value": 1.0},
|
||||||
|
{"item": "createpropulsion:platinum_nugget", "value": NUGGET},
|
||||||
|
{"item": "createpropulsion:platinum_sheet", "value": 1.0},
|
||||||
|
{"item": "createpropulsion:platinum_block", "value": BLOCK}],
|
||||||
|
tier=4, hardness=5.0, density=5.7, flexibility=3, durability=680,
|
||||||
|
enchantability=24, mining_speed=7, toughness=2, armor_durability=24,
|
||||||
|
armor_toughness=1.0, textures=("metallic", "shiny"),
|
||||||
|
properties={"default": {"fire_proof": True},
|
||||||
|
"handheld": speed(-0.08)}),
|
||||||
|
# Real platinum: nearly as dense as osmium, but soft, so it swings slow
|
||||||
|
# and hits no harder than steel. What it is actually for is the precious
|
||||||
|
# metal's bargain - gold-grade enchantability without gold's fragility -
|
||||||
|
# and it melts at 1768C, hence the heat proofing.
|
||||||
|
|
||||||
|
# -------------------------------------------------------------- AeroEngine
|
||||||
|
M("aviation_alloy", "aeroengineering", "metal", "Aviation Alloy",
|
||||||
|
"aeroengineering:aviation_alloy_ingot",
|
||||||
|
[{"item": "aeroengineering:aviation_alloy_ingot", "value": 1.0},
|
||||||
|
{"item": "aeroengineering:aviation_alloy_sheet", "value": 1.0}],
|
||||||
|
tier=5, hardness=6.6, density=2.4, flexibility=4, durability=1650,
|
||||||
|
enchantability=14, mining_speed=10, toughness=3, armor_durability=35,
|
||||||
|
armor_toughness=2.0, textures=("metallic", "bright"),
|
||||||
|
properties={"default": {"fire_proof": True},
|
||||||
|
"handheld": speed(0.08)}),
|
||||||
|
# Iron superheated with netherite powder: a turbine superalloy. Light and
|
||||||
|
# heat-proof like titanium, harder and more flexible, worse to enchant -
|
||||||
|
# it sits between titanium and titanium alloy, which is where its recipe
|
||||||
|
# sits too.
|
||||||
|
|
||||||
# ------------------------------------------------------- Create: The Air War
|
# ------------------------------------------------------- Create: The Air War
|
||||||
M("sulfur", "air_war", "crystal", "Sulfur", "create_the_air_wars:raw_sulfur",
|
M("sulfur", "air_war", "crystal", "Sulfur", "create_the_air_wars:raw_sulfur",
|
||||||
[{"item": "create_the_air_wars:raw_sulfur", "value": 1.0},
|
[{"item": "create_the_air_wars:raw_sulfur", "value": 1.0},
|
||||||
|
|
@ -589,14 +632,44 @@ MATERIALS = [
|
||||||
properties={"handheld": speed(0.12)}),
|
properties={"handheld": speed(0.12)}),
|
||||||
# Light enough to swing fast and enchant well, in the Tolkien sense.
|
# Light enough to swing fast and enchant well, in the Tolkien sense.
|
||||||
|
|
||||||
M("arcane_metal", "irons_spellbooks", "metal", "Arcane Steel",
|
# "Arcane Alloy" rather than Arcane Steel: Create: Wizardry ships a resource
|
||||||
|
# pack that renames the ingot, and that is what the item is called in game.
|
||||||
|
M("arcane_metal", "irons_spellbooks", "metal", "Arcane Alloy",
|
||||||
"irons_spellbooks:arcane_ingot",
|
"irons_spellbooks:arcane_ingot",
|
||||||
[{"item": "irons_spellbooks:arcane_ingot", "value": 1.0}],
|
[{"item": "irons_spellbooks:arcane_ingot", "value": 1.0}],
|
||||||
tier=5, hardness=6.2, density=2.8, flexibility=3, durability=1700,
|
tier=5, hardness=6.2, density=2.8, flexibility=3, durability=1700,
|
||||||
enchantability=26, mining_speed=9, toughness=3, armor_durability=34,
|
enchantability=26, mining_speed=9, toughness=3, armor_durability=34,
|
||||||
armor_toughness=2.0,
|
armor_toughness=2.0,
|
||||||
properties={"handheld": {"attributes": [
|
# The one thing arcane alloy is for: spells come back faster. Cooldown
|
||||||
attribute("irons_spellbooks:spell_power", 0.05, "mainhand", "*")]}}),
|
# reduction is the whole reason to build out of it rather than out of
|
||||||
|
# mithril, so it is deliberately the strongest effect on any metal here.
|
||||||
|
#
|
||||||
|
# Under `default`, not `handheld`, so armour plated in it counts too - a
|
||||||
|
# caster wants the set, not just the sword. Per-slot rather than one
|
||||||
|
# `armor`-wide modifier, for the same reasons as arcane essence: a helmet
|
||||||
|
# can be worth more than boots, and a weapon reads as a held bonus
|
||||||
|
# instead of claiming something "when worn".
|
||||||
|
#
|
||||||
|
# Iron's Spells treats the attribute as a factor on a base of 1, hence the
|
||||||
|
# `*` operation - a flat `+` would be added to a base of zero and do
|
||||||
|
# nothing - and spends it as `cooldown * (2 - value)`. So +0.10 is 10% off
|
||||||
|
# the wait, and +1.00 in total would be instant casting.
|
||||||
|
#
|
||||||
|
# These stack per module, and that is what sets the numbers. A weapon is
|
||||||
|
# about four modules, so one built entirely of arcane alloy is 40% - well
|
||||||
|
# past the 25% of Iron's Spells' own best staff, which is the point. The
|
||||||
|
# armour values are smaller because a full set is a dozen modules: all of
|
||||||
|
# it in arcane alloy lands near 45%, so even a player wearing the set and
|
||||||
|
# holding the staff stays under the 100% the formula bottoms out at.
|
||||||
|
properties={"default": {"attributes": [
|
||||||
|
attribute("irons_spellbooks:cooldown_reduction", 0.10, "mainhand", "*"),
|
||||||
|
attribute("irons_spellbooks:cooldown_reduction", 0.05, "head", "*"),
|
||||||
|
attribute("irons_spellbooks:cooldown_reduction", 0.04, "chest", "*"),
|
||||||
|
attribute("irons_spellbooks:cooldown_reduction", 0.03, "legs", "*"),
|
||||||
|
attribute("irons_spellbooks:cooldown_reduction", 0.03, "feet", "*"),
|
||||||
|
attribute("irons_spellbooks:cooldown_reduction", 0.03, "offhand", "*"),
|
||||||
|
attribute("irons_spellbooks:spell_power", 0.05, "mainhand", "*"),
|
||||||
|
]}}),
|
||||||
|
|
||||||
# ------------------------------------------------- Immersive Engineering
|
# ------------------------------------------------- Immersive Engineering
|
||||||
# Steel, lead, uranium and silver are not here - Immersive Engineering adds
|
# Steel, lead, uranium and silver are not here - Immersive Engineering adds
|
||||||
|
|
@ -1064,14 +1137,26 @@ _GEM_BAND = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Nuggets, in effect: Pastel's two float-gems break into eight fragments on an
|
||||||
|
# anvil and nine come back out of a floatblock, so a fragment is an eighth of a
|
||||||
|
# gem and worth accepting as one.
|
||||||
|
GEM_FRAGMENTS = {
|
||||||
|
"paltaeria_gem": ("pastel:paltaeria_fragments", 0.125),
|
||||||
|
"stratine_gem": ("pastel:stratine_fragments", 0.125),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _gem_family(pack, namespace, table):
|
def _gem_family(pack, namespace, table):
|
||||||
out = []
|
out = []
|
||||||
for item, (tier, props) in table.items():
|
for item, (tier, props) in table.items():
|
||||||
label = item.replace("_shard", "").replace("_crystal", "").replace("_gem", "")
|
label = item.replace("_shard", "").replace("_crystal", "").replace("_gem", "")
|
||||||
|
items = [{"item": f"{namespace}:{item}", "value": 1.0}]
|
||||||
|
if item in GEM_FRAGMENTS:
|
||||||
|
fragment, value = GEM_FRAGMENTS[item]
|
||||||
|
items.append({"item": fragment, "value": value})
|
||||||
out.append(M(
|
out.append(M(
|
||||||
item, pack, "crystal", label.replace("_", " ").title(),
|
item, pack, "crystal", label.replace("_", " ").title(),
|
||||||
f"{namespace}:{item}",
|
f"{namespace}:{item}", items,
|
||||||
[{"item": f"{namespace}:{item}", "value": 1.0}],
|
|
||||||
tier=tier, groups=("crystal", "gem"), textures=("crystal", "bright"),
|
tier=tier, groups=("crystal", "gem"), textures=("crystal", "bright"),
|
||||||
properties={"default": props} if props else None,
|
properties={"default": props} if props else None,
|
||||||
**_GEM_BAND[tier]))
|
**_GEM_BAND[tier]))
|
||||||
|
|
@ -1100,21 +1185,50 @@ for _material in MATERIALS:
|
||||||
g for g in GEM_SOCKET_GROUPS if g not in _material["groups"]]
|
g for g in GEM_SOCKET_GROUPS if g not in _material["groups"]]
|
||||||
|
|
||||||
|
|
||||||
# Extensions add data to a material that already exists rather than replacing it.
|
# Extensions edit a material that already exists instead of adding a new one.
|
||||||
# Ice and Fire's amethyst is the same stone MIAPI already ships, so it just
|
# The file goes in the materials folder like any other and is told apart by its
|
||||||
# becomes another way to craft it.
|
# shape: `parent` names the material it edits and `data` is merged onto a copy
|
||||||
|
# of it - the same form MIAPI's own stained glass uses to vary plain glass.
|
||||||
|
#
|
||||||
|
# The merge overwrites whole fields rather than appending to them, so an
|
||||||
|
# extension that adds an ingredient has to repeat the ones it wants to keep.
|
||||||
EXTENSIONS = [
|
EXTENSIONS = [
|
||||||
|
# Ice and Fire's amethyst is the same stone MIAPI already ships, so it just
|
||||||
|
# becomes another way to craft it. The item id really is spelled
|
||||||
|
# "amythest_gem" - that typo is in Ice and Fire itself.
|
||||||
{
|
{
|
||||||
"pack": "iceandfire",
|
"pack": "iceandfire",
|
||||||
"path": "crystal/amethyst",
|
"path": "crystal/amethyst",
|
||||||
"data": {
|
"data": {
|
||||||
"key": "miapi:crystal/amethyst",
|
"parent": "miapi:crystal/amethyst",
|
||||||
"items": [{"item": "iceandfire:amethyst_gem", "value": 1.0}],
|
"data": {
|
||||||
|
"items": [
|
||||||
|
{"item": "minecraft:amethyst_shard", "value": 0.25},
|
||||||
|
{"item": "minecraft:amethyst_cluster", "value": 0.25},
|
||||||
|
{"item": "minecraft:amethyst_block", "value": 1.0},
|
||||||
|
{"item": "iceandfire:amythest_gem", "value": 0.25},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Forms of a material that a *different* mod adds. Create: Wizardry presses
|
||||||
|
# Iron's Spells' arcane ingots into sheets and stacks them into blocks, and adds
|
||||||
|
# the mithril nugget the base mod never had, so all of those are the same metal.
|
||||||
|
#
|
||||||
|
# They cannot simply be listed on the material: it lives in the Iron's Spells
|
||||||
|
# pack, and an item id belonging to a mod that is not installed stops the whole
|
||||||
|
# material from loading. An extension in Create: Wizardry's own pack is only
|
||||||
|
# read when that mod is there.
|
||||||
|
EXTRA_ITEM_FORMS = {
|
||||||
|
"arcane_metal": [("create_wizardry:arcane_sheet", 1.0),
|
||||||
|
("create_wizardry:arcane_block", BLOCK)],
|
||||||
|
"mithril": [("create_wizardry:mithril_nugget", NUGGET)],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------- identical materials, one entry
|
# ------------------------------------------------- identical materials, one entry
|
||||||
# Several of these metals and gems are added by more than one mod. Every
|
# Several of these metals and gems are added by more than one mod. Every
|
||||||
# variant should behave as the same material rather than as a near-duplicate,
|
# variant should behave as the same material rather than as a near-duplicate,
|
||||||
|
|
@ -1143,7 +1257,7 @@ COMMON_TAGS = {
|
||||||
"energetic_alloy": "energetic_alloy", "vibrant_alloy": "vibrant_alloy",
|
"energetic_alloy": "energetic_alloy", "vibrant_alloy": "vibrant_alloy",
|
||||||
"conductive_alloy": "conductive_alloy", "pulsating_alloy": "pulsating_alloy",
|
"conductive_alloy": "conductive_alloy", "pulsating_alloy": "pulsating_alloy",
|
||||||
"redstone_alloy": "redstone_alloy", "soularium": "soularium",
|
"redstone_alloy": "redstone_alloy", "soularium": "soularium",
|
||||||
"mithril": "mithril",
|
"mithril": "mithril", "platinum": "platinum",
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMON_GEM_TAGS = {
|
COMMON_GEM_TAGS = {
|
||||||
|
|
@ -1178,3 +1292,30 @@ def _accept_every_provider():
|
||||||
|
|
||||||
|
|
||||||
_accept_every_provider()
|
_accept_every_provider()
|
||||||
|
|
||||||
|
|
||||||
|
def _extend_with_extra_forms(pack="create_wizardry"):
|
||||||
|
"""Turn EXTRA_ITEM_FORMS into material extensions.
|
||||||
|
|
||||||
|
Built after the common tags are appended, and out of the material's own item
|
||||||
|
list, because the merge replaces the ingredient list rather than adding to
|
||||||
|
it - everything the material already accepted has to be carried over.
|
||||||
|
"""
|
||||||
|
by_name = {material["name"]: material for material in MATERIALS}
|
||||||
|
for name, extras in EXTRA_ITEM_FORMS.items():
|
||||||
|
base = by_name[name]
|
||||||
|
path = f"{base['group']}/{name}"
|
||||||
|
EXTENSIONS.append({
|
||||||
|
"pack": pack,
|
||||||
|
"path": path,
|
||||||
|
"data": {
|
||||||
|
"parent": f"cmmodular:{path}",
|
||||||
|
"data": {
|
||||||
|
"items": base["items"] + [{"item": item, "value": value}
|
||||||
|
for item, value in extras],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
_extend_with_extra_forms()
|
||||||
|
|
|
||||||