Repository navigation
Bridges
Library bridges and engine bridges. Back to Home; see also Architecture.
Libraries that were never updated are replaced by their modern equivalent instead of being loaded, when that mod is installed (the same idea as Connector Extras bridging Trinkets to Curios):
| Legacy library | Modern replacement | Status |
|---|---|---|
Baubles 1.0 (baubles.api) |
Curios | Baubles is skipped; IBauble items become curios in the ring/necklace/belt slots; BaublesApi.getBaubles reads the Curios slots. |
NotEnoughItems (codechicken.nei) |
JEI | NEI is skipped; mods' NEI*Config plugins run; each legacy recipe handler becomes a JEI category drawn by the handler itself (details); NEI-hidden items are hidden in JEI. NEI always came with CodeChickenLib, so without a 1.7.10 CodeChickenLib jar its API (codechicken.lib: GuiDraw, Rectangle4i, ...) is bridged too (a modern CodeChickenLib in the pack does not count); NEI's GUI hooks (INEIGuiHandler, INEIGuiAdapter, API.registerNEIGuiHandler) are accepted and ignored, as JEI lays out its own panel. |
Waila (mcp.mobius.waila.api) |
Jade | Waila is skipped; legacy tooltip providers registered through Waila's IMC callback show their lines in Jade. |
Patchouli 1.12 (vazkii.patchouli.api, 1.12.2 only) |
Patchouli | The legacy Patchouli is skipped; legacy mods' books are shown by the modern one (details). |
CoFH RF API (cofh.api.energy, shaded by most tech mods) |
NeoForge Energy capability (built in) | Always on: RF tiles and items expose IEnergyStorage (1 RF = 1 FE), so modern cables and machines connect. |
| IC2 EU, BuildCraft MJ, Forge fluids, IInventory | NeoForge Energy / Fluid / Item capabilities (built in) | Always on: legacy tiles and items are capabilities by default (EU at energy.fePerEu = 4 FE, MJ at energy.fePerMj = 10 FE; .in/.out suffixes set each direction, 0 turns it off, see Configuration). Details in Addon-API. |
Without the modern mod, the legacy library is translated and loaded as usual (except the RF API, which needs none).
Mods that only make sense on 1.7.10's engine or launcher (performance/bug-fix patches such as FastCraft or Hodgepodge,
ID extenders, LWJGL 3 ports) are not loaded; client mods (JourneyMap, Inventory Tweaks, ...) are;
legacyconnector-report.txt says why.
New bridges are declared in loader/.../LibraryBridges.java and implemented under the shim namespace.
Two kinds of bridge exist. Library bridges replace an outdated legacy library by its modern equivalent (the table above); engine bridges map a legacy system onto the 1.21 one it corresponds to. Status for 1.7.10:
Implemented
| Bridge | Legacy side | Modern side |
|---|---|---|
| Baubles → Curios | baubles.api |
Curios slots |
| NEI → JEI | codechicken.nei |
JEI categories and hidden items |
| Waila → Jade | mcp.mobius.waila.api |
Jade tooltips |
| Patchouli 1.12 → Patchouli | vazkii.patchouli.api |
books, multiblocks, custom components (details) |
| CoFH RF → NeoForge Energy | cofh.api.energy |
IEnergyStorage (1 RF = 1 FE) |
| Blocks and tile entities |
Block, TileEntity, metadata |
registered blocks and block entities, one per legacy block plus one per block subtype that has an item (flattening) |
| Items and ItemStacks |
Item, ItemStack damage/NBT |
one item per metadata subtype, CUSTOM_DATA NBT |
| Recipes and smelting |
GameRegistry / CraftingManager / OreDictionary, custom IRecipe classes (IC2, AE2, Blood Magic, Witchery ...) |
data-pack recipes, tags; a custom recipe is a legacyconnector:legacy_recipe that matches and crafts through the legacy object |
| Entities |
Entity, spawn/save/load, mob AI |
entity types, spawns, saving |
| Fluids | Forge Fluid / containers |
fluid types |
| Villagers |
VillagerRegistry ids, skins, trade handlers, village creation handlers |
minecraft:villager_<id> professions (a vanilla villager with another job, so Jade names its mod "Minecraft"; named after the mod's skin file, e.g. "Wizard"), trades, clothes layer; some new unemployed villagers take a legacy profession; legacy village buildings are elements of the vanilla village house pools with their 1.7.10 share (see World generation) |
| GUIs and containers |
GuiHandler, Container
|
menus and screens |
| Networking | FML SimpleNetworkWrapper / channels |
NeoForge payloads |
| Commands |
ICommand, server command manager |
Brigadier |
| Dimension physics |
WorldProvider gravity, fall damage and sound attenuation (Galacticraft's IGalacticraftWorldProvider) |
gravity attribute, fall damage multiplier, client sound volume per dimension |
| Chest loot |
ChestGenHooks.addItem for dungeon, mineshaft, pyramid, stronghold, village and bonus chests |
an extra pool on the matching vanilla chest loot table; chests that legacy structures fill from one of these categories get the matching modern loot table instead, so the pack's loot (and modern mods' loot modifiers) applies |
| Fishing loot |
FishingHooks fish, junk and treasure entries (MineFactoryReloaded's junk) |
a global loot modifier swaps a catch of the same category for a mod entry with its 1.7.10 weight share |
| Brewing |
Item.getPotionEffect ingredients, PotionHelper potion values and requirements |
one brewing recipe running 1.7.10's potion values: mod ingredients and mod-effect potions brew as in 1.7.10 (redstone, glowstone, gunpowder apply), vanilla potions stay vanilla, water breathing (pufferfish) is back |
| Biomes, world types, mod dimensions |
BiomeGenBase, GenLayer, WorldProvider
|
data-driven biomes placed by climate (a TerraBlender region), legacy world types as their own biome source, legacyconnector:dim_<id>
|
| World generation |
IWorldGenerator, decorators |
one placed feature per legacy generator (<mod>:legacy_worldgen/<generator>) and one per generator for the layer below y=0 (<mod>:legacy_worldgen_deep/<generator>), added by biome modifiers |
| Events | Forge/FML event buses | NeoForge event bus |
| Sounds, potions, creative tabs |
SoundHandler, Potion, CreativeTabs
|
sound events (details), effects, tabs |
| Stats and achievements |
StatList, AchievementList, StatBase.addStat
|
general stats count in their modern counterparts, mod stats become custom stats named after their legacy key (OpenBlocks' bricks dropped); the stat file reads them back |
| Translations |
.lang files, LanguageRegistry, StatCollector/StringTranslate/I18n, vanilla 1.7.10 keys (tile.stone.name) |
converted lang/<code>.json files, a generated lang file, and legacy keys resolved on a miss of the modern language (translations) |
| Coremods that patch mods |
IClassTransformer plugins |
applied to mod classes before translation |
| Java 8 → 21 | reflection hacks, removed JDK classes |
ReflectionCompat, ResourceCompat, JDK stand-ins |
| API drift between mods | a library method whose return type changed | relinked to the installed signature |
In progress / partial
| Bridge | State |
|---|---|
| Entity rendering, armour and held items | bridged (including the player renderer and its RenderPlayerEvents, creeper and large chest models, flame and breaking particles), not verified in game for every mod |
Block rendering (ISimpleBlockRenderingHandler, TESRs) |
Handlers draw in the world (Tinkers' tables, AE2, AgriCraft crops), renderers can bind vanilla textures by their 1.7.10 names, blocks that colour themselves (leaves, grass, colorMultiplier) are biome tinted; a single-colour handler quad on a block face has 1.7.10's face shade divided out and gets modern shading and ambient occlusion (tinted blocks, OpenBlocks' elevators), other single colours get AO; per-vertex colour is still missing, some handlers (Tinkers' drying rack, barricades) still draw nothing |
| Dimension sky/fog/clouds | Implemented (see Mod dimensions); Twilight Forest's fog and Galacticraft's planets work, but the skies of other mods' dimensions are not all verified |
| Portal placement | Twilight Forest's portal works; other mods' portals are not verified |
| Coremods that patch Minecraft itself | cannot run on the shim; the common cases (DragonAPI's recipe list and smelting hook) are handled one by one |
| Mods built for a different version of another mod | only return-type drift is relinked (Binnie's mods against Forestry 4.2.16 still fail) |
| 1.12.2 | alpha: most of the API mods use is implemented on both sides; see the status table and issue #64 |
| 1.20.1, 1.16.5, 1.2.5 bridges | planned, in that order |
With the modern Patchouli (NeoForge 1.21.1) installed, 1.12.2 mods' Patchouli books work through it and the 1.12 Patchouli jar is skipped
(bridges.patchouli.enabled = false loads the 1.12 jar instead; without the modern mod it loads as usual).
-
API (
legacyconnector/v1_12_2/vazkii/patchouli/api, implementation incompat/patchouli):PatchouliAPI.instancewithgetBookStack,openBookGUI,setConfigFlag/getConfigFlag,registerMultiblock/getMultiblock/makeMultiblock, the state matcher factories (1.12IBlockStateandBlockarguments become modern states),registerTemplateAsBuiltin,serializeItemStack/deserializeItemStackand the ingredient variants. Multiblocks and matchers are built when first used and registered with Patchouli once every mod's blocks exist (1.12 mods build them in preInit).ICustomComponentandIComponentProcessorimplementations are also modern ones, so the class names in a book's json work;@VariableHolderstring fields are filled from the page variables. TheBookEventclasses exist but are not posted yet. Classes mods use that are not API (vazkii.patchouli.client...,common...) are not provided. -
Books as resources. 1.12 mods keep books in
assets/<mod>/patchouli_books/<book>/(book.json,<lang>/{categories,entries,templates}). The modern Patchouli (1.20+) finds books by scanning each mod jar fordata/<mod>/patchouli_books/<book>/book.jsonand requiresuse_resource_pack: true, with the contents in the resource packs (assets/), as in 1.12. So the loader writes the convertedbook.jsoninto the translated jar's data folder (PatchouliBookJson, no registries needed) and stages the original folder underlegacyconnector_legacy/(the originals stay in assets for the 1.12 Patchouli); the runtime writes the converted contents to the generated client resource pack when it is built (PatchouliBooks, unit tested;PatchouliBooks1122supplies the ids from the registries): itemsmod:item:metabecome the flattened item (mod:item_3), also in icons,spotlightpages and template components; multiblockmappingblocks go through the state bridge (mod:block[meta=3]);craftingrecipe names become the id of the data-pack recipe the layer generated (mod:name_code);smeltingpages (1.12 names the input item) become recipe pages of the generated furnace recipe, or aspotlightof the input when there is none; page types getpatchouli:; template pages and includes get the book's namespace; template component types getpatchouli:(the modern reader drops unknown types, which left every template page blank);advancementlocks are kept for vanilla advancements and for the mod advancements the layer converted (see 1.12.2 advancements); a lock on any other advancement would hide the entry for good and is dropped; values 1.12 processors return are read as modern ids (stacks are serialized with the modern item id, renamed vanilla entities such aszombie_pigmanget their modern name); resource ids are lower-cased;creative_tabmaps the 1.12 tab names to modern tabs (an unknown tab is dropped). -
The book item.
getBookStack("mod:book")returns the modern guide book stack with itspatchouli:bookcomponent, wrapped for legacy code (thepatchouli:guide_bookitem is visible in the legacy item registry, so 1.12 recipes and loot that name it work, and a stack with the 1.12 NBT tagpatchouli:bookbecomes the modern book stack and back). -
Other legacy versions. The loader bridge (
LibraryBridges:Bridge("patchouli", "vazkii/patchouli/api/", "patchouli", "patchouli"),bridges.patchouli.enabled, skipping the legacy Patchouli jar) does not depend on the Minecraft version: it applies to every legacy version that is or will be added. Patchouli exists for 1.12.2 and for 1.14 to 1.20; the 1.20.1, 1.19.2, 1.18.2 and 1.16.5 layers are in-place remaps onto NeoForge 1.21.1, so theirPatchouliAPI.get()calls resolve against the real modern API directly and only the books need converting. Each version adds oneBookConverter(interface and registryBookConverter.BY_VERSION, with a unit test): 1.12.2 is the table above; for 1.14 to 1.20 the files are already indata/with the modern structure, and the converter has to turnmod:item{nbt}stacks intomod:item[components], move the contents to the resource pack (use_resource_pack), and map renamed fields (extend, multiblockpatternkeys,advancement/flag). No converter is registered for them yet because those layers do not exist.
1.12 mods ship advancements as assets/<mod>/advancements/**.json (read from the mod's jar); the modern game reads data/<mod>/advancement/**.json in
another format. Advancements1122 converts every file when the data pack is built (item subtypes, entity types, recipes and biomes need the
registries) and serves the result from the bottom data pack, so world data packs replace or remove them like any mod's advancement; the
conversion rules are AdvancementConverter1122 (pure JSON, unit tested). The server logs 1.12.2 advancements of mod jars: N converted ... and,
once started, 1.12.2 advancements loaded by the server: X of N.
-
Display: icon
{item, data}becomes{id}of the flattened item (an unknown item shows a barrier), title/description text components,frame,background,hidden,show_toast,announce_to_chatandparentcarry over (mod advancements whose parent does not exist become roots). -
Rewards:
experience,recipes(ids of the generated data pack recipes,mod:name_code) andloot;functionis dropped (logged). -
Vanilla triggers become the modern conditions (
itemswithdatabecome the list of the item's flattened subtypes):inventory_changed,consume_item,enchanted_item,item_durability_changed,used_totem,filled_bucket,placed_block,enter_block,recipe_unlocked,tick,location(biome, dimension, position, vanilla structures),changed_dimension,effects_changed,player_killed_entity,entity_killed_player,player_hurt_entity,entity_hurt_player,tame_animal,bred_animals,summoned_entity,villager_trade,cured_zombie_villager,construct_beacon,brewed_potion,levitation,nether_travel,impossible. Entity predicates becomeentity_propertiesconditions. What cannot be expressed (an entity, item or block the layer did not register, a structure of a mod's own world generator, a trigger 1.21 does not have) makes that criterionminecraft:impossibleand is listed in the log once per kind; NBT and damage-type conditions are dropped. -
Triggers of mods (
CriteriaTriggers.register(new MyTrigger())): the criterion becomeslegacyconnector:legacycarrying the original conditions; when a player's advancements start listening, the mod's ownICriterionTrigger.deserializeInstanceparses them and itsaddListenergets a legacy listener whosegrantCriterionawards the criterion. Mods keep firing their triggers from code as in 1.12. -
Code:
AdvancementManager.getAdvancement,EntityPlayerMP.getAdvancements().grantCriterion/revokeCriterion/getProgressare views over the modern server's. -
Not done: 1.12
.mcfunctionrewards,killing_blowand damage-type conditions, item/entity NBT conditions.
1.7.10 mods' achievements (new Achievement(...).registerStat()) and AchievementPages are written to the generated data pack as advancements
(Achievements1710): each page is a tab (a generated root named after the page; achievements of no page, or hung off vanilla ones, are in a
"Legacy achievements" tab), parents are kept, the icon is the achievement's item, title and description are the achievement's translation keys.
The criterion is impossible and is awarded from EntityPlayer.addStat when legacy code earns the achievement (and at login for those already
recorded), so the advancements screen shows what the legacy record says. The legacy toast stays; the advancements do not toast or announce.
Other book systems that could be shown as modern Patchouli books by a generic converter (not implemented; the effort is for a generic
conversion of the content into book.json + entries, not a per-mod fix):
| Legacy book system | Modern equivalent | Effort |
|---|---|---|
Guide-API (1.7.10 and 1.12 amerifrance.guideapi) |
Patchouli (or the Guide-API port) | Medium: books are registered in code (IGuideBook, categories, entries, pages of text/recipes/images); a generic walk of the registered structure could write Patchouli categories and entries |
| Thaumonomicon (Thaumcraft 4/6 research) | none (progression system, not a book) | High: research has prerequisites, aspects and a puzzle UI; only a read-only entry list is realistic |
| Lexica Botania (Botania 1.7.10 lexicon) | Botania's own Patchouli book | Low for the book itself (modern Botania ships it), but the legacy lexicon is mod-internal; only entry text could be exported |
| Tinkers' Construct manual (1.7.10 and 1.12) | Tinkers' Construct's modern Patchouli-style manual | Medium: pages are an in-jar XML and a custom page renderer; text/image/recipe pages map, interactive ones do not |
| Forestry and Mystcraft books | none | Forestry's handbook is not a book system; Mystcraft's notebooks are items holding data, not documentation |
| NEI handbook / Waila-style help | JEI | Already covered by the NEI bridge |
Every TemplateRecipeHandler a mod registers through its NEI*Config plugin becomes one JEI category
(<mod>:nei_<handler class>, 166 pixels wide like NEI's recipe area; 65 high, or 130 for handlers that show one
recipe a page). Its title is the handler's getRecipeName() (translated when it is a key); its icon and catalysts are the
machines that run it: the stacks registered with NEI's API.addRecipeCatalyst, else the mod's block or item whose name best
matches the title and the handler's class name, else the vanilla machine of the crafting/smelting/brewing ids. <mod> (the
mod JEI names) is the machine's mod, else the mod whose jar holds the handler, else the mod most of its results come from. Its recipes are the ones the handler lists for its overlay id and the ids of its transfer rectangles; JEI's
"recipes / uses of this item" ask the handler with loadCraftingRecipes("item", stack) / loadUsageRecipes("item", stack), as
NEI did. Each recipe keeps the handler instance that loaded it and its index there, and JEI's draw runs the handler's own
drawBackground(i) and drawForeground(i) (which calls drawExtras(i)) inside the legacy GUI render context, at NEI's origin
(where the handler's PositionedStacks are). So whatever the handler draws appears: the machine picture, fuel/energy/fluid
gauges, progress bars, temperatures, text. TemplateRecipeHandler implements NEI's defaults (drawBackground: region
(5, 11, 166x65) of getGuiTexture(); drawForeground: rebinds it, then drawExtras; drawProgressBar in its eight
directions); cycleticks follows the clock, so progress bars animate. A handler whose drawing throws is logged once.
Texture names: getGuiTexture() is a legacy location string. Domain-qualified names (witchery:textures/gui/distiller.png)
map like any legacy texture. Reika's handlers return class path files (/Reika/RotaryCraft/Textures/GUI/blastfurngui.png) and
bind them through DragonAPI's ReikaTextureHelper (raw GL ids, see Rendering); if such a name reaches the texture
manager anyway (new ResourceLocation("/Reika/...")) it is read from the mods' class path with its original case and
registered once as legacyconnector:classpath/<path> (a missing file gets the missing texture once, never a lookup per frame).
A 1.7.10 block has 16 metadata values, and its item usually lists some of them as subtypes (wool colours, Chisel variants,
machine types). Legacy Connector registers one modern block per legacy block with the metadata as a meta property, and one
modern item per subtype (mod:name, mod:name_1, ...). Modern code takes a block item's block and places or compares its
default state (EvilCraft's display stand per planks item, Rechiseled, Cyclops Core's BlockHelpers, framed and copycat
blocks), so with one block every subtype came out as metadata 0 (EvilCraft even made duplicate creative tab stacks, see
CreativeTabDuplicateMixin). As in the 1.13 flattening, each subtype now has a block of its own
(v1_7_10/bridge/BlockFlattening1710, config blocks.flattenSubtypes, default on):
- For every metadata value
N > 0that a subtype item places (ItemBlock.getMetadata(damage)), a member blockmod:name_Nis registered once all legacy mods have loaded. It is the same legacy block (aLegacyBlockAdapterwith the base block's properties and behaviour) whose default state is metadataN. The subtype item'sBlockItem.getBlock(),Item.byBlockand the member'sasItem()point at each other, the member is named after its subtype, and it gets the mineable/tool tier tags of its own metadata. - A member also holds the metadata values the block drops as that subtype (
damageDropped): a birch log rotated to metadata 5, 9 or 13 stays inname_1. Itsmetaproperty only has those values (a single value: no property). Metadata without an item of its own stays in the base blockmod:name, which keeps its id and all 16 values. Each legacy block gains at most 16 block states however many subtypes it has. - Legacy code sees no difference:
World.getBlock/getBlockMetadataread any member,setBlock/setBlockMetadatawrite the member that owns the metadata. A metadata change that moves the state to another member of the same legacy block is not a new block: nobreakBlock/onBlockAdded, the tile entity stays (the host block entity type accepts every member), scheduled ticks and block events queued for the legacy block still run (ServerLevelBlockFamilyMixin) and the client keeps its block entity (LevelChunkBlockFamilyMixin).LegacyBlockAdapter.metaOf(state)reads the metadata of any member;LegacyBlockAdapter.METAis only the base block's property. - Models: a member's blockstate file points at the base block's per-metadata models (
block/name_mN). - Saved worlds hold
mod:name[meta=N]base states. When a chunk loads, states whose metadata a member owns now are moved into it, in place (same legacy block and metadata, tile entity kept). Withblocks.flattenSubtypes = falsethe members are still registered, nothing points at them, and the same conversion moves their states back into the base block: switching either way loses no block. - Not flattened: blocks whose items all place metadata 0 (the subtype lives in the tile entity), deepslate ore twins (one twin per legacy block, all metadata), and a member id another block already has (that subtype stays in the base block).
1.12.2 is not flattened yet: there an ItemBlock is one modern item (no per-subtype items), so the flattening would first
need per-subtype block items.
1.7.10 had two tables: the server's StringTranslate (what StatCollector reads) and the client's Locale (I18n, which
replaced the server table once resources loaded). FML read every mod jar's assets/<domain>/lang/en_US.lang into the server
table before constructing the mods, so mods translate in static initializers: ReactorCraft builds its ore names
(ore.cadmium -> "Cadmium Ore") in the constructor of its ore enum, and ElectriCraft and RotaryCraft do the same. How the
layer serves each source:
- Lang files of a jar become
assets/<ns>/lang/<code>.json(loader,LegacyResourceConverter), which the client loads like any mod's. Before the first 1.7.10 mod is constructed,Platform1710also reads every legacy jar'sen_US.langintoGeneratedTranslations' bundled table (LanguageRegistry.mcc$loadLanguagesFor), as FML did:StatCollectoranswers from it on the server and on a client whose languages are not loaded yet. These entries are not exported again. - Code-registered strings (
LanguageRegistry.addStringLocalization/addName, writes toStringTranslate.languageList) go toGeneratedTranslations, exported asassets/legacyconnector/lang/<code>.jsonof the generated pack on every reload. - Vanilla 1.7.10 keys (
tile.stone.name,item.ingotIron.name, subtypes such astile.cloth.red.nameoritem.dyePowder.blue.name, entity and attribute names) map to their modern keys (VanillaNames.modernKey, through the legacy wrapper of the vanilla block or item, so the key names the modern object the bridge maps it to). The legacygetLocalizedNameof a vanilla wrapper returns the modern block's name: ChromatiCraft's hidden ores name themselvesBlocks.stone.getLocalizedName(). - On the client, a key the loaded languages miss is looked up in all of the above (
ClientLanguageLegacyKeysMixin->LegacyLang), so strings registered after the last resource reload and legacy vanilla keys also resolve in aComponent.translatable(item and block names, Jade/WTHIT). Only misses pay. - Names: a legacy item that overrides
getItemStackDisplayNameis named by it; otherwise its name is the translatable<unlocalized>.name. A modern block'sgetName()(Jade without a pick item) is the legacygetLocalizedNamewhen the block overrides it, else its lang key.
- World sounds (
World.playSoundEffect,playSoundAtEntity, ...) become modern level sounds; client sounds (SoundHandler.playSoundwithPositionedSoundRecords or a mod's ownISound/ITickableSound) become sound instances that keep the legacy object's volume, pitch, position, repeat and attenuation, and stop when the mod stops them. Sounds naming a file instead of an event (DragonAPI'scustom_path:Reika/.../x.ogg) are played from that file (LegacySoundFiles). -
Volume sliders: 1.7.10 took a sound's category from its sounds.json event (
"category": "block"); the loader keeps it aslegacy_category(the modern format has none) and the sound plays under the matchingSoundSource(block, hostile, neutral, player, ambient, weather, record, music, master). Events without one play under the entity's own slider (Entity.playSound,playSoundAtEntity), as blocks (other world sounds) or master (client sounds). -
Names:
modid:nameis the mod's event. A name without a domain was minecraft's in 1.7.10: one a mod declares in its ownassets/minecraft/sounds.jsonplays that event, one in the mod's own sounds.json plays the mod's, and the 1.7.10 vanilla names (mob.zombie.say,game.hostile.die,random.pop...) are translated to their 1.9+ events (SoundBridge). Only names 1.7.10 itself declared are translated, each to its exact event: an unknownmob.<mob>.<x>is not guessed to a modern mob's ambient or hurt sound. -
Mob sounds: a legacy mob's idle, hurt and death sounds are its
getLivingSound/getHurtSound/getDeathSound, and a mob that overridesplayLivingSoundplays its idle sounds through it. (OreSpawn's beaver sounding like its frog is the mod's own choice: both useorespawn:scorpion_hitas their hurt sound.) -
Fall-off with distance (
LegacyAttenuation): 1.7.10's sound library computed a linear source's gain itself,1 - distance / rangewith range 16 blocks times the volume when that is above 1 (a volume above 1 only reaches further, the gain is capped at 1). The modern engine leaves the fall-off to OpenAL, which does not attenuate stereo files, and most mods of that time ship stereo files (111 of ChromatiCraft's 147): their hums and pulses played at full volume however far away. Legacy positioned sounds (client sounds, and world sounds of a legacy mod's namespace) therefore play without OpenAL attenuation and with the 1.7.10 gain recomputed every tick from the camera distance; loops out of range start silent and fade in.
Mod models and blockstates name vanilla textures the 1.12 way (blocks/planks_oak, items/dye_powder_blue). The loader's
resource/VanillaTextureRenames maps them to 1.21.1 (block/oak_planks, item/lapis_lazuli) from
loader/src/main/resources/legacyconnector/resource/vanilla-texture-renames.tsv (about 420 rows, block and item names kept apart); the runtime
VanillaTextures1122 reads a copy that build.gradle puts into the mod jar. The table comes from the MIT-licensed Retromod project (see
THIRD_PARTY_NOTICES.md) and every row is checked against the 1.21.1 client jar: the new texture exists and the old one is gone. Vanilla model
parents that were renamed live in LegacyResourceConverter.MODEL_RENAMES. Ore dictionary names map to common tags in OreDictBridge (SPECIAL
for exact names, prefixes such as ingot for the rest).