From ce068c3aad027a6cfc7c54aaeba490af43a3b9ae Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Wed, 4 Nov 2026 22:23:02 +0000 Subject: [PATCH] Add brick and stone fireplaces to the Rye kit --- CHANGELOG.txt | 13 ++ README.md | 9 +- docs/BUILDING-GUIDE.md | 44 +++- docs/DEVELOPMENT.md | 9 +- gradle.properties | 2 +- scripts/generate-resources.cjs | 25 +++ scripts/invoke-client-preview.ps1 | 4 +- scripts/invoke-runtime-probe.ps1 | 3 +- .../ArchitectureBlocks.java | 20 ++ .../ArchitectureConfig.java | 3 +- .../ArchitectureRecipes.java | 20 ++ .../IronAgeArchitecture.java | 2 +- .../block/FireplaceBlock.java | 201 ++++++++++++++++++ .../block/FireplaceDraft.java | 53 +++++ .../block/FireplaceGeometry.java | 119 +++++++++++ .../block/FireplaceItem.java | 31 +++ .../client/ClientProxy.java | 16 ++ .../client/FireplaceBakedModel.java | 46 ++++ .../client/RoofBakedModel.java | 78 ++++++- .../blockstates/fireplace_brick_collar.json | 28 +++ .../blockstates/fireplace_brick_firebox.json | 28 +++ .../blockstates/fireplace_brick_flue.json | 28 +++ .../blockstates/fireplace_brick_hearth.json | 28 +++ .../blockstates/fireplace_brick_jamb.json | 28 +++ .../blockstates/fireplace_brick_lintel.json | 28 +++ .../blockstates/fireplace_brick_pot_cap.json | 28 +++ .../blockstates/fireplace_brick_slab_cap.json | 28 +++ .../blockstates/fireplace_stone_collar.json | 28 +++ .../blockstates/fireplace_stone_firebox.json | 28 +++ .../blockstates/fireplace_stone_flue.json | 28 +++ .../blockstates/fireplace_stone_hearth.json | 28 +++ .../blockstates/fireplace_stone_jamb.json | 28 +++ .../blockstates/fireplace_stone_lintel.json | 28 +++ .../blockstates/fireplace_stone_pot_cap.json | 28 +++ .../blockstates/fireplace_stone_slab_cap.json | 28 +++ .../ironagearchitecture/lang/en_GB.lang | 24 +++ .../ironagearchitecture/lang/en_US.lang | 24 +++ .../models/block/fireplace_brick_mesh.json | 7 + .../models/block/fireplace_stone_mesh.json | 7 + .../models/item/fireplace_brick_collar.json | 3 + .../models/item/fireplace_brick_firebox.json | 3 + .../models/item/fireplace_brick_flue.json | 3 + .../models/item/fireplace_brick_hearth.json | 3 + .../models/item/fireplace_brick_jamb.json | 3 + .../models/item/fireplace_brick_lintel.json | 3 + .../models/item/fireplace_brick_pot_cap.json | 3 + .../models/item/fireplace_brick_slab_cap.json | 3 + .../models/item/fireplace_stone_collar.json | 3 + .../models/item/fireplace_stone_firebox.json | 3 + .../models/item/fireplace_stone_flue.json | 3 + .../models/item/fireplace_stone_hearth.json | 3 + .../models/item/fireplace_stone_jamb.json | 3 + .../models/item/fireplace_stone_lintel.json | 3 + .../models/item/fireplace_stone_pot_cap.json | 3 + .../models/item/fireplace_stone_slab_cap.json | 3 + .../probe/ArchitectureProbe.java | 15 +- .../probe/ClientProbe.java | 110 +++++++++- .../ironagearchitecture/probe/EraProbe.java | 14 +- .../probe/FireplaceProbe.java | 147 +++++++++++++ .../probe/RecipeProbe.java | 3 + .../probe/RyeFireplacePreview.java | 66 ++++++ .../probe/RyeTilePreview.java | 5 +- 62 files changed, 1586 insertions(+), 30 deletions(-) create mode 100644 src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceBlock.java create mode 100644 src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceDraft.java create mode 100644 src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceGeometry.java create mode 100644 src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceItem.java create mode 100644 src/main/java/zone/moddev/mc/ironagearchitecture/client/FireplaceBakedModel.java create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_collar.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_firebox.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_flue.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_hearth.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_jamb.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_lintel.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_pot_cap.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_slab_cap.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_collar.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_firebox.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_flue.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_hearth.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_jamb.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_lintel.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_pot_cap.json create mode 100644 src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_slab_cap.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/block/fireplace_brick_mesh.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/block/fireplace_stone_mesh.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_collar.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_firebox.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_flue.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_hearth.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_jamb.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_lintel.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_pot_cap.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_slab_cap.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_collar.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_firebox.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_flue.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_hearth.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_jamb.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_lintel.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_pot_cap.json create mode 100644 src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_slab_cap.json create mode 100644 src/probe/java/zone/moddev/mc/ironagearchitecture/probe/FireplaceProbe.java create mode 100644 src/probe/java/zone/moddev/mc/ironagearchitecture/probe/RyeFireplacePreview.java diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 9ad0cbe..42dfb91 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,16 @@ +0.1.13.110021 - Alpha + +I've added brick and stone fireplaces to the Rye kit. You can build a small +hearth or widen it with matching pieces and add your own surround. + +- Light the firebox with flint and steel. Sneak and right-click with both hands + empty to put it out. +- Run flues side by side so fireplaces on different floors can share a stack. + Each pot smokes when the fire below it is lit. +- Leave the flue open or finish it with a pot or vented cap. Use a clay roof + collar where the stack passes through a straight slope. + + 0.1.12.110021 - Alpha I've tidied up the eaves on the Rye cottages. The grain now runs along the fascia diff --git a/README.md b/README.md index 479ee87..589f59d 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,13 @@ match the timber and daub to your walls, then stack sections to make taller case They swing outwards with a right-click or redstone, and each column opens separately. Full and half-depth surrounds fit both ordinary walls and projecting upper floors. +## Fireplaces and chimneys + +Build a small brick hearth or a wider stone inglenook with separate jambs and lintels. +Light the firebox with flint and steel. Run straight flues side by side to carry smoke +from fireplaces on different floors through one stack, with a separate outlet for each fire. +Clay tile collars carry the roof slope up to the sides of the stack. + ## Overhanging upper floors Projecting upper storeys, known as jetties, are a central part of the kit. Half-depth walls, @@ -52,7 +59,7 @@ can be joined back together. Item tooltips give a reminder while you build. You can limewash pieces before or after shaping, singly or in batches of eight. The [crafting guide](docs/BUILDING-GUIDE.md#crafting) covers the wall patterns, floors, -brackets and roofs. +brackets, roofs and fireplaces. ## Building through the ages diff --git a/docs/BUILDING-GUIDE.md b/docs/BUILDING-GUIDE.md index ae17b46..c9c0deb 100644 --- a/docs/BUILDING-GUIDE.md +++ b/docs/BUILDING-GUIDE.md @@ -3,11 +3,11 @@ Permanent building components for the Iron Age series, starting on Minecraft 1.10.2 Forge. Architecture runs independently of Iron Age Furniture. -Version 0.1.12.110021 contains raw and limewashed cob blocks, +Version 0.1.13.110021 contains raw and limewashed cob blocks, stairs and slabs; modular wattle-and-daub walls in all six vanilla woods; and smooth thatch, slate and clay tile roofs with automatic corners and separate ridge caps, plus jettied-storey walls, -timber floors, support brackets, hanging clay tiles and openable leaded windows. There are 526 visible -variants including the wood and finish choices. Architecture remains standalone. +timber floors, support brackets, hanging clay tiles, openable leaded windows, and brick and +stone fireplaces. There are 542 visible variants including the wood and finish choices. ## Wattle and daub @@ -127,6 +127,27 @@ power next changes, just like a wooden door. A powered window blocked from openi tries again when the obstruction is removed. Windows open instantly through 90 degrees. Breaking a section, including through its open pane, returns its intact window item. +## Fireplaces and chimneys + +Start with a firebox at floor level. Set matching hearth pieces beside it to widen the +hearth, with every piece facing the room. Jambs and lintels are separate, so you can build +a compact fireplace or frame a wide inglenook with your own masonry around it. + +Right-click the firebox with flint and steel to light it. Sneak and right-click with +both hands empty to put it out. The fire gives off light and sometimes crackles. It +burns without fuel and stays contained in the firebox. + +Build a straight run of flue blocks directly above each firebox. Offset the upstairs +firebox by one block so its flue can run alongside the lower one. Matching brick or stone +flues join visually, while each column carries smoke from its own firebox. Leave an open +flue at the top or finish it with a pot or slab cap. Pots need air above them and slab +caps need a clear side vent. Keep the run continuous and the outlet within 32 blocks of +the firebox. + +On a straight clay slope, use a roof collar in place of the slope where the flue crosses +the roof. Place it facing up the slope just like a roof tile. The collar follows the same +pitch and continues the flue. + ## Crafting Start with a few base materials, then shape them into the pieces you need. Match the wood, @@ -203,6 +224,21 @@ or six from L-shaped corners. Either inside/outside pattern can be recovered thi alone to get the slope back. Two full panels vertically make four thin panels. Two thin panels side by side rejoin into one full panel. +### Fireplaces + +Use brick blocks or plain stone bricks throughout each recipe. + +| Piece | Recipe | +| --- | --- | +| Four hearths | Two masonry blocks on a diagonal | +| Firebox | One hearth and one iron bars block | +| Four jambs | Three masonry blocks vertically | +| Four lintels | Two masonry blocks side by side | +| Four flues | Two columns of three masonry blocks with the middle column empty | +| Pot cap | One flue and a flower pot | +| Slab cap | One flue and a stone slab | +| Roof collar | One flue and a clay roof slope | + ### Limewashing Every raw cob, daub or timber-and-daub piece can be limewashed after shaping. Use one piece @@ -241,6 +277,8 @@ All content families are enabled by default. Framed panels require the cob famil The `blocks.leadedWindows` switch controls both glazing and windows and requires timber frames and cob. Era recipe filtering is separate from this content switch. The `blocks.clayTiles` switch controls the clay slopes, ridge caps, trim, hanging panels and iron guttering. +The `blocks.fireplaces` switch controls the fireplace kit in Late Medieval & Tudor. +Clay tiles also need to be enabled to use roof collars. Thatch and timber-bearing walls burn; plain daub, cob and slate do not. There is no world generation or collapse simulation. See [development instructions](DEVELOPMENT.md) for builds, Eclipse and disposable runtime checks. diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index ffba78b..6f1fc14 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -189,9 +189,14 @@ other building families switched off. Guttering checks cover fitting and recover ends, both offsets and the rain path. The legacy-fascia mode opens a copy of the roof trim preview and verifies the original bare fascias. Use a fresh runtime root for each candidate. +Fireplace checks cover saved state and canonical drops, firebox light and interaction, independent +flues across a chunk border, blocked and disconnected runs, the three outlets and roof collar pitch. +The core reload checks that the fires still draw from the correct floor. + The optional client probe requires iaa.probe=true, iaa.clientProbe=true and iaa.keepRunning=true. -It creates its own Rye Eaves Preview, checks mesh and material variants and both -creative tabs, captures dry and rain views of the cottage row, then shuts down. +It creates its own Rye Fireplace Preview, checks mesh and material variants and both +creative tabs, captures the interiors and the stack with one fire and then both lit, +then shuts down. With fireplaces disabled it captures the eaves and guttering instead. Every visible item must also provide a translated crafting hint without tooltip errors. The client script's PreviewName argument selects a separate save without replacing an earlier preview. After verification copy the preview save into the ordinary run/saves directory and launch without the probe. diff --git a/gradle.properties b/gradle.properties index f7d5a0f..864d600 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ org.gradle.parallel=false net.minecraftforge.gradle.merge-source-sets=false minecraft_version=1.10.2 forge_version=12.18.3.2511 -mod_version=0.1.12.110021 +mod_version=0.1.13.110021 mod_group=zone.moddev.mc mod_id=ironagearchitecture mod_name=Iron Age Architecture diff --git a/scripts/generate-resources.cjs b/scripts/generate-resources.cjs index 14bd967..2cf5c1c 100644 --- a/scripts/generate-resources.cjs +++ b/scripts/generate-resources.cjs @@ -154,6 +154,31 @@ model('dark_oak_soffit',{parent:'minecraft:block/block',textures:{wood:'minecraf ['down','up','north','south','west','east'].map(face=>[face,{texture:'#wood'}]))}]}); item('dark_oak_soffit','dark_oak_soffit'); lang[`item.${ns}.dark_oak_soffit.name`] = 'Dark Oak Soffit'; +const fireplaceParts = { + hearth:'Hearth', firebox:'Firebox', jamb:'Fireplace Jamb', lintel:'Fireplace Lintel', + flue:'Chimney Flue', collar:'Clay Roof Collar', pot_cap:'Chimney Pot', slab_cap:'Vented Chimney Cap' +}; +for (const [material,label,texture] of [['brick','Brick','brick'],['stone','Stone','stonebrick']]) { + const mesh = `fireplace_${material}_mesh`; + model(mesh,{parent:'minecraft:block/block',textures:{particle:`minecraft:blocks/${texture}`},elements:[]}); + for (const [kind,part] of Object.entries(fireplaceParts)) { + const name = `fireplace_${material}_${kind}`, variants = {}; + for (const facing of Object.keys(facings)) for (const lit of [false,true]) + variants[`facing=${facing},lit=${lit}`] = {model:`${ns}:${mesh}`}; + state(name,variants); item(name,mesh); + lang[`tile.${ns}.${name}.name`] = `${label} ${part}`; + } +} +for (const [kind,hint] of Object.entries({ + hearth:'Place beside a matching hearth or firebox for a wider fireplace.', + firebox:'Light with flint and steel. Sneak and right-click with empty hands to put it out.', + jamb:'Place beside the opening to frame the fireplace.', + lintel:'Span the opening with matching lintels.', + flue:'Stack directly above a firebox. Each column has its own smoke path.', + collar:'Place facing uphill on a straight clay slope. Stack the flue through it.', + pot_cap:'Place on top of a flue and leave the mouth clear.', + slab_cap:'Place on top of a flue and leave a side vent clear.' +})) lang[`hint.${ns}.fireplace.${kind}`] = hint; model('drain_mesh',{parent:'minecraft:block/block',textures:{particle:'minecraft:blocks/iron_block'}}); for (const [name,label] of [['iron_gutter','Iron Gutter'],['iron_gutter_outlet','Iron Gutter Outlet']]) { item(name,'drain_mesh'); diff --git a/scripts/invoke-client-preview.ps1 b/scripts/invoke-client-preview.ps1 index b39060f..9296526 100644 --- a/scripts/invoke-client-preview.ps1 +++ b/scripts/invoke-client-preview.ps1 @@ -1,6 +1,6 @@ param( - [string]$Runtime='D:\IronAgeArchitecture\manual-testing\rye-eaves-0.1.12\native-client-verified', - [string]$PreviewName='Rye Eaves Preview', + [string]$Runtime='D:\IronAgeArchitecture\manual-testing\rye-fireplaces-0.1.13\native-client-verified', + [string]$PreviewName='Rye Fireplace Preview', [string]$ServerTemplate='D:\IronAgeArchitecture\manual-testing\jetties-0.1.2-final\core', [string]$GradleHome='D:\GradleCaches\minecraft-mods-shared', [string]$AssetsDirectory='', diff --git a/scripts/invoke-runtime-probe.ps1 b/scripts/invoke-runtime-probe.ps1 index 72ccb1c..82a58a3 100644 --- a/scripts/invoke-runtime-probe.ps1 +++ b/scripts/invoke-runtime-probe.ps1 @@ -1,6 +1,6 @@ param( [ValidateSet('core','reload','furniture','disabled','legacy','legacy-daub','legacy-jetties','legacy-fascia','iron-age','late-medieval','mixed-eras','no-eras','invalid-era','windows-disabled','clay-disabled','clay-only')][string]$Mode='core', - [string]$RuntimeRoot='D:\IronAgeArchitecture\manual-testing\rye-eaves-0.1.12', + [string]$RuntimeRoot='D:\IronAgeArchitecture\manual-testing\rye-fireplaces-0.1.13', [string]$ServerTemplate='D:\IronAgeArchitecture\manual-testing\jetties-0.1.2-final\core', [string]$FurnitureJar='D:\IronAgeArchitecture\manual-testing\jetties-0.1.2-final\furniture\mods\iron-age-furniture-0.3.0.110021.jar', [string]$Java8='C:\Users\johnb\.gradle\jdks\temurin-8-amd64-windows.2\bin\java.exe' @@ -72,6 +72,7 @@ blocks { B:thatch=false B:slate=false B:clayTiles=$clayTiles + B:fireplaces=false } "@ | Set-Content -LiteralPath (Join-Path $folder 'config/ironagearchitecture.cfg') -Encoding ascii } diff --git a/src/main/java/zone/moddev/mc/ironagearchitecture/ArchitectureBlocks.java b/src/main/java/zone/moddev/mc/ironagearchitecture/ArchitectureBlocks.java index e6722b5..991ce3c 100644 --- a/src/main/java/zone/moddev/mc/ironagearchitecture/ArchitectureBlocks.java +++ b/src/main/java/zone/moddev/mc/ironagearchitecture/ArchitectureBlocks.java @@ -62,6 +62,7 @@ public static List meshes() { List result=new ArrayList<>(WALLS);result.addAll(PARTIALS);result.addAll(FLOORS);return result; } public static FrameBlock DAUB; + public static final List FIREPLACES = new ArrayList<>(); public static final List ROOFS = new ArrayList<>(); public static TileHangingBlock CLAY_HANGING, CLAY_HANGING_THIN; public static FasciaBlock CLAY_FASCIA, CLAY_FASCIA_LINED; @@ -132,8 +133,27 @@ public static void register() { SOFFIT.setUnlocalizedName(IronAgeArchitecture.MODID + ".dark_oak_soffit"); GameRegistry.register(SOFFIT); } + if (ArchitectureConfig.fireplaces) registerFireplaces(); EraCatalog.assignPrimaryTabs(); } + private static void registerFireplaces() { + for (FireplaceBlock.Masonry masonry : FireplaceBlock.Masonry.values()) { + for (FireplaceBlock.Kind kind : FireplaceBlock.Kind.values()) { + if (kind == FireplaceBlock.Kind.COLLAR && !ArchitectureConfig.clayTiles) continue; + String name = "fireplace_" + masonry.key + "_" + kind.name().toLowerCase(java.util.Locale.ROOT); + FireplaceBlock part = block(new FireplaceBlock(masonry, kind), name); + item(part, new FireplaceItem(part)); + FIREPLACES.add(part); + } + } + } + + public static FireplaceBlock fireplace(FireplaceBlock.Masonry masonry, FireplaceBlock.Kind kind) { + for (FireplaceBlock block : FIREPLACES) + if (block.masonry == masonry && block.kind == kind) return block; + throw new IllegalArgumentException("Unregistered fireplace part " + masonry + " " + kind); + } + private static GutterItem gutter(String name, boolean outlet) { GutterItem item = new GutterItem(outlet); item.setRegistryName(new ResourceLocation(IronAgeArchitecture.MODID, name)); diff --git a/src/main/java/zone/moddev/mc/ironagearchitecture/ArchitectureConfig.java b/src/main/java/zone/moddev/mc/ironagearchitecture/ArchitectureConfig.java index 06fe2a9..d2c12c1 100644 --- a/src/main/java/zone/moddev/mc/ironagearchitecture/ArchitectureConfig.java +++ b/src/main/java/zone/moddev/mc/ironagearchitecture/ArchitectureConfig.java @@ -5,7 +5,7 @@ /** Complete content-family switches. Framed panels require the cob family. */ public final class ArchitectureConfig { - public static boolean cob, frames, thatch, slate, windows, clayTiles; + public static boolean cob, frames, thatch, slate, windows, clayTiles, fireplaces; public static EraSelection survivalEras=EraSelection.parse("all"); private ArchitectureConfig() { } public static void load(File file) { @@ -17,6 +17,7 @@ public static void load(File file) { thatch = config.getBoolean("thatch", "blocks", true, "Thatch slopes and ridge caps."); slate = config.getBoolean("slate", "blocks", true, "Crafted slate slopes and ridge caps."); clayTiles = config.getBoolean("clayTiles", "blocks", true, "Clay tile roofs, ridge caps and hanging tiles."); + fireplaces = config.getBoolean("fireplaces", "blocks", true, "Hearths, fireboxes, surrounds and chimney parts."); net.minecraftforge.common.config.Property eras=config.get("recipes","survivalEras",new String[]{"all"}, "Allowed survival palettes: all, iron_age, late_medieval_tudor. Select one or more IDs. An empty list disables Architecture recipes. Shared materials stay craftable when any selected era uses them. Does not hide creative items or remove existing blocks. Restart required."); eras.setRequiresMcRestart(true); diff --git a/src/main/java/zone/moddev/mc/ironagearchitecture/ArchitectureRecipes.java b/src/main/java/zone/moddev/mc/ironagearchitecture/ArchitectureRecipes.java index 2275556..81c957b 100644 --- a/src/main/java/zone/moddev/mc/ironagearchitecture/ArchitectureRecipes.java +++ b/src/main/java/zone/moddev/mc/ironagearchitecture/ArchitectureRecipes.java @@ -26,6 +26,7 @@ public static void register() { } } if(ArchitectureConfig.windows) registerWindows(); + if (ArchitectureConfig.fireplaces) registerFireplaces(); if (ArchitectureConfig.clayTiles) { registerGuttering(); shaped(new ItemStack(ArchitectureBlocks.SOFFIT, 4), "D", "D", 'D', new ItemStack(Blocks.WOODEN_SLAB, 1, 5)); @@ -56,6 +57,25 @@ public static void register() { } } } + private static void registerFireplaces() { + for (FireplaceBlock.Masonry masonry : FireplaceBlock.Masonry.values()) { + Block material = masonry == FireplaceBlock.Masonry.BRICK ? Blocks.BRICK_BLOCK : Blocks.STONEBRICK; + FireplaceBlock hearth = ArchitectureBlocks.fireplace(masonry, FireplaceBlock.Kind.HEARTH); + FireplaceBlock flue = ArchitectureBlocks.fireplace(masonry, FireplaceBlock.Kind.FLUE); + shaped(new ItemStack(hearth, 4), "M ", " M", 'M', material); + shaped(new ItemStack(ArchitectureBlocks.fireplace(masonry, FireplaceBlock.Kind.JAMB), 4), "M", "M", 'M', material); + shaped(new ItemStack(ArchitectureBlocks.fireplace(masonry, FireplaceBlock.Kind.LINTEL), 4), "MM", 'M', material); + shaped(new ItemStack(flue, 4), "M M", "M M", "M M", 'M', material); + shapeless(new ItemStack(ArchitectureBlocks.fireplace(masonry, FireplaceBlock.Kind.FIREBOX)), hearth, Blocks.IRON_BARS); + shapeless(new ItemStack(ArchitectureBlocks.fireplace(masonry, FireplaceBlock.Kind.POT_CAP)), flue, Items.FLOWER_POT); + shapeless(new ItemStack(ArchitectureBlocks.fireplace(masonry, FireplaceBlock.Kind.SLAB_CAP)), flue, new ItemStack(Blocks.STONE_SLAB)); + if (ArchitectureConfig.clayTiles) { + Block claySlope = Block.getBlockFromName(IronAgeArchitecture.MODID + ":clay_tile_roof"); + shapeless(new ItemStack(ArchitectureBlocks.fireplace(masonry, FireplaceBlock.Kind.COLLAR)), flue, claySlope); + } + } + } + private static void registerGuttering() { shaped(new ItemStack(ArchitectureBlocks.GUTTER, 6), "III", 'I', Items.IRON_INGOT); shapeless(new ItemStack(ArchitectureBlocks.GUTTER_OUTLET), ArchitectureBlocks.GUTTER, Items.IRON_INGOT); diff --git a/src/main/java/zone/moddev/mc/ironagearchitecture/IronAgeArchitecture.java b/src/main/java/zone/moddev/mc/ironagearchitecture/IronAgeArchitecture.java index 69cb874..aa565d1 100644 --- a/src/main/java/zone/moddev/mc/ironagearchitecture/IronAgeArchitecture.java +++ b/src/main/java/zone/moddev/mc/ironagearchitecture/IronAgeArchitecture.java @@ -7,7 +7,7 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; /** Permanent building components in the Iron Age series. */ -@Mod(modid = IronAgeArchitecture.MODID, name = "Iron Age Architecture", version = "0.1.12.110021", +@Mod(modid = IronAgeArchitecture.MODID, name = "Iron Age Architecture", version = "0.1.13.110021", acceptedMinecraftVersions = "[1.10.2]", dependencies = "required-after:Forge@[12.18.3.2511,)") public final class IronAgeArchitecture { public static final String MODID = "ironagearchitecture"; diff --git a/src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceBlock.java b/src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceBlock.java new file mode 100644 index 0000000..cd17411 --- /dev/null +++ b/src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceBlock.java @@ -0,0 +1,201 @@ +package zone.moddev.mc.ironagearchitecture.block; + +import java.util.List; +import java.util.Random; +import javax.annotation.Nullable; +import net.minecraft.block.BlockHorizontal; +import net.minecraft.block.SoundType; +import net.minecraft.block.material.Material; +import net.minecraft.block.properties.IProperty; +import net.minecraft.block.properties.PropertyBool; +import net.minecraft.block.state.BlockStateContainer; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Items; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.ItemStack; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.Mirror; +import net.minecraft.util.Rotation; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.property.ExtendedBlockState; +import net.minecraftforge.common.property.IExtendedBlockState; +import net.minecraftforge.common.property.IUnlistedProperty; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public final class FireplaceBlock extends BlockHorizontal { + public enum Masonry { + BRICK("brick", "minecraft:blocks/brick"), STONE("stone", "minecraft:blocks/stonebrick"); + + public final String key, texture; + Masonry(String key, String texture) { + this.key = key; + this.texture = texture; + } + } + + public enum Kind { + HEARTH, FIREBOX, JAMB, LINTEL, FLUE, COLLAR, POT_CAP, SLAB_CAP; + + public boolean hearth() { return this == HEARTH || this == FIREBOX; } + public boolean flue() { return this == FLUE || this == COLLAR; } + } + + public static final PropertyBool LIT = PropertyBool.create("lit"); + public static final IUnlistedProperty JOINS = new IUnlistedProperty() { + public String getName() { return "fireplace_joins"; } + public boolean isValid(Integer value) { return value != null && value >= 0 && value <= 15; } + public Class getType() { return Integer.class; } + public String valueToString(Integer value) { return value.toString(); } + }; + + public final Masonry masonry; + public final Kind kind; + + public FireplaceBlock(Masonry masonry, Kind kind) { + super(Material.ROCK); + this.masonry = masonry; + this.kind = kind; + setHardness(2); + setResistance(6); + setSoundType(SoundType.STONE); + setHarvestLevel("pickaxe", 0); + setLightOpacity(0); + setDefaultState(blockState.getBaseState().withProperty(FACING, EnumFacing.NORTH).withProperty(LIT, false)); + } + + @Override protected BlockStateContainer createBlockState() { + return new ExtendedBlockState(this, new IProperty[]{FACING, LIT}, new IUnlistedProperty[]{JOINS}); + } + + @Override public IBlockState getStateFromMeta(int meta) { + return getDefaultState().withProperty(FACING, EnumFacing.getHorizontal(meta & 3)) + .withProperty(LIT, kind == Kind.FIREBOX && (meta & 4) != 0); + } + + @Override public int getMetaFromState(IBlockState state) { + return state.getValue(FACING).getHorizontalIndex() | (kind == Kind.FIREBOX && state.getValue(LIT) ? 4 : 0); + } + + @Override public int damageDropped(IBlockState state) { return 0; } + + @Override public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing side, float x, float y, float z, + int meta, EntityLivingBase player) { + EnumFacing facing = player.getHorizontalFacing(); + return getDefaultState().withProperty(FACING, kind == Kind.COLLAR ? facing : facing.getOpposite()); + } + + @Override public IBlockState withRotation(IBlockState state, Rotation rotation) { + return state.withProperty(FACING, rotation.rotate(state.getValue(FACING))); + } + + @Override public IBlockState withMirror(IBlockState state, Mirror mirror) { + return state.withProperty(FACING, mirror.mirror(state.getValue(FACING))); + } + + public int joins(IBlockState state, IBlockAccess world, BlockPos pos) { + if (!kind.hearth() && !kind.flue()) return 0; + EnumFacing front = state.getValue(FACING); + int result = 0; + for (int i = 0; i < FireplaceGeometry.JOIN_SIDES.length; i++) { + EnumFacing local = FireplaceGeometry.JOIN_SIDES[i]; + if (kind.hearth() && local.getAxis() != EnumFacing.Axis.X) continue; + BlockPos adjacent = pos.offset(FireplaceGeometry.rotateSide(local, front)); + if (world instanceof World && !((World)world).isBlockLoaded(adjacent)) continue; + IBlockState other = world.getBlockState(adjacent); + if (!(other.getBlock() instanceof FireplaceBlock)) continue; + FireplaceBlock neighbour = (FireplaceBlock)other.getBlock(); + if (masonry == neighbour.masonry && (kind.flue() ? neighbour.kind.flue() + : neighbour.kind.hearth() && other.getValue(FACING) == front)) result |= 1 << i; + } + return result; + } + + @Override public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos) { + return ((IExtendedBlockState)state).withProperty(JOINS, joins(state, world, pos)); + } + + public List boxes(IBlockState state, IBlockAccess world, BlockPos pos) { + return FireplaceGeometry.collision(kind, joins(state, world, pos), state.getValue(FACING)); + } + + @Override public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos) { + return WindowBlock.union(boxes(state, world, pos)); + } + + @Nullable @Override public AxisAlignedBB getCollisionBoundingBox(IBlockState state, World world, BlockPos pos) { + return NULL_AABB; + } + + @Override public void addCollisionBoxToList(IBlockState state, World world, BlockPos pos, AxisAlignedBB mask, + List boxes, @Nullable Entity entity) { + for (AxisAlignedBB box : boxes(state, world, pos)) addCollisionBoxToList(pos, mask, boxes, box); + } + + @Nullable @Override public RayTraceResult collisionRayTrace(IBlockState state, World world, BlockPos pos, Vec3d start, Vec3d end) { + RayTraceResult closest = null; + for (AxisAlignedBB box : boxes(state, world, pos)) { + RayTraceResult hit = rayTrace(pos, start, end, box); + if (hit != null && (closest == null || start.squareDistanceTo(hit.hitVec) < start.squareDistanceTo(closest.hitVec))) + closest = hit; + } + return closest; + } + + @Override public boolean isOpaqueCube(IBlockState state) { return false; } + @Override public boolean isFullCube(IBlockState state) { return false; } + @Override public boolean isSideSolid(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing side) { return false; } + @Override public int getLightValue(IBlockState state) { return kind == Kind.FIREBOX && state.getValue(LIT) ? 13 : 0; } + @Override public int getLightValue(IBlockState state, IBlockAccess world, BlockPos pos) { return getLightValue(state); } + + @SideOnly(Side.CLIENT) + @Override public BlockRenderLayer getBlockLayer() { return BlockRenderLayer.CUTOUT; } + + @Override public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, + EnumHand hand, @Nullable ItemStack held, EnumFacing side, float x, float y, float z) { + if (kind != Kind.FIREBOX) return false; + boolean lit = state.getValue(LIT); + boolean flint = held != null && held.getItem() == Items.FLINT_AND_STEEL; + if (lit && flint) return true; + boolean light = flint; + boolean extinguish = lit && player.isSneaking() && hand == EnumHand.MAIN_HAND + && held == null && player.getHeldItemOffhand() == null; + if (!light && !extinguish) return false; + ItemStack tool = light ? held : new ItemStack(this); + if (!world.isBlockModifiable(player, pos) || !player.canPlayerEdit(pos, side, tool)) return false; + if (!world.isRemote) { + if (!world.setBlockState(pos, state.withProperty(LIT, light), 3)) return false; + world.playSound(null, pos, light ? SoundEvents.ITEM_FLINTANDSTEEL_USE : SoundEvents.BLOCK_FIRE_EXTINGUISH, + SoundCategory.BLOCKS, .7F, 1); + if (light && !player.capabilities.isCreativeMode) held.damageItem(1, player); + } + return true; + } + + @SideOnly(Side.CLIENT) + @Override public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random) { + if (kind == Kind.FIREBOX && state.getValue(LIT)) { + world.spawnParticle(EnumParticleTypes.FLAME, pos.getX()+.5, pos.getY()+.52, pos.getZ()+.5, 0, .015, 0); + if (random.nextInt(8) == 0) + world.playSound(pos.getX()+.5, pos.getY()+.5, pos.getZ()+.5, SoundEvents.BLOCK_FIRE_AMBIENT, + SoundCategory.BLOCKS, .45F, .95F, false); + return; + } + Vec3d outlet = FireplaceDraft.smokeOutlet(world, pos, state); + if (outlet != null) + world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, pos.getX()+outlet.xCoord + (random.nextDouble()-.5)*.14, + pos.getY()+outlet.yCoord, pos.getZ()+outlet.zCoord + (random.nextDouble()-.5)*.14, 0, .045, 0); + } +} diff --git a/src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceDraft.java b/src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceDraft.java new file mode 100644 index 0000000..4a64ee4 --- /dev/null +++ b/src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceDraft.java @@ -0,0 +1,53 @@ +package zone.moddev.mc.ironagearchitecture.block; + +import javax.annotation.Nullable; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import zone.moddev.mc.ironagearchitecture.block.FireplaceBlock.Kind; + +/** A stack can share masonry, but every outlet reads only its own vertical channel. */ +public final class FireplaceDraft { + public static final int MAX_DEPTH = 32; + + private FireplaceDraft() { } + + @Nullable + public static Vec3d smokeOutlet(World world, BlockPos pos, IBlockState state) { + if (!(state.getBlock() instanceof FireplaceBlock)) return null; + Kind kind = ((FireplaceBlock)state.getBlock()).kind; + Vec3d outlet; + if (kind == Kind.FLUE || kind == Kind.POT_CAP) { + if (!clear(world, pos.up())) return null; + outlet = new Vec3d(.5, 1.05, .5); + } else if (kind == Kind.SLAB_CAP) { + EnumFacing front = state.getValue(FireplaceBlock.FACING); + EnumFacing open = null; + for (EnumFacing side : new EnumFacing[]{front, front.rotateY(), front.getOpposite(), front.rotateYCCW()}) { + if (clear(world, pos.offset(side))) { + open = side; + break; + } + } + if (open == null) return null; + outlet = new Vec3d(.5 + open.getFrontOffsetX() * .55, .7, .5 + open.getFrontOffsetZ() * .55); + } else return null; + + BlockPos.MutableBlockPos below = new BlockPos.MutableBlockPos(pos); + for (int depth = 1; depth <= MAX_DEPTH; depth++) { + below.setPos(pos.getX(), pos.getY() - depth, pos.getZ()); + if (below.getY() < 0 || !world.isBlockLoaded(below)) return null; + IBlockState source = world.getBlockState(below); + if (!(source.getBlock() instanceof FireplaceBlock)) return null; + Kind part = ((FireplaceBlock)source.getBlock()).kind; + if (!part.flue()) return part == Kind.FIREBOX && source.getValue(FireplaceBlock.LIT) ? outlet : null; + } + return null; + } + + private static boolean clear(World world, BlockPos pos) { + return world.isBlockLoaded(pos) && world.isAirBlock(pos); + } +} diff --git a/src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceGeometry.java b/src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceGeometry.java new file mode 100644 index 0000000..1379055 --- /dev/null +++ b/src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceGeometry.java @@ -0,0 +1,119 @@ +package zone.moddev.mc.ironagearchitecture.block; + +import java.util.ArrayList; +import java.util.List; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.AxisAlignedBB; +import zone.moddev.mc.ironagearchitecture.block.FireplaceBlock.Kind; + +/** Model and collision dimensions in sixteenths of a block. */ +public final class FireplaceGeometry { + public static final EnumFacing[] JOIN_SIDES = {EnumFacing.WEST, EnumFacing.EAST, EnumFacing.NORTH, EnumFacing.SOUTH}; + public enum Surface { MASONRY, GRATE, POT, STONE, COALS } + + private FireplaceGeometry() { } + + public static final class Part { + public final double x0, y0, z0, x1, y1, z1; + public final Surface surface; + + Part(double x0, double y0, double z0, double x1, double y1, double z1, Surface surface) { + this.x0 = x0; this.y0 = y0; this.z0 = z0; this.x1 = x1; this.y1 = y1; this.z1 = z1; + this.surface = surface; + } + } + + public static List parts(Kind kind, int joins, boolean lit) { + List result = new ArrayList<>(); + double x0 = (joins & 1) != 0 ? 0 : 2, x1 = (joins & 2) != 0 ? 16 : 14; + double z0 = (joins & 4) != 0 ? 0 : 2, z1 = (joins & 8) != 0 ? 16 : 14; + switch (kind) { + case HEARTH: + case FIREBOX: + add(result, (joins & 1) != 0 ? 0 : 1, 0, 1, (joins & 2) != 0 ? 16 : 15, 3, 15, Surface.MASONRY); + add(result, (joins & 1) != 0 ? 0 : .5, 3, .5, (joins & 2) != 0 ? 16 : 15.5, 4.5, 15.5, Surface.MASONRY); + if (kind == Kind.FIREBOX) { + add(result, 4, 4.5, 4, 12, 4.85, 12, Surface.GRATE); + for (int i = 5; i <= 11; i += 2) + add(result, i, 4.85, 4, i + .6, 5.2, 12, Surface.GRATE); + add(result, 5.5, 5.2, 5.5, 10.5, 6.15, 10.5, lit ? Surface.COALS : Surface.GRATE); + } + break; + case JAMB: + add(result, 2, 0, 2, 14, 2, 11, Surface.MASONRY); + add(result, 3, 2, 3, 13, 14, 10, Surface.MASONRY); + add(result, 2, 14, 2, 14, 16, 11, Surface.MASONRY); + break; + case LINTEL: + add(result, 0, 0, 3, 16, 4, 16, Surface.MASONRY); + add(result, 0, 4, 2, 16, 6, 16, Surface.MASONRY); + add(result, 0, 6, 3, 16, 16, 16, Surface.MASONRY); + break; + case FLUE: + case COLLAR: + ring(result, x0, z0, x1, z1, 0, 16, Surface.MASONRY); + break; + case POT_CAP: + ring(result, 1, 1, 15, 15, 0, 2, Surface.MASONRY); + ring(result, 4.5, 4.5, 11.5, 11.5, 2, 14, Surface.POT); + ring(result, 3.75, 3.75, 12.25, 12.25, 14, 16, Surface.POT); + break; + case SLAB_CAP: + ring(result, 1, 1, 15, 15, 0, 3, Surface.MASONRY); + for (int x : new int[]{3, 11}) for (int z : new int[]{3, 11}) + add(result, x, 3, z, x+2, 12, z+2, Surface.MASONRY); + add(result, .5, 12, .5, 15.5, 15, 15.5, Surface.STONE); + break; + default: throw new AssertionError(kind); + } + return result; + } + + private static void ring(List parts, double x0, double z0, double x1, double z1, + double bottom, double top, Surface surface) { + add(parts, x0, bottom, z0, 6, top, z1, surface); + add(parts, 10, bottom, z0, x1, top, z1, surface); + add(parts, 6, bottom, z0, 10, top, 6, surface); + add(parts, 6, bottom, 10, 10, top, z1, surface); + } + + private static void add(List parts, double x0, double y0, double z0, double x1, double y1, double z1, Surface surface) { + parts.add(new Part(x0, y0, z0, x1, y1, z1, surface)); + } + + public static List collarStrips(int joins) { + double x0 = (joins & 1) != 0 ? 0 : 2, x1 = (joins & 2) != 0 ? 16 : 14; + double z0 = (joins & 4) != 0 ? 0 : 2, z1 = (joins & 8) != 0 ? 16 : 14; + List strips = new ArrayList<>(4); + if (x0 > 0) add(strips, 0, 0, 0, x0, 16, 16, Surface.MASONRY); + if (x1 < 16) add(strips, x1, 0, 0, 16, 16, 16, Surface.MASONRY); + if (z0 > 0) add(strips, x0, 0, 0, x1, 16, z0, Surface.MASONRY); + if (z1 < 16) add(strips, x0, 0, z1, x1, 16, 16, Surface.MASONRY); + return strips; + } + + public static List collision(Kind kind, int joins, EnumFacing facing) { + List boxes = new ArrayList<>(); + for (Part part : parts(kind, joins, false)) + boxes.add(rotateBox(part.x0, part.y0, part.z0, part.x1, part.y1, part.z1, facing)); + if (kind == Kind.COLLAR) for (Part strip : collarStrips(joins)) { + for (double z = strip.z0; z < strip.z1; z++) { + double high = 16 * RoofGeometry.height(RoofShape.STRAIGHT, false, strip.x0/16, z/16); + boxes.add(rotateBox(strip.x0, 0, z, strip.x1, high, z+1, facing)); + } + } + return boxes; + } + + private static AxisAlignedBB rotateBox(double x0, double y0, double z0, double x1, double y1, double z1, EnumFacing facing) { + double[] a = RoofGeometry.rotate(x0/16,y0/16,z0/16,facing); + double[] b = RoofGeometry.rotate(x1/16,y1/16,z1/16,facing); + return new AxisAlignedBB(Math.min(a[0],b[0]),a[1],Math.min(a[2],b[2]),Math.max(a[0],b[0]),b[1],Math.max(a[2],b[2])); + } + + public static EnumFacing rotateSide(EnumFacing side, EnumFacing facing) { + int turns = facing == EnumFacing.NORTH ? 0 : facing == EnumFacing.EAST ? 1 : facing == EnumFacing.SOUTH ? 2 : 3; + for (int i = 0; i < turns; i++) side = side.rotateY(); + return side; + } +} diff --git a/src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceItem.java b/src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceItem.java new file mode 100644 index 0000000..bf26d61 --- /dev/null +++ b/src/main/java/zone/moddev/mc/ironagearchitecture/block/FireplaceItem.java @@ -0,0 +1,31 @@ +package zone.moddev.mc.ironagearchitecture.block; + +import java.util.List; +import java.util.Locale; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public final class FireplaceItem extends EraItemBlock { + private final FireplaceBlock fireplace; + + public FireplaceItem(FireplaceBlock block) { + super(block); + this.fireplace = block; + } + + @Override public boolean placeBlockAt(ItemStack stack, EntityPlayer player, World world, BlockPos pos, + EnumFacing side, float x, float y, float z, IBlockState state) { + for (AxisAlignedBB box : fireplace.boxes(state, world, pos)) + if (!world.checkNoEntityCollision(box.offset(pos))) return false; + return super.placeBlockAt(stack, player, world, pos, side, x, y, z, state); + } + + @Override public void addInformation(ItemStack stack, EntityPlayer player, List tooltip, boolean advanced) { + hint(tooltip, "fireplace." + fireplace.kind.name().toLowerCase(Locale.ROOT)); + } +} diff --git a/src/main/java/zone/moddev/mc/ironagearchitecture/client/ClientProxy.java b/src/main/java/zone/moddev/mc/ironagearchitecture/client/ClientProxy.java index fa8b99c..567fa45 100644 --- a/src/main/java/zone/moddev/mc/ironagearchitecture/client/ClientProxy.java +++ b/src/main/java/zone/moddev/mc/ironagearchitecture/client/ClientProxy.java @@ -7,6 +7,7 @@ import net.minecraft.block.properties.IProperty; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.block.model.IBakedModel; import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.item.Item; @@ -18,6 +19,7 @@ import zone.moddev.mc.ironagearchitecture.CommonProxy; import zone.moddev.mc.ironagearchitecture.block.DownpipeBlock; import zone.moddev.mc.ironagearchitecture.block.GutterItem; +import zone.moddev.mc.ironagearchitecture.block.FireplaceBlock; import zone.moddev.mc.ironagearchitecture.block.FrameBlock; import zone.moddev.mc.ironagearchitecture.block.RoofBlock; import zone.moddev.mc.ironagearchitecture.block.JettyBracketItem; @@ -85,6 +87,17 @@ public final class ClientProxy extends CommonProxy { } } } + for (FireplaceBlock block : ArchitectureBlocks.FIREPLACES) { + TextureAtlasSprite masonry = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(block.masonry.texture); + for (IBlockState state : block.getBlockState().getValidStates()) { + ModelResourceLocation key = new ModelResourceLocation(block.getRegistryName(), variant(state)); + event.getModelRegistry().putObject(key, + new FireplaceBakedModel(event.getModelRegistry().getObject(key), block, state, masonry)); + } + ModelResourceLocation inventory = new ModelResourceLocation(block.getRegistryName(), "inventory"); + event.getModelRegistry().putObject(inventory, + new FireplaceBakedModel(event.getModelRegistry().getObject(inventory), block, block.getDefaultState(), masonry)); + } for (RoofBlock block : ArchitectureBlocks.ROOFS) { String texture = "ironagearchitecture:blocks/" + block.textureKey(); for (IBlockState state : block.getBlockState().getValidStates()) { @@ -106,6 +119,9 @@ private static GutterItem[] gutterItems() { @SubscribeEvent public void stitch(TextureStitchEvent.Pre event) { event.getMap().registerSprite(new ResourceLocation("minecraft:blocks/glass_silver"));event.getMap().registerSprite(new ResourceLocation("minecraft:blocks/iron_block")); event.getMap().registerSprite(new ResourceLocation("minecraft:blocks/planks_big_oak")); + if (!ArchitectureBlocks.FIREPLACES.isEmpty()) for (String material : new String[]{ + "brick", "stonebrick", "hardened_clay_stained_orange", "stone_slab_top", "magma", "fire_layer_0"}) + event.getMap().registerSprite(new ResourceLocation("minecraft:blocks/" + material)); for(String wood:ArchitectureBlocks.WOODS) { event.getMap().registerSprite(new ResourceLocation("ironagearchitecture:blocks/beam_"+wood)); event.getMap().registerSprite(new ResourceLocation("minecraft:blocks/log_"+(wood.equals("dark_oak")?"big_oak":wood)+"_top")); diff --git a/src/main/java/zone/moddev/mc/ironagearchitecture/client/FireplaceBakedModel.java b/src/main/java/zone/moddev/mc/ironagearchitecture/client/FireplaceBakedModel.java new file mode 100644 index 0000000..76b4b10 --- /dev/null +++ b/src/main/java/zone/moddev/mc/ironagearchitecture/client/FireplaceBakedModel.java @@ -0,0 +1,46 @@ +package zone.moddev.mc.ironagearchitecture.client; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import javax.annotation.Nullable; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.client.renderer.block.model.ItemCameraTransforms; +import net.minecraft.client.renderer.block.model.ItemOverrideList; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.property.IExtendedBlockState; +import zone.moddev.mc.ironagearchitecture.block.FireplaceBlock; + +/** Cache the local join shapes while keeping the baked model free of world references. */ +final class FireplaceBakedModel implements IBakedModel { + private final IBakedModel base; + private final FireplaceBlock block; + private final IBlockState state; + private final TextureAtlasSprite masonry; + private final ConcurrentMap meshes = new ConcurrentHashMap<>(); + + FireplaceBakedModel(IBakedModel base, FireplaceBlock block, IBlockState state, TextureAtlasSprite masonry) { + this.base = base; + this.block = block; + this.state = state; + this.masonry = masonry; + } + + @Override public List getQuads(@Nullable IBlockState extended, @Nullable EnumFacing side, long seed) { + if (side != null) return Collections.emptyList(); + Integer mask = extended instanceof IExtendedBlockState ? ((IExtendedBlockState)extended).getValue(FireplaceBlock.JOINS) : null; + return meshes.computeIfAbsent(mask == null ? 0 : mask, + joins -> RoofBakedModel.fireplace(base, block, state, masonry, joins)).getQuads(null, null, seed); + } + + @Override public boolean isAmbientOcclusion() { return false; } + @Override public boolean isGui3d() { return true; } + @Override public boolean isBuiltInRenderer() { return false; } + @Override public TextureAtlasSprite getParticleTexture() { return masonry; } + @Override public ItemCameraTransforms getItemCameraTransforms() { return base.getItemCameraTransforms(); } + @Override public ItemOverrideList getOverrides() { return ItemOverrideList.NONE; } +} diff --git a/src/main/java/zone/moddev/mc/ironagearchitecture/client/RoofBakedModel.java b/src/main/java/zone/moddev/mc/ironagearchitecture/client/RoofBakedModel.java index cca98fc..fd7d6ae 100644 --- a/src/main/java/zone/moddev/mc/ironagearchitecture/client/RoofBakedModel.java +++ b/src/main/java/zone/moddev/mc/ironagearchitecture/client/RoofBakedModel.java @@ -17,6 +17,9 @@ import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad; import zone.moddev.mc.ironagearchitecture.block.DownpipeBlock; import zone.moddev.mc.ironagearchitecture.block.FasciaBlock; +import zone.moddev.mc.ironagearchitecture.block.FireplaceBlock; +import zone.moddev.mc.ironagearchitecture.block.FireplaceGeometry; +import zone.moddev.mc.ironagearchitecture.block.FireplaceGeometry.Part; import zone.moddev.mc.ironagearchitecture.block.RoofBlock; import zone.moddev.mc.ironagearchitecture.block.RoofGeometry; import zone.moddev.mc.ironagearchitecture.block.RoofShape; @@ -83,8 +86,70 @@ static RoofBakedModel pipe(IBakedModel base, DownpipeBlock block, IBlockState st return model; } + static RoofBakedModel fireplace(IBakedModel base, FireplaceBlock block, IBlockState state, + TextureAtlasSprite masonry, int joins) { + RoofBakedModel model = new RoofBakedModel(base, masonry); + EnumFacing facing = state.getValue(FireplaceBlock.FACING); + boolean lit = block.kind == FireplaceBlock.Kind.FIREBOX && state.getValue(FireplaceBlock.LIT); + for (Part part : FireplaceGeometry.parts(block.kind, joins, lit)) { + TextureAtlasSprite texture = masonry; + float tint = 1; + switch (part.surface) { + case GRATE: texture = iron(); tint = .26F; break; + case POT: texture = atlas("minecraft:blocks/hardened_clay_stained_orange"); tint = .78F; break; + case STONE: texture = atlas("minecraft:blocks/stone_slab_top"); break; + case COALS: texture = atlas("minecraft:blocks/magma"); break; + default: break; + } + model.addFireplacePart(part, facing, texture, tint, false); + } + if (block.kind == FireplaceBlock.Kind.COLLAR) { + TextureAtlasSprite tile = atlas("ironagearchitecture:blocks/clay_tile"); + for (Part strip : FireplaceGeometry.collarStrips(joins)) + model.addFireplacePart(strip, facing, tile, 1, true); + } + if (lit) model.addFlames(facing); + return model; + } + + private void addFireplacePart(Part part, EnumFacing facing, TextureAtlasSprite texture, float tint, boolean sloping) { + double[][] corners = {{part.x0,part.z0},{part.x1,part.z0},{part.x1,part.z1},{part.x0,part.z1}}; + double[][] top = new double[4][], bottom = new double[4][]; + for (int i = 0; i < corners.length; i++) { + double x = corners[i][0] / 16, z = corners[i][1] / 16; + double y = sloping ? RoofGeometry.height(RoofShape.STRAIGHT, false, x, z) : part.y1 / 16; + top[i] = new double[]{x,y,z}; + bottom[i] = new double[]{x,part.y0/16,z}; + } + add(new double[][]{top[0],top[3],top[2],top[1]}, facing, true, texture, null, tint,tint,tint); + add(bottom, facing, true, texture, null, tint,tint,tint); + for (int i = 0; i < 4; i++) { + int next = (i+1)%4; + add(new double[][]{bottom[i],top[i],top[next],bottom[next]}, facing, false, texture, null, tint,tint,tint); + } + } + + private void addFlames(EnumFacing facing) { + TextureAtlasSprite fire = atlas("minecraft:blocks/fire_layer_0"); + for (double z : new double[]{.32, .57}) { + double[][] a = {{.31,.32,z},{.31,.84,z+.10},{.69,.84,z+.10},{.69,.32,z}}; + flamePlane(a, facing, fire); + } + flamePlane(new double[][]{{.38,.32,.28},{.62,.84,.28},{.62,.84,.72},{.38,.32,.72}}, facing, fire); + } + + private void flamePlane(double[][] face, EnumFacing facing, TextureAtlasSprite fire) { + float[][] uv = {{0,16},{0,0},{16,0},{16,16}}; + add(face, facing, false, fire, null, 1,1,1, uv); + add(new double[][]{face[3],face[2],face[1],face[0]}, facing, false, fire, null, 1,1,1, uv); + } + + private static TextureAtlasSprite atlas(String key) { + return net.minecraft.client.Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(key); + } + private static TextureAtlasSprite iron() { - return net.minecraft.client.Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite("minecraft:blocks/iron_block"); + return atlas("minecraft:blocks/iron_block"); } private DrainMesh.Face ironFaces(EnumFacing facing) { @@ -174,6 +239,11 @@ private void add(double[][] points, EnumFacing facing, boolean top, TextureAtlas private void add(double[][] points, EnumFacing facing, boolean top, TextureAtlasSprite texture, @Nullable TrimmedRoofBlock.Kind board, float red, float green, float blue) { + add(points, facing, top, texture, board, red, green, blue, null); + } + + private void add(double[][] points, EnumFacing facing, boolean top, TextureAtlasSprite texture, + @Nullable TrimmedRoofBlock.Kind board, float red, float green, float blue, @Nullable float[][] uv) { if (java.util.Arrays.equals(points[0],points[1])) points = new double[][]{points[0],points[2],points[3],points[3]}; double[][] rotated = new double[4][]; @@ -188,7 +258,7 @@ private void add(double[][] points, EnumFacing facing, boolean top, TextureAtlas UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format); builder.setTexture(texture); builder.setQuadOrientation(EnumFacing.getFacingFromVector((float)nx,(float)ny,(float)nz)); - builder.setApplyDiffuseLighting(true); + builder.setApplyDiffuseLighting(uv == null); for (int vertex = 0; vertex < 4; vertex++) { double[] p = rotated[vertex], source = points[vertex]; boolean alongX = Math.abs(points[0][0]-points[2][0]) > 1e-8; @@ -202,6 +272,10 @@ private void add(double[][] points, EnumFacing facing, boolean top, TextureAtlas textureV = textureU; textureU = acrossGrain; } + if (uv != null) { + textureU = uv[vertex][0]; + textureV = uv[vertex][1]; + } for (int element = 0; element < format.getElementCount(); element++) { switch (format.getElement(element).getUsage()) { case POSITION: builder.put(element,(float)p[0],(float)p[1],(float)p[2],1); break; diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_collar.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_collar.json new file mode 100644 index 0000000..a984a36 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_collar.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_firebox.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_firebox.json new file mode 100644 index 0000000..a984a36 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_firebox.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_flue.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_flue.json new file mode 100644 index 0000000..a984a36 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_flue.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_hearth.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_hearth.json new file mode 100644 index 0000000..a984a36 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_hearth.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_jamb.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_jamb.json new file mode 100644 index 0000000..a984a36 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_jamb.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_lintel.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_lintel.json new file mode 100644 index 0000000..a984a36 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_lintel.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_pot_cap.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_pot_cap.json new file mode 100644 index 0000000..a984a36 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_pot_cap.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_slab_cap.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_slab_cap.json new file mode 100644 index 0000000..a984a36 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_brick_slab_cap.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_brick_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_brick_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_collar.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_collar.json new file mode 100644 index 0000000..f072a44 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_collar.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_firebox.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_firebox.json new file mode 100644 index 0000000..f072a44 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_firebox.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_flue.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_flue.json new file mode 100644 index 0000000..f072a44 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_flue.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_hearth.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_hearth.json new file mode 100644 index 0000000..f072a44 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_hearth.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_jamb.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_jamb.json new file mode 100644 index 0000000..f072a44 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_jamb.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_lintel.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_lintel.json new file mode 100644 index 0000000..f072a44 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_lintel.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_pot_cap.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_pot_cap.json new file mode 100644 index 0000000..f072a44 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_pot_cap.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_slab_cap.json b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_slab_cap.json new file mode 100644 index 0000000..f072a44 --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/blockstates/fireplace_stone_slab_cap.json @@ -0,0 +1,28 @@ +{ + "variants": { + "facing=north,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=north,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=east,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=south,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=false": { + "model": "ironagearchitecture:fireplace_stone_mesh" + }, + "facing=west,lit=true": { + "model": "ironagearchitecture:fireplace_stone_mesh" + } + } +} diff --git a/src/main/resources/assets/ironagearchitecture/lang/en_GB.lang b/src/main/resources/assets/ironagearchitecture/lang/en_GB.lang index 5ec06c6..2f07330 100644 --- a/src/main/resources/assets/ironagearchitecture/lang/en_GB.lang +++ b/src/main/resources/assets/ironagearchitecture/lang/en_GB.lang @@ -491,6 +491,30 @@ tile.ironagearchitecture.clay_tile_fascia.name=Clay Tile Fascia tile.ironagearchitecture.clay_tile_verge.name=Clay Tile Verge tile.ironagearchitecture.clay_tile_ridge_end.name=Clay Tile Ridge End item.ironagearchitecture.dark_oak_soffit.name=Dark Oak Soffit +tile.ironagearchitecture.fireplace_brick_hearth.name=Brick Hearth +tile.ironagearchitecture.fireplace_brick_firebox.name=Brick Firebox +tile.ironagearchitecture.fireplace_brick_jamb.name=Brick Fireplace Jamb +tile.ironagearchitecture.fireplace_brick_lintel.name=Brick Fireplace Lintel +tile.ironagearchitecture.fireplace_brick_flue.name=Brick Chimney Flue +tile.ironagearchitecture.fireplace_brick_collar.name=Brick Clay Roof Collar +tile.ironagearchitecture.fireplace_brick_pot_cap.name=Brick Chimney Pot +tile.ironagearchitecture.fireplace_brick_slab_cap.name=Brick Vented Chimney Cap +tile.ironagearchitecture.fireplace_stone_hearth.name=Stone Hearth +tile.ironagearchitecture.fireplace_stone_firebox.name=Stone Firebox +tile.ironagearchitecture.fireplace_stone_jamb.name=Stone Fireplace Jamb +tile.ironagearchitecture.fireplace_stone_lintel.name=Stone Fireplace Lintel +tile.ironagearchitecture.fireplace_stone_flue.name=Stone Chimney Flue +tile.ironagearchitecture.fireplace_stone_collar.name=Stone Clay Roof Collar +tile.ironagearchitecture.fireplace_stone_pot_cap.name=Stone Chimney Pot +tile.ironagearchitecture.fireplace_stone_slab_cap.name=Stone Vented Chimney Cap +hint.ironagearchitecture.fireplace.hearth=Place beside a matching hearth or firebox for a wider fireplace. +hint.ironagearchitecture.fireplace.firebox=Light with flint and steel. Sneak and right-click with empty hands to put it out. +hint.ironagearchitecture.fireplace.jamb=Place beside the opening to frame the fireplace. +hint.ironagearchitecture.fireplace.lintel=Span the opening with matching lintels. +hint.ironagearchitecture.fireplace.flue=Stack directly above a firebox. Each column has its own smoke path. +hint.ironagearchitecture.fireplace.collar=Place facing uphill on a straight clay slope. Stack the flue through it. +hint.ironagearchitecture.fireplace.pot_cap=Place on top of a flue and leave the mouth clear. +hint.ironagearchitecture.fireplace.slab_cap=Place on top of a flue and leave a side vent clear. item.ironagearchitecture.iron_gutter.name=Iron Gutter item.ironagearchitecture.iron_gutter_outlet.name=Iron Gutter Outlet tile.ironagearchitecture.iron_downpipe.name=Iron Downpipe diff --git a/src/main/resources/assets/ironagearchitecture/lang/en_US.lang b/src/main/resources/assets/ironagearchitecture/lang/en_US.lang index 5ec06c6..2f07330 100644 --- a/src/main/resources/assets/ironagearchitecture/lang/en_US.lang +++ b/src/main/resources/assets/ironagearchitecture/lang/en_US.lang @@ -491,6 +491,30 @@ tile.ironagearchitecture.clay_tile_fascia.name=Clay Tile Fascia tile.ironagearchitecture.clay_tile_verge.name=Clay Tile Verge tile.ironagearchitecture.clay_tile_ridge_end.name=Clay Tile Ridge End item.ironagearchitecture.dark_oak_soffit.name=Dark Oak Soffit +tile.ironagearchitecture.fireplace_brick_hearth.name=Brick Hearth +tile.ironagearchitecture.fireplace_brick_firebox.name=Brick Firebox +tile.ironagearchitecture.fireplace_brick_jamb.name=Brick Fireplace Jamb +tile.ironagearchitecture.fireplace_brick_lintel.name=Brick Fireplace Lintel +tile.ironagearchitecture.fireplace_brick_flue.name=Brick Chimney Flue +tile.ironagearchitecture.fireplace_brick_collar.name=Brick Clay Roof Collar +tile.ironagearchitecture.fireplace_brick_pot_cap.name=Brick Chimney Pot +tile.ironagearchitecture.fireplace_brick_slab_cap.name=Brick Vented Chimney Cap +tile.ironagearchitecture.fireplace_stone_hearth.name=Stone Hearth +tile.ironagearchitecture.fireplace_stone_firebox.name=Stone Firebox +tile.ironagearchitecture.fireplace_stone_jamb.name=Stone Fireplace Jamb +tile.ironagearchitecture.fireplace_stone_lintel.name=Stone Fireplace Lintel +tile.ironagearchitecture.fireplace_stone_flue.name=Stone Chimney Flue +tile.ironagearchitecture.fireplace_stone_collar.name=Stone Clay Roof Collar +tile.ironagearchitecture.fireplace_stone_pot_cap.name=Stone Chimney Pot +tile.ironagearchitecture.fireplace_stone_slab_cap.name=Stone Vented Chimney Cap +hint.ironagearchitecture.fireplace.hearth=Place beside a matching hearth or firebox for a wider fireplace. +hint.ironagearchitecture.fireplace.firebox=Light with flint and steel. Sneak and right-click with empty hands to put it out. +hint.ironagearchitecture.fireplace.jamb=Place beside the opening to frame the fireplace. +hint.ironagearchitecture.fireplace.lintel=Span the opening with matching lintels. +hint.ironagearchitecture.fireplace.flue=Stack directly above a firebox. Each column has its own smoke path. +hint.ironagearchitecture.fireplace.collar=Place facing uphill on a straight clay slope. Stack the flue through it. +hint.ironagearchitecture.fireplace.pot_cap=Place on top of a flue and leave the mouth clear. +hint.ironagearchitecture.fireplace.slab_cap=Place on top of a flue and leave a side vent clear. item.ironagearchitecture.iron_gutter.name=Iron Gutter item.ironagearchitecture.iron_gutter_outlet.name=Iron Gutter Outlet tile.ironagearchitecture.iron_downpipe.name=Iron Downpipe diff --git a/src/main/resources/assets/ironagearchitecture/models/block/fireplace_brick_mesh.json b/src/main/resources/assets/ironagearchitecture/models/block/fireplace_brick_mesh.json new file mode 100644 index 0000000..5c4ecab --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/block/fireplace_brick_mesh.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:block/block", + "textures": { + "particle": "minecraft:blocks/brick" + }, + "elements": [] +} diff --git a/src/main/resources/assets/ironagearchitecture/models/block/fireplace_stone_mesh.json b/src/main/resources/assets/ironagearchitecture/models/block/fireplace_stone_mesh.json new file mode 100644 index 0000000..23bd0dc --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/block/fireplace_stone_mesh.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:block/block", + "textures": { + "particle": "minecraft:blocks/stonebrick" + }, + "elements": [] +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_collar.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_collar.json new file mode 100644 index 0000000..6e5e8ba --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_collar.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_brick_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_firebox.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_firebox.json new file mode 100644 index 0000000..6e5e8ba --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_firebox.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_brick_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_flue.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_flue.json new file mode 100644 index 0000000..6e5e8ba --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_flue.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_brick_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_hearth.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_hearth.json new file mode 100644 index 0000000..6e5e8ba --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_hearth.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_brick_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_jamb.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_jamb.json new file mode 100644 index 0000000..6e5e8ba --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_jamb.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_brick_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_lintel.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_lintel.json new file mode 100644 index 0000000..6e5e8ba --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_lintel.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_brick_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_pot_cap.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_pot_cap.json new file mode 100644 index 0000000..6e5e8ba --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_pot_cap.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_brick_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_slab_cap.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_slab_cap.json new file mode 100644 index 0000000..6e5e8ba --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_brick_slab_cap.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_brick_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_collar.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_collar.json new file mode 100644 index 0000000..02f493f --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_collar.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_stone_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_firebox.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_firebox.json new file mode 100644 index 0000000..02f493f --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_firebox.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_stone_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_flue.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_flue.json new file mode 100644 index 0000000..02f493f --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_flue.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_stone_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_hearth.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_hearth.json new file mode 100644 index 0000000..02f493f --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_hearth.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_stone_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_jamb.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_jamb.json new file mode 100644 index 0000000..02f493f --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_jamb.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_stone_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_lintel.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_lintel.json new file mode 100644 index 0000000..02f493f --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_lintel.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_stone_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_pot_cap.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_pot_cap.json new file mode 100644 index 0000000..02f493f --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_pot_cap.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_stone_mesh" +} diff --git a/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_slab_cap.json b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_slab_cap.json new file mode 100644 index 0000000..02f493f --- /dev/null +++ b/src/main/resources/assets/ironagearchitecture/models/item/fireplace_stone_slab_cap.json @@ -0,0 +1,3 @@ +{ + "parent": "ironagearchitecture:block/fireplace_stone_mesh" +} diff --git a/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/ArchitectureProbe.java b/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/ArchitectureProbe.java index e552ae2..1d015f6 100644 --- a/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/ArchitectureProbe.java +++ b/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/ArchitectureProbe.java @@ -45,7 +45,7 @@ /** Disposable packaged-runtime verification mod. Never part of the player jar. */ @Mod(modid="ironagearchitectureprobe",name="Architecture Verification",version="1",acceptableRemoteVersions="*", - dependencies="required-after:ironagearchitecture@[0.1.12.110021]") + dependencies="required-after:ironagearchitecture@[0.1.13.110021]") public final class ArchitectureProbe { @SidedProxy(clientSide="zone.moddev.mc.ironagearchitecture.probe.ClientProbe",serverSide="zone.moddev.mc.ironagearchitecture.probe.ProbeProxy") public static ProbeProxy proxy; @@ -77,7 +77,7 @@ public final class ArchitectureProbe { if(Boolean.getBoolean("iaa.legacyJetties")) { int index=0; for(Block block:savedBlocks) { - if (ClayTileProbe.isClay(block)) continue; + if (ClayTileProbe.isClay(block) || block instanceof FireplaceBlock) continue; for(int meta=0;meta<16;meta++) { require(world.getBlockState(new BlockPos(100+index,70,100)).equals(block.getStateFromMeta(meta)),"0.1.2 saved state "+index); index++; @@ -149,6 +149,7 @@ public final class ArchitectureProbe { } ClayTileProbe.verify(world); GutterProbe.verify(world); + FireplaceProbe.verify(world, reload); if (!reload && clayClient) RyeTilePreview.build(world); if (Boolean.getBoolean("iaa.clayOnly")) { require(variants == 16 && recipes == 20 && RecipeProbe.verifyReachability() == 16, "Standalone clay tiles"); @@ -172,21 +173,21 @@ private static void finish(MinecraftServer server, String result) throws java.io } private void verifyConfigMatrix() throws Exception { boolean cob=ArchitectureConfig.cob,frames=ArchitectureConfig.frames,thatch=ArchitectureConfig.thatch,slate=ArchitectureConfig.slate,windows=ArchitectureConfig.windows; - boolean clayTiles = ArchitectureConfig.clayTiles; + boolean clayTiles = ArchitectureConfig.clayTiles, fireplaces = ArchitectureConfig.fireplaces; zone.moddev.mc.ironagearchitecture.EraSelection eras=ArchitectureConfig.survivalEras; java.nio.file.Path directory=Paths.get("config-matrix");Files.createDirectories(directory); try { - for(int mask=0;mask<64;mask++) { + for(int mask=0;mask<128;mask++) { java.nio.file.Path file=directory.resolve(mask+".cfg"); String text="blocks {\n B:cob="+((mask&1)!=0)+"\n B:timberFrames="+((mask&2)!=0) +"\n B:thatch="+((mask&4)!=0)+"\n B:slate="+((mask&8)!=0)+"\n B:leadedWindows="+((mask&16)!=0) - +"\n B:clayTiles="+((mask&32)!=0)+"\n}\n"; + +"\n B:clayTiles="+((mask&32)!=0)+"\n B:fireplaces="+((mask&64)!=0)+"\n}\n"; Files.write(file,text.getBytes(StandardCharsets.UTF_8));ArchitectureConfig.load(file.toFile()); require(ArchitectureConfig.cob==((mask&1)!=0)&&ArchitectureConfig.frames==((mask&3)==3) &&ArchitectureConfig.thatch==((mask&4)!=0)&&ArchitectureConfig.slate==((mask&8)!=0)&&ArchitectureConfig.windows==((mask&19)==19) - &&ArchitectureConfig.clayTiles==((mask&32)!=0),"Config mask "+mask); + &&ArchitectureConfig.clayTiles==((mask&32)!=0)&&ArchitectureConfig.fireplaces==((mask&64)!=0),"Config mask "+mask); } - } finally {ArchitectureConfig.cob=cob;ArchitectureConfig.frames=frames;ArchitectureConfig.thatch=thatch;ArchitectureConfig.slate=slate;ArchitectureConfig.windows=windows;ArchitectureConfig.clayTiles=clayTiles;ArchitectureConfig.survivalEras=eras;} + } finally {ArchitectureConfig.cob=cob;ArchitectureConfig.frames=frames;ArchitectureConfig.thatch=thatch;ArchitectureConfig.slate=slate;ArchitectureConfig.windows=windows;ArchitectureConfig.clayTiles=clayTiles;ArchitectureConfig.fireplaces=fireplaces;ArchitectureConfig.survivalEras=eras;} } private void verifyWallHeads(WorldServer world) { BlockPos pos=new BlockPos(95,90,95); diff --git a/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/ClientProbe.java b/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/ClientProbe.java index 2e566d3..29acdaf 100644 --- a/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/ClientProbe.java +++ b/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/ClientProbe.java @@ -1,6 +1,7 @@ package zone.moddev.mc.ironagearchitecture.probe; import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.client.gui.GuiMainMenu; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.inventory.GuiContainerCreative; @@ -8,8 +9,13 @@ import zone.moddev.mc.ironagearchitecture.Era; import zone.moddev.mc.ironagearchitecture.EraTabs; import net.minecraft.client.renderer.block.model.IBakedModel; +import net.minecraft.block.BlockDoor; import net.minecraft.block.state.IBlockState; import net.minecraft.util.ScreenShotHelper; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.WorldServer; +import zone.moddev.mc.ironagearchitecture.block.FireplaceBlock; +import zone.moddev.mc.ironagearchitecture.block.FireplaceDraft; import net.minecraft.world.GameType; import net.minecraft.world.WorldSettings; import net.minecraft.world.WorldType; @@ -41,7 +47,10 @@ public final class ClientProbe extends ProbeProxy { if(phase==0&&mc.currentScreen instanceof GuiMainMenu&&ticks>60) { mc.gameSettings.pauseOnLostFocus=false; phase=1;ticks=0; - String preview=System.getProperty("iaa.previewName",RyeTilePreview.NAME); + String preview = System.getProperty("iaa.previewName", + ArchitectureConfig.fireplaces ? "Rye Fireplace Preview" : RyeTilePreview.NAME); + if (new java.io.File(mc.mcDataDir, "saves/" + preview).exists()) + throw new IllegalStateException("Use a fresh world for the native preview"); mc.launchIntegratedServer(preview,preview,new WorldSettings(137,GameType.CREATIVE,false,false,WorldType.FLAT)); } else if(phase==1&&mc.player!=null) { phase=2;ticks=0; @@ -49,7 +58,9 @@ public final class ClientProbe extends ProbeProxy { mc.gameSettings.showInventoryAchievementHint=false; mc.setIngameNotInFocus(); mc.player.capabilities.allowFlying=true;mc.player.capabilities.isFlying=true; - lookAt(mc,48,102,-85,48,73,4); + if (ArchitectureConfig.clayTiles && ArchitectureConfig.frames) + lookAt(mc, -32, 9.5, -12.4, -39.5, 17.5, 3.6); + else lookAt(mc,48,102,-85,48,73,4); } else if(phase==2&&ticks>260) { for(RoofBlock roof:ArchitectureBlocks.ROOFS) for(IBlockState state:roof.getBlockState().getValidStates()) { IBakedModel model=mc.getBlockRendererDispatcher().getModelForState(state); @@ -75,6 +86,7 @@ public final class ClientProbe extends ProbeProxy { if(!(model instanceof WindowBakedModel)||model.getQuads(state,null,0).isEmpty()) throw new IllegalStateException("Missing window model "+state); for(net.minecraft.client.renderer.block.model.BakedQuad quad:model.getQuads(state,null,0)) if(quad.getSprite().getIconName().contains("missingno")) throw new IllegalStateException("Missing window texture "+state); } + checkFireplaceModels(mc); if (ArchitectureConfig.clayTiles) { for (net.minecraft.block.Block panel : new net.minecraft.block.Block[]{ArchitectureBlocks.CLAY_HANGING, ArchitectureBlocks.CLAY_HANGING_THIN}) { for (IBlockState state : panel.getBlockState().getValidStates()) { @@ -92,7 +104,11 @@ public final class ClientProbe extends ProbeProxy { IBakedModel soffit = mc.getRenderItem().getItemModelMesher().getItemModel(new ItemStack(ArchitectureBlocks.SOFFIT)); if (soffit.getParticleTexture().getIconName().contains("missingno")) throw new IllegalStateException("Missing soffit item model"); - phase=60;ticks=0; + phase=ArchitectureConfig.fireplaces ? 70 : 60;ticks=0; + if (phase == 70) { + setPreviewGameType(mc, GameType.SPECTATOR); + setPreviewDoor(mc, true); + } return; } capture(mc,"jettied-street-overview.png"); @@ -142,6 +158,8 @@ public final class ClientProbe extends ProbeProxy { setPreviewRain(mc, false); checkPalettes(mc); mc.displayGuiScreen(new PaletteGui(mc,Era.IRON_AGE,true));phase=8;ticks=0; + } else if (phase >= 70 && phase <= 75) { + captureFireplacePreview(mc); } else if(phase==8) { if(!ensurePalette(mc,Era.IRON_AGE)) {ticks=0;return;} if(ticks>80) {capture(mc,"iron-age-palette.png");mc.displayGuiScreen(new PaletteGui(mc,Era.LATE_MEDIEVAL_TUDOR,false));phase=9;ticks=0;} @@ -154,6 +172,92 @@ public final class ClientProbe extends ProbeProxy { } } } + private void captureFireplacePreview(Minecraft mc) { + double[][] cameras = { + {-37.5, 10.03, 1.4, -37.5, 11.1, 4.0}, + {-37.1, 14.03, 1.68, -38.5, 15.05, 4.0}, + {-44.25, 12.02, 2.3, -44.5, 13.05, 6.0}, + {-32, 9.5, -12.4, -39.5, 17.5, 3.6}, + {-32, 9.5, -12.4, -39.5, 17.5, 3.6}, + {-30, 20, 9, -38.5, 20.8, 4.4} + }; + String[] names = {"stone-inglenook.png", "upstairs-hearth.png", "brick-hearth.png", + "rye-one-pot-smoking.png", "rye-both-pots-smoking.png", "rye-stack-and-collar.png"}; + mc.gameSettings.fovSetting = phase == 70 ? 86 : 70; + double[] camera = cameras[phase - 70]; + lookAt(mc, camera[0], camera[1], camera[2], camera[3], camera[4], camera[5]); + + if (phase >= 73 && (ticks == 114 || ticks == 121 || ticks == 128)) { + showOutlet(mc, RyeFireplacePreview.LOWER_POT, true); + showOutlet(mc, RyeFireplacePreview.UPPER_POT, phase >= 74); + } + if (ticks <= 130) return; + capture(mc, names[phase - 70]); + if (phase == 70) setPreviewDoor(mc, false); + if (phase == 70 || phase == 72 || phase == 73) setPreviewUpperFire(mc, phase != 72); + if (phase < 75) { + phase++; + ticks = 0; + return; + } + setPreviewGameType(mc, GameType.CREATIVE); + System.out.println("IAA_FIREPLACE_PREVIEW_PASS onePot=true twoPots=true"); + checkPalettes(mc); + mc.displayGuiScreen(new PaletteGui(mc, Era.IRON_AGE, true)); + phase = 8; + ticks = 0; + } + + private void setPreviewGameType(Minecraft mc, GameType gameType) { + mc.getIntegratedServer().addScheduledTask(() -> { + WorldServer world = mc.getIntegratedServer().worldServerForDimension(0); + for (EntityPlayer player : world.playerEntities) { + player.setGameType(gameType); + if (gameType == GameType.CREATIVE) { + BlockPos spawn = RyeTilePreview.SPAWN; + player.setPositionAndUpdate(spawn.getX() + .5, spawn.getY(), spawn.getZ() + .5); + } + } + }); + } + + private void setPreviewDoor(Minecraft mc, boolean open) { + mc.getIntegratedServer().addScheduledTask(() -> { + WorldServer world = mc.getIntegratedServer().worldServerForDimension(0); + BlockPos door = new BlockPos(-38, 10, 1); + world.setBlockState(door, world.getBlockState(door).withProperty(BlockDoor.OPEN, open), 3); + }); + } + + private void setPreviewUpperFire(Minecraft mc, boolean lit) { + mc.getIntegratedServer().addScheduledTask(() -> { + WorldServer world = mc.getIntegratedServer().worldServerForDimension(0); + BlockPos upper = RyeFireplacePreview.UPPER_FIRE; + world.setBlockState(upper, world.getBlockState(upper).withProperty(FireplaceBlock.LIT, lit), 3); + }); + } + + private void showOutlet(Minecraft mc, BlockPos pos, boolean expected) { + IBlockState state = mc.world.getBlockState(pos); + boolean active = FireplaceDraft.smokeOutlet(mc.world, pos, state) != null; + if (active != expected) throw new IllegalStateException("Unexpected fireplace preview draft at " + pos); + if (active) state.getBlock().randomDisplayTick(state, mc.world, pos, new java.util.Random(137L + ticks)); + } + + private static void checkFireplaceModels(Minecraft mc) { + for (FireplaceBlock fireplace : ArchitectureBlocks.FIREPLACES) { + for (IBlockState state : fireplace.getBlockState().getValidStates()) { + IBakedModel model = mc.getBlockRendererDispatcher().getModelForState(state); + java.util.List quads = model.getQuads(state, null, 0); + if (quads.isEmpty() || quads.stream().anyMatch(quad -> quad.getSprite().getIconName().contains("missingno"))) + throw new IllegalStateException("Missing fireplace mesh or texture " + state); + } + IBakedModel item = mc.getRenderItem().getItemModelMesher().getItemModel(new ItemStack(fireplace)); + if (item.getQuads(null, null, 0).isEmpty() || !fireplace.masonry.texture.equals(item.getParticleTexture().getIconName())) + throw new IllegalStateException("Missing fireplace inventory model " + fireplace); + } + } + private static void checkDrainModels(Minecraft mc) { for (ItemStack stack : ArchitectureBlocks.visibleStacks()) { String key = stack.getItem().getRegistryName().getResourcePath(); diff --git a/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/EraProbe.java b/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/EraProbe.java index 7ce5cc0..6af3071 100644 --- a/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/EraProbe.java +++ b/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/EraProbe.java @@ -15,10 +15,15 @@ final class EraProbe { private static void require(boolean condition,String message) {if(!condition) throw new IllegalStateException(message);} static int expectedRecipes() { - return ArchitectureConfig.survivalEras.allowed.contains(Era.LATE_MEDIEVAL_TUDOR)?(ArchitectureConfig.windows?2010:1863)+(ArchitectureConfig.clayTiles?20:0): + return ArchitectureConfig.survivalEras.allowed.contains(Era.LATE_MEDIEVAL_TUDOR)?(ArchitectureConfig.windows?2010:1863)+(ArchitectureConfig.clayTiles?20:0)+fireplaceParts(): ArchitectureConfig.survivalEras.allowed.contains(Era.IRON_AGE)?36:0; } - static int expectedVariants() { return (ArchitectureConfig.windows ? 510 : 460) + (ArchitectureConfig.clayTiles ? 16 : 0); } + static int expectedVariants() { + return (ArchitectureConfig.windows ? 510 : 460) + (ArchitectureConfig.clayTiles ? 16 : 0) + fireplaceParts(); + } + private static int fireplaceParts() { + return ArchitectureConfig.fireplaces ? (ArchitectureConfig.clayTiles ? 16 : 14) : 0; + } private static boolean ours(IRecipe recipe) { ItemStack output=recipe.getRecipeOutput(); return output!=null&&"ironagearchitecture".equals(output.getItem().getRegistryName().getResourceDomain()); @@ -41,7 +46,7 @@ static void verify(World world) throws Exception { List original=new ArrayList<>(recipes); EraSelection selected=ArchitectureConfig.survivalEras; boolean cob=ArchitectureConfig.cob,frames=ArchitectureConfig.frames,thatch=ArchitectureConfig.thatch,slate=ArchitectureConfig.slate,windows=ArchitectureConfig.windows; - boolean clayTiles = ArchitectureConfig.clayTiles; + boolean clayTiles = ArchitectureConfig.clayTiles, fireplaces = ArchitectureConfig.fireplaces; String[][] cases={{"all"},{"iron_age"},{"late_medieval_tudor"},{"iron_age","late_medieval_tudor"},{},{"typo"},{"iron_age","typo"},{" IRON_AGE ","iron_age"}}; try { recipes.removeIf(EraProbe::ours);ArchitectureConfig.survivalEras=EraSelection.parse("all");ArchitectureRecipes.register(); @@ -50,7 +55,7 @@ static void verify(World world) throws Exception { Files.createDirectories(Paths.get("era-matrix")); for(int c=0;c\n}\n"; + String text="blocks {\n B:leadedWindows="+windows+"\n B:clayTiles="+clayTiles+"\n B:fireplaces="+fireplaces+"\n}\nrecipes {\n S:survivalEras <\n"+String.join("\n",cases[c])+"\n >\n}\n"; Files.write(file,text.getBytes(StandardCharsets.UTF_8));ArchitectureConfig.load(file.toFile()); recipes.removeIf(EraProbe::ours);ArchitectureRecipes.register(); int count=0;for(IRecipe recipe:recipes) if(ours(recipe)) {require(EraCatalog.canCraft(recipe.getRecipeOutput()),"Prohibited registered output");count++;} @@ -75,6 +80,7 @@ static void verify(World world) throws Exception { recipes.clear();recipes.addAll(original);ArchitectureConfig.survivalEras=selected; ArchitectureConfig.cob=cob;ArchitectureConfig.frames=frames;ArchitectureConfig.thatch=thatch;ArchitectureConfig.slate=slate;ArchitectureConfig.windows=windows; ArchitectureConfig.clayTiles = clayTiles; + ArchitectureConfig.fireplaces = fireplaces; } } } diff --git a/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/FireplaceProbe.java b/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/FireplaceProbe.java new file mode 100644 index 0000000..9704098 --- /dev/null +++ b/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/FireplaceProbe.java @@ -0,0 +1,147 @@ +package zone.moddev.mc.ironagearchitecture.probe; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.EnumSkyBlock; +import net.minecraft.world.WorldServer; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.common.util.FakePlayerFactory; +import zone.moddev.mc.ironagearchitecture.ArchitectureBlocks; +import zone.moddev.mc.ironagearchitecture.ArchitectureConfig; +import zone.moddev.mc.ironagearchitecture.block.FireplaceBlock; +import zone.moddev.mc.ironagearchitecture.block.FireplaceBlock.Kind; +import zone.moddev.mc.ironagearchitecture.block.FireplaceBlock.Masonry; +import zone.moddev.mc.ironagearchitecture.block.FireplaceDraft; +import zone.moddev.mc.ironagearchitecture.block.RoofGeometry; + +final class FireplaceProbe { + static void verify(WorldServer world, boolean reload) { + if (!ArchitectureConfig.fireplaces) { + require(ArchitectureBlocks.FIREPLACES.isEmpty(), "disabled registration"); + return; + } + require(ArchitectureBlocks.FIREPLACES.size() == (ArchitectureConfig.clayTiles ? 16 : 14), "registration"); + for (FireplaceBlock block : ArchitectureBlocks.FIREPLACES) { + for (int meta = 0; meta < 16; meta++) { + IBlockState state = block.getStateFromMeta(meta); + require(block.getMetaFromState(state) == (meta & (block.kind == Kind.FIREBOX ? 7 : 3)), "metadata"); + require(block.damageDropped(state) == 0, "canonical drop"); + } + } + + BlockPos lower = new BlockPos(95, 105, 95); + BlockPos upper = lower.east().up(4); + BlockPos first = lower.up(8), second = first.east(); + // Forge's light propagation needs the surrounding chunks loaded in this disposable fixture. + for (int x = -2; x <= 2; x++) for (int z = -2; z <= 2; z++) + world.getChunkFromBlockCoords(first.add(16 * x, 0, 16 * z)); + if (reload) { + require(!smokes(world, first) && smokes(world, second), "saved fires and draft"); + return; + } + IBlockState firebox = block(Masonry.STONE, Kind.FIREBOX).getDefaultState(); + IBlockState flue = block(Masonry.BRICK, Kind.FLUE).getDefaultState(); + IBlockState pot = block(Masonry.BRICK, Kind.POT_CAP).getDefaultState(); + world.setBlockState(lower, firebox, 3); + world.setBlockState(upper, firebox, 3); + for (int y = lower.getY() + 1; y < first.getY(); y++) + world.setBlockState(new BlockPos(lower.getX(), y, lower.getZ()), flue, 3); + for (int y = upper.getY() + 1; y < second.getY(); y++) + world.setBlockState(new BlockPos(upper.getX(), y, upper.getZ()), flue, 3); + world.setBlockState(first, pot, 3); + world.setBlockState(second, pot, 3); + require(!smokes(world, first) && !smokes(world, second), "cold outlets"); + FireplaceBlock chimney = (FireplaceBlock)flue.getBlock(); + require(chimney.joins(flue, world, first.down()) == 2 + && chimney.joins(flue, world, second.down()) == 1, "masonry seam across chunks"); + require(chimney.collisionRayTrace(flue, world, first.down(), + point(first.down(), .5, -.1, .5), point(first.down(), .5, 1.1, .5)) == null, "hollow channel"); + require(chimney.collisionRayTrace(flue, world, first.down(), + point(first.down(), .2, -.1, .5), point(first.down(), .2, 1.1, .5)) != null, "masonry targeting"); + + FakePlayer player = FakePlayerFactory.getMinecraft(world); + ItemStack tool = new ItemStack(Items.FLINT_AND_STEEL); + require(use(world, lower, player, tool) && tool.getItemDamage() == 1, "flint and steel"); + require(use(world, lower, player, tool) && tool.getItemDamage() == 1 && world.isAirBlock(lower.north()), + "repeated click does not start vanilla fire"); + int emitted = world.getLightFor(EnumSkyBlock.BLOCK, lower); + require(emitted == 13, "emitted block light (got " + emitted + ")"); + require(smokes(world, first) && !smokes(world, second), "only downstairs smokes"); + require(use(world, upper, player, tool) && smokes(world, first) && smokes(world, second), "both floors smoke"); + world.setBlockState(first.up(), Blocks.STONE.getDefaultState(), 3); + require(!smokes(world, first) && smokes(world, second), "blocked pot independent"); + world.setBlockToAir(first.up()); + world.setBlockState(first, flue, 3); + require(smokes(world, first), "open flue"); + world.setBlockState(first, block(Masonry.BRICK, Kind.SLAB_CAP).getDefaultState(), 3); + require(smokes(world, first), "side vent"); + for (EnumFacing side : EnumFacing.HORIZONTALS) + if (side != EnumFacing.EAST) world.setBlockState(first.offset(side), Blocks.STONE.getDefaultState(), 3); + require(!smokes(world, first) && smokes(world, second), "blocked side vents"); + for (EnumFacing side : EnumFacing.HORIZONTALS) if (side != EnumFacing.EAST) world.setBlockToAir(first.offset(side)); + world.setBlockState(first, pot, 3); + world.setBlockToAir(first.down()); + require(!smokes(world, first) && smokes(world, second), "disconnected channel"); + world.setBlockState(first.down(), flue, 3); + player.setSneaking(true); + try { require(use(world, lower, player, null), "snuff fire"); } + finally { player.setSneaking(false); } + require(!smokes(world, first) && smokes(world, second) + && world.getLightFor(EnumSkyBlock.BLOCK, lower) < 13, "only upstairs smokes after snuffing"); + + if (ArchitectureConfig.clayTiles) { + FireplaceBlock collar = block(Masonry.BRICK, Kind.COLLAR); + for (EnumFacing facing : EnumFacing.HORIZONTALS) { + BlockPos pos = first.down(2); + IBlockState state = collar.getDefaultState().withProperty(FireplaceBlock.FACING, facing); + world.setBlockState(pos, state, 3); + require(collar.joins(state, world, pos) != 0, "paired roof collar " + facing); + world.setBlockToAir(pos.east()); + double[] high = RoofGeometry.rotate(.06, .65, .1, facing); + double[] low = RoofGeometry.rotate(.06, .65, .9, facing); + boolean firstHit = collar.boxes(state, world, pos).stream() + .anyMatch(box -> box.isVecInside(new Vec3d(high[0], high[1], high[2]))); + boolean secondHit = collar.boxes(state, world, pos).stream() + .anyMatch(box -> box.isVecInside(new Vec3d(low[0], low[1], low[2]))); + require(firstHit != secondHit, "roof collar slope " + facing); + world.setBlockState(pos.east(), flue, 3); + } + } + BlockPos tall = first.south(4).up(32); + for (int distance = 1; distance <= FireplaceDraft.MAX_DEPTH; distance++) + world.setBlockState(tall.down(distance), flue, 2); + world.setBlockState(tall, pot, 2); + world.setBlockState(tall.down(FireplaceDraft.MAX_DEPTH + 1), firebox.withProperty(FireplaceBlock.LIT, true), 2); + require(!smokes(world, tall), "scan stops after 32 blocks"); + world.setBlockState(tall.down(FireplaceDraft.MAX_DEPTH), firebox.withProperty(FireplaceBlock.LIT, true), 2); + require(smokes(world, tall), "32nd block is included"); + System.out.println("IAA_FIREPLACE_PASS twoFloors=true separateDraft=true chunkBorder=true light=true caps=3 scan=32"); + } + + private static Vec3d point(BlockPos pos, double x, double y, double z) { + return new Vec3d(pos.getX() + x, pos.getY() + y, pos.getZ() + z); + } + + private static boolean use(WorldServer world, BlockPos pos, FakePlayer player, ItemStack held) { + IBlockState state = world.getBlockState(pos); + return state.getBlock().onBlockActivated(world, pos, state, player, EnumHand.MAIN_HAND, held, EnumFacing.NORTH, .5F, .3F, .5F); + } + + private static boolean smokes(WorldServer world, BlockPos pos) { + return FireplaceDraft.smokeOutlet(world, pos, world.getBlockState(pos)) != null; + } + + private static FireplaceBlock block(Masonry masonry, Kind kind) { + return ArchitectureBlocks.fireplace(masonry, kind); + } + + private static void require(boolean condition, String message) { + if (!condition) throw new IllegalStateException("Fireplace probe failed: " + message); + } +} diff --git a/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/RecipeProbe.java b/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/RecipeProbe.java index 8d76b6e..b06f935 100644 --- a/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/RecipeProbe.java +++ b/src/probe/java/zone/moddev/mc/ironagearchitecture/probe/RecipeProbe.java @@ -104,6 +104,8 @@ private static void resources(Map quantities,ItemStack stack,int if(stack.getItem() instanceof LeadedPaneItem) {add(quantities,"leaded-glazing",count);return;} Block block=Block.getBlockFromItem(stack.getItem()); if(block instanceof WindowBlock) {WindowBlock window=(WindowBlock)block;add(quantities,"frame:"+window.wood+":"+window.finish,(window.thin?2:4)*count);add(quantities,"leaded-glazing",count);return;} + if (block instanceof FireplaceBlock && ((FireplaceBlock)block).kind == FireplaceBlock.Kind.COLLAR) + add(quantities, "roof:clay_tile", 4 * count); add(quantities,material(stack),units(stack)*count); } private static String material(ItemStack stack) { @@ -113,6 +115,7 @@ private static String material(ItemStack stack) { if(block instanceof JettyFloorBlock) return "floor:"+((JettyFloorBlock)block).wood; if(block instanceof FrameBlock) {FrameBlock wall=(FrameBlock)block;return wall.family==FrameFamily.INFILL?"daub:"+wall.finish(stack.getMetadata()):"frame:"+wall.wood+":"+wall.finish(stack.getMetadata());} if(item instanceof GutterItem || block instanceof DownpipeBlock) return "iron_drain"; + if(block instanceof FireplaceBlock) return "fireplace:" + ((FireplaceBlock)block).masonry.key; if(block instanceof RoofBlock) return "roof:"+((RoofBlock)block).materialKey; if(block instanceof TileHangingBlock) return "roof:clay_tile"; for(int finish=0;finish