Repository navigation
Creating a Content Pack Mod
This guide takes you from a downloaded copy of the repository to your own content pack .jar, ready to put in Minecraft's mods folder. You do not need to understand Java programming to complete the first example: you will copy a small Java file, create a few text files, and run the supplied build tool.
The finished pack is a separate mod that requires Flan's Mod Ultimate. It contains your definitions, assets, and models. It loads its content directly from the JAR without extracting it into flan/. One mod can contain several individually selectable content packs.
Use the repository branch for your target game and loader. A branch is a version of the repository with its own build setup.
| Branch | Minecraft | Loader | Java development kit |
|---|---|---|---|
master |
1.20.1 | Forge | JDK 17 |
1.21.1 |
1.21.1 | NeoForge | JDK 21 |
The complete copy-and-paste example below is for master, Minecraft 1.20.1, and Forge. For NeoForge, use the 1.21.1 branch and its existing pack entrypoint and loader metadata as your template. Forge Java imports and META-INF/mods.toml cannot simply be copied into a NeoForge pack. The repository README describes other development branches and their support status.
Read gradle.properties in the downloaded branch to confirm its Minecraft version, loader version, and main mod version. Build and test against that branch's version of Flan's Mod Ultimate.
You need an internet connection for the first build, disk space for downloaded libraries, and these tools:
- A JDK, which includes the Java compiler. For this walkthrough, install a 64-bit JDK 17. A Java runtime alone (JRE) is insufficient. Forge's setup documentation specifies Java 17 for this version.
- A plain-text editor. An editor with a folder view and syntax highlighting makes it easier to spot mistakes. You can also use an IDE such as IntelliJ IDEA to open the Gradle project. Do not use a word processor to create source files.
- Git, optionally. Git lets you clone the repository and save your changes. Downloading a ZIP from GitHub also works for this guide.
For example, use the Eclipse Temurin downloads. With its Windows installer, enable the options to add Java to PATH and set JAVA_HOME; see the Adoptium Windows installation instructions. Close and reopen your terminal after installation.
Open PowerShell and run each command separately:
java -version
javac -versionBoth should report version 17.... If javac is missing, check that you installed the JDK and enabled its path option. If a different Java version appears, correct JAVA_HOME and your Java path before continuing. An IDE's Gradle JVM setting should also point to JDK 17.
You do not need to install Gradle separately or download a Forge MDK. This repository already includes its Gradle wrapper and development setup. A wrapper downloads and runs the build-tool version chosen by the project.
- Open the repository.
- Select the
masterbranch. - Choose Code → Download ZIP.
- Extract the ZIP completely, for example under
C:\MinecraftDev\. Do not work inside the ZIP viewer. - Open the extracted folder in your editor.
Open PowerShell in the parent folder where you want to keep the project, then run:
git clone --branch master https://github.com/AntonIT99/Flans-Mod-Ultimate-2.0.git
cd Flans-Mod-Ultimate-2.0For either option, the project root means the folder containing build.gradle, gradle.properties, gradlew.bat, and src. Every project-relative path below starts there.
Open a PowerShell terminal in that folder. In File Explorer, you can open the folder, type powershell in its address bar, and press Enter. Run:
.\gradlew.bat --versionThe wrapper may download Gradle. It should then print its version information without an error. On macOS or Linux, use ./gradlew in place of .\gradlew.bat in every command; if necessary, first run chmod +x gradlew.
Check that libs/ contains the Custom NPCs JAR named by version_custom_npcs in gradle.properties. This checkout uses it as a development dependency, even when your pack does not use NPCs. Keep the supplied file and name intact. This does not make Custom NPCs a runtime requirement of the simple pack created here.
Several names have different jobs. This guide uses the following values; keep them unchanged while following the example, then customize them consistently when it works.
| Name | Example | Purpose |
|---|---|---|
| Module directory and source set | mypack |
The folder under src, and the group of sources Gradle builds together |
| Mod ID | flansmodultimate_mypack |
Identifies your mod to Forge; must match the build file, Java entrypoint, and metadata |
| Logical pack ID | mypack |
A folder under flans_content; identifies one selectable content pack |
| Display name | My First Content Pack |
A readable name shown to players |
| Pack build task | myPackJar |
The command that builds your separate JAR |
| Item short name | mypack_training_part |
Identifies an item definition; use a prefix to avoid other packs' names |
Use lowercase letters, digits, and underscores for IDs. Avoid spaces and punctuation in IDs and resource filenames. Display names may contain spaces. Do not use an existing module name or mod ID.
The main mod ID is flansmodultimate, but Flan item IDs and content assets use the flansmod namespace. For example, our item will be flansmod:mypack_training_part, and its resources belong under assets/flansmod/, even though our mod has its own mod ID.
Create these files and folders in your editor. You can create folders one at a time; the tree shows where each file belongs.
src/
mypack/
fmu-module.gradle
java/
com/flansmodultimate/content/mypack/
PacksMod.java
resources/
META-INF/
mods.toml
flansmodultimate-content.json
pack.mcmeta
assets/
flansmod/
lang/
en_us.json
models/
item/
mypack_training_part.json
flans_content/
pack_names.json
mypack/
definitions/
parts/
TrainingPart.txt
data/
flansmod/
recipes/
mypack_training_part.json
The path com/flansmodultimate/content/mypack means four nested folders. Save files with their exact extensions: PacksMod.java must not become PacksMod.java.txt. Enable File name extensions in File Explorer if creating files there. Save new text files as UTF-8.
Put this in src/mypack/fmu-module.gradle:
registerFmuModule(
sourceSet: 'mypack',
modId: 'flansmodultimate_mypack',
jarTask: 'myPackJar',
archiveBaseName: "[$minecraft_version] My First Content Pack",
archiveVersion: '1.0.0',
implementationTitle: 'mypack'
)The root build automatically finds src/<folder>/fmu-module.gradle files. This registers your Java and resource folders, adds the main mod to the compile classpath, includes your mod in development runs, and creates your JAR task. You do not need to edit build.gradle or settings.gradle.
archiveVersion controls your pack's release version. $minecraft_version is filled in from the root project's properties. Keep the quotation marks and commas exactly as shown.
An entrypoint is the small class Forge calls when it loads your mod. Put this in src/mypack/java/com/flansmodultimate/content/mypack/PacksMod.java:
package com.flansmodultimate.content.mypack;
import com.flansmodultimate.PackagedContentPackApi;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
@Mod(PacksMod.MOD_ID)
public class PacksMod
{
public static final String MOD_ID = "flansmodultimate_mypack";
public PacksMod(FMLJavaModLoadingContext context)
{
PackagedContentPackApi.register(context, MOD_ID, "flans_content", "flans_models");
}
}This tells Flan's Mod Ultimate to discover the logical packs below flans_content and where to look for separately packaged legacy model classes. The first example does not need any 3D model classes, so no flans_models folder is necessary yet.
Keep client rendering code out of this constructor. The same mod must load on a dedicated server, which has no Minecraft client classes.
This registration helper is the repository's packaged-content integration. It is separate from the independently published com.flansmodultimate.api artifact described on the API page. You do not need that artifact when building this module inside the repository.
The loader implementation lives in com.flansmodultimate.content. The registration
entry point remains com.flansmodultimate.PackagedContentPackApi with its existing
overloads, so existing packaged content mods keep the same imports and calls.
Internally, ContentManager coordinates discovery and type loading; separate
helpers handle models and blockstates, translations, generated textures, sounds,
and texture aliases.
Put this in src/mypack/resources/META-INF/mods.toml:
modLoader="javafml"
loaderVersion="[47,)"
license="All Rights Reserved"
[[mods]]
modId="flansmodultimate_mypack"
version="${module_version}"
displayName="My First Content Pack"
authors="Your Name"
description='''My first content pack for Flan's Mod Ultimate.'''
[[dependencies.flansmodultimate_mypack]]
modId="forge"
mandatory=true
versionRange="[47.4.10,)"
ordering="NONE"
side="BOTH"
[[dependencies.flansmodultimate_mypack]]
modId="minecraft"
mandatory=true
versionRange="[1.20.1,1.20.2)"
ordering="NONE"
side="BOTH"
[[dependencies.flansmodultimate_mypack]]
modId="flansmodultimate"
mandatory=true
versionRange="*"
ordering="BEFORE"
side="BOTH"Replace Your Name with your author name. Set license to the license you actually choose for your own work. Reusing other people's assets or code requires following their terms and retaining the appropriate credits; your metadata does not change those terms.
The dependency entries require Forge, Minecraft, and the main mod on both client and server. ordering="BEFORE" on the main-mod dependency makes your pack register before Flan's Mod Ultimate loads the definitions. Retain this order.
The example is scoped to Forge 47.4.10 or newer in the 1.20.1 environment and Flan's Mod Ultimate 2.1.x. If your checkout has different versions, match its properties and the versions you test. Do not claim compatibility with additional versions without testing them. ${module_version} must remain literal in this source file: Gradle replaces it with archiveVersion when building.
Put this in src/mypack/resources/META-INF/flansmodultimate-content.json:
{
"formatVersion": 1,
"kind": "pack_mod_bundle",
"contentRoots": ["flans_content"]
}This identifies the JAR as a content pack mod bundle, which belongs in mods/. It does not replace the Java registration call or Forge metadata.
Put this in src/mypack/resources/pack.mcmeta:
{
"pack": {
"description": "My First Content Pack resources",
"pack_format": 15
}
}Use the literal description shown here. Module resource processing expands module_version in mods.toml; it does not expand the main mod's property placeholders throughout your other resource files.
Put this in src/mypack/resources/flans_content/pack_names.json:
{
"mypack": "My First Content Pack"
}mypack must match the folder immediately below flans_content. Listing a name for a folder that does not exist causes registration to fail.
Start with a simple crafting part. It proves that your module, definitions, item model, translation, and recipe work before you add weapons or vehicles.
Put this in src/mypack/resources/flans_content/mypack/definitions/parts/TrainingPart.txt:
Name Training Part
ShortName mypack_training_part
Description A simple part from my first content pack.
Icon mypack_training_part
Category MISC
StackSize 64
These definitions use Parameter Value, one per line. ShortName is the technical name referenced by recipes and commands; Name is the human-readable name. parts/ selects the definition type. The .txt filename helps you organize the sources but does not define the item ID.
Put this in src/mypack/resources/assets/flansmod/models/item/mypack_training_part.json:
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "minecraft:item/iron_ingot"
}
}This deliberately uses Minecraft's existing iron-ingot texture, so you can test without drawing an image. The new item has its own ID and behavior; it only shares that appearance.
Later, draw a PNG icon and save it as resources/assets/flansmod/textures/item/mypack_training_part.png inside your module. Change layer0 to flansmod:item/mypack_training_part. Use an actual PNG, keep its name lowercase, and omit .png from the JSON reference.
Put this in src/mypack/resources/assets/flansmod/lang/en_us.json:
{
"item.flansmod.mypack_training_part": "Training Part"
}For more items, add more entries inside the same object, separated by commas. JSON does not allow comments or a comma after the last entry. Other languages use separate files with their Minecraft language code.
Put this in src/mypack/resources/flans_content/mypack/data/flansmod/recipes/mypack_training_part.json:
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{ "item": "minecraft:iron_ingot" }
],
"result": {
"item": "flansmod:mypack_training_part",
"count": 1
}
}On Minecraft 1.20.1, the folder is recipes, plural. This recipe turns one iron ingot into one Training Part. The logical pack's data/ folder supplies recipes when that pack is enabled.
Packaged content is treated as already prepared, read-only content. Supply the required modern JSON models, translations, and recipes in your source tree. Do not rely on the conversion process used for loose legacy packs to create missing assets inside your installed mod JAR. runData writes inspection output under build/datagen; it does not automatically package those files into your module.
Save every file. In PowerShell at the project root, run:
.\gradlew.bat myPackJarThe first build downloads dependencies and compiles the main mod as well as your module. Wait for BUILD SUCCESSFUL. The task also runs the Forge reobfuscation step, which prepares compiled classes for an installed Forge game; let the entire command finish.
Your result should be:
build/libs/[1.20.1] My First Content Pack-1.0.0.jar
This task builds your pack separately. It does not embed the main mod. To build the main mod JAR from this checkout too, run:
.\gradlew.bat jarbuild performs the repository's broader build and checks, including other module artifacts; myPackJar is the focused command to use while editing your pack. officialPacksJar builds the official packs, and packsManagerJar builds the extraction companion. Neither substitutes for your own task.
You can inspect the JAR with an archive viewer. At its root you should see META-INF, assets, flans_content, pack.mcmeta, and the compiled com/.../PacksMod.class. There should be no enclosing src/mypack/resources folder. Never repair the built JAR by hand: edit the source and rebuild.
Run:
.\gradlew.bat runClientGradle loads the main mod and registered modules from their development outputs, including your module. Do not also copy your built pack JAR into run/mods/; that would load the same mod twice. Existing modules in the repository also join development runs.
- Create a disposable Creative world with cheats enabled.
- Open chat and run
/give @s flansmod:mypack_training_part. - Check that the inventory item is named Training Part and looks like an iron ingot.
- Place one iron ingot in a crafting grid and check that the recipe produces the new part.
- Restart the client after changing definitions or metadata. Resource reloads do not register new items.
Look in run/logs/latest.log if anything fails. Search for flansmodultimate_mypack, Registering packaged Flan content module, or Registered 1 enabled packaged content pack(s) to check that registration occurred.
The pack-selection file is run/config/flansmodultimate_mypack-content-packs.toml. Its contentPacks.mypack setting defaults to true; setting it to false disables that logical pack after a restart. Keep it enabled for these tests.
Development runs include the Packs Manager, which can manage the loose run/flan folder. Keep your new module's authored files under src/mypack; use the installed-game test below to check the pack with only its intended dependencies.
Development success is only the first check. Test the actual release file in a separate Minecraft instance:
- Create an instance for Minecraft 1.20.1 with matching Forge, using your launcher's instance management. Use the Forge version required by your checkout and metadata.
- Find that instance's game directory. It contains folders such as
mods,config, andsaves; it may differ from the default.minecraftdirectory. - Copy the matching Flan's Mod Ultimate main mod JAR and your finished pack JAR into its
modsfolder. - Keep one version of each mod installed. Do not copy every file in
build/libs; it also contains unrelated pack and API artifacts. - Launch the instance, check that your pack appears in the Mods list, and repeat the
/give, appearance, name, and crafting checks in a test world.
Your packaged mod belongs in mods/, not flan/. Do not also install a loose copy of the same definitions. The simple pack needs neither the Packs Manager nor the official packs nor Custom NPCs in this instance.
For multiplayer, install the same main mod and pack JAR on the server and all clients. Match logical-pack selections as well. Before release, check a dedicated server using a separate test server directory: install the same two JARs, follow Forge's server setup, accept its EULA if you agree to it, start it, and join from your test client. This catches client-only code accidentally loaded on the server.
Once the first item works, add content gradually and rebuild after each small change.
Under flans_content/mypack/definitions/, use the folder for the kind of content you are adding. Common folders include:
| Folder | Content |
|---|---|
guns |
Guns and their firing, ammunition, handling, and model settings |
bullets |
Ammunition and projectile definitions |
grenades |
Thrown explosives and other grenades |
attachments |
Gun attachments |
parts |
Crafting parts, engines, and fuel items |
tools |
Tool definitions |
armorFiles |
Wearable armor |
vehicles |
Ground vehicles |
planes |
Aircraft |
mechas |
Mechas |
mechaItems |
Mecha equipment |
aaguns |
Placed AA guns |
boxes, armorBoxes
|
Gun supply boxes and armor boxes |
Use Config Reference for the full accepted parameters, values, defaults, and remaining definition types. Existing src/<pack>/resources/flans_content/.../definitions files are useful examples, but copy only material you are allowed to reuse. Include everything a definition references, such as ammunition, parts, textures, sounds, and models.
Prefix your short names and resource names with your pack ID. All packs share the flansmod resource namespace, so common names such as rifle, shell, or engine can conflict. Renaming an established short name can also break saved items and other definitions that refer to it.
Keep shared assets in your module's resources/assets/flansmod/ folder:
Path below assets/flansmod/
|
Purpose |
|---|---|
textures/item/ |
Inventory icons |
textures/skins/ |
Common gun, vehicle, and other model textures |
models/item/ |
Modern inventory item model JSON |
lang/ |
Translation JSON |
sounds/ |
Ogg sound files |
sounds.json |
Maps sound event names to sound files |
Follow the existing source packs for the asset structure of the specific content type. Guns and driveables usually need more than the simple flat item model used above. Confirm references in the client log and test rendering and sounds in game.
For standalone packs loaded from the content-pack folder, the client resolves
conflicts in textures/item/ and textures/block/ through a resource-pack view.
The modern PNG files and their animation .png.mcmeta files keep their original
names on disk. Legacy textures/items/ and textures/blocks/ sources are not
indexed or renamed by this conflict resolver; their existing conversion into
modern texture copies still runs as before.
The main mod and packaged content assets keep their resource names. Standalone
packs follow the content loader's alphabetical order. A conflicting texture
with different bytes or animation metadata receives a suffix such as _2 in
the client resource view. Identical textures and metadata may share a resource.
Names already present anywhere in the loaded assets are reserved, including
subdirectories, before choosing suffixes.
References are rewritten within the owning pack: model texture slots (including
particle), model parents, item/paintjob override models, and blockstate models
in both variants and multipart. Colliding helper models are isolated even
when their JSON is identical, because their textures or parents can differ
between packs. Item and block entry models keep the names required by their
registered shortnames; colliding helper or paintjob models receive aliases
instead. Supplied custom geometry and blockstate variants survive regeneration,
and retain their original filenames when a registry shortname receives an alias.
The resource view exposes them under the current registered ID, so removing a
conflicting pack also restores the original resource names. Packs previously
processed by the destructive model migration recover missing originals from
their old ID alias mapping where the aliased files are still available.
Texture variables such as #side, other namespaces, and references with no
matching local asset keep their existing behavior. The resolver handles the
standard model/blockstate JSON fields; custom loader-specific reference fields
are not rewritten. Custom block models using only the mod's basic
minecraft:block/cube_bottom_top shape and its standard texture slots are treated
as generated models, as are simple generated item models.
Aliases are deterministic for the same loaded assets and pack order and are rebuilt on resource discovery/reload; no additional alias files are written. An unrelated external resource pack can still override these resources through Minecraft's normal pack priority. Authors of immutable packaged content should continue prefixing resource names to avoid conflicts between packaged modules.
The first load of a standalone pack may generate modern copies, models,
translations, recipes, and sound indexes, then convert a JAR pack to ZIP.
An English en_us.json fallback is generated from registered definition names
when no English legacy language file is supplied. Authored modern English
translations take precedence over this fallback.
Later startups reuse successful preprocessing and asset indexes stored in
.flansmod-cache/content-packs/ inside the game directory, one subfolder per
kind of entry:
| Folder | Contents |
|---|---|
generation/ |
Whether each standalone pack's generated assets and data are up to date. |
asset-index/ |
Legacy texture names and pixel signatures, and modern asset digests, used to detect texture conflicts between packs. |
sound-index/ |
Sound events and measured .ogg lengths of each sound source. |
Every file is disposable. Deleting one costs a rebuild on the next start; deleting
generation/ makes every standalone pack regenerate once. Archive validation
checks the outer archive metadata; directory validation checks file names,
sizes, modification times, and file identities. Type definitions are still
loaded, and their effective values after category application and current ID
aliases participate in the preprocessing fingerprint. Unchanged packs avoid
PNG decoding, resource hashing, parsing source model JSON, sound-index scans,
recipe validation, extraction, and repacking. Cache and alias files are not
rewritten on an unchanged load.
Each entry stores a fingerprint of the file stamps it was built from, not the stamps themselves, so entries stay small however many files a folder pack holds. A folder pack is walked once per startup, on a worker thread; its asset and sound checks reuse that walk until something writes to the pack. Each entry also names the pack, archive or mod it describes. At most once a week, startup removes the entries whose source no longer exists, such as those of an older version of a renamed pack, along with temporary files left by a crash. A pack that comes back after its entries were removed is processed again once.
On a cold client load, legacy armor, GUI, and skin texture names are reserved before aliases are assigned. Only names shared by multiple packs need pixel signatures; unique textures are not decoded for conflict detection. Both armor layers still participate, and equal pixels share a name even when their PNG encoding differs. Adding a pack upgrades any previously name-only cache entries that now need comparison. Debug logs show the name-reservation time per pack. Unchanged pack sets reuse their signatures without decoding any PNGs for conflict detection. Packaged modules have separate cache identities based on their source location, even when the loader presents identical virtual asset paths.
The shared .flansmod-cache/ directory also holds muzzle-measurements.json
and pack-locations.json. Startup migrates only the cache files
used by version 2.1: .flancache/muzzle-measurements.json and the game-directory
.flansmod-pack-locations-cache.json, renamed to pack-locations.json. Contents and timestamps are preserved. Existing entries in
the new layout take precedence; conflicting old entries are retained. The later
development-only .flansmod-content-cache/ and .flansmod-cache/content/ are not
migrated; content indexes rebuild in content-packs/.
Added, removed, or normally edited files, changes to effective definitions, and changed aliases trigger processing. Client assets and server data have separate completion flags; loading a pack on a server first does not skip its first client asset generation. Missing or invalid caches are rebuilt. Output checks run after regeneration before a successful result is remembered.
Metadata validation deliberately does not hash unchanged file contents. An
edit that preserves size, modification time, and file identity can therefore
require forceRegenContentPacksAssetsAndIds or removing the external cache
before restarting. The force option reruns asset indexing as well as generation;
disable it again after the required regeneration.
Standalone duplicates with the same basename are selected deterministically: a directory takes precedence over ZIP, then JAR, with filename order breaking ties. Resource discovery uses that same selection. A JAR conversion never replaces an existing same-basename ZIP.
Legacy textures/items/ and textures/blocks/ remain untouched. Texture-copy
ownership manifests distinguish created files from authored destinations.
Cleanup removes only copies created by the generator whose contents still
match its recorded output; identical authored files and edited outputs are
preserved. Old manifests without reliable ownership are handled conservatively.
Armor aliases compare both layer files together, so a shared first layer cannot
hide a different second layer.
Startup reads the definition files of the packs on worker threads: the files of
each pack in parallel, and the next eight packs ahead of the one being registered.
Reading starts before the first registration, alongside the texture-name index.
Texture-name and sound indexes are built for all packs in parallel as well.
Registration itself stays on the loading thread, one pack after the other in the
usual order, so items, ID aliases and texture aliases come out exactly as on one
thread. contentLoadingThreads in config/flansmodultimate-content-loading.toml
sets the number of workers; 1 does everything on the loading thread.
The log reports the total, for example
Loaded 12 content pack(s) in 2140.512 ms using 7 thread(s). Debug logging adds
per-pack read, registration and cache-check timings.
The game indexes the tooltip of every item for the creative search tab, for each creative tab with a search bar (every Flan's Mod tab has one) and, through recipe results, for the recipe book. It rebuilds these indexes on opening the creative inventory, joining a world, every tag sync and every resource reload. With thousands of guns, vehicles and paintjobs, that work grows with every pack.
The mod builds each index the first time something is typed into its search box
instead, and again only after a resource reload. Search results are unchanged;
the first search in a tab can pause briefly while its index is built. Flan's
items are indexed with the tooltip shown at rest even when Shift is held while
typing. Debug logging reports each build and its duration. Launching with
-Dflansmodultimate.eagerSearchTrees=true restores the game's eager indexing,
for example if another mod expects the indexes to exist before any search.
This applies to Minecraft 1.20.1. From 1.21.1 the game builds these indexes on background threads itself, so the mod leaves them as they are; Flan's items are still indexed with the tooltip shown at rest.
config/flansmodultimate-content-loading.toml contains soundPackPriority.
The full discovered list is written automatically. Move entries to choose your
order: the first entry has the highest priority. For example, the beginning
of a list could be:
soundPackPriority = [
"pack:my_sound_overrides",
"mod:flansmodultimate_officialpacks",
"mod:flansmodultimate"
]Keep the other generated entries in your actual list. New sources are appended
at the end without changing your existing order. Removed or disabled sources
stay listed and are ignored while absent, so reinstalling restores their old
position. A standalone pack: entry uses the lowercase directory or archive
basename; converting a JAR to ZIP keeps that identity. A mod: entry represents
a packaged module, whose logical packs share one asset tree. The main mod's
built-in sounds also have a mod:flansmodultimate entry.
Restart after editing this order, and use the same order on server and clients. This setting controls Flan sounds independently of type registration, item IDs, textures, models, and recipes. A required sound-only resource overlay enforces the order, so moving ordinary Minecraft resource packs does not override these selected sounds. Put replacement audio in a standalone content pack and move its entry to the top when you want to override it.
For each event name in sounds.json, the first source defining that event wins.
Its definition replaces lower-priority definitions instead of merging their
variant lists. For each sounds/...ogg resource path, the first source supplying
that file wins independently. An event selected from one pack can therefore play
an audio file supplied by another, higher-priority pack.
When overrideConfiguredSoundLengths is enabled, timers follow that selected
event's actual audio files. Event aliases, nested sound events, subdirectories,
and declared JSON pitch are taken into account. For multiple variants, the
longest known duration is used. If a selected variant is missing, unreadable,
references an unsupported namespace, or is cyclic, the configured timer is kept;
a lower-priority file's measurement is never substituted for the selected file.
Disabled or unset timers retain their existing behavior.
Sound inventories, definitions, and durations are stored in the external startup
cache. Unchanged startups validate metadata and reuse these results; they do not
reread source sounds.json, measure audio again, or rewrite the priority list.
Reordering only this list reuses the inventories and does not reprocess packs.
The loader version advances to 7 for this change, causing one preprocessing
pass so dedicated servers also receive normalized legacy sounds. No client-only
sound engine classes are needed for duration resolution on a server.
For Java model sources, follow an existing source pack's layout. For example, ModelTrainingRifle.java with package com.flansmod.client.model.mypack belongs under src/mypack/java/com/flansmod/client/model/mypack/. A corresponding definition uses Model mypack.TrainingRifle. Gradle compiles Java sources and packages their classes in the module JAR.
When reusing supported compiled legacy model classes, put them under src/mypack/resources/flans_models/, preserving their package directories. For example:
resources/flans_models/com/flansmod/client/model/mypack/ModelTrainingRifle.class
The Java registration call's flans_models argument selects that root. .java files go in java/; .class files intended for legacy model loading go in resources/flans_models/. Do not bundle copies of the entire old mod or its shared model framework.
Legacy TMT Java models can also call addObj(...). Put the referenced geometry under assets/flansmod/models/ in the pack or module. OBJ resources load directly from directories, ZIPs, and JARs; extracting a pack by hand is unnecessary. A hardcoded old path such as /Old Pack/assets/flansmod/models/Body.obj resolves against the pack supplying the Java model class, even after the pack archive is renamed. Filename matching accepts legacy case differences, and the .obj extension is optional. Relative models/Body.obj and Body.obj references also work. The original loose resources/models, resources/mod/models, and Flan/flan locations remain fallbacks. Parsed OBJ geometry is isolated by resource source and cleared on client resource reload.
Model creation and adapting old Java sources are more advanced than defining an item. Use the current source models as references for supported classes and constructors, preserve the model's matching texture, and test held, dropped, inventory, and placed appearances where relevant. A successful compilation alone does not prove that an old model renders correctly.
Add another lowercase folder next to flans_content/mypack, with its own definitions/ and optional data/. Add its display name to pack_names.json. Registration discovers logical-pack directories automatically; you do not need another entrypoint or JAR task. Models and the module's root assets are shared. Each logical pack gets its own activation option in the mod's content-pack configuration.
A loose legacy pack is not necessarily ready to embed as an immutable module. Move its definitions into your logical pack's definitions/, prepare the modern assets/flansmod resources and recipe JSON, and put supported compiled model classes under flans_models as described above. Check references and names instead of placing the whole old archive under flans_content.
If your goal is specifically to distribute loose packs that are extracted into players' flan/ directories, follow Packs Manager. That is a different packaging workflow with extraction and backup behavior.
For group-based balancing, see Category System. For optional encrypted assets, see Encrypted Optional Content. Neither is required for the first pack.
- Save your source project and keep a backup or commit it with Git.
build/andrun/are build/runtime output; they are not substitutes for your authored sources. - Increase
archiveVersioninfmu-module.gradle, for example to1.0.1. - Build with
myPackJarand test that exact JAR in your separate game instance and server. - Distribute your pack JAR with a short description of its Minecraft, Forge, and Flan's Mod Ultimate requirements, installation instructions, credits, license, and any additional required content packs.
- Tell users to remove the previous pack JAR before installing the new one.
Keep the main mod, your pack, and optional companions as separate downloads. The pack version here is independent of the main mod version and the Packs Manager's bundled-packs version.
| Symptom | What to check |
|---|---|
PowerShell cannot find gradlew.bat
|
Open the terminal in the project root and include the .\ prefix. |
| Java version or compiler error | Check java -version, javac -version, JAVA_HOME, and your IDE's Gradle JVM against the chosen branch. |
Task 'myPackJar' not found |
Check the exact filename src/mypack/fmu-module.gradle, save it, and verify jarTask: 'myPackJar'. |
| Missing Custom NPCs dependency during the build | Check the JAR in libs/ against version_custom_npcs in the checked-out branch. |
| Failed download or unresolved dependency | Check internet access and the actual repository error. After fixing it, retry; --refresh-dependencies can refresh cached dependencies. |
| Gradle reports a syntax error | Read the named file and line. Check commas, matching quotes, brackets, and copied code fences; do not paste the surrounding Markdown backticks into files. |
| Duplicate mod ID | Keep one JAR version per mod; do not add your pack JAR to development runs that already load its source set. |
| Pack registration fails | Match all mod IDs; check flans_content exists and every pack_names.json key names a real lowercase directory. |
Pack loads but /give says unknown item |
Check ShortName, the definitions/parts/ path, startup parsing errors, and the logical pack's activation setting. Restart after changes. |
| Purple-and-black item | Check the item model JSON, texture path, namespace, and lowercase filename. For the first example, retain minecraft:item/iron_ingot. |
| Item shows a translation key | Check assets/flansmod/lang/en_us.json, its JSON syntax, and the exact item.flansmod.<shortname> key. |
| Recipe is missing | On 1.20.1 use flans_content/mypack/data/flansmod/recipes/; check JSON syntax, item IDs, and the client/server log. |
| Works in development but fails in installed Minecraft | Rebuild through myPackJar, let reobfuscation finish, and test with the same loader/main-mod versions and all required resources included. |
| Dedicated server crashes on client classes | Remove client imports or rendering initialization from common entrypoints; compare with a working pack's entrypoint. |
When asking for help, include the branch, Minecraft/loader/JDK versions, the command you ran, the first relevant error, and the relevant part of latest.log. For a failed build, rerun the failing command with --stacktrace if more detail is needed. Check the final build result rather than assuming every warning is a failure.