15 Commits
v1.5 ... v1.5.7

Author SHA1 Message Date
44f03b2c96 Merge pull request 'New minor version with fix for caching on dynamic models' (#12) from dev into master
All checks were successful
deploy / deploy (push) Successful in 5m25s
Reviewed-on: #12
2024-04-15 20:58:47 +02:00
c3e0ab16b7 fixed cache issue with dynamic models from continuity and athena. Finished wall logic + updated to minor version 1.5.7 2024-04-15 20:57:03 +02:00
d8e4153754 added all wall models 2024-04-12 19:23:35 +02:00
572182e9f0 imports cleanup 2024-04-12 01:06:11 +02:00
6f394bbe6f wip wall logic and models + moved generation for block into separate classes for better readability 2024-04-12 01:03:47 +02:00
b05c0ebd42 removed unused imports 2024-04-11 00:06:22 +02:00
4309310c02 added missing receipe cleaned up model names creating W.I.P. wall + typo 2024-04-11 00:05:47 +02:00
74a290fd16 improved additivity of blocks and added pillar 2024-03-28 19:01:33 +01:00
a430a8e62b moved tools to tool crafting tab 2024-03-27 23:24:33 +01:00
3afee9e501 added continuity to optional modrinth dependencies + made blocks addition possible by placing correct shape on existing frame 2024-03-27 23:14:24 +01:00
319d247e4c added continuity to optional modrinth dependencies 2024-03-25 17:12:05 +01:00
f1af00738e Merge pull request 'version 1.5.6 fix for server imports + support for continuity and MoreCulling compat' (#11) from dev into master
All checks were successful
deploy / deploy (push) Successful in 5m44s
Reviewed-on: #11
2024-03-25 16:33:09 +01:00
3048f53878 removed necessary implementation and updated to minor version 2024-03-25 16:27:58 +01:00
f222e4dc24 fixed incompatibility with MoreCulling + fixed server crash with clientside classes import + continuity connected textures support 2024-03-25 15:22:28 +01:00
5c064176b2 complied with FramedBlock assets License by making this project Multi-Licensed. In addition, wrote a README.md + cache reload fix on resource reload + items for hammer, blueprint and screwdriver + updated to v1.5.5 2024-03-15 23:30:10 +01:00
125 changed files with 5627 additions and 1199 deletions

1
.gitignore vendored
View File

@@ -33,3 +33,4 @@ local.properties
*-autosave.kra
*.kra~
/src/generated/
/libs/

16
LICENSE
View File

@@ -1,15 +1 @@
Copyright (c) 2019 B0undarybreaker (Meredith Espinosa)
Copyright (c) 2024 Adrien1106
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
MIT AND LGPL-3.0

165
LICENSE.LGPL-3.0 Normal file
View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

15
LICENSE.MIT Normal file
View File

@@ -0,0 +1,15 @@
Copyright (c) 2019 B0undarybreaker (Meredith Espinosa)\
Copyright (c) 2024 Adrien1106
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

43
README.md Normal file
View File

@@ -0,0 +1,43 @@
# ReFramed
## Overview
This Project is an unofficial port of [FramedBlocks](https://github.com/XFactHD/FramedBlocks)
forked from [Templates 2](https://github.com/quat1024/templates-mod).
It aims to add the same mechanics as [FramedBlocks](https://github.com/XFactHD/FramedBlocks) into Fabric.
For a complete Feature list please have a look at the [Modrinth](https://modrinth.com/mod/reframed) page.
## Information
### Where to get it?
The mod can be downloaded on [Modrinth](https://modrinth.com/mod/reframed).
### Issues/requests
Any issues/requests may be addressed on this repository in the [Issues](https://github.com/DriHut/ReFramed/issues) section.
### Out of date?
I will be adding new shapes as time passes, but I am currently not planing on keeping up with the newer versions of the game.
That said this mod is under permissive licenses and make it easy for anyone to create their own fork.
If anyone in the future plans to do so, I will gladly either link it from here and the modrinth page,
or based on preferences add the person(s) to the project
### What Shapes are planed to be added
Currently, the list of shapes to be added is pretty simple as the mod is still under development:
- Wall
- Fence
- Pane
- Button
- Pressure Plate
- Trapdoor
- Door
- Carpet
- Post
- Half Slab (maybe redundant with Layer)
- Slabs Stair (a stair with one end being of a second theme, might be done in multiple blocks)
Any Ideas feel free to make a suggestion [here](https://github.com/DriHut/ReFramed/issues).
## License
This work is dual-licensed under MIT and LGPL 3.0 both applying to different part of this project:
- The LGPL 3.0 license applies to all the textures that can be found in [`assets/reframed/textures`](src/main/resources/assets/reframed/textures)
- The MIT license applied to everything else so including all the code present within this project
`SPDX-License-Identifier: MIT AND LGPL-3.0`

View File

@@ -110,11 +110,15 @@ dependencies {
modCompileOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}"
modRuntimeOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}"
// Continuity for connectedTextures
modCompileOnly "maven.modrinth:continuity:${project.continuity_version}"
modRuntimeOnly "maven.modrinth:continuity:${project.continuity_version}"
// Chipped to test athena implementation
modRuntimeOnly "com.teamresourceful.resourcefullib:resourcefullib-fabric-${project.minecraft_version}:2.4.7"
modRuntimeOnly "earth.terrarium.chipped:Chipped-fabric-${project.minecraft_version}:3.1.2"
// Fabric API. This is technically optional, but you probably want it anyway.
// Fabric API.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
}
@@ -126,6 +130,7 @@ processResources {
inputs.property "athena_version", project.athena_version
inputs.property "indium_version", project.indium_version
inputs.property "sodium_version", project.sodium_version
inputs.property "continuity_version", project.continuity_version
filteringCharset "UTF-8"
filesMatching("fabric.mod.json") {
@@ -205,6 +210,7 @@ modrinth {
required.project "fabric-api"
optional.version "b1ZV3DIJ", "${project.athena_version}"
optional.version "Orvt0mRa", "${project.indium_version}+mc${project.minecraft_version}"
optional.version "1IjD5062", "${project.continuity_version}"
}
}

View File

@@ -9,7 +9,7 @@ loader_version=0.15.6
# Mod Properties
modrinth_id = jCpoCBpn
mod_version = 1.5
mod_version = 1.5.7
maven_group = fr.adrien1106
archives_base_name = ReFramed
mod_id = reframed
@@ -24,3 +24,4 @@ git_repo=ReFramed
athena_version=3.3.0
sodium_version=0.5.8
indium_version=1.0.30
continuity_version=3.0.0-beta.4+1.20.2

View File

@@ -1,6 +1,10 @@
package fr.adrien1106.reframed;
import fr.adrien1106.reframed.block.*;
import fr.adrien1106.reframed.item.ReFramedHammerItem;
import fr.adrien1106.reframed.item.ReFramedBlueprintItem;
import fr.adrien1106.reframed.item.ReFramedBlueprintWrittenItem;
import fr.adrien1106.reframed.item.ReFramedScrewdriverItem;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
@@ -8,10 +12,7 @@ import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.item.*;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.sound.BlockSoundGroup;
@@ -22,23 +23,26 @@ import net.minecraft.world.World;
import java.util.ArrayList;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT;
/**
* TODO make block pairable by right click -> for v1.6
* TODO add Hammer from framed ( removes theme ) -> for v1.5.5
* TODO add screwdriver ( iterate over theme states ) ?
* TODO add blueprint for survival friendly copy paste of a theme. -> for v1.5.5
* TODO add minecraft models like wall fence etc -> for v1.6
* TODO better connected textures -> maybe v1.6 ?
* TODO Dynamic Ambient Occlusion -> for v1.6
* TODO add minecraft models like wall fence etc -> for v1.6
* TODO better connected textures -> maybe v1.6 ?
* TODO support continuity overlays -> not scheduled
* TODO better state caching per models (e.g. wall only has 3 max per model) -> not scheduled
*/
public class ReFramed implements ModInitializer {
public static final String MODID = "reframed";
public static final ArrayList<Block> BLOCKS = new ArrayList<>();
public static Block CUBE, SMALL_CUBE, SMALL_CUBES_STEP, STAIR, HALF_STAIR, STAIRS_CUBE, HALF_STAIRS_SLAB, HALF_STAIRS_STAIR, SLAB, SLABS_CUBE, STEP, STEPS_SLAB, LAYER;
public static Block CUBE, SMALL_CUBE, SMALL_CUBES_STEP, STAIR, HALF_STAIR, STAIRS_CUBE, HALF_STAIRS_SLAB, HALF_STAIRS_STAIR, SLAB, SLABS_CUBE, STEP, STEPS_SLAB, LAYER, PILLAR, WALL;
public static final ArrayList<Item> ITEMS = new ArrayList<>();
public static Item HAMMER, SCREWDRIVER, BLUEPRINT, BLUEPRINT_WRITTEN;
public static ItemGroup ITEM_GROUP;
public static BlockEntityType<ReFramedEntity> REFRAMED_BLOCK_ENTITY;
@@ -48,19 +52,26 @@ public class ReFramed implements ModInitializer {
@Override
public void onInitialize() {
CUBE = registerReFramed("cube" , new ReFramedBlock(cp(Blocks.OAK_PLANKS)));
SMALL_CUBE = registerReFramed("small_cube" , new ReFramedSmallCubeBlock(cp(Blocks.OAK_PLANKS)));
SMALL_CUBES_STEP = registerReFramed("small_cubes_step" , new ReFramedSmallCubesStepBlock(cp(Blocks.OAK_PLANKS)));
STAIR = registerReFramed("stair" , new ReFramedStairBlock(cp(Blocks.OAK_STAIRS)));
STAIRS_CUBE = registerReFramed("stairs_cube" , new ReFramedStairsCubeBlock(cp(Blocks.OAK_STAIRS)));
HALF_STAIR = registerReFramed("half_stair" , new ReFramedHalfStairBlock(cp(Blocks.OAK_STAIRS)));
HALF_STAIRS_SLAB = registerReFramed("half_stairs_slab" , new ReFramedHalfStairsSlabBlock(cp(Blocks.OAK_STAIRS)));
HALF_STAIRS_STAIR = registerReFramed("half_stairs_stair" , new ReFramedHalfStairsStairBlock(cp(Blocks.OAK_STAIRS)));
LAYER = registerReFramed("layer" , new ReFramedLayerBlock(cp(Blocks.OAK_SLAB)));
SLAB = registerReFramed("slab" , new ReFramedSlabBlock(cp(Blocks.OAK_SLAB)));
SLABS_CUBE = registerReFramed("slabs_cube" , new ReFramedSlabsCubeBlock(cp(Blocks.OAK_SLAB)));
STEP = registerReFramed("step" , new ReFramedStepBlock(cp(Blocks.OAK_SLAB)));
STEPS_SLAB = registerReFramed("steps_slab" , new ReFramedStepsSlabBlock(cp(Blocks.OAK_SLAB)));
CUBE = registerBlock("cube" , new ReFramedBlock(cp(Blocks.OAK_PLANKS)));
SMALL_CUBE = registerBlock("small_cube" , new ReFramedSmallCubeBlock(cp(Blocks.OAK_PLANKS)));
SMALL_CUBES_STEP = registerBlock("small_cubes_step" , new ReFramedSmallCubesStepBlock(cp(Blocks.OAK_PLANKS)));
STAIR = registerBlock("stair" , new ReFramedStairBlock(cp(Blocks.OAK_STAIRS)));
STAIRS_CUBE = registerBlock("stairs_cube" , new ReFramedStairsCubeBlock(cp(Blocks.OAK_STAIRS)));
HALF_STAIR = registerBlock("half_stair" , new ReFramedHalfStairBlock(cp(Blocks.OAK_STAIRS)));
HALF_STAIRS_SLAB = registerBlock("half_stairs_slab" , new ReFramedHalfStairsSlabBlock(cp(Blocks.OAK_STAIRS)));
HALF_STAIRS_STAIR = registerBlock("half_stairs_stair" , new ReFramedHalfStairsStairBlock(cp(Blocks.OAK_STAIRS)));
LAYER = registerBlock("layer" , new ReFramedLayerBlock(cp(Blocks.OAK_SLAB)));
SLAB = registerBlock("slab" , new ReFramedSlabBlock(cp(Blocks.OAK_SLAB)));
SLABS_CUBE = registerBlock("slabs_cube" , new ReFramedSlabsCubeBlock(cp(Blocks.OAK_SLAB)));
STEP = registerBlock("step" , new ReFramedStepBlock(cp(Blocks.OAK_SLAB)));
STEPS_SLAB = registerBlock("steps_slab" , new ReFramedStepsSlabBlock(cp(Blocks.OAK_SLAB)));
PILLAR = registerBlock("pillar" , new ReFramedPillarBlock(cp(Blocks.OAK_FENCE)));
WALL = registerBlock("wall" , new ReframedWallBlock(cp(Blocks.OAK_FENCE)));
HAMMER = registerItem("hammer" , new ReFramedHammerItem(new Item.Settings().maxCount(1)));
SCREWDRIVER = registerItem("screwdriver" , new ReFramedScrewdriverItem(new Item.Settings().maxCount(1)));
BLUEPRINT = registerItem("blueprint" , new ReFramedBlueprintItem(new Item.Settings()));
BLUEPRINT_WRITTEN = registerItem("blueprint_written" , new ReFramedBlueprintWrittenItem(new Item.Settings().maxCount(1)));
REFRAMED_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, id("camo"),
FabricBlockEntityTypeBuilder.create(
@@ -81,7 +92,12 @@ public class ReFramed implements ModInitializer {
ITEM_GROUP = Registry.register(Registries.ITEM_GROUP, id("tab"), FabricItemGroup.builder()
.displayName(Text.translatable("itemGroup.reframed.tab"))
.icon(() -> new ItemStack(SLAB))
.entries((ctx, e) -> e.addAll(BLOCKS.stream().map(ItemStack::new).collect(Collectors.toList()))).build()
.entries((ctx, e) -> e.addAll(
Stream.concat(
ITEMS.stream().filter(item -> item != BLUEPRINT_WRITTEN),
BLOCKS.stream().map(Block::asItem)
).map(Item::getDefaultStack).toList())
).build()
);
}
@@ -94,8 +110,15 @@ public class ReFramed implements ModInitializer {
.suffocates((a,b,c) -> false)
.blockVision((a,b,c) -> false);
}
private static <I extends Item> I registerItem(String path, I item) {
Identifier id = id(path);
Registry.register(Registries.ITEM, id, item);
ITEMS.add(item);
return item;
}
private static <B extends Block> B registerReFramed(String path, B block) {
private static <B extends Block> B registerBlock(String path, B block) {
Identifier id = id(path);
Registry.register(Registries.BLOCK, id, block);

View File

@@ -1,13 +1,9 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.RecipeSetter;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.*;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem;
@@ -15,7 +11,8 @@ import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.nbt.NbtHelper;
import net.minecraft.registry.Registries;
import net.minecraft.state.StateManager;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
@@ -31,11 +28,15 @@ import net.minecraft.world.GameRules;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import static fr.adrien1106.reframed.block.ReFramedEntity.BLOCKSTATE_KEY;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT;
public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeSetter {
public class ReFramedBlock extends Block implements BlockEntityProvider {
public ReFramedBlock(Settings settings) {
super(settings);
@@ -97,7 +98,7 @@ public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeS
@Override
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
if(!state.isOf(newState.getBlock()) &&
if(!(newState.getBlock() instanceof ReFramedBlock) &&
world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity &&
world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS)
) {
@@ -122,14 +123,52 @@ public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeS
}
super.onStateReplaced(state, world, pos, newState, moved);
}
@Override
public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) {
if(world.isClient && world.getBlockEntity(pos) instanceof ReFramedEntity be) {
NbtCompound tag = BlockItem.getBlockEntityNbt(stack);
if(tag != null) be.readNbt(tag);
public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack, BlockState old_state, BlockEntity old_entity) {
if (!(world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity)) {
onPlaced(world, pos, state, placer, stack);
return;
}
super.onPlaced(world, pos, state, placer, stack);
// apply state change keeping the old information
if (old_state.getBlock() instanceof ReFramedBlock old_frame_block
&& old_entity instanceof ReFramedEntity old_frame_entity) {
Map<Integer, Integer> theme_map = old_frame_block.getThemeMap(old_state, state);
theme_map.forEach((self, other) ->
frame_entity.setTheme(old_frame_entity.getTheme(self), other)
);
// apply any changes needed to keep previous properties
if (old_frame_entity.emitsLight() && !frame_entity.emitsLight()) {
frame_entity.toggleLight();
world.setBlockState(pos, state.with(LIGHT, true));
}
if (old_frame_entity.emitsRedstone() && !frame_entity.emitsRedstone()) {
frame_entity.toggleRedstone();
world.updateNeighbors(pos, this);
}
if (old_frame_entity.isSolid() && !frame_entity.isSolid()) frame_entity.toggleSolidity();
// apply themes from item
NbtCompound tag = BlockItem.getBlockEntityNbt(stack);
if(tag != null) {
// determine a list of themes than can be used
Iterator<Integer> free_themes = IntStream
.rangeClosed(1, frame_entity.getThemes().size())
.filter(value -> !theme_map.containsValue(value))
.iterator();
// apply all the themes possible from item
for (int i = 1; tag.contains(BLOCKSTATE_KEY + i) && free_themes.hasNext(); i++) {
BlockState theme = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), tag.getCompound(BLOCKSTATE_KEY + i));
if (theme == null || theme.getBlock() == Blocks.AIR) continue;
frame_entity.setTheme(theme, free_themes.next());
}
}
} else if(world.isClient) { // prevents flashing with default texture before server sends the update
NbtCompound tag = BlockItem.getBlockEntityNbt(stack);
if(tag != null) frame_entity.readNbt(tag);
}
onPlaced(world, pos, state, placer, stack);
}
@Override
@@ -165,21 +204,20 @@ public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeS
return getWeakRedstonePower(state, view, pos, dir);
}
/**
* @param state - the block state to get the top theme index from
* @return the index of the top theme to use for the block
*/
public int getTopThemeIndex(BlockState state) {
return 1;
}
@Override
public void setRecipe(RecipeExporter exporter) {
ShapedRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, this)
.pattern("III")
.pattern("I~I")
.pattern("III")
.input('I', Items.BAMBOO)
.input('~', Items.STRING)
.criterion(FabricRecipeProvider.hasItem(Items.BAMBOO), FabricRecipeProvider.conditionsFromItem(Items.BAMBOO))
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
.offerTo(exporter);
/**
* @param state - the block state of the block that is being replaced
* @param new_state - the block state of the block that is replacing the block
* @return a map of the theme indexes to map when changing state so that the themes are preserved
*/
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
return Map.of();
}
}

View File

@@ -31,8 +31,11 @@ public abstract class ReFramedDoubleBlock extends ReFramedBlock {
return ReFramed.REFRAMED_DOUBLE_BLOCK_ENTITY.instantiate(pos, state);
}
protected int getHitShape(BlockState state, BlockHitResult hit) {
Direction side = hit.getSide();
public int getHitShape(BlockState state, BlockHitResult hit) {
return getHitShape(state, hit.getPos(), hit.getBlockPos(), hit.getSide());
}
public int getHitShape(BlockState state, Vec3d hit, BlockPos pos, Direction side) {
VoxelShape first_shape = getShape(state, 1);
VoxelShape second_shape = getShape(state, 2);
@@ -40,13 +43,20 @@ public abstract class ReFramedDoubleBlock extends ReFramedBlock {
if (isFaceFullSquare(first_shape, side)) return 1;
if (isFaceFullSquare(second_shape, side)) return 2;
Vec3d pos = BlockHelper.getRelativePos(hit.getPos(), hit.getBlockPos());
// System.out.println(side.getAxis().choose(hit.getPos().x, hit.getPos().y, hit.getPos().z));
if (BlockHelper.cursorMatchesFace(first_shape, pos)) return 1;
if (BlockHelper.cursorMatchesFace(second_shape, pos)) return 2;
Vec3d rel = BlockHelper.getRelativePos(hit, pos);
if (BlockHelper.cursorMatchesFace(first_shape, rel)) return 1;
if (BlockHelper.cursorMatchesFace(second_shape, rel)) return 2;
return 0;
}
public boolean matchesShape(Vec3d hit, BlockPos pos, BlockState state, int i) {
Vec3d rel = BlockHelper.getRelativePos(hit, pos);
return BlockHelper.cursorMatchesFace(
getShape(state, i),
rel
);
}
@Override
public boolean isTransparent(BlockState state, BlockView world, BlockPos pos) {
return world.getBlockEntity(pos) instanceof ThemeableBlockEntity framed_entity

View File

@@ -1,38 +1,31 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.util.VoxelHelper;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.util.blocks.Corner;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.state.StateManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.function.BooleanBiFunction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import org.jetbrains.annotations.Nullable;
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER_FACE;
import static fr.adrien1106.reframed.util.blocks.Corner.*;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
import java.util.Map;
public class ReFramedHalfStairBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.*;
import static fr.adrien1106.reframed.util.blocks.Corner.*;
import static net.minecraft.state.property.Properties.WATERLOGGED;
public class ReFramedHalfStairBlock extends WaterloggableReFramedBlock {
public static final VoxelShape[] HALF_STAIR_VOXELS;
@@ -58,8 +51,57 @@ public class ReFramedHalfStairBlock extends WaterloggableReFramedBlock implement
super.appendProperties(builder.add(CORNER,CORNER_FACE));
}
@Override
public boolean canReplace(BlockState state, ItemPlacementContext context) {
Direction dir = state.get(CORNER).getDirection(state.get(CORNER_FACE));
return !(
context.getPlayer().isSneaking()
|| !(context.getStack().getItem() instanceof BlockItem block_item)
|| (
!(
block_item.getBlock() == this
&& ((ReFramedHalfStairsStairBlock) ReFramed.HALF_STAIRS_STAIR)
.matchesShape(
context.getHitPos(),
context.getBlockPos(),
ReFramed.HALF_STAIRS_STAIR.getDefaultState()
.with(EDGE, state.get(CORNER).getEdge(dir)),
dir.getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
)
)
&& !(
block_item.getBlock() == ReFramed.SMALL_CUBE
&& BlockHelper.cursorMatchesFace(
ReFramed.SMALL_CUBE.getOutlineShape(
ReFramed.SMALL_CUBE.getDefaultState()
.with(CORNER, state.get(CORNER).getOpposite(state.get(CORNER_FACE))),
context.getWorld(),
context.getBlockPos(),
ShapeContext.absent()
),
BlockHelper.getRelativePos(context.getHitPos(), context.getBlockPos())
)
)
)
);
}
@Override
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
BlockState current_state = ctx.getWorld().getBlockState(ctx.getBlockPos());
if (current_state.isOf(ReFramed.SMALL_CUBE)) {
Corner corner = current_state.get(CORNER).getOpposite(ctx.getSide().getOpposite());
return ReFramed.HALF_STAIRS_SLAB.getDefaultState()
.with(CORNER, corner)
.with(CORNER_FACE, corner.getDirectionIndex(ctx.getSide().getOpposite()))
.with(WATERLOGGED, current_state.get(WATERLOGGED));
}
if (current_state.isOf(this))
return ReFramed.HALF_STAIRS_STAIR.getDefaultState()
.with(EDGE, current_state.get(CORNER).getEdge(current_state.get(CORNER).getDirection(current_state.get(CORNER_FACE))))
.with(WATERLOGGED, current_state.get(WATERLOGGED));
Corner corner = BlockHelper.getPlacementCorner(ctx);
return super.getPlacementState(ctx)
.with(CORNER, corner)
@@ -72,84 +114,16 @@ public class ReFramedHalfStairBlock extends WaterloggableReFramedBlock implement
}
@Override
public BlockStateSupplier getMultipart() {
return getHalfStairMultipart(
this,
ReFramed.id("half_stair_down_special"),
ReFramed.id("half_stair_side_special")
);
}
public static BlockStateSupplier getHalfStairMultipart(Block block, Identifier model_down, Identifier model_side) {
return MultipartBlockStateSupplier.create(block)
.with(GBlockstate.when(CORNER, NORTH_EAST_DOWN, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R0, R0))
.with(GBlockstate.when(CORNER, NORTH_EAST_DOWN, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R90, R270))
.with(GBlockstate.when(CORNER, NORTH_EAST_DOWN, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R0, R0))
.with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R0, R90))
.with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R90, R0))
.with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R0, R90))
.with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R0, R180))
.with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R90, R90))
.with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R0, R180))
.with(GBlockstate.when(CORNER, WEST_NORTH_DOWN, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R0, R270))
.with(GBlockstate.when(CORNER, WEST_NORTH_DOWN, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R90, R180))
.with(GBlockstate.when(CORNER, WEST_NORTH_DOWN, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R0, R270))
.with(GBlockstate.when(CORNER, EAST_SOUTH_UP, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R180, R0))
.with(GBlockstate.when(CORNER, EAST_SOUTH_UP, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R270, R90))
.with(GBlockstate.when(CORNER, EAST_SOUTH_UP, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R180, R0))
.with(GBlockstate.when(CORNER, SOUTH_WEST_UP, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R180, R90))
.with(GBlockstate.when(CORNER, SOUTH_WEST_UP, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R270, R180))
.with(GBlockstate.when(CORNER, SOUTH_WEST_UP, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R180, R90))
.with(GBlockstate.when(CORNER, WEST_NORTH_UP, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R180, R180))
.with(GBlockstate.when(CORNER, WEST_NORTH_UP, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R270, R270))
.with(GBlockstate.when(CORNER, WEST_NORTH_UP, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R180, R180))
.with(GBlockstate.when(CORNER, NORTH_EAST_UP, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R180, R270))
.with(GBlockstate.when(CORNER, NORTH_EAST_UP, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R270, R0))
.with(GBlockstate.when(CORNER, NORTH_EAST_UP, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R180, R270));
}
@Override
public void setRecipe(RecipeExporter exporter) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 2);
ShapedRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, this, 4)
.pattern("I ")
.pattern("II ")
.input('I', ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
.offerTo(exporter);
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
if (new_state.isOf(ReFramed.HALF_STAIRS_SLAB)) return Map.of(1, 1);
if (new_state.isOf(ReFramed.HALF_STAIRS_STAIR))
return Map.of(
1,
state.get(CORNER)
.getDirection(state.get(CORNER_FACE))
.getDirection() == Direction.AxisDirection.POSITIVE ? 2 : 1
);
return super.getThemeMap(state, new_state);
}
static {

View File

@@ -1,19 +1,11 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.util.blocks.Corner;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.state.StateManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.shape.VoxelShape;
@@ -21,7 +13,6 @@ import net.minecraft.world.BlockView;
import org.jetbrains.annotations.Nullable;
import static fr.adrien1106.reframed.block.ReFramedHalfStairBlock.HALF_STAIR_VOXELS;
import static fr.adrien1106.reframed.block.ReFramedHalfStairBlock.getHalfStairMultipart;
import static fr.adrien1106.reframed.block.ReFramedSlabBlock.getSlabShape;
import static fr.adrien1106.reframed.block.ReFramedSmallCubeBlock.SMALL_CUBE_VOXELS;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER;
@@ -29,7 +20,7 @@ import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER_FACE;
import static fr.adrien1106.reframed.util.blocks.Corner.NORTH_EAST_DOWN;
import static net.minecraft.util.shape.VoxelShapes.empty;
public class ReFramedHalfStairsSlabBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider {
public class ReFramedHalfStairsSlabBlock extends WaterloggableReFramedDoubleBlock {
private record ModelCacheKey(Corner corner, int face) {}
@@ -79,25 +70,4 @@ public class ReFramedHalfStairsSlabBlock extends WaterloggableReFramedDoubleBloc
? SMALL_CUBE_VOXELS[corner.getOpposite(face).getID()]
: HALF_STAIR_VOXELS[face + corner.getID() * 3];
}
@Override
public BlockStateSupplier getMultipart() {
return getHalfStairMultipart(
this,
ReFramed.id("half_stairs_slab_down_special"),
ReFramed.id("half_stairs_slab_side_special")
);
}
@Override
public void setRecipe(RecipeExporter exporter) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 2);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, this)
.input(ReFramed.HALF_STAIR)
.input(ReFramed.SMALL_CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
.offerTo(exporter);
}
}

View File

@@ -1,25 +1,14 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.util.blocks.Corner;
import fr.adrien1106.reframed.util.blocks.Edge;
import fr.adrien1106.reframed.util.blocks.StairShape;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.state.StateManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape;
@@ -30,10 +19,9 @@ import static fr.adrien1106.reframed.block.ReFramedHalfStairBlock.HALF_STAIR_VOX
import static fr.adrien1106.reframed.block.ReFramedStairBlock.getStairShape;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
import static fr.adrien1106.reframed.util.blocks.Edge.*;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
import static net.minecraft.util.shape.VoxelShapes.empty;
public class ReFramedHalfStairsStairBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider {
public class ReFramedHalfStairsStairBlock extends WaterloggableReFramedDoubleBlock {
public ReFramedHalfStairsStairBlock(Settings settings) {
super(settings);
setDefaultState(getDefaultState().with(EDGE, NORTH_DOWN));
@@ -89,50 +77,4 @@ public class ReFramedHalfStairsStairBlock extends WaterloggableReFramedDoubleBlo
public int getTopThemeIndex(BlockState state) {
return 2;
}
@Override
public BlockStateSupplier getMultipart() {
Identifier model_id = ReFramed.id("half_stairs_stair_down_special");
Identifier side_model_id = ReFramed.id("half_stairs_stair_side_special");
Identifier reverse_model_id = ReFramed.id("half_stairs_stair_reverse_special");
return MultipartBlockStateSupplier.create(this)
/* X AXIS */
.with(GBlockstate.when(EDGE, NORTH_DOWN),
GBlockstate.variant(side_model_id, true, R90, R180))
.with(GBlockstate.when(EDGE, DOWN_SOUTH),
GBlockstate.variant(side_model_id, true, R0, R180))
.with(GBlockstate.when(EDGE, SOUTH_UP),
GBlockstate.variant(side_model_id, true, R270, R180))
.with(GBlockstate.when(EDGE, UP_NORTH),
GBlockstate.variant(side_model_id, true, R180, R180))
/* Y AXIS */
.with(GBlockstate.when(EDGE, NORTH_EAST),
GBlockstate.variant(model_id, true, R0, R0))
.with(GBlockstate.when(EDGE, EAST_SOUTH),
GBlockstate.variant(model_id, true, R0, R90))
.with(GBlockstate.when(EDGE, SOUTH_WEST),
GBlockstate.variant(model_id, true, R0, R180))
.with(GBlockstate.when(EDGE, WEST_NORTH),
GBlockstate.variant(model_id, true, R0, R270))
/* Z AXIS */
.with(GBlockstate.when(EDGE, DOWN_EAST),
GBlockstate.variant(side_model_id, true, R0, R90))
.with(GBlockstate.when(EDGE, EAST_UP),
GBlockstate.variant(reverse_model_id, true, R180, R270))
.with(GBlockstate.when(EDGE, UP_WEST),
GBlockstate.variant(side_model_id, true, R180, R90))
.with(GBlockstate.when(EDGE, WEST_DOWN),
GBlockstate.variant(reverse_model_id, true, R0, R270));
}
@Override
public void setRecipe(RecipeExporter exporter) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 2);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, this)
.input(ReFramed.HALF_STAIR, 2)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
.offerTo(exporter);
}
}

View File

@@ -1,15 +1,12 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.util.VoxelHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.state.StateManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape;
@@ -17,7 +14,6 @@ import net.minecraft.world.BlockView;
import org.jetbrains.annotations.Nullable;
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
import static net.minecraft.state.property.Properties.FACING;
import static net.minecraft.state.property.Properties.LAYERS;
@@ -52,8 +48,12 @@ public class ReFramedLayerBlock extends ReFramedSlabBlock {
}
@Override
public boolean canReplace(BlockState state, ItemPlacementContext ctx) {
return !(!state.isOf(this) || ctx.getPlayer().isSneaking() || state.get(LAYERS) == 8);
public boolean canReplace(BlockState state, ItemPlacementContext context) {
return !(
context.getPlayer().isSneaking()
|| !(context.getStack().getItem() instanceof BlockItem block_item)
|| !(block_item.getBlock() == this && state.get(LAYERS) < 8)
);
}
@Override
@@ -63,29 +63,6 @@ public class ReFramedLayerBlock extends ReFramedSlabBlock {
return previous.with(LAYERS, previous.get(LAYERS) + 1);
}
@Override
public MultipartBlockStateSupplier getMultipart() {
String model_pattern = "layer_x_special";
MultipartBlockStateSupplier supplier = MultipartBlockStateSupplier.create(this);
for (int i = 1; i <= 8; i++) {
Identifier model = ReFramed.id(model_pattern.replace("x", i + ""));
supplier
.with(GBlockstate.when(FACING, Direction.DOWN, LAYERS, i),
GBlockstate.variant(model, true, R0, R0))
.with(GBlockstate.when(FACING, Direction.SOUTH, LAYERS, i),
GBlockstate.variant(model, true, R90, R0))
.with(GBlockstate.when(FACING, Direction.UP, LAYERS, i),
GBlockstate.variant(model, true, R180, R0))
.with(GBlockstate.when(FACING, Direction.NORTH, LAYERS, i),
GBlockstate.variant(model, true, R270, R0))
.with(GBlockstate.when(FACING, Direction.WEST, LAYERS, i),
GBlockstate.variant(model, true, R90, R90))
.with(GBlockstate.when(FACING, Direction.EAST, LAYERS, i),
GBlockstate.variant(model, true, R90, R270));
}
return supplier;
}
static {
VoxelListBuilder builder = VoxelListBuilder.create(createCuboidShape(0, 0, 0, 16, 2, 16), 48)
.add(createCuboidShape(0, 0, 0, 16, 4, 16))

View File

@@ -0,0 +1,83 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.util.VoxelHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.state.StateManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.world.BlockView;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import static net.minecraft.state.property.Properties.AXIS;
public class ReFramedPillarBlock extends WaterloggableReFramedBlock {
public static final VoxelShape[] PILLAR_VOXELS;
public ReFramedPillarBlock(Settings settings) {
super(settings);
setDefaultState(getDefaultState().with(AXIS, Direction.Axis.Y));
}
@Override
public Object getModelCacheKey(BlockState state) {
return state.get(AXIS);
}
@Override
public int getModelStateCount() {
return 3;
}
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
super.appendProperties(builder.add(AXIS));
}
@Override
public boolean canReplace(BlockState state, ItemPlacementContext context) {
return !(context.getPlayer().isSneaking()
|| !(context.getStack().getItem() instanceof BlockItem block_item)
|| !(
block_item.getBlock() == this
&& state.get(AXIS) != context.getSide().getAxis()
)
);
}
@Override
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
// TODO: PILLARS WALL
return super.getPlacementState(ctx).with(AXIS, ctx.getSide().getAxis());
}
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
return getPillarShape(state.get(AXIS));
}
public static VoxelShape getPillarShape(Direction.Axis axis) {
return PILLAR_VOXELS[axis.ordinal()];
}
@Override
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
// if (new_state.getBlock() == ReFramed.PILLARS_WALL) return Map.of(1, 1); // TODO: PILLARS WALL
return super.getThemeMap(state, new_state);
}
static {
final VoxelShape PILLAR = createCuboidShape(0, 4, 4, 16, 12, 12);
PILLAR_VOXELS = VoxelHelper.VoxelListBuilder.create(PILLAR, 3)
.add(VoxelHelper::rotateZ)
.add(VoxelHelper::rotateX)
.build();
}
}

View File

@@ -1,20 +1,12 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.state.StateManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape;
@@ -22,10 +14,12 @@ import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import org.jetbrains.annotations.Nullable;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
import java.util.Map;
import static net.minecraft.state.property.Properties.AXIS;
import static net.minecraft.state.property.Properties.FACING;
public class ReFramedSlabBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
public class ReFramedSlabBlock extends WaterloggableReFramedBlock {
protected static final VoxelShape DOWN = VoxelShapes.cuboid(0f, 0f, 0f, 1f, 0.5f, 1f);
protected static final VoxelShape UP = VoxelShapes.cuboid(0f, 0.5f, 0f, 1f, 1f, 1f);
@@ -53,10 +47,33 @@ public class ReFramedSlabBlock extends WaterloggableReFramedBlock implements Blo
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
super.appendProperties(builder.add(FACING));
}
@Override
public boolean canReplace(BlockState state, ItemPlacementContext context) {
return !(
context.getPlayer().isSneaking()
|| !(context.getStack().getItem() instanceof BlockItem block_item)
|| !(
block_item.getBlock() == this
&& ((ReFramedSlabsCubeBlock) ReFramed.SLABS_CUBE)
.matchesShape(
context.getHitPos(),
context.getBlockPos(),
ReFramed.SLABS_CUBE.getDefaultState().with(AXIS, state.get(FACING).getAxis()),
state.get(FACING).getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
)
)
);
}
@Nullable
@Override
public BlockState getPlacementState(ItemPlacementContext ctx) {
BlockState current_state = ctx.getWorld().getBlockState(ctx.getBlockPos());
if (current_state.isOf(this))
return ReFramed.SLABS_CUBE.getDefaultState()
.with(AXIS, current_state.get(FACING).getAxis());
return super.getPlacementState(ctx).with(FACING, ctx.getSide().getOpposite());
}
@@ -77,32 +94,8 @@ public class ReFramedSlabBlock extends WaterloggableReFramedBlock implements Blo
}
@Override
public MultipartBlockStateSupplier getMultipart() {
Identifier model_id = ReFramed.id("slab_special");
return MultipartBlockStateSupplier.create(this)
.with(GBlockstate.when(FACING, Direction.DOWN),
GBlockstate.variant(model_id, true, R0, R0))
.with(GBlockstate.when(FACING, Direction.SOUTH),
GBlockstate.variant(model_id, true, R90, R0))
.with(GBlockstate.when(FACING, Direction.UP),
GBlockstate.variant(model_id, true, R180, R0))
.with(GBlockstate.when(FACING, Direction.NORTH),
GBlockstate.variant(model_id, true, R270, R0))
.with(GBlockstate.when(FACING, Direction.WEST),
GBlockstate.variant(model_id, true, R90, R90))
.with(GBlockstate.when(FACING, Direction.EAST),
GBlockstate.variant(model_id, true, R90, R270));
}
@Override
public void setRecipe(RecipeExporter exporter) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 2);
ShapedRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, this, 6)
.pattern("III")
.input('I', ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
.offerTo(exporter);
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
if (new_state.isOf(ReFramed.SLABS_CUBE)) return Map.of(1, state.get(FACING).getDirection() == Direction.AxisDirection.POSITIVE ? 2 : 1);
return super.getThemeMap(state, new_state);
}
}

View File

@@ -1,29 +1,17 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.state.StateManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape;
import org.jetbrains.annotations.Nullable;
import static fr.adrien1106.reframed.block.ReFramedSlabBlock.*;
import static net.minecraft.data.client.VariantSettings.Rotation.R0;
import static net.minecraft.data.client.VariantSettings.Rotation.R90;
import static net.minecraft.state.property.Properties.AXIS;
public class ReFramedSlabsCubeBlock extends ReFramedDoubleBlock implements BlockStateProvider {
public class ReFramedSlabsCubeBlock extends ReFramedDoubleBlock {
public ReFramedSlabsCubeBlock(Settings settings) {
super(settings);
@@ -55,37 +43,13 @@ public class ReFramedSlabsCubeBlock extends ReFramedDoubleBlock implements Block
public VoxelShape getShape(BlockState state, int i) {
return switch (state.get(AXIS)) {
case Y -> i == 2 ? UP : DOWN;
case Z -> i == 2 ? NORTH : SOUTH;
case Z -> i == 2 ? SOUTH : NORTH;
case X -> i == 2 ? EAST : WEST;
};
}
@Override
public int getTopThemeIndex(BlockState state) {
// when the side is shared just return one
return state.get(AXIS) == Direction.Axis.Y ? 2: super.getTopThemeIndex(state);
}
@Override
public MultipartBlockStateSupplier getMultipart() {
Identifier model_id = ReFramed.id("double_slab_special");
return MultipartBlockStateSupplier.create(this)
.with(GBlockstate.when(AXIS, Direction.Axis.Y),
GBlockstate.variant(model_id, true, R0, R0))
.with(GBlockstate.when(AXIS, Direction.Axis.Z),
GBlockstate.variant(model_id, true, R90, R0))
.with(GBlockstate.when(AXIS, Direction.Axis.X),
GBlockstate.variant(model_id, true, R90, R90));
}
@Override
public void setRecipe(RecipeExporter exporter) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, this)
.input(ReFramed.SLAB, 2)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
.offerTo(exporter);
return 2;
}
}

View File

@@ -1,35 +1,31 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.util.VoxelHelper;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import fr.adrien1106.reframed.util.blocks.Corner;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.state.StateManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import org.jetbrains.annotations.Nullable;
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER;
import static fr.adrien1106.reframed.util.blocks.Corner.*;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
import java.util.Map;
public class ReFramedSmallCubeBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.*;
import static fr.adrien1106.reframed.util.blocks.Corner.*;
import static net.minecraft.state.property.Properties.WATERLOGGED;
public class ReFramedSmallCubeBlock extends WaterloggableReFramedBlock {
public static final VoxelShape[] SMALL_CUBE_VOXELS;
@@ -53,8 +49,84 @@ public class ReFramedSmallCubeBlock extends WaterloggableReFramedBlock implement
super.appendProperties(builder.add(CORNER));
}
@Override
public boolean canReplace(BlockState state, ItemPlacementContext context) {
Corner corner = state.get(CORNER);
return !(
context.getPlayer().isSneaking()
|| !(context.getStack().getItem() instanceof BlockItem block_item)
|| (
!(
block_item.getBlock() == ReFramed.HALF_STAIR
&& !(corner.hasDirection(context.getSide())
|| (corner.hasDirection(context.getSide().getOpposite())
&& BlockHelper.cursorMatchesFace(
getOutlineShape(state, context.getWorld(), context.getBlockPos(), null),
BlockHelper.getRelativePos(context.getHitPos(), context.getBlockPos())
)
)
)
)
&& !(
block_item.getBlock() == this
&& (
((ReFramedSmallCubesStepBlock) ReFramed.SMALL_CUBES_STEP)
.matchesShape(
context.getHitPos(),
context.getBlockPos(),
ReFramed.SMALL_CUBES_STEP.getDefaultState().with(EDGE, corner.getEdge(corner.getFirstDirection())),
corner.getFirstDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
)
|| ((ReFramedSmallCubesStepBlock) ReFramed.SMALL_CUBES_STEP)
.matchesShape(
context.getHitPos(),
context.getBlockPos(),
ReFramed.SMALL_CUBES_STEP.getDefaultState().with(EDGE, corner.getEdge(corner.getSecondDirection())),
corner.getSecondDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
)
|| ((ReFramedSmallCubesStepBlock) ReFramed.SMALL_CUBES_STEP)
.matchesShape(
context.getHitPos(),
context.getBlockPos(),
ReFramed.SMALL_CUBES_STEP.getDefaultState().with(EDGE, corner.getEdge(corner.getThirdDirection())),
corner.getThirdDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
)
)
)
)
);
}
@Override
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
BlockPos pos = ctx.getBlockPos();
BlockState current_state = ctx.getWorld().getBlockState(pos);
if (current_state.isOf(ReFramed.HALF_STAIR))
return ReFramed.HALF_STAIRS_SLAB.getDefaultState()
.with(CORNER, current_state.get(CORNER))
.with(CORNER_FACE, current_state.get(CORNER_FACE))
.with(WATERLOGGED, current_state.get(WATERLOGGED));
if (current_state.isOf(this)) {
Vec3d hit = ctx.getHitPos();
Corner corner = current_state.get(CORNER);
ReFramedSmallCubesStepBlock block = ((ReFramedSmallCubesStepBlock) ReFramed.SMALL_CUBES_STEP);
BlockState state = block.getDefaultState()
.with(EDGE, corner.getEdge(corner.getFirstDirection()))
.with(WATERLOGGED, current_state.get(WATERLOGGED));
if (block.matchesShape(
hit, pos, state,
corner.getFirstDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
)) return state;
state = state.with(EDGE, corner.getEdge(corner.getSecondDirection()));
if (block.matchesShape(
hit, pos, state,
corner.getSecondDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
)) return state;
return state.with(EDGE, corner.getEdge(corner.getThirdDirection()));
}
return super.getPlacementState(ctx).with(CORNER, BlockHelper.getPlacementCorner(ctx));
}
@@ -64,36 +136,16 @@ public class ReFramedSmallCubeBlock extends WaterloggableReFramedBlock implement
}
@Override
public BlockStateSupplier getMultipart() {
Identifier small_cube_id = ReFramed.id("small_cube_special");
return MultipartBlockStateSupplier.create(this)
.with(GBlockstate.when(CORNER, NORTH_EAST_DOWN),
GBlockstate.variant(small_cube_id, true, R0, R0))
.with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN),
GBlockstate.variant(small_cube_id, true, R0, R90))
.with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN),
GBlockstate.variant(small_cube_id, true, R0, R180))
.with(GBlockstate.when(CORNER, WEST_NORTH_DOWN),
GBlockstate.variant(small_cube_id, true, R0, R270))
.with(GBlockstate.when(CORNER, EAST_SOUTH_UP),
GBlockstate.variant(small_cube_id, true, R180, R0))
.with(GBlockstate.when(CORNER, SOUTH_WEST_UP),
GBlockstate.variant(small_cube_id, true, R180, R90))
.with(GBlockstate.when(CORNER, WEST_NORTH_UP),
GBlockstate.variant(small_cube_id, true, R180, R180))
.with(GBlockstate.when(CORNER, NORTH_EAST_UP),
GBlockstate.variant(small_cube_id, true, R180, R270));
}
@Override
public void setRecipe(RecipeExporter exporter) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 8);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, this, 8)
.input(ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
.offerTo(exporter);
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
if (new_state.isOf(ReFramed.HALF_STAIRS_SLAB)) return Map.of(1, 2);
if (new_state.isOf(ReFramed.SMALL_CUBES_STEP))
return Map.of(
1,
state.get(CORNER)
.getOtherDirection(new_state.get(EDGE))
.getDirection() == Direction.AxisDirection.POSITIVE ? 2 : 1
);
return super.getThemeMap(state, new_state);
}
static {

View File

@@ -1,24 +1,13 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.util.blocks.Corner;
import fr.adrien1106.reframed.util.blocks.Edge;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.state.StateManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.world.BlockView;
@@ -27,11 +16,9 @@ import org.jetbrains.annotations.Nullable;
import static fr.adrien1106.reframed.block.ReFramedSmallCubeBlock.SMALL_CUBE_VOXELS;
import static fr.adrien1106.reframed.block.ReFramedStepBlock.getStepShape;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
import static fr.adrien1106.reframed.util.blocks.Edge.*;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
import static net.minecraft.util.shape.VoxelShapes.empty;
public class ReFramedSmallCubesStepBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider {
public class ReFramedSmallCubesStepBlock extends WaterloggableReFramedDoubleBlock {
public ReFramedSmallCubesStepBlock(Settings settings) {
super(settings);
@@ -85,49 +72,4 @@ public class ReFramedSmallCubesStepBlock extends WaterloggableReFramedDoubleBloc
public int getTopThemeIndex(BlockState state) {
return 2;
}
@Override
public BlockStateSupplier getMultipart() {
Identifier model_id = ReFramed.id("small_cubes_step_special");
Identifier reverse_model_id = ReFramed.id("small_cubes_step_reverse_special");
return MultipartBlockStateSupplier.create(this)
/* X AXIS */
.with(GBlockstate.when(EDGE, DOWN_EAST),
GBlockstate.variant(reverse_model_id, true, R0, R0))
.with(GBlockstate.when(EDGE, EAST_UP),
GBlockstate.variant(model_id, true, R180, R0))
.with(GBlockstate.when(EDGE, UP_WEST),
GBlockstate.variant(reverse_model_id, true, R180, R180))
.with(GBlockstate.when(EDGE, WEST_DOWN),
GBlockstate.variant(model_id, true, R0, R180))
/* Y AXIS */
.with(GBlockstate.when(EDGE, EAST_SOUTH),
GBlockstate.variant(model_id, true, R90, R0))
.with(GBlockstate.when(EDGE, SOUTH_WEST),
GBlockstate.variant(model_id, true, R90, R90))
.with(GBlockstate.when(EDGE, WEST_NORTH),
GBlockstate.variant(model_id, true, R90, R180))
.with(GBlockstate.when(EDGE, NORTH_EAST),
GBlockstate.variant(model_id, true, R90, R270))
/* Z AXIS */
.with(GBlockstate.when(EDGE, DOWN_SOUTH),
GBlockstate.variant(reverse_model_id, true, R0, R90))
.with(GBlockstate.when(EDGE, NORTH_DOWN),
GBlockstate.variant(model_id, true, R0, R270))
.with(GBlockstate.when(EDGE, UP_NORTH),
GBlockstate.variant(reverse_model_id, true, R180, R270))
.with(GBlockstate.when(EDGE, SOUTH_UP),
GBlockstate.variant(model_id, true, R180, R90));
}
@Override
public void setRecipe(RecipeExporter exporter) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 4);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, this)
.input(ReFramed.SMALL_CUBE, 2)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
.offerTo(exporter);
}
}

View File

@@ -1,25 +1,16 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.util.VoxelHelper;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.util.blocks.Edge;
import fr.adrien1106.reframed.util.blocks.StairShape;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.client.When;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.state.StateManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.function.BooleanBiFunction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
@@ -30,16 +21,15 @@ import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.stream.Stream;
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.STAIR_SHAPE;
import static fr.adrien1106.reframed.util.blocks.Edge.*;
import static fr.adrien1106.reframed.util.blocks.StairShape.*;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
public class ReFramedStairBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
public class ReFramedStairBlock extends WaterloggableReFramedBlock {
public static final VoxelShape[] STAIR_VOXELS;
private record ModelCacheKey(Edge edge, StairShape shape) {}
@@ -63,6 +53,24 @@ public class ReFramedStairBlock extends WaterloggableReFramedBlock implements Bl
super.appendProperties(builder.add(EDGE, STAIR_SHAPE));
}
@Override
public boolean canReplace(BlockState state, ItemPlacementContext context) {
return !(
context.getPlayer().isSneaking()
|| !(context.getStack().getItem() instanceof BlockItem block_item)
|| !(
block_item.getBlock() == ReFramed.STEP
&& ((ReFramedStairsCubeBlock) ReFramed.STAIRS_CUBE)
.matchesShape(
context.getHitPos(),
context.getBlockPos(),
state,
2
)
)
);
}
@Override
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighbor_state, WorldAccess world, BlockPos pos, BlockPos moved) {
return super.getStateForNeighborUpdate(state, direction, neighbor_state, world, pos, moved)
@@ -70,11 +78,20 @@ public class ReFramedStairBlock extends WaterloggableReFramedBlock implements Bl
}
@Nullable
@Override // Pretty happy of how clean it is (also got it on first try :) )
@Override
public BlockState getPlacementState(ItemPlacementContext ctx) {
Edge face = BlockHelper.getPlacementEdge(ctx);
StairShape shape = BlockHelper.getStairsShape(face, ctx.getWorld(), ctx.getBlockPos());
return super.getPlacementState(ctx).with(EDGE, face).with(STAIR_SHAPE, shape);
BlockState current_state = ctx.getWorld().getBlockState(ctx.getBlockPos());
if (current_state.isOf(ReFramed.STEP)) {
Edge edge = current_state.get(EDGE).opposite();
StairShape shape = BlockHelper.getStairsShape(edge, ctx.getWorld(), ctx.getBlockPos());
return ReFramed.STAIRS_CUBE.getDefaultState()
.with(EDGE, edge)
.with(STAIR_SHAPE, shape);
}
Edge edge = BlockHelper.getPlacementEdge(ctx);
StairShape shape = BlockHelper.getStairsShape(edge, ctx.getWorld(), ctx.getBlockPos());
return super.getPlacementState(ctx).with(EDGE, edge).with(STAIR_SHAPE, shape);
}
@Override
@@ -94,245 +111,9 @@ public class ReFramedStairBlock extends WaterloggableReFramedBlock implements Bl
}
@Override
public MultipartBlockStateSupplier getMultipart() {
return getStairMultipart(this, false);
}
public static MultipartBlockStateSupplier getStairMultipart(Block block, boolean is_double) {
String infix = is_double ? "s_cube" : "";
Identifier straight_id = ReFramed.id("stair" + infix + "_special");
Identifier double_outer_id = ReFramed.id("outers_stair" + infix + "_special");
Identifier inner_id = ReFramed.id("inner_stair" + infix + "_special");
Identifier outer_id = ReFramed.id("outer_stair" + infix + "_special");
Identifier outer_side_id = ReFramed.id("outer_side_stair" + infix + "_special");
return MultipartBlockStateSupplier.create(block)
/* STRAIGHT X AXIS */
.with(GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R0, R0))
.with(GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R180, R0))
.with(GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R180, R180))
.with(GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R0, R180))
/* STRAIGHT Y AXIS */
.with(GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R90, R0))
.with(GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R90, R90))
.with(GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R90, R180))
.with(GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R90, R270))
/* STRAIGHT Z AXIS */
.with(GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R0, R90))
.with(GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R0, R270))
.with(GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R180, R270))
.with(GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R180, R90))
/* INNER BOTTOM */
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, INNER_LEFT)),
GBlockstate.variant(inner_id, true, R0, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, INNER_LEFT)),
GBlockstate.variant(inner_id, true, R0, R270))
.with(When.anyOf(
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, INNER_RIGHT)),
GBlockstate.variant(inner_id, true, R0, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, INNER_RIGHT)),
GBlockstate.variant(inner_id, true, R0, R90))
/* INNER TOP */
.with(When.anyOf(
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, INNER_LEFT)),
GBlockstate.variant(inner_id, true, R180, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, INNER_LEFT)),
GBlockstate.variant(inner_id, true, R180, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, INNER_RIGHT)),
GBlockstate.variant(inner_id, true, R180, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, INNER_LEFT)),
GBlockstate.variant(inner_id, true, R180, R270))
/* OUTER BOTTOM */
.with(When.anyOf(
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
GBlockstate.variant(outer_id, true, R0, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
GBlockstate.variant(outer_id, true, R0, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, FIRST_OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_LEFT)),
GBlockstate.variant(outer_id, true, R0, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, FIRST_OUTER_LEFT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_LEFT)),
GBlockstate.variant(outer_id, true, R0, R270))
/* OUTER TOP */
.with(When.anyOf(
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, FIRST_OUTER_LEFT)),
GBlockstate.variant(outer_id, true, R180, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, FIRST_OUTER_LEFT),
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
GBlockstate.variant(outer_id, true, R180, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, FIRST_OUTER_RIGHT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
GBlockstate.variant(outer_id, true, R180, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, SECOND_OUTER_LEFT)),
GBlockstate.variant(outer_id, true, R180, R270))
/* OUTER EAST */
.with(When.anyOf(
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R0, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R90, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, FIRST_OUTER_LEFT),
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, SECOND_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R180, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, FIRST_OUTER_RIGHT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R270, R0))
/* OUTER SOUTH */
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, SECOND_OUTER_RIGHT),
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R0, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, SECOND_OUTER_LEFT),
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R90, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, FIRST_OUTER_LEFT),
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, SECOND_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R180, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, FIRST_OUTER_RIGHT),
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, FIRST_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R270, R90))
/* OUTER WEST */
.with(When.anyOf(
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R0, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, FIRST_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R90, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, FIRST_OUTER_LEFT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R180, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, FIRST_OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R270, R180))
/* OUTER NORTH */
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, SECOND_OUTER_RIGHT),
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, SECOND_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R0, R270))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, SECOND_OUTER_LEFT),
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, FIRST_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R90, R270))
.with(When.anyOf(
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, FIRST_OUTER_LEFT),
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R180, R270))
.with(When.anyOf(
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, FIRST_OUTER_RIGHT),
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R270, R270))
/* OUTER BOTTOM */
.with(When.anyOf(
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, OUTER_RIGHT)),
GBlockstate.variant(double_outer_id, true, R0, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, OUTER_RIGHT)),
GBlockstate.variant(double_outer_id, true, R0, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, OUTER_RIGHT)),
GBlockstate.variant(double_outer_id, true, R0, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, OUTER_RIGHT)),
GBlockstate.variant(double_outer_id, true, R0, R270))
/* OUTER TOP */
.with(When.anyOf(
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, OUTER_LEFT)),
GBlockstate.variant(double_outer_id, true, R180, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, OUTER_LEFT)),
GBlockstate.variant(double_outer_id, true, R180, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, OUTER_LEFT)),
GBlockstate.variant(double_outer_id, true, R180, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, OUTER_LEFT)),
GBlockstate.variant(double_outer_id, true, R180, R270));
}
@Override
public void setRecipe(RecipeExporter exporter) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE);
ShapedRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, this, 4)
.pattern("I ")
.pattern("II ")
.pattern("III")
.input('I', ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
.offerTo(exporter);
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
if (new_state.isOf(ReFramed.STAIRS_CUBE)) return Map.of(1, 1);
return super.getThemeMap(state, new_state);
}
static {
@@ -382,51 +163,51 @@ public class ReFramedStairBlock extends WaterloggableReFramedBlock implements Bl
.add(25, VoxelHelper::rotateCX).add(26, VoxelHelper::rotateCX)
// WEST_DOWN
.add(0, VoxelHelper::rotateCY)
.add(10).add(1)
.add(12).add(3)
.add(16).add(5)
.add(7, VoxelHelper::rotateCY).add(8, VoxelHelper::rotateCY)
.add(1).add(10)
.add(3).add(12)
.add(5).add(16)
.add(8, VoxelHelper::rotateCY).add(7, VoxelHelper::rotateCY)
// DOWN_EAST
.add(36, VoxelHelper::rotateZ)
.add(11).add(2)
.add(13).add(4)
.add(2).add(11)
.add(4).add(13)
.add(41, VoxelHelper::rotateZ).add(42, VoxelHelper::rotateZ)
.add(17).add(6)
.add(6).add(17)
// EAST_UP
.add(45, VoxelHelper::rotateZ)
.add(20).add(29)
.add(22).add(31)
.add(24).add(35)
.add(29).add(20)
.add(31).add(22)
.add(35).add(24)
.add(52, VoxelHelper::rotateZ).add(53, VoxelHelper::rotateZ)
// UP_WEST
.add(54, VoxelHelper::rotateZ)
.add(19).add(28)
.add(21).add(30)
.add(28).add(19)
.add(30).add(21)
.add(59, VoxelHelper::rotateZ).add(60, VoxelHelper::rotateZ)
.add(23).add(34)
.add(34).add(23)
// WEST_NORTH
.add(0, VoxelHelper::rotateCZ)
.add(1).add(28)
.add(3).add(30)
.add(7).add(32)
.add(44).add(69)
.add(43).add(68)
// NORTH_EAST
.add(72, VoxelHelper::rotateY)
.add(2).add(29)
.add(4).add(31)
.add(51).add(62)
.add(50).add(61)
.add(8).add(33)
// EAST_SOUTH
.add(81, VoxelHelper::rotateY)
.add(11).add(20)
.add(13).add(22)
.add(15).add(26)
.add(50).add(61)
.add(51).add(62)
// SOUTH_WEST
.add(90, VoxelHelper::rotateY)
.add(10).add(19)
.add(12).add(21)
.add(43).add(68)
.add(44).add(69)
.add(14).add(25)
.build();
}

View File

@@ -1,19 +1,11 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.util.blocks.Edge;
import fr.adrien1106.reframed.util.blocks.StairShape;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.state.StateManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
@@ -27,7 +19,7 @@ import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.STAIR_SHAPE;
public class ReFramedStairsCubeBlock extends ReFramedDoubleBlock implements BlockStateProvider {
public class ReFramedStairsCubeBlock extends ReFramedDoubleBlock {
private static final VoxelShape[] STAIRS_CUBE_VOXELS = VoxelListBuilder.buildFrom(STAIR_VOXELS);
private record ModelCacheKey(Edge edge, StairShape shape) {}
@@ -80,21 +72,4 @@ public class ReFramedStairsCubeBlock extends ReFramedDoubleBlock implements Bloc
StairShape shape = state.get(STAIR_SHAPE);
return i == 2 ? STAIRS_CUBE_VOXELS[edge.getID() * 9 + shape.getID()] : getStairShape(edge, shape);
}
@Override
public MultipartBlockStateSupplier getMultipart() {
return getStairMultipart(this, true);
}
@Override
public void setRecipe(RecipeExporter exporter) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, this)
.input(ReFramed.STAIR)
.input(ReFramed.STEP)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
.offerTo(exporter);
}
}

View File

@@ -1,35 +1,31 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.util.VoxelHelper;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.util.blocks.Edge;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.state.StateManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.world.BlockView;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
import static fr.adrien1106.reframed.util.blocks.Edge.*;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.STAIR_SHAPE;
import static net.minecraft.state.property.Properties.*;
import static net.minecraft.state.property.Properties.WATERLOGGED;
public class ReFramedStepBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
public class ReFramedStepBlock extends WaterloggableReFramedBlock {
public static final VoxelShape[] STEP_VOXELS;
@@ -53,9 +49,84 @@ public class ReFramedStepBlock extends WaterloggableReFramedBlock implements Blo
super.appendProperties(builder.add(EDGE));
}
@Override
public boolean canReplace(BlockState state, ItemPlacementContext context) {
Edge edge = state.get(EDGE);
return !(
context.getPlayer().isSneaking()
|| !(context.getStack().getItem() instanceof BlockItem block_item)
|| (
!(
block_item.getBlock() == ReFramed.STAIR
&& ((ReFramedStairsCubeBlock) ReFramed.STAIRS_CUBE)
.matchesShape(
context.getHitPos(),
context.getBlockPos(),
ReFramed.STAIRS_CUBE.getDefaultState().with(EDGE, edge.opposite()),
1
)
)
&& !(
block_item.getBlock() == this
&& (
((ReFramedStepsSlabBlock) ReFramed.STEPS_SLAB)
.matchesShape(
context.getHitPos(),
context.getBlockPos(),
ReFramed.STEPS_SLAB.getDefaultState()
.with(FACING, edge.getFirstDirection())
.with(AXIS, edge.getSecondDirection().getAxis()),
edge.getSecondDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
)
|| ((ReFramedStepsSlabBlock) ReFramed.STEPS_SLAB)
.matchesShape(
context.getHitPos(),
context.getBlockPos(),
ReFramed.STEPS_SLAB.getDefaultState()
.with(FACING, edge.getSecondDirection())
.with(AXIS, edge.getFirstDirection().getAxis()),
edge.getFirstDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
)
)
)
)
);
}
@Nullable
@Override
public BlockState getPlacementState(ItemPlacementContext ctx) {
BlockPos pos = ctx.getBlockPos();
BlockState current_state = ctx.getWorld().getBlockState(pos);
if (current_state.isOf(ReFramed.STAIR))
return ReFramed.STAIRS_CUBE.getDefaultState()
.with(EDGE, current_state.get(EDGE))
.with(STAIR_SHAPE, current_state.get(STAIR_SHAPE));
if (current_state.isOf(this)) {
Vec3d hit = ctx.getHitPos();
Edge edge = current_state.get(EDGE);
Direction dir = edge.getFirstDirection();
ReFramedStepsSlabBlock block = ((ReFramedStepsSlabBlock) ReFramed.STEPS_SLAB);
BlockState state = block.getDefaultState()
.with(FACING, dir)
.with(AXIS, edge.getOtherDirection(dir).getAxis())
.with(WATERLOGGED, current_state.get(WATERLOGGED));
if (!block.matchesShape(
hit, pos,
state,
edge.getOtherDirection(dir).getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2
)) {
dir = edge.getSecondDirection();
state = state
.with(FACING, dir)
.with(AXIS, edge.getOtherDirection(dir).getAxis());
}
return state;
}
return super.getPlacementState(ctx).with(EDGE, BlockHelper.getPlacementEdge(ctx));
}
@@ -69,48 +140,16 @@ public class ReFramedStepBlock extends WaterloggableReFramedBlock implements Blo
}
@Override
public BlockStateSupplier getMultipart() {
Identifier model_id = ReFramed.id("step_special");
return MultipartBlockStateSupplier.create(this)
/* X AXIS */
.with(GBlockstate.when(EDGE, DOWN_EAST),
GBlockstate.variant(model_id, true, R0, R0))
.with(GBlockstate.when(EDGE, EAST_UP),
GBlockstate.variant(model_id, true, R180, R0))
.with(GBlockstate.when(EDGE, UP_WEST),
GBlockstate.variant(model_id, true, R180, R180))
.with(GBlockstate.when(EDGE, WEST_DOWN),
GBlockstate.variant(model_id, true, R0, R180))
/* Y AXIS */
.with(GBlockstate.when(EDGE, EAST_SOUTH),
GBlockstate.variant(model_id, true, R90, R0))
.with(GBlockstate.when(EDGE, SOUTH_WEST),
GBlockstate.variant(model_id, true, R90, R90))
.with(GBlockstate.when(EDGE, WEST_NORTH),
GBlockstate.variant(model_id, true, R90, R180))
.with(GBlockstate.when(EDGE, NORTH_EAST),
GBlockstate.variant(model_id, true, R90, R270))
/* Z AXIS */
.with(GBlockstate.when(EDGE, DOWN_SOUTH),
GBlockstate.variant(model_id, true, R0, R90))
.with(GBlockstate.when(EDGE, NORTH_DOWN),
GBlockstate.variant(model_id, true, R0, R270))
.with(GBlockstate.when(EDGE, UP_NORTH),
GBlockstate.variant(model_id, true, R180, R270))
.with(GBlockstate.when(EDGE, SOUTH_UP),
GBlockstate.variant(model_id, true, R180, R90));
}
@Override
public void setRecipe(RecipeExporter exporter) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 4);
ShapedRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, this, 8)
.pattern("II")
.input('I', ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
.offerTo(exporter);
public Map<Integer, Integer> getThemeMap(BlockState state, BlockState new_state) {
if (new_state.isOf(ReFramed.STAIRS_CUBE)) return Map.of(1, 2);
if (new_state.isOf(ReFramed.STEPS_SLAB))
return Map.of(
1,
state.get(EDGE)
.getOtherDirection(new_state.get(FACING))
.getDirection() == Direction.AxisDirection.POSITIVE ? 2 : 1
);
return super.getThemeMap(state, new_state);
}
static {

View File

@@ -1,22 +1,12 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.util.blocks.Edge;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.state.StateManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Direction.Axis;
@@ -27,12 +17,11 @@ import org.jetbrains.annotations.Nullable;
import static fr.adrien1106.reframed.block.ReFramedSlabBlock.getSlabShape;
import static fr.adrien1106.reframed.block.ReFramedStepBlock.getStepShape;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
import static net.minecraft.state.property.Properties.AXIS;
import static net.minecraft.state.property.Properties.FACING;
import static net.minecraft.util.shape.VoxelShapes.empty;
public class ReFramedStepsSlabBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider {
public class ReFramedStepsSlabBlock extends WaterloggableReFramedDoubleBlock {
private record ModelCacheKey(Direction facing, Axis axis) {}
public ReFramedStepsSlabBlock(Settings settings) {
@@ -81,7 +70,7 @@ public class ReFramedStepsSlabBlock extends WaterloggableReFramedDoubleBlock imp
switch (axis) {
case X -> i == 1 ? Direction.WEST : Direction.EAST;
case Y -> i == 1 ? Direction.DOWN : Direction.UP;
case Z -> i == 1 ? Direction.SOUTH : Direction.NORTH;
case Z -> i == 1 ? Direction.NORTH : Direction.SOUTH;
}
));
}
@@ -90,47 +79,4 @@ public class ReFramedStepsSlabBlock extends WaterloggableReFramedDoubleBlock imp
public int getTopThemeIndex(BlockState state) {
return 2;
}
@Override
public MultipartBlockStateSupplier getMultipart() {
Identifier step_id = ReFramed.id("steps_slab_special");
Identifier step_side_id = ReFramed.id("steps_slab_side_special");
return MultipartBlockStateSupplier.create(this)
.with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Axis.X),
GBlockstate.variant(step_id, true, R0, R180))
.with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Axis.Z),
GBlockstate.variant(step_id, true, R0, R90))
.with(GBlockstate.when(FACING, Direction.UP, AXIS, Axis.X),
GBlockstate.variant(step_id, true, R180, R180))
.with(GBlockstate.when(FACING, Direction.UP, AXIS, Axis.Z),
GBlockstate.variant(step_id, true, R180, R90))
.with(GBlockstate.when(FACING, Direction.EAST, AXIS, Axis.Z),
GBlockstate.variant(step_side_id, true, R180, R0))
.with(GBlockstate.when(FACING, Direction.EAST, AXIS, Axis.Y),
GBlockstate.variant(step_side_id, true, R90, R0))
.with(GBlockstate.when(FACING, Direction.SOUTH, AXIS, Axis.X),
GBlockstate.variant(step_side_id, true, R180, R90))
.with(GBlockstate.when(FACING, Direction.SOUTH, AXIS, Axis.Y),
GBlockstate.variant(step_side_id, true, R90, R90))
.with(GBlockstate.when(FACING, Direction.WEST, AXIS, Axis.Z),
GBlockstate.variant(step_side_id, true, R0, R180))
.with(GBlockstate.when(FACING, Direction.WEST, AXIS, Axis.Y),
GBlockstate.variant(step_side_id, true, R90, R180))
.with(GBlockstate.when(FACING, Direction.NORTH, AXIS, Axis.X),
GBlockstate.variant(step_side_id, true, R0, R270))
.with(GBlockstate.when(FACING, Direction.NORTH, AXIS, Axis.Y),
GBlockstate.variant(step_side_id, true, R90, R270));
}
@Override
public void setRecipe(RecipeExporter exporter) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 2);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, this)
.input(ReFramed.STEP, 2)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this))
.offerTo(exporter);
}
}

View File

@@ -0,0 +1,217 @@
package fr.adrien1106.reframed.block;
import fr.adrien1106.reframed.util.VoxelHelper;
import net.minecraft.block.*;
import net.minecraft.block.enums.WallShape;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.registry.tag.BlockTags;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.Property;
import net.minecraft.util.function.BooleanBiFunction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import org.jetbrains.annotations.Nullable;
import java.util.stream.Stream;
import static net.minecraft.state.property.Properties.*;
public class ReframedWallBlock extends WaterloggableReFramedBlock {
public static final VoxelShape[] WALL_VOXELS;
private record ModelCacheKey(boolean up, WallShape east, WallShape north, WallShape west, WallShape south) {}
public ReframedWallBlock(Settings settings) {
super(settings);
setDefaultState(getDefaultState()
.with(UP, true)
.with(EAST_WALL_SHAPE, WallShape.NONE)
.with(NORTH_WALL_SHAPE, WallShape.NONE)
.with(WEST_WALL_SHAPE, WallShape.NONE)
.with(SOUTH_WALL_SHAPE, WallShape.NONE)
);
}
@Override
public Object getModelCacheKey(BlockState state) {
return new ModelCacheKey(
state.get(UP),
state.get(EAST_WALL_SHAPE),
state.get(NORTH_WALL_SHAPE),
state.get(WEST_WALL_SHAPE),
state.get(SOUTH_WALL_SHAPE)
);
}
@Override
public int getModelStateCount() {
return 162;
}
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
super.appendProperties(builder.add(UP, EAST_WALL_SHAPE, NORTH_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE));
}
@Override
public BlockState getStateForNeighborUpdate(BlockState state, Direction dir, BlockState other_state, WorldAccess world, BlockPos pos, BlockPos moved) {
BlockState new_state = super.getStateForNeighborUpdate(state, dir, other_state, world, pos, moved);
if (dir == Direction.DOWN) return new_state;
BlockState top_state = dir == Direction.UP? other_state: world.getBlockState(pos.up());
boolean fs = top_state.isSideSolidFullSquare(world, pos.up(), Direction.DOWN);
VoxelShape top_shape = fs ? null : top_state.getCollisionShape(world, pos.up()).getFace(Direction.DOWN);
if (dir == Direction.UP) {
for (Direction d : Direction.Type.HORIZONTAL) {
Property<WallShape> wall_shape = getWallShape(d);
if (state.get(wall_shape) == WallShape.NONE) continue;
new_state = new_state.with(
wall_shape,
fs
|| (top_state.contains(wall_shape) && top_state.get(wall_shape) != WallShape.NONE)
|| shouldUseTall(WALL_VOXELS[dir.ordinal() + 3], top_shape)
? WallShape.TALL
: WallShape.LOW
);
}
return new_state.with(UP, shouldHavePost(new_state, top_state, top_shape));
}
boolean side_full = other_state.isSideSolidFullSquare(world, moved, dir.getOpposite());
if (shouldConnectTo(other_state, side_full, dir.getOpposite())) {
new_state = new_state.with(
getWallShape(dir),
fs || shouldUseTall(WALL_VOXELS[dir.ordinal() + 3], top_shape)
? WallShape.TALL
: WallShape.LOW
);
} else new_state = new_state.with(getWallShape(dir), WallShape.NONE);
return new_state.with(UP, shouldHavePost(new_state, top_state, top_shape));
}
@Override
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
BlockState state = super.getPlacementState(ctx);
World world = ctx.getWorld();
BlockPos pos = ctx.getBlockPos();
BlockState top_state = world.getBlockState(pos.up());
boolean fs = top_state.isSideSolidFullSquare(world, pos.up(), Direction.DOWN);
VoxelShape top_shape = fs ? null : top_state.getCollisionShape(world, pos.up()).getFace(Direction.DOWN);
for (Direction dir : Direction.Type.HORIZONTAL) {
BlockPos offset = pos.offset(dir);
BlockState neighbor = world.getBlockState(offset);
boolean side_full = neighbor.isSideSolidFullSquare(world, offset, dir.getOpposite());
if (shouldConnectTo(neighbor, side_full, dir.getOpposite())) {
state = state.with(
getWallShape(dir),
fs || shouldUseTall(WALL_VOXELS[dir.ordinal() + 3], top_shape)
? WallShape.TALL
: WallShape.LOW
);
}
}
return state.with(UP, shouldHavePost(state, top_state, top_shape));
}
@Override
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
super.onStateReplaced(state, world, pos, new_state, moved);
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
}
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
VoxelShape shape = state.get(UP) ? WALL_VOXELS[0]: VoxelShapes.empty();
for (Direction dir : Direction.Type.HORIZONTAL) {
WallShape wall_shape = state.get(getWallShape(dir));
if (wall_shape != WallShape.NONE)
shape = VoxelShapes.union(shape, WALL_VOXELS[1 + (wall_shape.ordinal()-1) * 4 + (dir.ordinal() - 2)]);
}
return shape;
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
VoxelShape shape = state.get(UP) ? WALL_VOXELS[9]: VoxelShapes.empty();
for (Direction dir : Direction.Type.HORIZONTAL) {
if (state.get(getWallShape(dir)) != WallShape.NONE)
shape = VoxelShapes.union(shape, WALL_VOXELS[8 + dir.ordinal()]);
}
return shape;
}
private static boolean shouldHavePost(BlockState state, BlockState top_state, VoxelShape top_shape) {
// above has post
if (top_state.contains(NORTH_WALL_SHAPE) && top_state.get(UP)) return true;
if (Stream.of(Direction.SOUTH, Direction.EAST) // Opposites are different
.anyMatch(dir -> state.get(getWallShape(dir)) != state.get(getWallShape(dir.getOpposite())))
) return true;
// no sides
if (Direction.Type.HORIZONTAL.stream().allMatch(dir -> state.get(getWallShape(dir)) == WallShape.NONE))
return true;
// tall Matching sides
if (Stream.of(Direction.SOUTH, Direction.EAST)
.anyMatch(dir ->
state.get(getWallShape(dir)) == WallShape.TALL
&& state.get(getWallShape(dir.getOpposite())) == WallShape.TALL
)) return false;
return top_state.isIn(BlockTags.WALL_POST_OVERRIDE) || top_shape == null || shouldUseTall(WALL_VOXELS[0], top_shape);
}
private static boolean shouldConnectTo(BlockState state, boolean side_full, Direction side) {
Block block = state.getBlock();
boolean bl = block instanceof FenceGateBlock && FenceGateBlock.canWallConnect(state, side);
return state.isIn(BlockTags.WALLS) || !WallBlock.cannotConnect(state) && side_full || block instanceof PaneBlock || bl;
}
private static boolean shouldUseTall(VoxelShape self_shape, VoxelShape other_shape) {
return !VoxelShapes.matchesAnywhere(
self_shape,
other_shape,
BooleanBiFunction.ONLY_FIRST
);
}
private static Property<WallShape> getWallShape(Direction dir) {
return switch (dir) {
case EAST -> EAST_WALL_SHAPE;
case NORTH -> NORTH_WALL_SHAPE;
case WEST -> WEST_WALL_SHAPE;
case SOUTH -> SOUTH_WALL_SHAPE;
default -> null;
};
}
static {
VoxelShape POST = createCuboidShape(4, 0, 4, 12, 16, 12);
VoxelShape POST_COLLISION = createCuboidShape(4, 0, 4, 12, 24, 12);
VoxelShape LOW = createCuboidShape(5, 0, 0, 11, 14, 8);
VoxelShape TALL = createCuboidShape(5, 0, 0, 11, 16, 8);
VoxelShape SIDE_COLLISION = createCuboidShape(5, 0, 0, 11, 24, 8);
WALL_VOXELS = VoxelHelper.VoxelListBuilder.create(POST, 14)
.add(LOW)
.add(VoxelHelper::mirrorZ)
.add(VoxelHelper::rotateY)
.add(VoxelHelper::mirrorX)
.add(TALL)
.add(VoxelHelper::mirrorZ)
.add(VoxelHelper::rotateY)
.add(VoxelHelper::mirrorX)
.add(POST_COLLISION)
.add(SIDE_COLLISION)
.add(VoxelHelper::mirrorZ)
.add(VoxelHelper::rotateY)
.add(VoxelHelper::mirrorX)
.build();
}
}

View File

@@ -16,6 +16,7 @@ import org.jetbrains.annotations.Nullable;
public class WaterloggableReFramedDoubleBlock extends ReFramedDoubleBlock implements Waterloggable {
public WaterloggableReFramedDoubleBlock(Settings settings) {
super(settings);
setDefaultState(getDefaultState().with(Properties.WATERLOGGED, false));
}
@Override

View File

@@ -27,67 +27,110 @@ public class ReFramedClient implements ClientModInitializer {
BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), ReFramed.BLOCKS.toArray(new Block[0]));
// CUBE
HELPER.addReFramedModel("cube_special" , HELPER.auto(new Identifier("block/cube")));
HELPER.addReFramedModel("cube" , HELPER.auto(new Identifier("block/cube")));
// SMALL_CUBE
HELPER.addReFramedModel("small_cube_special" , HELPER.auto(ReFramed.id("block/small_cube/base")));
HELPER.addReFramedModel("small_cube" , HELPER.auto(ReFramed.id("block/small_cube/base")));
// SMALL_CUBES_STEP
HELPER.addReFramedModel("small_cubes_step_special" , HELPER.autoDouble(ReFramed.id("block/small_cube/base"), ReFramed.id("block/small_cube/step/base")));
HELPER.addReFramedModel("small_cubes_step_reverse_special" , HELPER.autoDouble(ReFramed.id("block/small_cube/step/base"), ReFramed.id("block/small_cube/base")));
HELPER.addReFramedModel("small_cubes_step" , HELPER.autoDouble(ReFramed.id("block/small_cube/base"), ReFramed.id("block/small_cube/step/base")));
HELPER.addReFramedModel("small_cubes_step_reverse" , HELPER.autoDouble(ReFramed.id("block/small_cube/step/base"), ReFramed.id("block/small_cube/base")));
// SLAB
HELPER.addReFramedModel("slab_special" , HELPER.auto(new Identifier("block/slab")));
HELPER.addReFramedModel("slab" , HELPER.auto(new Identifier("block/slab")));
// SLAB_CUBE
HELPER.addReFramedModel("double_slab_special" , HELPER.autoDouble(new Identifier("block/slab"), new Identifier("block/slab_top")));
HELPER.addReFramedModel("double_slab" , HELPER.autoDouble(new Identifier("block/slab"), new Identifier("block/slab_top")));
// STAIR
HELPER.addReFramedModel("stair_special" , HELPER.auto(ReFramed.id("block/stair/straight")));
HELPER.addReFramedModel("outers_stair_special" , HELPER.auto(ReFramed.id("block/stair/double_outer")));
HELPER.addReFramedModel("inner_stair_special" , HELPER.auto(ReFramed.id("block/stair/inner")));
HELPER.addReFramedModel("outer_stair_special" , HELPER.auto(ReFramed.id("block/stair/outer")));
HELPER.addReFramedModel("outer_side_stair_special" , HELPER.auto(ReFramed.id("block/stair/outer_side")));
HELPER.addReFramedModel("stair" , HELPER.auto(ReFramed.id("block/stair/straight")));
HELPER.addReFramedModel("outers_stair" , HELPER.auto(ReFramed.id("block/stair/double_outer")));
HELPER.addReFramedModel("inner_stair" , HELPER.auto(ReFramed.id("block/stair/inner")));
HELPER.addReFramedModel("outer_stair" , HELPER.auto(ReFramed.id("block/stair/outer")));
HELPER.addReFramedModel("outer_side_stair" , HELPER.auto(ReFramed.id("block/stair/outer_side")));
// STAIRS_CUBE
HELPER.addReFramedModel("stairs_cube_special" , HELPER.autoDouble(ReFramed.id("block/stair/straight"), ReFramed.id("block/stair/cube/straight")));
HELPER.addReFramedModel("outers_stairs_cube_special" , HELPER.autoDouble(ReFramed.id("block/stair/double_outer"), ReFramed.id("block/stair/cube/double_outer")));
HELPER.addReFramedModel("inner_stairs_cube_special" , HELPER.autoDouble(ReFramed.id("block/stair/inner"), ReFramed.id("block/stair/cube/inner")));
HELPER.addReFramedModel("outer_stairs_cube_special" , HELPER.autoDouble(ReFramed.id("block/stair/outer"), ReFramed.id("block/stair/cube/outer")));
HELPER.addReFramedModel("outer_side_stairs_cube_special" , HELPER.autoDouble(ReFramed.id("block/stair/outer_side"), ReFramed.id("block/stair/cube/outer_side")));
HELPER.addReFramedModel("stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/straight"), ReFramed.id("block/stair/cube/straight")));
HELPER.addReFramedModel("outers_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/double_outer"), ReFramed.id("block/stair/cube/double_outer")));
HELPER.addReFramedModel("inner_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/inner"), ReFramed.id("block/stair/cube/inner")));
HELPER.addReFramedModel("outer_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/outer"), ReFramed.id("block/stair/cube/outer")));
HELPER.addReFramedModel("outer_side_stairs_cube" , HELPER.autoDouble(ReFramed.id("block/stair/outer_side"), ReFramed.id("block/stair/cube/outer_side")));
// HALF_STAIR
HELPER.addReFramedModel("half_stair_down_special" , HELPER.auto(ReFramed.id("block/half_stair/down")));
HELPER.addReFramedModel("half_stair_side_special" , HELPER.auto(ReFramed.id("block/half_stair/side")));
HELPER.addReFramedModel("half_stair_down" , HELPER.auto(ReFramed.id("block/half_stair/down")));
HELPER.addReFramedModel("half_stair_side" , HELPER.auto(ReFramed.id("block/half_stair/side")));
// HALF_STAIRS_SLAB
HELPER.addReFramedModel("half_stairs_slab_down_special" , HELPER.autoDouble(ReFramed.id("block/half_stair/down"), ReFramed.id("block/half_stair/slab/down")));
HELPER.addReFramedModel("half_stairs_slab_side_special" , HELPER.autoDouble(ReFramed.id("block/half_stair/side"), ReFramed.id("block/half_stair/slab/side")));
HELPER.addReFramedModel("half_stairs_slab_down" , HELPER.autoDouble(ReFramed.id("block/half_stair/down"), ReFramed.id("block/half_stair/slab/down")));
HELPER.addReFramedModel("half_stairs_slab_side" , HELPER.autoDouble(ReFramed.id("block/half_stair/side"), ReFramed.id("block/half_stair/slab/side")));
// HALF_STAIRS_STAIR
HELPER.addReFramedModel("half_stairs_stair_down_special" , HELPER.autoDouble(ReFramed.id("block/half_stair/down"), ReFramed.id("block/half_stair/stair/down")));
HELPER.addReFramedModel("half_stairs_stair_side_special" , HELPER.autoDouble(ReFramed.id("block/half_stair/side"), ReFramed.id("block/half_stair/stair/side")));
HELPER.addReFramedModel("half_stairs_stair_reverse_special" , HELPER.autoDouble(ReFramed.id("block/half_stair/stair/side"), ReFramed.id("block/half_stair/side")));
HELPER.addReFramedModel("half_stairs_stair_down" , HELPER.autoDouble(ReFramed.id("block/half_stair/down"), ReFramed.id("block/half_stair/stair/down")));
HELPER.addReFramedModel("half_stairs_stair_side" , HELPER.autoDouble(ReFramed.id("block/half_stair/side"), ReFramed.id("block/half_stair/stair/side")));
HELPER.addReFramedModel("half_stairs_stair_reverse" , HELPER.autoDouble(ReFramed.id("block/half_stair/stair/side"), ReFramed.id("block/half_stair/side")));
// STEP
HELPER.addReFramedModel("step_special" , HELPER.auto(ReFramed.id("block/step/down")));
HELPER.addReFramedModel("step" , HELPER.auto(ReFramed.id("block/step/down")));
// STEPS_SLAB
HELPER.addReFramedModel("steps_slab_special" , HELPER.autoDouble(ReFramed.id("block/step/down"), ReFramed.id("block/step/slab/down")));
HELPER.addReFramedModel("steps_slab_side_special" , HELPER.autoDouble(ReFramed.id("block/step/side"), ReFramed.id("block/step/slab/side")));
HELPER.addReFramedModel("steps_slab" , HELPER.autoDouble(ReFramed.id("block/step/down"), ReFramed.id("block/step/slab/down")));
HELPER.addReFramedModel("steps_slab_side" , HELPER.autoDouble(ReFramed.id("block/step/side"), ReFramed.id("block/step/slab/side")));
// LAYER
HELPER.addReFramedModel("layer_1_special" , HELPER.auto(new Identifier("block/snow_height2")));
HELPER.addReFramedModel("layer_2_special" , HELPER.auto(new Identifier("block/snow_height4")));
HELPER.addReFramedModel("layer_3_special" , HELPER.auto(new Identifier("block/snow_height6")));
HELPER.addReFramedModel("layer_4_special" , HELPER.auto(new Identifier("block/snow_height8")));
HELPER.addReFramedModel("layer_5_special" , HELPER.auto(new Identifier("block/snow_height10")));
HELPER.addReFramedModel("layer_6_special" , HELPER.auto(new Identifier("block/snow_height12")));
HELPER.addReFramedModel("layer_7_special" , HELPER.auto(new Identifier("block/snow_height14")));
HELPER.addReFramedModel("layer_8_special" , HELPER.auto(new Identifier("block/cube")));
HELPER.addReFramedModel("layer_1" , HELPER.auto(new Identifier("block/snow_height2")));
HELPER.addReFramedModel("layer_2" , HELPER.auto(new Identifier("block/snow_height4")));
HELPER.addReFramedModel("layer_3" , HELPER.auto(new Identifier("block/snow_height6")));
HELPER.addReFramedModel("layer_4" , HELPER.auto(new Identifier("block/snow_height8")));
HELPER.addReFramedModel("layer_5" , HELPER.auto(new Identifier("block/snow_height10")));
HELPER.addReFramedModel("layer_6" , HELPER.auto(new Identifier("block/snow_height12")));
HELPER.addReFramedModel("layer_7" , HELPER.auto(new Identifier("block/snow_height14")));
HELPER.addReFramedModel("layer_8" , HELPER.auto(new Identifier("block/cube")));
// PILLAR
HELPER.addReFramedModel("pillar" , HELPER.auto(ReFramed.id("block/pillar")));
// WALL
HELPER.addReFramedModel("wall_inventory" , HELPER.auto(ReFramed.id("block/wall/inventory/default")));
// --------------------- pillar
HELPER.addReFramedModel("wall_core" , HELPER.auto(ReFramed.id("block/wall/pillar/core")));
HELPER.addReFramedModel("wall_pillar_low" , HELPER.auto(ReFramed.id("block/wall/pillar/low")));
HELPER.addReFramedModel("wall_pillar_tall" , HELPER.auto(ReFramed.id("block/wall/pillar/tall")));
HELPER.addReFramedModel("wall_pillar_none" , HELPER.auto(ReFramed.id("block/wall/pillar/none")));
// --------------------- side
HELPER.addReFramedModel("wall_side_low" , HELPER.auto(ReFramed.id("block/wall/side/low")));
HELPER.addReFramedModel("wall_side_tall" , HELPER.auto(ReFramed.id("block/wall/side/tall")));
// --------------------- junction
HELPER.addReFramedModel("wall_low_e" , HELPER.auto(ReFramed.id("block/wall/junction/low")));
HELPER.addReFramedModel("wall_tall_e" , HELPER.auto(ReFramed.id("block/wall/junction/tall")));
// --------------------- junction_i
HELPER.addReFramedModel("wall_low_i" , HELPER.auto(ReFramed.id("block/wall/junction/low_i")));
HELPER.addReFramedModel("wall_tall_i" , HELPER.auto(ReFramed.id("block/wall/junction/tall_i")));
HELPER.addReFramedModel("wall_low_tall_i" , HELPER.auto(ReFramed.id("block/wall/junction/low_tall_i")));
// --------------------- junction_c
HELPER.addReFramedModel("wall_low_c" , HELPER.auto(ReFramed.id("block/wall/junction/low_c")));
HELPER.addReFramedModel("wall_tall_c" , HELPER.auto(ReFramed.id("block/wall/junction/tall_c")));
HELPER.addReFramedModel("wall_low_tall_c" , HELPER.auto(ReFramed.id("block/wall/junction/low_tall_c")));
HELPER.addReFramedModel("wall_tall_low_c" , HELPER.auto(ReFramed.id("block/wall/junction/tall_low_c")));
// --------------------- junction_t
HELPER.addReFramedModel("wall_low_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_t")));
HELPER.addReFramedModel("wall_tall_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_t")));
HELPER.addReFramedModel("wall_tall_low_c_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_low_c_t")));
HELPER.addReFramedModel("wall_tall_i_low_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_i_low_t")));
HELPER.addReFramedModel("wall_low_i_tall_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_i_tall_t")));
HELPER.addReFramedModel("wall_low_tall_c_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_tall_c_t")));
HELPER.addReFramedModel("wall_low_c_tall_t" , HELPER.auto(ReFramed.id("block/wall/junction/low_c_tall_t")));
HELPER.addReFramedModel("wall_tall_c_low_t" , HELPER.auto(ReFramed.id("block/wall/junction/tall_c_low_t")));
// --------------------- junction_x
HELPER.addReFramedModel("wall_low_x" , HELPER.auto(ReFramed.id("block/wall/junction/low_x")));
HELPER.addReFramedModel("wall_tall_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_x")));
HELPER.addReFramedModel("wall_tall_i_low_i_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_i_low_i_x")));
HELPER.addReFramedModel("wall_tall_low_t_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_low_t_x")));
HELPER.addReFramedModel("wall_tall_c_low_c_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_c_low_c_x")));
HELPER.addReFramedModel("wall_tall_t_low_x" , HELPER.auto(ReFramed.id("block/wall/junction/tall_t_low_x")));
//item model assignments (in lieu of models/item/___.json)
HELPER.assignItemModel("cube_special" , ReFramed.CUBE);
HELPER.assignItemModel("small_cube_special" , ReFramed.SMALL_CUBE);
HELPER.assignItemModel("small_cubes_step_special" , ReFramed.SMALL_CUBES_STEP);
HELPER.assignItemModel("slab_special" , ReFramed.SLAB);
HELPER.assignItemModel("double_slab_special" , ReFramed.SLABS_CUBE);
HELPER.assignItemModel("stair_special" , ReFramed.STAIR);
HELPER.assignItemModel("stairs_cube_special" , ReFramed.STAIRS_CUBE);
HELPER.assignItemModel("half_stair_down_special" , ReFramed.HALF_STAIR);
HELPER.assignItemModel("half_stairs_slab_down_special" , ReFramed.HALF_STAIRS_SLAB);
HELPER.assignItemModel("half_stairs_stair_down_special", ReFramed.HALF_STAIRS_STAIR);
HELPER.assignItemModel("step_special" , ReFramed.STEP);
HELPER.assignItemModel("steps_slab_special" , ReFramed.STEPS_SLAB);
HELPER.assignItemModel("layer_1_special" , ReFramed.LAYER);
HELPER.assignItemModel("cube" , ReFramed.CUBE);
HELPER.assignItemModel("small_cube" , ReFramed.SMALL_CUBE);
HELPER.assignItemModel("small_cubes_step" , ReFramed.SMALL_CUBES_STEP);
HELPER.assignItemModel("slab" , ReFramed.SLAB);
HELPER.assignItemModel("double_slab" , ReFramed.SLABS_CUBE);
HELPER.assignItemModel("stair" , ReFramed.STAIR);
HELPER.assignItemModel("stairs_cube" , ReFramed.STAIRS_CUBE);
HELPER.assignItemModel("half_stair_down" , ReFramed.HALF_STAIR);
HELPER.assignItemModel("half_stairs_slab_down" , ReFramed.HALF_STAIRS_SLAB);
HELPER.assignItemModel("half_stairs_stair_down", ReFramed.HALF_STAIRS_STAIR);
HELPER.assignItemModel("step" , ReFramed.STEP);
HELPER.assignItemModel("steps_slab" , ReFramed.STEPS_SLAB);
HELPER.assignItemModel("layer_1" , ReFramed.LAYER);
HELPER.assignItemModel("pillar" , ReFramed.PILLAR);
HELPER.assignItemModel("wall_inventory" , ReFramed.WALL);
}
private void privateInit() {
@@ -105,7 +148,7 @@ public class ReFramedClient implements ClientModInitializer {
//supporting code for the TemplatesModelProvider
ModelLoadingRegistry.INSTANCE.registerResourceProvider(rm -> PROVIDER); //block models
ModelLoadingRegistry.INSTANCE.registerVariantProvider(rm -> PROVIDER); //item models
ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() {
@Override public Identifier getFabricId() { return ReFramed.id("dump-caches"); }
@Override public void reload(ResourceManager blah) { PROVIDER.dumpCache(); }

View File

@@ -40,15 +40,15 @@ public class ReFramedClientHelper {
}
public void addReFramedModel(String id, UnbakedModel unbaked) {
prov.addReFramedModel(ReFramed.id(id), unbaked);
prov.addReFramedModel(ReFramed.id(id + "_special"), unbaked);
}
public void assignItemModel(String id, ItemConvertible... item_convertibles) {
prov.assignItemModel(ReFramed.id(id), item_convertibles);
prov.assignItemModel(ReFramed.id(id + "_special"), item_convertibles);
}
public CamoAppearanceManager getCamoApperanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
return prov.getCamoApperanceManager(spriteLookup);
public CamoAppearanceManager getCamoAppearanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
return prov.getCamoAppearanceManager(spriteLookup);
}
public @NotNull Renderer getFabricRenderer() {

View File

@@ -44,7 +44,7 @@ public class ReFramedModelProvider implements ModelResourceProvider, ModelVarian
/// camo appearance manager cache
public CamoAppearanceManager getCamoApperanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
public CamoAppearanceManager getCamoAppearanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
//This is kind of needlessly sketchy using the "volatile double checked locking" pattern.
//I'd like all frame models to use the same CamoApperanceManager, despite the model
//baking process happening concurrently on several threads, but I also don't want to
@@ -70,6 +70,7 @@ public class ReFramedModelProvider implements ModelResourceProvider, ModelVarian
}
public void dumpCache() {
CamoAppearanceManager.dumpCahe();
appearanceManager = null; //volatile write
}

View File

@@ -4,7 +4,8 @@ import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockRenderView;
import org.jetbrains.annotations.Nullable;
public interface DynamicBakedModel {
BakedModel computeQuads(BlockRenderView level, BlockState state, BlockPos pos, int theme_index);
BakedModel computeQuads(@Nullable BlockRenderView level, BlockState origin_state, @Nullable BlockPos pos, int theme_index);
}

View File

@@ -114,7 +114,9 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
if (camo instanceof WeightedComputedAppearance wca) model_id = wca.getAppearanceIndex(seed);
int tint = 0xFF000000 | MinecraftClient.getInstance().getBlockColors().getColor(theme, world, pos, 0);
Mesh untintedMesh = getRetexturedMesh(new MeshCacheKey(frame_block.getModelCacheKey(state), camo, model_id), state);
MeshCacheKey key = new MeshCacheKey(frame_block.getModelCacheKey(state), camo, model_id);
// do not clutter the cache with single-use meshes
Mesh untintedMesh = camo.hashCode() == -1 ? transformMesh(key, state) : getRetexturedMesh(key, state);
//The specific tint might vary a lot; imagine grass color smoothly changing. Trying to bake the tint into
//the cached mesh will pollute it with a ton of single-use meshes with only slightly different colors.

View File

@@ -33,7 +33,7 @@ public class UnbakedAutoRetexturedModel extends UnbakedRetexturedModel {
public BakedModel bake(Baker baker, Function<SpriteIdentifier, Sprite> texture_getter, ModelBakeSettings bake_settings, Identifier identifier) {
return new RetexturingBakedModel(
baker.bake(parent, bake_settings),
ReFramedClient.HELPER.getCamoApperanceManager(texture_getter),
ReFramedClient.HELPER.getCamoAppearanceManager(texture_getter),
theme_index,
bake_settings,
item_state,

View File

@@ -41,7 +41,7 @@ public class UnbakedJsonRetexturedModel extends UnbakedRetexturedModel {
return new RetexturingBakedModel(
baker.bake(parent, bake_settings),
ReFramedClient.HELPER.getCamoApperanceManager(spriteLookup),
ReFramedClient.HELPER.getCamoAppearanceManager(spriteLookup),
theme_index,
bake_settings,
item_state,

View File

@@ -20,8 +20,9 @@ public abstract class UnbakedRetexturedModel implements UnbakedModel {
this.parent = parent;
}
public void setThemeIndex(int theme_index) {
public UnbakedRetexturedModel setThemeIndex(int theme_index) {
this.theme_index = theme_index;
return this;
}
@Override

View File

@@ -6,6 +6,7 @@ import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.client.ReFramedClient;
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
import fr.adrien1106.reframed.client.model.QuadPosBounds;
import fr.adrien1106.reframed.compat.RebakedModel;
import fr.adrien1106.reframed.mixin.model.WeightedBakedModelAccessor;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@@ -39,6 +40,12 @@ import java.util.function.Function;
@Environment(EnvType.CLIENT)
public class CamoAppearanceManager {
protected static final SpriteIdentifier DEFAULT_SPRITE_MAIN = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier(ReFramed.MODID, "block/framed_block"));
protected static final SpriteIdentifier DEFAULT_SPRITE_SECONDARY = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier(ReFramed.MODID, "block/framed_accent_block"));
private static final SpriteIdentifier BARRIER_SPRITE_ID = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier("minecraft:item/barrier"));
private static final Cache<BlockState, CamoAppearance> APPEARANCE_CACHE = CacheBuilder.newBuilder().maximumSize(2048).build();
public CamoAppearanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
MaterialFinder finder = ReFramedClient.HELPER.getFabricRenderer().materialFinder();
for(BlendMode blend : BlendMode.values()) {
@@ -59,22 +66,20 @@ public class CamoAppearanceManager {
sprite = spriteLookup.apply(BARRIER_SPRITE_ID);
this.barrierItemAppearance = new SingleSpriteAppearance(sprite, materials.get(BlendMode.CUTOUT), serial_number.getAndIncrement());
}
protected static final SpriteIdentifier DEFAULT_SPRITE_MAIN = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier(ReFramed.MODID, "block/framed_block"));
protected static final SpriteIdentifier DEFAULT_SPRITE_SECONDARY = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier(ReFramed.MODID, "block/framed_accent_block"));
private static final SpriteIdentifier BARRIER_SPRITE_ID = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier("minecraft:item/barrier"));
private final CamoAppearance default_appearance;
private final CamoAppearance accent_appearance;
private final CamoAppearance barrierItemAppearance;
private static final Cache<BlockState, CamoAppearance> APPEARANCE_CACHE = CacheBuilder.newBuilder().maximumSize(2048).build();
private final AtomicInteger serial_number = new AtomicInteger(0); //Mutable
private final EnumMap<BlendMode, RenderMaterial> ao_materials = new EnumMap<>(BlendMode.class);
private final EnumMap<BlendMode, RenderMaterial> materials = new EnumMap<>(BlendMode.class); //Immutable contents
public static void dumpCahe() {
APPEARANCE_CACHE.invalidateAll();
}
public CamoAppearance getDefaultAppearance(int appearance) {
return appearance == 2 ? accent_appearance: default_appearance;
}
@@ -82,20 +87,24 @@ public class CamoAppearanceManager {
public CamoAppearance getCamoAppearance(BlockRenderView world, BlockState state, BlockPos pos, int theme_index, boolean item) {
BakedModel model = MinecraftClient.getInstance().getBlockRenderManager().getModel(state);
// add support for connected textures and more generally any compatible models injected so that they return baked quads
// add support for connected textures that uses dynamic baking
if (model instanceof DynamicBakedModel dynamic_model) {
// cache items as they get rendered more often
if (item && APPEARANCE_CACHE.asMap().containsKey(state)) return APPEARANCE_CACHE.getIfPresent(state);
CamoAppearance appearance = computeAppearance(dynamic_model.computeQuads(world, state, pos, theme_index), state);
if (item) APPEARANCE_CACHE.put(state, appearance);
return appearance;
model = dynamic_model.computeQuads(world, state, pos, theme_index);
// if model isn't rebaked its just wrapped (i.e. not dynamic and may be cached)
if (model instanceof RebakedModel) {
CamoAppearance appearance = computeAppearance(model, state, !item);
if (item) APPEARANCE_CACHE.put(state, appearance);
return appearance;
}
}
// refresh cache
if (APPEARANCE_CACHE.asMap().containsKey(state)) return APPEARANCE_CACHE.getIfPresent(state);
CamoAppearance appearance = computeAppearance(model, state);
CamoAppearance appearance = computeAppearance(model, state, false);
APPEARANCE_CACHE.put(state, appearance);
return appearance;
}
@@ -109,7 +118,7 @@ public class CamoAppearanceManager {
// The computeIfAbsent map update will work without corrupting the map, but there will be some "wasted effort" computing the value twice.
// The results are going to be the same, apart from their serialNumbers differing (= their equals & hashCode differing).
// Tiny amount of wasted space in some caches if CamoAppearances are used as a map key, then. IMO it's not a critical issue.
private CamoAppearance computeAppearance(BakedModel model, BlockState state) {
private CamoAppearance computeAppearance(BakedModel model, BlockState state, boolean is_dynamic) {
if(state.getBlock() == Blocks.BARRIER) return barrierItemAppearance;
if (!(model instanceof WeightedBakedModelAccessor weighted_model)) {
@@ -117,7 +126,7 @@ public class CamoAppearanceManager {
getAppearance(model),
getCachedMaterial(state, true),
getCachedMaterial(state, false),
serial_number.getAndIncrement()
is_dynamic ? -1 : serial_number.getAndIncrement()
);
}
List<Weighted.Present<Appearance>> appearances = weighted_model.getModels().stream()
@@ -128,7 +137,7 @@ public class CamoAppearanceManager {
appearances,
getCachedMaterial(state, true),
getCachedMaterial(state, false),
serial_number.getAndIncrement()
is_dynamic ? -1 : serial_number.getAndIncrement()
);
}

View File

@@ -0,0 +1,177 @@
package fr.adrien1106.reframed.client.util;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import fr.adrien1106.reframed.block.ReFramedBlock;
import fr.adrien1106.reframed.client.ReFramedClient;
import fr.adrien1106.reframed.client.model.QuadPosBounds;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.util.function.BooleanBiFunction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockRenderView;
import net.minecraft.world.BlockView;
import java.util.List;
import java.util.Objects;
import static net.minecraft.util.shape.VoxelShapes.combine;
@Environment(EnvType.CLIENT)
public class RenderHelper {
// self culling cache of the models not made thread local so that it is only computed once
private static final Cache<CullElement, Integer[]> INNER_CULL_MAP = CacheBuilder.newBuilder().maximumSize(1024).build();
private record CullElement(Block block, Object state_key, int model) {}
/**
* compute which quad might cull with another model quad
* @param state - the state of the model
* @param models - list of models on the same block
*/
public static void computeInnerCull(BlockState state, List<ForwardingBakedModel> models) {
if (!(state.getBlock() instanceof ReFramedBlock frame_block)) return;
Object key = frame_block.getModelCacheKey(state);
if (INNER_CULL_MAP.asMap().containsKey(new CullElement(frame_block, key, 1))) return;
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
QuadEmitter quad_emitter = r.meshBuilder().getEmitter();
RenderMaterial material = r.materialFinder().clear().find();
Random random = Random.create();
List<List<QuadPosBounds>> model_bounds = models.stream()
.map(ForwardingBakedModel::getWrappedModel)
.filter(Objects::nonNull)
.map(wrapped -> wrapped.getQuads(state, null, random))
.map(quads -> quads.stream().map(quad -> {
quad_emitter.fromVanilla(quad, material, null);
return QuadPosBounds.read(quad_emitter, false);
}).toList()).toList();
Integer[] cull_array;
for(int self_id = 1; self_id <= model_bounds.size(); self_id++) {
List<QuadPosBounds> self_bounds = model_bounds.get(self_id - 1);
cull_array = new Integer[self_bounds.size()];
for (int self_quad = 0; self_quad < cull_array.length; self_quad++) {
QuadPosBounds self_bound = self_bounds.get(self_quad);
for(int other_id = 1; other_id <= model_bounds.size(); other_id++) {
if (other_id == self_id) continue;
if (model_bounds.get(other_id - 1).stream().anyMatch(other_bound -> other_bound.equals(self_bound))) {
cull_array[self_quad] = other_id;
break;
}
}
}
INNER_CULL_MAP.put(new CullElement(frame_block, key, self_id), cull_array);
}
}
public static boolean shouldDrawInnerFace(BlockState state, BlockRenderView view, BlockPos pos, int quad_index, int theme_index) {
if ( !(state.getBlock() instanceof ReFramedBlock frame_block)
|| !(view.getBlockEntity(pos) instanceof ThemeableBlockEntity frame_entity)
) return true;
CullElement key = new CullElement(frame_block, frame_block.getModelCacheKey(state), theme_index);
if (!INNER_CULL_MAP.asMap().containsKey(key)) return true;
// needs to be Integer object because array is initialized with null not 0
Integer cull_theme = Objects.requireNonNull(INNER_CULL_MAP.getIfPresent(key))[quad_index];
if (cull_theme == null) return true; // no culling possible
BlockState self_theme = frame_entity.getTheme(theme_index);
BlockState other_theme = frame_entity.getTheme(cull_theme);
if (self_theme.isSideInvisible(other_theme, null)) return false;
return !self_theme.isOpaque() || !other_theme.isOpaque();
}
// Doing this method from scratch as it is simpler to do than injecting everywhere
public static boolean shouldDrawSide(BlockState self_state, BlockView world, BlockPos pos, Direction side, BlockPos other_pos, int theme_index) {
ThemeableBlockEntity self = world.getBlockEntity(pos) instanceof ThemeableBlockEntity e ? e : null;
ThemeableBlockEntity other = world.getBlockEntity(other_pos) instanceof ThemeableBlockEntity e ? e : null;
BlockState other_state = world.getBlockState(other_pos);
// normal behaviour
if (self == null && other == null) return Block.shouldDrawSide(self_state, world, pos, side, other_pos);
// self is a normal Block
if (self == null && other_state.getBlock() instanceof ReFramedBlock other_block) {
VoxelShape self_shape = self_state.getCullingShape(world, pos);
if (self_shape.isEmpty()) return true;
int i = 0;
VoxelShape other_shape = VoxelShapes.empty();
for (BlockState s: other.getThemes()) {
i++;
if (self_state.isSideInvisible(s, side) || s.isOpaque())
other_shape = combine(
other_shape,
other_block
.getShape(other_state, i)
.getFace(side.getOpposite()),
BooleanBiFunction.OR
);
}
// determine if side needs to be rendered
return VoxelShapes.matchesAnywhere(self_shape, other_shape, BooleanBiFunction.ONLY_FIRST);
}
BlockState self_theme = self.getTheme(theme_index);
// other is normal Block
if (other == null && self_state.getBlock() instanceof ReFramedBlock self_block) {
// Transparent is simple if self and the neighbor are invisible don't render side (like default)
if (self_theme.isSideInvisible(other_state, side)) return false;
// Opaque is also simple as each model are rendered one by one
if (other_state.isOpaque()) {
// no cache section :( because it differs between each instance of the frame
VoxelShape self_shape = self_block.getShape(self_state, theme_index).getFace(side);
if (self_shape.isEmpty()) return true;
VoxelShape other_shape = other_state.getCullingFace(world, other_pos, side.getOpposite());
// determine if side needs to be rendered
return VoxelShapes.matchesAnywhere(self_shape, other_shape, BooleanBiFunction.ONLY_FIRST);
}
return true;
}
// Both are frames
// here both are computed in the same zone as there will necessarily a shape comparison
if (self_state.getBlock() instanceof ReFramedBlock self_block && other_state.getBlock() instanceof ReFramedBlock other_block) {
VoxelShape self_shape = self_block.getShape(self_state, theme_index).getFace(side);
if (self_shape.isEmpty()) return true;
int i = 0;
VoxelShape other_shape = VoxelShapes.empty();
for (BlockState s: other.getThemes()) {
i++;
if (self_theme.isSideInvisible(s, side) || s.isOpaque())
other_shape = combine(
other_shape,
other_block
.getShape(other_state, i)
.getFace(side.getOpposite()),
BooleanBiFunction.OR
);
}
// determine if side needs to be rendered
return VoxelShapes.matchesAnywhere(self_shape, other_shape, BooleanBiFunction.ONLY_FIRST);
}
return true;
}
}

View File

@@ -0,0 +1,22 @@
package fr.adrien1106.reframed.compat;
import me.pepperbell.continuity.client.model.QuadProcessors;
import me.pepperbell.continuity.impl.client.ProcessingContextImpl;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.minecraft.block.BlockState;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.BlockRenderView;
import java.util.function.Function;
import java.util.function.Supplier;
public interface ICTMQuadTransform extends RenderContext.QuadTransform {
void invokePrepare(BlockRenderView view, BlockState state, BlockPos pos, Supplier<Random> random, boolean manual_culling, Function<Sprite, QuadProcessors.Slice> slice);
ProcessingContextImpl getProcessingContext();
void invokeReset();
}

View File

@@ -12,10 +12,10 @@ import net.minecraft.util.math.random.Random;
import java.util.List;
import java.util.Map;
public class RebakedAthenaModel implements BakedModel {
public class RebakedModel implements BakedModel {
protected final Map<Direction, List<BakedQuad>> face_quads;
public RebakedAthenaModel(Map<Direction, List<BakedQuad>> face_quads) {
public RebakedModel(Map<Direction, List<BakedQuad>> face_quads) {
this.face_quads = face_quads;
}
@@ -26,7 +26,7 @@ public class RebakedAthenaModel implements BakedModel {
@Override
public boolean useAmbientOcclusion() {
return false;
return true;
}
@Override
@@ -51,11 +51,11 @@ public class RebakedAthenaModel implements BakedModel {
@Override
public ModelTransformation getTransformation() {
return null;
return ModelTransformation.NONE;
}
@Override
public ModelOverrideList getOverrides() {
return null;
return ModelOverrideList.EMPTY;
}
}

View File

@@ -1,7 +1,8 @@
package fr.adrien1106.reframed.generator;
import net.minecraft.block.Block;
import net.minecraft.data.client.BlockStateSupplier;
public interface BlockStateProvider {
BlockStateSupplier getMultipart();
BlockStateSupplier getMultipart(Block block);
}

View File

@@ -1,14 +1,23 @@
package fr.adrien1106.reframed.generator;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.block.*;
import fr.adrien1106.reframed.generator.block.*;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider.BlockTagProvider;
import net.minecraft.block.Block;
import net.minecraft.registry.RegistryWrapper.WrapperLookup;
import net.minecraft.registry.tag.BlockTags;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class GBlockTag extends BlockTagProvider {
private static final Map<Class<? extends Block>, TagGetter> providers = new HashMap<>();
static {
providers.put(ReframedWallBlock.class, new Wall());
}
public GBlockTag(FabricDataOutput output, CompletableFuture<WrapperLookup> registries) {
super(output, registries);
@@ -17,6 +26,10 @@ public class GBlockTag extends BlockTagProvider {
@Override
protected void configure(WrapperLookup arg) {
FabricTagBuilder builder = getOrCreateTagBuilder(BlockTags.AXE_MINEABLE);
ReFramed.BLOCKS.forEach(builder::add);
ReFramed.BLOCKS.forEach((block) -> {
if (providers.containsKey(block.getClass()))
providers.get(block.getClass()).getTags().forEach((tag) -> getOrCreateTagBuilder(tag).add(block));
builder.add(block);
});
}
}

View File

@@ -1,17 +1,39 @@
package fr.adrien1106.reframed.generator;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.block.*;
import fr.adrien1106.reframed.generator.block.*;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.*;
import net.minecraft.state.property.Property;
import net.minecraft.util.Identifier;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import static net.minecraft.data.client.VariantSettings.Rotation.R0;
public class GBlockstate extends FabricModelProvider {
private static final Map<Class<? extends Block>, BlockStateProvider> providers = new HashMap<>();
static {
providers.put(ReFramedHalfStairBlock.class, new HalfStair());
providers.put(ReFramedHalfStairsSlabBlock.class, new HalfStairsSlab());
providers.put(ReFramedHalfStairsStairBlock.class, new HalfStairsStair());
providers.put(ReFramedLayerBlock.class, new Layer());
providers.put(ReFramedPillarBlock.class, new Pillar());
providers.put(ReFramedSlabBlock.class, new Slab());
providers.put(ReFramedSlabsCubeBlock.class, new SlabsCube());
providers.put(ReFramedSmallCubeBlock.class, new SmallCube());
providers.put(ReFramedSmallCubesStepBlock.class, new SmallCubesStep());
providers.put(ReFramedStairBlock.class, new Stair());
providers.put(ReFramedStairsCubeBlock.class, new StairsCube());
providers.put(ReFramedStepBlock.class, new Step());
providers.put(ReFramedStepsSlabBlock.class, new StepsSlab());
providers.put(ReframedWallBlock.class, new Wall());
}
public GBlockstate(FabricDataOutput output) {
super(output);
@@ -23,7 +45,7 @@ public class GBlockstate extends FabricModelProvider {
.forEach(model_generator::excludeFromSimpleItemModelGeneration);
ReFramed.BLOCKS.stream()
.map(block -> {
if (block instanceof BlockStateProvider multipart_block) return multipart_block.getMultipart();
if (providers.containsKey(block.getClass())) return providers.get(block.getClass()).getMultipart(block);
return VariantsBlockStateSupplier.create(
block,
GBlockstate.variant(
@@ -38,7 +60,9 @@ public class GBlockstate extends FabricModelProvider {
}
@Override
public void generateItemModels(ItemModelGenerator itemModelGenerator) {}
public void generateItemModels(ItemModelGenerator model_generator) {
ReFramed.ITEMS.forEach(item -> model_generator.register(item, Models.GENERATED));
}
public static BlockStateVariant variant(Identifier model, boolean uv_lock, VariantSettings.Rotation x, VariantSettings.Rotation y) {
BlockStateVariant variant = BlockStateVariant.create().put(VariantSettings.MODEL, model);
@@ -52,11 +76,57 @@ public class GBlockstate extends FabricModelProvider {
return When.create().set(property_1, value_1);
}
public static <T extends Comparable<T>, U extends Comparable<U>> When when(Property<T> property_1, T value_1, Property<U> property_2, U value_2) {
return When.allOf(when(property_1, value_1), when(property_2, value_2));
public static <T extends Comparable<T>,
U extends Comparable<U>> When when(Property<T> property_1, T value_1,
Property<U> property_2, U value_2) {
return When.allOf(
when(property_1, value_1),
when(property_2, value_2)
);
}
public static <T extends Comparable<T>, U extends Comparable<U>, V extends Comparable<V>> When when(Property<T> property_1, T value_1, Property<U> property_2, U value_2, Property<V> property_3, V value_3) {
return When.allOf(when(property_1, value_1), when(property_2, value_2), when(property_3, value_3));
public static <T extends Comparable<T>,
U extends Comparable<U>,
V extends Comparable<V>> When when(Property<T> property_1, T value_1,
Property<U> property_2, U value_2,
Property<V> property_3, V value_3) {
return When.allOf(
when(property_1, value_1),
when(property_2, value_2),
when(property_3, value_3)
);
}
public static <T extends Comparable<T>,
U extends Comparable<U>,
V extends Comparable<V>,
W extends Comparable<W>> When when(Property<T> property_1, T value_1,
Property<U> property_2, U value_2,
Property<V> property_3, V value_3,
Property<W> property_4, W value_4) {
return When.allOf(
when(property_1, value_1),
when(property_2, value_2),
when(property_3, value_3),
when(property_4, value_4)
);
}
public static <T extends Comparable<T>,
U extends Comparable<U>,
V extends Comparable<V>,
W extends Comparable<W>,
X extends Comparable<X>> When when(Property<T> property_1, T value_1,
Property<U> property_2, U value_2,
Property<V> property_3, V value_3,
Property<W> property_4, W value_4,
Property<X> property_5, X value_5) {
return When.allOf(
when(property_1, value_1),
when(property_2, value_2),
when(property_3, value_3),
when(property_4, value_4),
when(property_5, value_5)
);
}
}

View File

@@ -18,6 +18,7 @@ public class GLanguage extends FabricLanguageProvider {
builder.add(Registries.ITEM_GROUP.getKey(ReFramed.ITEM_GROUP).get(), "Frames");
builder.add("advancements.reframed.description", "Get all the frame types.");
ReFramed.BLOCKS.forEach(block -> builder.add(block, beautify(Registries.BLOCK.getId(block).getPath()) + " Frame"));
ReFramed.ITEMS.forEach(block -> builder.add(block, beautify(Registries.ITEM.getId(block).getPath())));
}
private static String beautify(String name) {

View File

@@ -1,11 +1,45 @@
package fr.adrien1106.reframed.generator;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.block.*;
import fr.adrien1106.reframed.generator.block.*;
import fr.adrien1106.reframed.generator.item.Blueprint;
import fr.adrien1106.reframed.generator.item.Hammer;
import fr.adrien1106.reframed.generator.item.Screwdriver;
import fr.adrien1106.reframed.item.ReFramedBlueprintItem;
import fr.adrien1106.reframed.item.ReFramedHammerItem;
import fr.adrien1106.reframed.item.ReFramedScrewdriverItem;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.item.ItemConvertible;
import java.util.HashMap;
import java.util.Map;
public class GRecipe extends FabricRecipeProvider {
private static final Map<Class<? extends ItemConvertible>, RecipeSetter> providers = new HashMap<>();
static {
providers.put(ReFramedBlock.class, new Cube());
providers.put(ReFramedHalfStairBlock.class, new HalfStair());
providers.put(ReFramedHalfStairsSlabBlock.class, new HalfStairsSlab());
providers.put(ReFramedHalfStairsStairBlock.class, new HalfStairsStair());
providers.put(ReFramedLayerBlock.class, new Layer());
providers.put(ReFramedPillarBlock.class, new Pillar());
providers.put(ReFramedSlabBlock.class, new Slab());
providers.put(ReFramedSlabsCubeBlock.class, new SlabsCube());
providers.put(ReFramedSmallCubeBlock.class, new SmallCube());
providers.put(ReFramedSmallCubesStepBlock.class, new SmallCubesStep());
providers.put(ReFramedStairBlock.class, new Stair());
providers.put(ReFramedStairsCubeBlock.class, new StairsCube());
providers.put(ReFramedStepBlock.class, new Step());
providers.put(ReFramedStepsSlabBlock.class, new StepsSlab());
providers.put(ReframedWallBlock.class, new Wall());
providers.put(ReFramedBlueprintItem.class, new Blueprint());
providers.put(ReFramedHammerItem.class, new Hammer());
providers.put(ReFramedScrewdriverItem.class, new Screwdriver());
}
public GRecipe(FabricDataOutput output) {
super(output);
}
@@ -13,7 +47,10 @@ public class GRecipe extends FabricRecipeProvider {
@Override
public void generate(RecipeExporter exporter) {
ReFramed.BLOCKS.forEach(block -> {
if (block instanceof RecipeSetter provider) provider.setRecipe(exporter);
if (providers.containsKey(block.getClass())) providers.get(block.getClass()).setRecipe(exporter, block);
});
ReFramed.ITEMS.forEach(item -> {
if (providers.containsKey(item.getClass())) providers.get(item.getClass()).setRecipe(exporter, item);
});
}
}

View File

@@ -1,8 +1,9 @@
package fr.adrien1106.reframed.generator;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.item.ItemConvertible;
public interface RecipeSetter {
void setRecipe(RecipeExporter exporter);
void setRecipe(RecipeExporter exporter, ItemConvertible convertible);
}

View File

@@ -0,0 +1,11 @@
package fr.adrien1106.reframed.generator;
import net.minecraft.block.Block;
import net.minecraft.registry.tag.TagKey;
import java.util.List;
public interface TagGetter {
List<TagKey<Block>> getTags();
}

View File

@@ -0,0 +1,26 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.Items;
import net.minecraft.recipe.book.RecipeCategory;
public class Cube implements RecipeSetter {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
ShapedRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
.pattern("III")
.pattern("I~I")
.pattern("III")
.input('I', Items.BAMBOO)
.input('~', Items.STRING)
.criterion(FabricRecipeProvider.hasItem(Items.BAMBOO), FabricRecipeProvider.conditionsFromItem(Items.BAMBOO))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
}

View File

@@ -0,0 +1,106 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.util.Identifier;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER_FACE;
import static fr.adrien1106.reframed.util.blocks.Corner.*;
import static fr.adrien1106.reframed.util.blocks.Corner.NORTH_EAST_UP;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
public class HalfStair implements RecipeSetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 2);
ShapedRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 4)
.pattern("I ")
.pattern("II")
.input('I', ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public BlockStateSupplier getMultipart(Block block) {
return getMultipart(
block,
ReFramed.id("half_stair_down_special"),
ReFramed.id("half_stair_side_special")
);
}
public static BlockStateSupplier getMultipart(Block block, Identifier model_down, Identifier model_side) {
return MultipartBlockStateSupplier.create(block)
.with(GBlockstate.when(CORNER, NORTH_EAST_DOWN, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R0, R0))
.with(GBlockstate.when(CORNER, NORTH_EAST_DOWN, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R90, R270))
.with(GBlockstate.when(CORNER, NORTH_EAST_DOWN, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R0, R0))
.with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R0, R90))
.with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R90, R0))
.with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R0, R90))
.with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R0, R180))
.with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R90, R90))
.with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R0, R180))
.with(GBlockstate.when(CORNER, WEST_NORTH_DOWN, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R0, R270))
.with(GBlockstate.when(CORNER, WEST_NORTH_DOWN, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R90, R180))
.with(GBlockstate.when(CORNER, WEST_NORTH_DOWN, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R0, R270))
.with(GBlockstate.when(CORNER, EAST_SOUTH_UP, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R180, R0))
.with(GBlockstate.when(CORNER, EAST_SOUTH_UP, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R270, R90))
.with(GBlockstate.when(CORNER, EAST_SOUTH_UP, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R180, R0))
.with(GBlockstate.when(CORNER, SOUTH_WEST_UP, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R180, R90))
.with(GBlockstate.when(CORNER, SOUTH_WEST_UP, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R270, R180))
.with(GBlockstate.when(CORNER, SOUTH_WEST_UP, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R180, R90))
.with(GBlockstate.when(CORNER, WEST_NORTH_UP, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R180, R180))
.with(GBlockstate.when(CORNER, WEST_NORTH_UP, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R270, R270))
.with(GBlockstate.when(CORNER, WEST_NORTH_UP, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R180, R180))
.with(GBlockstate.when(CORNER, NORTH_EAST_UP, CORNER_FACE, 0),
GBlockstate.variant(model_side, true, R180, R270))
.with(GBlockstate.when(CORNER, NORTH_EAST_UP, CORNER_FACE, 1),
GBlockstate.variant(model_side, true, R270, R0))
.with(GBlockstate.when(CORNER, NORTH_EAST_UP, CORNER_FACE, 2),
GBlockstate.variant(model_down, true, R180, R270));
}
}

View File

@@ -0,0 +1,37 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
public class HalfStairsSlab implements RecipeSetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 2);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
.input(ReFramed.HALF_STAIR)
.input(ReFramed.SMALL_CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public BlockStateSupplier getMultipart(Block block) {
return HalfStair.getMultipart(
block,
ReFramed.id("half_stairs_slab_down_special"),
ReFramed.id("half_stairs_slab_side_special")
);
}
}

View File

@@ -0,0 +1,70 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.util.Identifier;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
import static fr.adrien1106.reframed.util.blocks.Edge.*;
import static fr.adrien1106.reframed.util.blocks.Edge.WEST_DOWN;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
public class HalfStairsStair implements RecipeSetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 2);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
.input(ReFramed.HALF_STAIR, 2)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public BlockStateSupplier getMultipart(Block block) {
Identifier model_id = ReFramed.id("half_stairs_stair_down_special");
Identifier side_model_id = ReFramed.id("half_stairs_stair_side_special");
Identifier reverse_model_id = ReFramed.id("half_stairs_stair_reverse_special");
return MultipartBlockStateSupplier.create(block)
/* X AXIS */
.with(GBlockstate.when(EDGE, NORTH_DOWN),
GBlockstate.variant(side_model_id, true, R90, R180))
.with(GBlockstate.when(EDGE, DOWN_SOUTH),
GBlockstate.variant(side_model_id, true, R0, R180))
.with(GBlockstate.when(EDGE, SOUTH_UP),
GBlockstate.variant(side_model_id, true, R270, R180))
.with(GBlockstate.when(EDGE, UP_NORTH),
GBlockstate.variant(side_model_id, true, R180, R180))
/* Y AXIS */
.with(GBlockstate.when(EDGE, NORTH_EAST),
GBlockstate.variant(model_id, true, R0, R0))
.with(GBlockstate.when(EDGE, EAST_SOUTH),
GBlockstate.variant(model_id, true, R0, R90))
.with(GBlockstate.when(EDGE, SOUTH_WEST),
GBlockstate.variant(model_id, true, R0, R180))
.with(GBlockstate.when(EDGE, WEST_NORTH),
GBlockstate.variant(model_id, true, R0, R270))
/* Z AXIS */
.with(GBlockstate.when(EDGE, DOWN_EAST),
GBlockstate.variant(reverse_model_id, true, R0, R90))
.with(GBlockstate.when(EDGE, EAST_UP),
GBlockstate.variant(side_model_id, true, R180, R270))
.with(GBlockstate.when(EDGE, UP_WEST),
GBlockstate.variant(reverse_model_id, true, R180, R90))
.with(GBlockstate.when(EDGE, WEST_DOWN),
GBlockstate.variant(side_model_id, true, R0, R270));
}
}

View File

@@ -0,0 +1,58 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
import static net.minecraft.state.property.Properties.FACING;
import static net.minecraft.state.property.Properties.LAYERS;
public class Layer implements RecipeSetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 8);
ShapedRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 16)
.pattern("II")
.input('I', ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public MultipartBlockStateSupplier getMultipart(Block block) {
String model_pattern = "layer_x_special";
MultipartBlockStateSupplier supplier = MultipartBlockStateSupplier.create(block);
for (int i = 1; i <= 8; i++) {
Identifier model = ReFramed.id(model_pattern.replace("x", i + ""));
supplier
.with(GBlockstate.when(FACING, Direction.DOWN, LAYERS, i),
GBlockstate.variant(model, true, R0, R0))
.with(GBlockstate.when(FACING, Direction.SOUTH, LAYERS, i),
GBlockstate.variant(model, true, R90, R0))
.with(GBlockstate.when(FACING, Direction.UP, LAYERS, i),
GBlockstate.variant(model, true, R180, R0))
.with(GBlockstate.when(FACING, Direction.NORTH, LAYERS, i),
GBlockstate.variant(model, true, R270, R0))
.with(GBlockstate.when(FACING, Direction.WEST, LAYERS, i),
GBlockstate.variant(model, true, R90, R90))
.with(GBlockstate.when(FACING, Direction.EAST, LAYERS, i),
GBlockstate.variant(model, true, R90, R270));
}
return supplier;
}
}

View File

@@ -0,0 +1,49 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import static net.minecraft.data.client.VariantSettings.Rotation.R0;
import static net.minecraft.data.client.VariantSettings.Rotation.R90;
import static net.minecraft.state.property.Properties.AXIS;
public class Pillar implements RecipeSetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 4);
ShapedRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 8)
.pattern("I")
.pattern("I")
.input('I', ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public BlockStateSupplier getMultipart(Block block) {
Identifier model_id = ReFramed.id("pillar_special");
return MultipartBlockStateSupplier.create(block)
.with(GBlockstate.when(AXIS, Direction.Axis.X),
GBlockstate.variant(model_id, true, R90, R90))
.with(GBlockstate.when(AXIS, Direction.Axis.Y),
GBlockstate.variant(model_id, true, R0, R0))
.with(GBlockstate.when(AXIS, Direction.Axis.Z),
GBlockstate.variant(model_id, true, R90, R0));
}
}

View File

@@ -0,0 +1,52 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
import static net.minecraft.state.property.Properties.FACING;
public class Slab implements RecipeSetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 2);
ShapedRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 6)
.pattern("III")
.input('I', ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public MultipartBlockStateSupplier getMultipart(Block block) {
Identifier model_id = ReFramed.id("slab_special");
return MultipartBlockStateSupplier.create(block)
.with(GBlockstate.when(FACING, Direction.DOWN),
GBlockstate.variant(model_id, true, R0, R0))
.with(GBlockstate.when(FACING, Direction.SOUTH),
GBlockstate.variant(model_id, true, R90, R0))
.with(GBlockstate.when(FACING, Direction.UP),
GBlockstate.variant(model_id, true, R180, R0))
.with(GBlockstate.when(FACING, Direction.NORTH),
GBlockstate.variant(model_id, true, R270, R0))
.with(GBlockstate.when(FACING, Direction.WEST),
GBlockstate.variant(model_id, true, R90, R90))
.with(GBlockstate.when(FACING, Direction.EAST),
GBlockstate.variant(model_id, true, R90, R270));
}
}

View File

@@ -0,0 +1,46 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
import static net.minecraft.data.client.VariantSettings.Rotation.R90;
import static net.minecraft.state.property.Properties.AXIS;
public class SlabsCube implements RecipeSetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
.input(ReFramed.SLAB, 2)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public MultipartBlockStateSupplier getMultipart(Block block) {
Identifier model_id = ReFramed.id("double_slab_special");
return MultipartBlockStateSupplier.create(block)
.with(GBlockstate.when(AXIS, Direction.Axis.Y),
GBlockstate.variant(model_id, true, R0, R0))
.with(GBlockstate.when(AXIS, Direction.Axis.Z),
GBlockstate.variant(model_id, true, R270, R0))
.with(GBlockstate.when(AXIS, Direction.Axis.X),
GBlockstate.variant(model_id, true, R90, R90));
}
}

View File

@@ -0,0 +1,57 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.util.Identifier;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER;
import static fr.adrien1106.reframed.util.blocks.Corner.*;
import static fr.adrien1106.reframed.util.blocks.Corner.NORTH_EAST_UP;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
public class SmallCube implements RecipeSetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 8);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 8)
.input(ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public BlockStateSupplier getMultipart(Block block) {
Identifier small_cube_id = ReFramed.id("small_cube_special");
return MultipartBlockStateSupplier.create(block)
.with(GBlockstate.when(CORNER, NORTH_EAST_DOWN),
GBlockstate.variant(small_cube_id, true, R0, R0))
.with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN),
GBlockstate.variant(small_cube_id, true, R0, R90))
.with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN),
GBlockstate.variant(small_cube_id, true, R0, R180))
.with(GBlockstate.when(CORNER, WEST_NORTH_DOWN),
GBlockstate.variant(small_cube_id, true, R0, R270))
.with(GBlockstate.when(CORNER, EAST_SOUTH_UP),
GBlockstate.variant(small_cube_id, true, R180, R0))
.with(GBlockstate.when(CORNER, SOUTH_WEST_UP),
GBlockstate.variant(small_cube_id, true, R180, R90))
.with(GBlockstate.when(CORNER, WEST_NORTH_UP),
GBlockstate.variant(small_cube_id, true, R180, R180))
.with(GBlockstate.when(CORNER, NORTH_EAST_UP),
GBlockstate.variant(small_cube_id, true, R180, R270));
}
}

View File

@@ -0,0 +1,69 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.util.Identifier;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
import static fr.adrien1106.reframed.util.blocks.Edge.*;
import static fr.adrien1106.reframed.util.blocks.Edge.SOUTH_UP;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
public class SmallCubesStep implements RecipeSetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 4);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
.input(ReFramed.SMALL_CUBE, 2)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public BlockStateSupplier getMultipart(Block block) {
Identifier model_id = ReFramed.id("small_cubes_step_special");
Identifier reverse_model_id = ReFramed.id("small_cubes_step_reverse_special");
return MultipartBlockStateSupplier.create(block)
/* X AXIS */
.with(GBlockstate.when(EDGE, DOWN_EAST),
GBlockstate.variant(model_id, true, R0, R0))
.with(GBlockstate.when(EDGE, EAST_UP),
GBlockstate.variant(reverse_model_id, true, R180, R0))
.with(GBlockstate.when(EDGE, UP_WEST),
GBlockstate.variant(model_id, true, R180, R180))
.with(GBlockstate.when(EDGE, WEST_DOWN),
GBlockstate.variant(reverse_model_id, true, R0, R180))
/* Y AXIS */
.with(GBlockstate.when(EDGE, EAST_SOUTH),
GBlockstate.variant(model_id, true, R90, R0))
.with(GBlockstate.when(EDGE, SOUTH_WEST),
GBlockstate.variant(model_id, true, R90, R90))
.with(GBlockstate.when(EDGE, WEST_NORTH),
GBlockstate.variant(model_id, true, R90, R180))
.with(GBlockstate.when(EDGE, NORTH_EAST),
GBlockstate.variant(model_id, true, R90, R270))
/* Z AXIS */
.with(GBlockstate.when(EDGE, DOWN_SOUTH),
GBlockstate.variant(reverse_model_id, true, R0, R90))
.with(GBlockstate.when(EDGE, NORTH_DOWN),
GBlockstate.variant(model_id, true, R0, R270))
.with(GBlockstate.when(EDGE, UP_NORTH),
GBlockstate.variant(reverse_model_id, true, R180, R270))
.with(GBlockstate.when(EDGE, SOUTH_UP),
GBlockstate.variant(model_id, true, R180, R90));
}
}

View File

@@ -0,0 +1,267 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.client.When;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.util.Identifier;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.STAIR_SHAPE;
import static fr.adrien1106.reframed.util.blocks.Edge.*;
import static fr.adrien1106.reframed.util.blocks.StairShape.*;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
public class Stair implements RecipeSetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE);
ShapedRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 4)
.pattern("I ")
.pattern("II ")
.pattern("III")
.input('I', ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public MultipartBlockStateSupplier getMultipart(Block block) {
return getMultipart(block, false);
}
public static MultipartBlockStateSupplier getMultipart(Block block, boolean is_double) {
String infix = is_double ? "s_cube" : "";
Identifier straight_id = ReFramed.id("stair" + infix + "_special");
Identifier double_outer_id = ReFramed.id("outers_stair" + infix + "_special");
Identifier inner_id = ReFramed.id("inner_stair" + infix + "_special");
Identifier outer_id = ReFramed.id("outer_stair" + infix + "_special");
Identifier outer_side_id = ReFramed.id("outer_side_stair" + infix + "_special");
return MultipartBlockStateSupplier.create(block)
/* STRAIGHT X AXIS */
.with(GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R0, R0))
.with(GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R180, R0))
.with(GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R180, R180))
.with(GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R0, R180))
/* STRAIGHT Y AXIS */
.with(GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R90, R0))
.with(GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R90, R90))
.with(GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R90, R180))
.with(GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R90, R270))
/* STRAIGHT Z AXIS */
.with(GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R0, R90))
.with(GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R0, R270))
.with(GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R180, R270))
.with(GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, STRAIGHT),
GBlockstate.variant(straight_id, true, R180, R90))
/* INNER BOTTOM */
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, INNER_RIGHT)),
GBlockstate.variant(inner_id, true, R0, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, INNER_RIGHT)),
GBlockstate.variant(inner_id, true, R0, R270))
.with(When.anyOf(
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, INNER_LEFT)),
GBlockstate.variant(inner_id, true, R0, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, INNER_LEFT)),
GBlockstate.variant(inner_id, true, R0, R90))
/* INNER TOP */
.with(When.anyOf(
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, INNER_LEFT)),
GBlockstate.variant(inner_id, true, R180, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, INNER_LEFT)),
GBlockstate.variant(inner_id, true, R180, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, INNER_LEFT)),
GBlockstate.variant(inner_id, true, R180, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, INNER_RIGHT),
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, INNER_LEFT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, INNER_RIGHT)),
GBlockstate.variant(inner_id, true, R180, R270))
/* OUTER BOTTOM */
.with(When.anyOf(
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_LEFT)),
GBlockstate.variant(outer_id, true, R0, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_LEFT)),
GBlockstate.variant(outer_id, true, R0, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, FIRST_OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
GBlockstate.variant(outer_id, true, R0, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, FIRST_OUTER_LEFT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
GBlockstate.variant(outer_id, true, R0, R270))
/* OUTER TOP */
.with(When.anyOf(
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
GBlockstate.variant(outer_id, true, R180, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, FIRST_OUTER_LEFT),
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, FIRST_OUTER_LEFT)),
GBlockstate.variant(outer_id, true, R180, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, FIRST_OUTER_RIGHT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, SECOND_OUTER_LEFT)),
GBlockstate.variant(outer_id, true, R180, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
GBlockstate.variant(outer_id, true, R180, R270))
/* OUTER EAST */
.with(When.anyOf(
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R0, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, SECOND_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R90, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, FIRST_OUTER_LEFT),
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R180, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, FIRST_OUTER_RIGHT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R270, R0))
/* OUTER SOUTH */
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, SECOND_OUTER_RIGHT),
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R0, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, SECOND_OUTER_LEFT),
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R90, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, FIRST_OUTER_LEFT),
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, SECOND_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R180, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, FIRST_OUTER_RIGHT),
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, FIRST_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R270, R90))
/* OUTER WEST */
.with(When.anyOf(
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, SECOND_OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R0, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, SECOND_OUTER_LEFT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R90, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, FIRST_OUTER_LEFT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, FIRST_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R180, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, FIRST_OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R270, R180))
/* OUTER NORTH */
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, SECOND_OUTER_RIGHT),
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, SECOND_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R0, R270))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, SECOND_OUTER_LEFT),
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, FIRST_OUTER_LEFT)),
GBlockstate.variant(outer_side_id, true, R90, R270))
.with(When.anyOf(
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, FIRST_OUTER_LEFT),
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, FIRST_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R180, R270))
.with(When.anyOf(
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, FIRST_OUTER_RIGHT),
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, SECOND_OUTER_RIGHT)),
GBlockstate.variant(outer_side_id, true, R270, R270))
/* OUTER BOTTOM */
.with(When.anyOf(
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, OUTER_RIGHT)),
GBlockstate.variant(double_outer_id, true, R0, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, OUTER_RIGHT)),
GBlockstate.variant(double_outer_id, true, R0, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, OUTER_RIGHT)),
GBlockstate.variant(double_outer_id, true, R0, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, OUTER_RIGHT)),
GBlockstate.variant(double_outer_id, true, R0, R270))
/* OUTER TOP */
.with(When.anyOf(
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, OUTER_LEFT)),
GBlockstate.variant(double_outer_id, true, R180, R0))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, OUTER_LEFT)),
GBlockstate.variant(double_outer_id, true, R180, R90))
.with(When.anyOf(
GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, OUTER_LEFT),
GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, OUTER_LEFT)),
GBlockstate.variant(double_outer_id, true, R180, R180))
.with(When.anyOf(
GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, OUTER_RIGHT),
GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, OUTER_LEFT)),
GBlockstate.variant(double_outer_id, true, R180, R270));
}
}

View File

@@ -0,0 +1,33 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
public class StairsCube implements RecipeSetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
.input(ReFramed.STAIR)
.input(ReFramed.STEP)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public MultipartBlockStateSupplier getMultipart(Block block) {
return Stair.getMultipart(block, true);
}
}

View File

@@ -0,0 +1,69 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.util.Identifier;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
import static fr.adrien1106.reframed.util.blocks.Edge.*;
import static fr.adrien1106.reframed.util.blocks.Edge.SOUTH_UP;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
public class Step implements RecipeSetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 4);
ShapedRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 8)
.pattern("II")
.input('I', ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public BlockStateSupplier getMultipart(Block block) {
Identifier model_id = ReFramed.id("step_special");
return MultipartBlockStateSupplier.create(block)
/* X AXIS */
.with(GBlockstate.when(EDGE, DOWN_EAST),
GBlockstate.variant(model_id, true, R0, R0))
.with(GBlockstate.when(EDGE, EAST_UP),
GBlockstate.variant(model_id, true, R180, R0))
.with(GBlockstate.when(EDGE, UP_WEST),
GBlockstate.variant(model_id, true, R180, R180))
.with(GBlockstate.when(EDGE, WEST_DOWN),
GBlockstate.variant(model_id, true, R0, R180))
/* Y AXIS */
.with(GBlockstate.when(EDGE, EAST_SOUTH),
GBlockstate.variant(model_id, true, R90, R0))
.with(GBlockstate.when(EDGE, SOUTH_WEST),
GBlockstate.variant(model_id, true, R90, R90))
.with(GBlockstate.when(EDGE, WEST_NORTH),
GBlockstate.variant(model_id, true, R90, R180))
.with(GBlockstate.when(EDGE, NORTH_EAST),
GBlockstate.variant(model_id, true, R90, R270))
/* Z AXIS */
.with(GBlockstate.when(EDGE, DOWN_SOUTH),
GBlockstate.variant(model_id, true, R0, R90))
.with(GBlockstate.when(EDGE, NORTH_DOWN),
GBlockstate.variant(model_id, true, R0, R270))
.with(GBlockstate.when(EDGE, UP_NORTH),
GBlockstate.variant(model_id, true, R180, R270))
.with(GBlockstate.when(EDGE, SOUTH_UP),
GBlockstate.variant(model_id, true, R180, R90));
}
}

View File

@@ -0,0 +1,66 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
import static net.minecraft.data.client.VariantSettings.Rotation.R270;
import static net.minecraft.state.property.Properties.AXIS;
import static net.minecraft.state.property.Properties.FACING;
public class StepsSlab implements RecipeSetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 2);
ShapelessRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible)
.input(ReFramed.STEP, 2)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public MultipartBlockStateSupplier getMultipart(Block block) {
Identifier step_id = ReFramed.id("steps_slab_special");
Identifier step_side_id = ReFramed.id("steps_slab_side_special");
return MultipartBlockStateSupplier.create(block)
.with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Direction.Axis.X),
GBlockstate.variant(step_id, true, R0, R180))
.with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Direction.Axis.Z),
GBlockstate.variant(step_id, true, R0, R270))
.with(GBlockstate.when(FACING, Direction.UP, AXIS, Direction.Axis.X),
GBlockstate.variant(step_id, true, R180, R180))
.with(GBlockstate.when(FACING, Direction.UP, AXIS, Direction.Axis.Z),
GBlockstate.variant(step_id, true, R180, R270))
.with(GBlockstate.when(FACING, Direction.EAST, AXIS, Direction.Axis.Z),
GBlockstate.variant(step_side_id, true, R0, R0))
.with(GBlockstate.when(FACING, Direction.EAST, AXIS, Direction.Axis.Y),
GBlockstate.variant(step_side_id, true, R90, R0))
.with(GBlockstate.when(FACING, Direction.SOUTH, AXIS, Direction.Axis.X),
GBlockstate.variant(step_side_id, true, R180, R90))
.with(GBlockstate.when(FACING, Direction.SOUTH, AXIS, Direction.Axis.Y),
GBlockstate.variant(step_side_id, true, R90, R90))
.with(GBlockstate.when(FACING, Direction.WEST, AXIS, Direction.Axis.Z),
GBlockstate.variant(step_side_id, true, R180, R180))
.with(GBlockstate.when(FACING, Direction.WEST, AXIS, Direction.Axis.Y),
GBlockstate.variant(step_side_id, true, R90, R180))
.with(GBlockstate.when(FACING, Direction.NORTH, AXIS, Direction.Axis.X),
GBlockstate.variant(step_side_id, true, R0, R270))
.with(GBlockstate.when(FACING, Direction.NORTH, AXIS, Direction.Axis.Y),
GBlockstate.variant(step_side_id, true, R90, R270));
}
}

View File

@@ -0,0 +1,788 @@
package fr.adrien1106.reframed.generator.block;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.BlockStateProvider;
import fr.adrien1106.reframed.generator.GBlockstate;
import fr.adrien1106.reframed.generator.RecipeSetter;
import fr.adrien1106.reframed.generator.TagGetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.client.BlockStateSupplier;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.registry.tag.BlockTags;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
import java.util.List;
import static net.minecraft.block.enums.WallShape.*;
import static net.minecraft.data.client.VariantSettings.Rotation.*;
import static net.minecraft.state.property.Properties.*;
public class Wall implements RecipeSetter, TagGetter, BlockStateProvider {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 1);
ShapedRecipeJsonBuilder
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 4)
.pattern("III")
.pattern("III")
.input('I', ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
@Override
public List<TagKey<Block>> getTags() {
return List.of(BlockTags.WALLS);
}
@Override
public BlockStateSupplier getMultipart(Block block) {
Identifier
side_low = ReFramed.id("wall_side_low_special"),
side_tall = ReFramed.id("wall_side_tall_special"),
pillar_low = ReFramed.id("wall_pillar_low_special"),
pillar_tall = ReFramed.id("wall_pillar_tall_special"),
pillar_none = ReFramed.id("wall_pillar_none_special"),
low_e = ReFramed.id("wall_low_e_special"),
tall_e = ReFramed.id("wall_tall_e_special"),
low_i = ReFramed.id("wall_low_i_special"),
tall_i = ReFramed.id("wall_tall_i_special"),
low_tall_i = ReFramed.id("wall_low_tall_i_special"),
low_c = ReFramed.id("wall_low_c_special"),
tall_c = ReFramed.id("wall_tall_c_special"),
low_tall_c = ReFramed.id("wall_low_tall_c_special"),
tall_low_c = ReFramed.id("wall_tall_low_c_special"),
low_t = ReFramed.id("wall_low_t_special"),
tall_t = ReFramed.id("wall_tall_t_special"),
tall_low_c_t = ReFramed.id("wall_tall_low_c_t_special"),
tall_i_low_t = ReFramed.id("wall_tall_i_low_t_special"),
low_i_tall_t = ReFramed.id("wall_low_i_tall_t_special"),
low_tall_c_t = ReFramed.id("wall_low_tall_c_t_special"),
low_c_tall_t = ReFramed.id("wall_low_c_tall_t_special"),
tall_c_low_t = ReFramed.id("wall_tall_c_low_t_special"),
tall_i_low_i_x = ReFramed.id("wall_tall_i_low_i_x_special"),
tall_low_t_x = ReFramed.id("wall_tall_low_t_x_special"),
tall_c_low_c_x = ReFramed.id("wall_tall_c_low_c_x_special"),
tall_t_low_x = ReFramed.id("wall_tall_t_low_x_special");
return MultipartBlockStateSupplier.create(block)
// PILLAR CORE
.with(GBlockstate.when(UP, true),
GBlockstate.variant(ReFramed.id("wall_core_special"), true, R0, R0))
// LOW
.with(GBlockstate.when(NORTH_WALL_SHAPE, LOW),
GBlockstate.variant(side_low, true, R0, R0))
.with(GBlockstate.when(EAST_WALL_SHAPE, LOW),
GBlockstate.variant(side_low, true, R0, R90))
.with(GBlockstate.when(SOUTH_WALL_SHAPE, LOW),
GBlockstate.variant(side_low, true, R0, R180))
.with(GBlockstate.when(WEST_WALL_SHAPE, LOW),
GBlockstate.variant(side_low, true, R0, R270))
// TALL
.with(GBlockstate.when(NORTH_WALL_SHAPE, TALL),
GBlockstate.variant(side_tall, true, R0, R0))
.with(GBlockstate.when(EAST_WALL_SHAPE, TALL),
GBlockstate.variant(side_tall, true, R0, R90))
.with(GBlockstate.when(SOUTH_WALL_SHAPE, TALL),
GBlockstate.variant(side_tall, true, R0, R180))
.with(GBlockstate.when(WEST_WALL_SHAPE, TALL),
GBlockstate.variant(side_tall, true, R0, R270))
// PILLAR LOW
.with(GBlockstate.when(NORTH_WALL_SHAPE, LOW, UP, true),
GBlockstate.variant(pillar_low, true, R0, R0))
.with(GBlockstate.when(EAST_WALL_SHAPE, LOW, UP, true),
GBlockstate.variant(pillar_low, true, R0, R90))
.with(GBlockstate.when(SOUTH_WALL_SHAPE, LOW, UP, true),
GBlockstate.variant(pillar_low, true, R0, R180))
.with(GBlockstate.when(WEST_WALL_SHAPE, LOW, UP, true),
GBlockstate.variant(pillar_low, true, R0, R270))
// PILLAR TALL
.with(GBlockstate.when(NORTH_WALL_SHAPE, TALL, UP, true),
GBlockstate.variant(pillar_tall, true, R0, R0))
.with(GBlockstate.when(EAST_WALL_SHAPE, TALL, UP, true),
GBlockstate.variant(pillar_tall, true, R0, R90))
.with(GBlockstate.when(SOUTH_WALL_SHAPE, TALL, UP, true),
GBlockstate.variant(pillar_tall, true, R0, R180))
.with(GBlockstate.when(WEST_WALL_SHAPE, TALL, UP, true),
GBlockstate.variant(pillar_tall, true, R0, R270))
// PILLAR NONE
.with(GBlockstate.when(NORTH_WALL_SHAPE, NONE, UP, true),
GBlockstate.variant(pillar_none, true, R0, R0))
.with(GBlockstate.when(EAST_WALL_SHAPE, NONE, UP, true),
GBlockstate.variant(pillar_none, true, R0, R90))
.with(GBlockstate.when(SOUTH_WALL_SHAPE, NONE, UP, true),
GBlockstate.variant(pillar_none, true, R0, R180))
.with(GBlockstate.when(WEST_WALL_SHAPE, NONE, UP, true),
GBlockstate.variant(pillar_none, true, R0, R270))
// JUNCTION LOW
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_e, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_e, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_e, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_e, true, R0, R270))
// JUNCTION TALL
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(tall_e, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(tall_e, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(tall_e, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_e, true, R0, R270))
// JUNCTION LOW I
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_i, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_i, true, R0, R90))
// JUNCTION TALL I
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(tall_i, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_i, true, R0, R90))
// JUNCTION LOW TALL I
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_tall_i, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(low_tall_i, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_tall_i, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_tall_i, true, R0, R270))
// JUNCTION LOW C
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_c, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_c, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_c, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_c, true, R0, R270))
// JUNCTION TALL C
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_c, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(tall_c, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(tall_c, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_c, true, R0, R270))
// JUNCTION LOW TALL C
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(low_tall_c, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_tall_c, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_tall_c, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_tall_c, true, R0, R270))
// JUNCTION TALL LOW C
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(tall_low_c, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(tall_low_c, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(tall_low_c, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_low_c, true, R0, R270))
// JUNCTION LOW T
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_t, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_t, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_t, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_t, true, R0, R270))
// JUNCTION TALL T
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_t, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(tall_t, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_t, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_t, true, R0, R270))
// JUNCTION TALL LOW C T
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(tall_low_c_t, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(tall_low_c_t, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_low_c_t, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(tall_low_c_t, true, R0, R270))
// JUNCTION TALL I LOW T
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_i_low_t, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(tall_i_low_t, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_i_low_t, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(tall_i_low_t, true, R0, R270))
// JUNCTION LOW I TALL T
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_i_tall_t, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_i_tall_t, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_i_tall_t, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(low_i_tall_t, true, R0, R270))
// JUNCTION LOW TALL C T
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(low_tall_c_t, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_tall_c_t, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_tall_c_t, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(low_tall_c_t, true, R0, R270))
// JUNCTION LOW C TALL T
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(low_c_tall_t, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(low_c_tall_t, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_c_tall_t, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(low_c_tall_t, true, R0, R270))
// JUNCTION TALL C LOW T
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, NONE,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(tall_c_low_t, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, NONE,
UP, false
),
GBlockstate.variant(tall_c_low_t, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, NONE,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_c_low_t, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, NONE,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_c_low_t, true, R0, R270))
// JUNCTION X
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(ReFramed.id("wall_low_x_special"), true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(ReFramed.id("wall_tall_x_special"), true, R0, R0))
// JUNCTION I X
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_i_low_i_x, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(tall_i_low_i_x, true, R0, R90))
// JUNCTION TALL LOW T X
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(tall_low_t_x, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(tall_low_t_x, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_low_t_x, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(tall_low_t_x, true, R0, R270))
// JUNCTION TALL C LOW C X
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(tall_c_low_c_x, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(tall_c_low_c_x, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_c_low_c_x, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_c_low_c_x, true, R0, R270))
// JUNCTION TALL C LOW C X
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, LOW,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_t_low_x, true, R0, R0))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, LOW,
UP, false
),
GBlockstate.variant(tall_t_low_x, true, R0, R90))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, LOW,
EAST_WALL_SHAPE, TALL,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_t_low_x, true, R0, R180))
.with(GBlockstate.when(
NORTH_WALL_SHAPE, TALL,
EAST_WALL_SHAPE, LOW,
SOUTH_WALL_SHAPE, TALL,
WEST_WALL_SHAPE, TALL,
UP, false
),
GBlockstate.variant(tall_t_low_x, true, R0, R270));
}
}

View File

@@ -0,0 +1,25 @@
package fr.adrien1106.reframed.generator.item;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.Items;
import net.minecraft.recipe.book.RecipeCategory;
public class Blueprint implements RecipeSetter {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
ShapedRecipeJsonBuilder
.create(RecipeCategory.TOOLS, convertible, 3)
.pattern("PI")
.pattern("PP")
.input('P', Items.PAPER)
.input('I', Items.INK_SAC)
.criterion(FabricRecipeProvider.hasItem(Items.PAPER), FabricRecipeProvider.conditionsFromItem(Items.PAPER))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
}

View File

@@ -0,0 +1,28 @@
package fr.adrien1106.reframed.generator.item;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.Items;
import net.minecraft.recipe.book.RecipeCategory;
public class Hammer implements RecipeSetter {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
ShapedRecipeJsonBuilder
.create(RecipeCategory.TOOLS, convertible)
.pattern(" CI")
.pattern(" ~C")
.pattern("~ ")
.input('I', Items.IRON_INGOT)
.input('C', ReFramed.CUBE)
.input('~', Items.STICK)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
}

View File

@@ -0,0 +1,27 @@
package fr.adrien1106.reframed.generator.item;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.generator.RecipeSetter;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.Items;
import net.minecraft.recipe.book.RecipeCategory;
public class Screwdriver implements RecipeSetter {
@Override
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
ShapedRecipeJsonBuilder
.create(RecipeCategory.TOOLS, convertible)
.pattern(" I")
.pattern(" I ")
.pattern("C ")
.input('I', Items.IRON_INGOT)
.input('C', ReFramed.CUBE)
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
.offerTo(exporter);
}
}

View File

@@ -0,0 +1,36 @@
package fr.adrien1106.reframed.item;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.block.ReFramedEntity;
import net.minecraft.block.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUsageContext;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.ActionResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class ReFramedBlueprintItem extends Item {
public ReFramedBlueprintItem(Settings settings) {
super(settings);
}
@Override
public ActionResult useOnBlock(ItemUsageContext context) {
BlockPos pos = context.getBlockPos();
World world = context.getWorld();
if (!(world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity)
|| frame_entity.getThemes().stream().noneMatch(state -> state.getBlock() != Blocks.AIR)
) return ActionResult.PASS;
context.getStack().decrement(1);
ItemStack stack = ReFramed.BLUEPRINT_WRITTEN.getDefaultStack();
frame_entity.setStackNbt(stack);
context.getPlayer().giveItemStack(stack);
world.playSound(context.getPlayer(), context.getPlayer().getBlockPos(), SoundEvents.ITEM_BOOK_PUT, SoundCategory.PLAYERS);
return ActionResult.SUCCESS;
}
}

View File

@@ -0,0 +1,113 @@
package fr.adrien1106.reframed.item;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.block.ReFramedEntity;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUsageContext;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtHelper;
import net.minecraft.registry.Registries;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Formatting;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static fr.adrien1106.reframed.block.ReFramedEntity.BLOCKSTATE_KEY;
public class ReFramedBlueprintWrittenItem extends Item {
public ReFramedBlueprintWrittenItem(Settings settings) {
super(settings);
}
@Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
ItemStack stack = player.getStackInHand(hand);
if (!player.isSneaking() || !stack.hasNbt()) return super.use(world, player, hand);
stack.decrement(1);
player.giveItemStack(ReFramed.BLUEPRINT.getDefaultStack());
world.playSound(player, player.getBlockPos(), SoundEvents.ITEM_BOOK_PUT, SoundCategory.PLAYERS);
return TypedActionResult.success(stack);
}
@Override
public ActionResult useOnBlock(ItemUsageContext context) {
BlockPos pos = context.getBlockPos();
World world = context.getWorld();
if (!(world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity)
|| frame_entity.getThemes().stream().anyMatch(state -> state.getBlock() != Blocks.AIR)
|| !context.getStack().hasNbt()
) return ActionResult.PASS;
NbtCompound tag = BlockItem.getBlockEntityNbt(context.getStack());
if(tag == null) return ActionResult.FAIL;
PlayerEntity player = context.getPlayer();
if (!player.isCreative()) { // verify player has blocks and remove them
PlayerInventory inventory = player.getInventory();
List<ItemStack> stacks = getBlockStates(tag).values().stream()
.map(AbstractBlock.AbstractBlockState::getBlock)
.map(Block::asItem)
.map(Item::getDefaultStack)
.toList();
if (stacks.stream().anyMatch(stack -> !inventory.contains(stack)))
return ActionResult.FAIL;
stacks.stream().map(inventory::getSlotWithStack).forEach(index -> inventory.removeStack(index, 1));
player.playSound(SoundEvents.ENTITY_ITEM_PICKUP, 0.5f, 0.5f);
}
frame_entity.readNbt(tag);
world.playSound(player, player.getBlockPos(), SoundEvents.ITEM_BOOK_PAGE_TURN, SoundCategory.PLAYERS);
return ActionResult.SUCCESS;
}
@Override
public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> tooltip, TooltipContext context) {
NbtCompound tag = BlockItem.getBlockEntityNbt(stack);
if(tag == null) return;
Map<Integer, BlockState> states = getBlockStates(tag);
states.forEach((index, state) -> tooltip.add(
Text.literal("Theme " + index + ": ")
.append(
Text.translatable(state.getBlock().getTranslationKey())
.formatted(Formatting.GRAY)
)
));
super.appendTooltip(stack, world, tooltip, context);
}
private static Map<Integer, BlockState> getBlockStates(NbtCompound tag) {
return tag.getKeys().stream()
.filter(key ->
key.startsWith(BLOCKSTATE_KEY)
&& key.replace(BLOCKSTATE_KEY,"").chars().allMatch(Character::isDigit)
)
.collect(Collectors.toMap(
key -> Integer.parseInt(key.substring(BLOCKSTATE_KEY.length())),
key -> NbtHelper.toBlockState(
Registries.BLOCK.getReadOnlyWrapper(),
tag.getCompound(key)
)
));
}
}

View File

@@ -0,0 +1,49 @@
package fr.adrien1106.reframed.item;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.block.ReFramedDoubleBlock;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUsageContext;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.ActionResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class ReFramedHammerItem extends Item {
public ReFramedHammerItem(Settings settings) {
super(settings);
}
@Override
public ActionResult useOnBlock(ItemUsageContext context) {
World world = context.getWorld();
BlockPos pos = context.getBlockPos();
if (!(world.getBlockEntity(pos) instanceof ThemeableBlockEntity frame_entity)) return ActionResult.PASS;
BlockState state = world.getBlockState(pos);
PlayerEntity player = context.getPlayer();
int theme_index = state.getBlock() instanceof ReFramedDoubleBlock b
? b.getHitShape(
state,
context.getHitPos(),
context.getBlockPos(),
context.getSide()
)
: 1;
if (frame_entity.getTheme(theme_index).getBlock() == Blocks.AIR) return ActionResult.PASS;
if (!player.isCreative()) {
player.giveItemStack(new ItemStack(frame_entity.getTheme(theme_index).getBlock()));
world.playSound(player, pos, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, 1f, 1.1f);
}
frame_entity.setTheme(Blocks.AIR.getDefaultState(), theme_index);
ReFramed.chunkRerenderProxy.accept(world, pos);
return ActionResult.SUCCESS;
}
}

View File

@@ -0,0 +1,58 @@
package fr.adrien1106.reframed.item;
import fr.adrien1106.reframed.ReFramed;
import fr.adrien1106.reframed.block.ReFramedDoubleBlock;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemUsageContext;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.sound.SoundCategory;
import net.minecraft.state.property.Properties;
import net.minecraft.util.ActionResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
public class ReFramedScrewdriverItem extends Item {
public ReFramedScrewdriverItem(Settings settings) {
super(settings);
}
@Override
public ActionResult useOnBlock(ItemUsageContext context) {
World world = context.getWorld();
BlockPos pos = context.getBlockPos();
if (!(world.getBlockEntity(pos) instanceof ThemeableBlockEntity frame_entity)) return ActionResult.PASS;
BlockState state = world.getBlockState(pos);
PlayerEntity player = context.getPlayer();
int theme_index = state.getBlock() instanceof ReFramedDoubleBlock b
? b.getHitShape(
state,
context.getHitPos(),
context.getBlockPos(),
context.getSide()
)
: 1;
BlockState theme = frame_entity.getTheme(theme_index);
if (!theme.contains(Properties.AXIS)) return ActionResult.PASS;
Direction.Axis axis = theme.get(Properties.AXIS);
BlockSoundGroup group = theme.getSoundGroup();
world.playSound(player, pos, group.getPlaceSound(), SoundCategory.BLOCKS, group.getVolume(), group.getPitch());
frame_entity.setTheme(theme.with(
Properties.AXIS,
switch (axis) {
case X -> Direction.Axis.Y;
case Y -> Direction.Axis.Z;
case Z -> Direction.Axis.X;
}
), theme_index);
ReFramed.chunkRerenderProxy.accept(world, pos);
return ActionResult.SUCCESS;
}
}

View File

@@ -7,6 +7,7 @@ import org.slf4j.LoggerFactory;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -16,24 +17,27 @@ public class CompatMixinPlugin implements IMixinConfigPlugin {
private static final FabricLoader LOADER = FabricLoader.getInstance();
private static final Logger LOGGER = LoggerFactory.getLogger("ReFramed MIXIN");
private static final List<String> COMPAT_MOD = List.of("athena", "indium", "sodium");
private static final Map<String, Supplier<Boolean>> CONDITIONS = Map.of(
"fr.adrien1106.reframed.mixin.compat.AthenaBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(0)),
"fr.adrien1106.reframed.mixin.compat.AthenaWrappedGetterMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(0)),
"fr.adrien1106.reframed.mixin.render.TerrainRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.render.BlockRenderInfoMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.render.AbstractBlockRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.compat.IndiumTerrainRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.compat.IndiumTerrainBlockRenderInfoMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.compat.IndiumAbstractBlockRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.compat.SodiumBlockOcclusionCacheMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2))
);
private static final List<String> COMPAT_MOD = List.of("athena", "indium", "sodium", "special-model-loader", "continuity");
private static final Map<String, Supplier<Boolean>> CONDITIONS = new HashMap<>();
static {
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AthenaBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(0)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AthenaWrappedGetterMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(0)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.render.TerrainRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.render.BlockRenderInfoMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.render.AbstractBlockRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumTerrainRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumTerrainBlockRenderInfoMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumAbstractBlockRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.SodiumBlockOcclusionCacheMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityConnectionPredicateMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityCTMBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityCTMQuadTransformMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityModelWrappingHandlerMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
}
@Override
public void onLoad(String mixin_package) {
}
public void onLoad(String mixin_package) {}
@Override
public String getRefMapperConfig() {
@@ -46,9 +50,7 @@ public class CompatMixinPlugin implements IMixinConfigPlugin {
}
@Override
public void acceptTargets(Set<String> mine, Set<String> others) {
}
public void acceptTargets(Set<String> mine, Set<String> others) {}
@Override
public List<String> getMixins() {
@@ -56,9 +58,7 @@ public class CompatMixinPlugin implements IMixinConfigPlugin {
}
@Override
public void preApply(String target_class_name, ClassNode target_class, String mixin_class_name, IMixinInfo mixin_info) {
}
public void preApply(String target_class_name, ClassNode target_class, String mixin_class_name, IMixinInfo mixin_info) {}
@Override
public void postApply(String target_class, ClassNode target, String mixin_class, IMixinInfo mixin_info) {

View File

@@ -5,7 +5,7 @@ import earth.terrarium.athena.api.client.fabric.WrappedGetter;
import earth.terrarium.athena.api.client.models.AthenaBlockModel;
import fr.adrien1106.reframed.client.ReFramedClient;
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
import fr.adrien1106.reframed.compat.RebakedAthenaModel;
import fr.adrien1106.reframed.compat.RebakedModel;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
@@ -18,6 +18,7 @@ import net.minecraft.client.texture.Sprite;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockRenderView;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -35,27 +36,27 @@ public abstract class AthenaBakedModelMixin implements DynamicBakedModel, BakedM
* Reuses the emitQuad method to compute the quads to be used by the frame
*
* @param level - the world
* @param state - the current block camo
* @param origin_state - the current block camo
* @param pos - the block position
* @return - the rebakedmodel containing the computed quads
*/
@Override
public BakedModel computeQuads(BlockRenderView level, BlockState state, BlockPos pos, int theme_index) {
public BakedModel computeQuads(@Nullable BlockRenderView level, BlockState origin_state, @Nullable BlockPos pos, int theme_index) {
Map<Direction, List<BakedQuad>> face_quads = new HashMap<>();
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
QuadEmitter emitter = r.meshBuilder().getEmitter();
WrappedGetter getter = new WrappedGetter(level);
BlockState state = level != null && pos != null
&& level.getBlockEntity(pos) instanceof ThemeableBlockEntity framed_entity
? framed_entity.getTheme(theme_index)
: origin_state;
Arrays.stream(Direction.values()).forEach(direction -> {
face_quads.put(direction, new ArrayList<>());
(level == null || pos == null
? model.getDefaultQuads(direction).get(direction)
: model.getQuads(
getter,
level.getBlockEntity(pos) instanceof ThemeableBlockEntity framed_entity
? framed_entity.getTheme(theme_index)
: state, pos, direction)
: model.getQuads(getter, state, pos, direction)
).forEach(sprite -> face_quads.computeIfPresent(direction, (d, quads) -> {
Sprite texture = textures.get(sprite.sprite());
if (texture == null) return quads;
@@ -76,6 +77,6 @@ public abstract class AthenaBakedModelMixin implements DynamicBakedModel, BakedM
}));
});
return new RebakedAthenaModel(face_quads);
return new RebakedModel(face_quads);
}
}

View File

@@ -13,10 +13,13 @@ import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(WrappedGetter.class)
public class AthenaWrappedGetterMixin {
@Redirect(method = "query",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/BlockRenderView;" +
"getBlockState(Lnet/minecraft/util/math/BlockPos;)" +
"Lnet/minecraft/block/BlockState;"))
@Redirect(
method = "query",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/BlockRenderView;getBlockState(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/block/BlockState;"
)
) // TODO better connected textures
private BlockState queryCamoState(BlockRenderView world, BlockPos pos, @Local(argsOnly = true) BlockState reference_state) {
// get Any that will connect or return any other (/!\ isOf is an uncertain check)
if (world.getBlockEntity(pos) instanceof ThemeableBlockEntity framed_entity)

View File

@@ -0,0 +1,94 @@
package fr.adrien1106.reframed.mixin.compat;
import fr.adrien1106.reframed.client.ReFramedClient;
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
import fr.adrien1106.reframed.compat.ICTMQuadTransform;
import fr.adrien1106.reframed.compat.RebakedModel;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import me.pepperbell.continuity.client.config.ContinuityConfig;
import me.pepperbell.continuity.client.model.CTMBakedModel;
import me.pepperbell.continuity.client.model.ModelObjectsContainer;
import me.pepperbell.continuity.client.model.QuadProcessors;
import me.pepperbell.continuity.client.util.RenderUtil;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.BlockRenderView;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
@Mixin(CTMBakedModel.class)
public abstract class ContinuityCTMBakedModelMixin extends ForwardingBakedModel implements DynamicBakedModel {
@Shadow protected abstract Function<Sprite, QuadProcessors.Slice> getSliceFunc(BlockState state);
@Override
public BakedModel computeQuads(@Nullable BlockRenderView level, BlockState origin_state, @Nullable BlockPos pos, int theme_index) {
if (wrapped instanceof DynamicBakedModel wrapped_dynamic) // support wrap of dynamic models
return wrapped_dynamic.computeQuads(level, origin_state, pos, theme_index);
ModelObjectsContainer container = ModelObjectsContainer.get();
// normally baked model / wrapped or feature disabled or item (i.e. no need to compute quads)
if (level == null || pos == null
|| !ContinuityConfig.INSTANCE.connectedTextures.get()
|| !container.featureStates.getConnectedTexturesState().isEnabled()
) return wrapped;
Map<Direction, List<BakedQuad>> face_quads = new HashMap<>();
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
QuadEmitter emitter = r.meshBuilder().getEmitter();
// get applicable state
BlockState state = level.getBlockEntity(pos) instanceof ThemeableBlockEntity framed_entity
? framed_entity.getTheme(theme_index)
: origin_state;
// get random supplier
Random random = Random.create();
Supplier<Random> random_supplier = () -> {
random.setSeed(state.getRenderingSeed(pos));
return random;
};
// get quad transform and prepare
ICTMQuadTransform transform = ((ICTMQuadTransform) container.ctmQuadTransform);
transform.invokePrepare(
level,
state,
pos,
random_supplier,
ContinuityConfig.INSTANCE.useManualCulling.get(),
getSliceFunc(state)
);
Arrays.stream(Direction.values()).forEach(direction -> {
face_quads.put(direction, new ArrayList<>());
wrapped.getQuads(state, direction, random_supplier.get()).forEach(quad -> face_quads.computeIfPresent(direction, (d, quads) -> {
emitter.fromVanilla(quad, emitter.material(), direction);
transform.transform(emitter);
quads.add(emitter.toBakedQuad(RenderUtil.getSpriteFinder().find(emitter)));
return quads;
}));
// transform.getProcessingContext().getExtraQuadEmitter(); // TODO start here for overlay support
});
transform.getProcessingContext().reset(); // reset instead of outputting to emitter
transform.invokeReset();
return new RebakedModel(face_quads);
}
}

View File

@@ -0,0 +1,56 @@
package fr.adrien1106.reframed.mixin.compat;
import fr.adrien1106.reframed.compat.ICTMQuadTransform;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import me.pepperbell.continuity.client.model.CullingCache;
import me.pepperbell.continuity.client.model.QuadProcessors;
import me.pepperbell.continuity.impl.client.ProcessingContextImpl;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
import net.minecraft.block.BlockState;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.BlockRenderView;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.util.function.Function;
import java.util.function.Supplier;
@Mixin(targets = "me.pepperbell.continuity.client.model.CTMBakedModel$CTMQuadTransform")
public abstract class ContinuityCTMQuadTransformMixin implements ICTMQuadTransform {
@Shadow(remap = false) @Final protected ProcessingContextImpl processingContext;
@Shadow public abstract void prepare(BlockRenderView view, BlockState state, BlockPos pos, Supplier<Random> random, boolean manual_culling, Function<Sprite, QuadProcessors.Slice> slice);
@Shadow(remap = false) public abstract void reset();
@Redirect(
method = "transform",
at = @At(
value = "INVOKE",
target = "Lme/pepperbell/continuity/client/model/CullingCache;shouldCull(Lnet/fabricmc/fabric/api/renderer/v1/mesh/QuadView;Lnet/minecraft/world/BlockRenderView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)Z"
)
)
private boolean camo_replacement(CullingCache cache, QuadView quad, BlockRenderView view, BlockPos pos, BlockState state) {
if (view.getBlockEntity(pos) instanceof ThemeableBlockEntity) return false;
return cache.shouldCull(quad, view, pos, state);
}
// uses this because invoker did not want to work for some reason
public void invokePrepare(BlockRenderView view, BlockState state, BlockPos pos, Supplier<Random> random, boolean manual_culling, Function<Sprite, QuadProcessors.Slice> slice) {
prepare(view, state, pos, random, manual_culling, slice);
}
@Override
public ProcessingContextImpl getProcessingContext() {
return processingContext;
}
@Override
public void invokeReset() {
reset();
}
}

View File

@@ -0,0 +1,32 @@
package fr.adrien1106.reframed.mixin.compat;
import com.llamalad7.mixinextras.sugar.Local;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import me.pepperbell.continuity.client.processor.ConnectionPredicate;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockRenderView;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(ConnectionPredicate.class)
public interface ContinuityConnectionPredicateMixin {
@Redirect(
method = "shouldConnect(Lnet/minecraft/world/BlockRenderView;Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;Lnet/minecraft/client/texture/Sprite;)Z",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/BlockRenderView;getBlockState(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/block/BlockState;"
)
) // TODO better connected textures
private BlockState getBlockState(BlockRenderView view, BlockPos pos, @Local(argsOnly = true) BlockState state) {
if (!(view.getBlockEntity(pos) instanceof ThemeableBlockEntity frame_entity)) return view.getBlockState(pos);
return frame_entity.getThemes()
.stream()
.filter(theme -> theme.getBlock() == state.getBlock())
.findFirst()
.orElse(frame_entity.getTheme(0));
}
}

View File

@@ -0,0 +1,29 @@
package fr.adrien1106.reframed.mixin.compat;
import fr.adrien1106.reframed.block.ReFramedBlock;
import me.pepperbell.continuity.client.resource.ModelWrappingHandler;
import net.minecraft.block.Block;
import net.minecraft.registry.DefaultedRegistry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.util.Iterator;
@Mixin(ModelWrappingHandler.class)
public class ContinuityModelWrappingHandlerMixin {
@Redirect(
method = "createBlockStateModelIdMap",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/registry/DefaultedRegistry;iterator()Ljava/util/Iterator;"
)
)
private static Iterator<Block> filterFrames(DefaultedRegistry<Block> registry) {
return registry
.stream()
.filter(block -> !(block instanceof ReFramedBlock))
.iterator();
}
}

View File

@@ -1,7 +1,7 @@
package fr.adrien1106.reframed.mixin.compat;
import com.llamalad7.mixinextras.sugar.Local;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.client.util.RenderHelper;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import link.infra.indium.renderer.mesh.MutableQuadViewImpl;
import link.infra.indium.renderer.render.AbstractBlockRenderContext;
@@ -24,6 +24,6 @@ public abstract class IndiumAbstractBlockRenderContextMixin {
private boolean shouldDrawInnerQuad(AbstractBlockRenderContext instance, Direction face, @Local(argsOnly = true) MutableQuadViewImpl quad) {
if (face != null || quad.tag() == 0 || !(blockInfo instanceof IBlockRenderInfoMixin info) || info.getThemeIndex() == 0) return isFaceCulled(face);
return !BlockHelper.shouldDrawInnerFace(blockInfo.blockState, blockInfo.blockView, blockInfo.blockPos, quad.tag() >>> 8, info.getThemeIndex());
return !RenderHelper.shouldDrawInnerFace(blockInfo.blockState, blockInfo.blockView, blockInfo.blockPos, quad.tag() >>> 8, info.getThemeIndex());
}
}

View File

@@ -1,6 +1,6 @@
package fr.adrien1106.reframed.mixin.compat;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.client.util.RenderHelper;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import link.infra.indium.renderer.render.BlockRenderInfo;
@@ -32,7 +32,7 @@ public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo
if (!(view.getBlockEntity(pos) instanceof ThemeableBlockEntity
|| view.getBlockEntity(other_pos) instanceof ThemeableBlockEntity))
return instance.shouldDrawSide(state, view, pos, face);
return BlockHelper.shouldDrawSide(state, view, pos, face, other_pos, theme_index);
return RenderHelper.shouldDrawSide(state, view, pos, face, other_pos, theme_index);
}
@Override

View File

@@ -1,7 +1,7 @@
package fr.adrien1106.reframed.mixin.compat;
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.client.util.RenderHelper;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin;
import link.infra.indium.renderer.render.AbstractBlockRenderContext;
@@ -32,7 +32,7 @@ public abstract class IndiumTerrainRenderContextMixin extends AbstractBlockRende
|| !(wrapped.getModel(ctx.state()) instanceof MultiRetexturableModel retexturing_model)) return;
List<ForwardingBakedModel> models = retexturing_model.models();
BlockHelper.computeInnerCull(ctx.state(), models);
RenderHelper.computeInnerCull(ctx.state(), models);
int i = 0;
for (BakedModel model : models) {
i++;

View File

@@ -1,7 +1,7 @@
package fr.adrien1106.reframed.mixin.compat;
import com.llamalad7.mixinextras.sugar.Local;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.client.util.RenderHelper;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache;
import net.minecraft.block.BlockState;
@@ -19,12 +19,12 @@ public class SodiumBlockOcclusionCacheMixin {
@Inject(
method = "shouldDrawSide",
at = @At(
value = "INVOKE_ASSIGN",
target = "Lnet/minecraft/world/BlockView;getBlockState(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/block/BlockState;",
value = "INVOKE",
target = "Lnet/minecraft/util/math/BlockPos$Mutable;set(III)Lnet/minecraft/util/math/BlockPos$Mutable;",
shift = At.Shift.AFTER
), cancellable = true)
private void shouldDrawFrameNeighborSide(BlockState self_state, BlockView view, BlockPos self_pos, Direction face, CallbackInfoReturnable<Boolean> cir, @Local BlockPos.Mutable other_pos) {
if (!(view.getBlockEntity(other_pos) instanceof ThemeableBlockEntity)) return;
cir.setReturnValue(BlockHelper.shouldDrawSide(self_state, view, self_pos, face, other_pos, 0));
cir.setReturnValue(RenderHelper.shouldDrawSide(self_state, view, self_pos, face, other_pos, 0));
}
}

View File

@@ -0,0 +1,57 @@
package fr.adrien1106.reframed.mixin.logic;
import fr.adrien1106.reframed.block.ReFramedBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(BlockItem.class)
public class BlockItemMixin {
@Unique private final ThreadLocal<BlockState> old_state = new ThreadLocal<>();
@Unique private final ThreadLocal<BlockEntity> old_entity = new ThreadLocal<>();
@Redirect(
method = "place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/block/Block;onPlaced(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/item/ItemStack;)V"
)
)
private void placeMoreInfo(Block block, World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack) {
if (!(block instanceof ReFramedBlock frame_block)) {
block.onPlaced(world, pos, state, placer, itemStack);
return;
}
frame_block.onPlaced(world, pos, state, placer, itemStack, old_state.get(), old_entity.get());
}
@Inject(
method = "place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/item/BlockItem;place(Lnet/minecraft/item/ItemPlacementContext;Lnet/minecraft/block/BlockState;)Z",
shift = At.Shift.BEFORE
)
)
private void savePreviousInfo(ItemPlacementContext context, CallbackInfoReturnable<ActionResult> cir) {
World world = context.getWorld();
BlockPos pos = context.getBlockPos();
old_state.set(world.getBlockState(pos));
old_entity.set(world.getBlockEntity(pos));
}
}

View File

@@ -1,7 +1,7 @@
package fr.adrien1106.reframed.mixin.render;
import com.llamalad7.mixinextras.sugar.Local;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.client.util.RenderHelper;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.AbstractBlockRenderContext;
@@ -31,6 +31,6 @@ public abstract class AbstractBlockRenderContextMixin {
private boolean shouldDrawInnerQuad(AbstractBlockRenderContext instance, Direction face, @Local(argsOnly = true) MutableQuadViewImpl quad) {
if (face != null || quad.tag() == 0 || !(blockInfo instanceof IBlockRenderInfoMixin info) || info.getThemeIndex() == 0) return isFaceCulled(face);
return !BlockHelper.shouldDrawInnerFace(blockInfo.blockState, blockInfo.blockView, blockInfo.blockPos, quad.tag() >>> 8, info.getThemeIndex());
return !RenderHelper.shouldDrawInnerFace(blockInfo.blockState, blockInfo.blockView, blockInfo.blockPos, quad.tag() >>> 8, info.getThemeIndex());
}
}

View File

@@ -1,7 +1,7 @@
package fr.adrien1106.reframed.mixin.render;
import com.llamalad7.mixinextras.sugar.Local;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.client.util.RenderHelper;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo;
@@ -37,7 +37,7 @@ public abstract class BlockRenderInfoMixin implements IBlockRenderInfoMixin {
@Redirect(method = "shouldDrawFace", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;shouldDrawSide(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;Lnet/minecraft/util/math/BlockPos;)Z"))
private boolean shouldDrawAdjacentCamoSide(BlockState state, BlockView world, BlockPos pos, Direction side, BlockPos other_pos) {
return BlockHelper.shouldDrawSide(state, world, pos, side, other_pos, theme_index);
return RenderHelper.shouldDrawSide(state, world, pos, side, other_pos, theme_index);
}
@Override

View File

@@ -1,7 +1,7 @@
package fr.adrien1106.reframed.mixin.render;
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.client.util.RenderHelper;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
@@ -31,7 +31,7 @@ public abstract class TerrainRenderContextMixin extends AbstractBlockRenderConte
|| !(wrapped.getModel(state) instanceof MultiRetexturableModel retexturing_model)) return;
List<ForwardingBakedModel> models = retexturing_model.models();
BlockHelper.computeInnerCull(state, models);
RenderHelper.computeInnerCull(state, models);
int i = 0;
for (BakedModel model : models) {
i++;

View File

@@ -1,19 +1,8 @@
package fr.adrien1106.reframed.util.blocks;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import fr.adrien1106.reframed.block.ReFramedBlock;
import fr.adrien1106.reframed.block.ReFramedEntity;
import fr.adrien1106.reframed.block.ReFramedStairBlock;
import fr.adrien1106.reframed.block.ReFramedStairsCubeBlock;
import fr.adrien1106.reframed.client.ReFramedClient;
import fr.adrien1106.reframed.client.model.QuadPosBounds;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
import net.minecraft.block.Block;
import net.minecraft.block.BlockEntityProvider;
import net.minecraft.block.BlockState;
@@ -25,33 +14,27 @@ import net.minecraft.sound.SoundEvents;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.Pair;
import net.minecraft.util.function.BooleanBiFunction;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.random.Random;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockRenderView;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import java.util.*;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT;
import static fr.adrien1106.reframed.util.blocks.StairShape.*;
import static net.minecraft.util.shape.VoxelShapes.combine;
public class BlockHelper {
// self culling cache of the models not made thread local so that it is only computed once
private static final Cache<CullElement, Integer[]> INNER_CULL_MAP = CacheBuilder.newBuilder().maximumSize(1024).build();
private record CullElement(Block block, Object state_key, int model) {}
public static Corner getPlacementCorner(ItemPlacementContext ctx) {
Direction side = ctx.getSide().getOpposite();
Vec3d pos = getHitPos(ctx.getHitPos(), ctx.getBlockPos());
@@ -147,14 +130,14 @@ public class BlockHelper {
return shape;
}
public static String getNeighborPos(Edge face, Direction direction, Boolean reverse, Direction reference, BlockView world, BlockPos pos) {
public static String getNeighborPos(Edge edge, Direction direction, Boolean reverse, Direction reference, BlockView world, BlockPos pos) {
BlockState block_state = world.getBlockState(
pos.offset(reverse ? direction.getOpposite() : direction)
);
if (isStair(block_state) && block_state.get(EDGE).hasDirection(reference)) {
if (block_state.get(EDGE).hasDirection(face.getLeftDirection())) return "left";
else if (block_state.get(EDGE).hasDirection(face.getRightDirection())) return "right";
if (block_state.get(EDGE).hasDirection(edge.getLeftDirection())) return "left";
else if (block_state.get(EDGE).hasDirection(edge.getRightDirection())) return "right";
}
return "";
}
@@ -167,8 +150,8 @@ public class BlockHelper {
public static ActionResult useCamo(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit, int theme_index) {
if(!(world.getBlockEntity(pos) instanceof ReFramedEntity block_entity)) return ActionResult.PASS;
// Changing the theme
ItemStack held = player.getStackInHand(hand);
// Changing the theme
if(held.getItem() instanceof BlockItem block_item && block_entity.getTheme(theme_index).getBlock() == Blocks.AIR) {
Block block = block_item.getBlock();
ItemPlacementContext ctx = new ItemPlacementContext(new ItemUsageContext(player, hand, hit));
@@ -232,148 +215,6 @@ public class BlockHelper {
return ActionResult.PASS;
}
/**
* compute which quad might cull with another model quad
* @param state - the state of the model
* @param models - list of models on the same block
*/
@Environment(EnvType.CLIENT)
public static void computeInnerCull(BlockState state, List<ForwardingBakedModel> models) {
if (!(state.getBlock() instanceof ReFramedBlock frame_block)) return;
Object key = frame_block.getModelCacheKey(state);
if (INNER_CULL_MAP.asMap().containsKey(new CullElement(frame_block, key, 1))) return;
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
QuadEmitter quad_emitter = r.meshBuilder().getEmitter();
RenderMaterial material = r.materialFinder().clear().find();
Random random = Random.create();
List<List<QuadPosBounds>> model_bounds = models.stream()
.map(ForwardingBakedModel::getWrappedModel)
.filter(Objects::nonNull)
.map(wrapped -> wrapped.getQuads(state, null, random))
.map(quads -> quads.stream().map(quad -> {
quad_emitter.fromVanilla(quad, material, null);
return QuadPosBounds.read(quad_emitter, false);
}).toList()).toList();
Integer[] cull_array;
for(int self_id = 1; self_id <= model_bounds.size(); self_id++) {
List<QuadPosBounds> self_bounds = model_bounds.get(self_id - 1);
cull_array = new Integer[self_bounds.size()];
for (int self_quad = 0; self_quad < cull_array.length; self_quad++) {
QuadPosBounds self_bound = self_bounds.get(self_quad);
for(int other_id = 1; other_id <= model_bounds.size(); other_id++) {
if (other_id == self_id) continue;
if (model_bounds.get(other_id - 1).stream().anyMatch(other_bound -> other_bound.equals(self_bound))) {
cull_array[self_quad] = other_id;
break;
}
}
}
INNER_CULL_MAP.put(new CullElement(frame_block, key, self_id), cull_array);
}
}
@Environment(EnvType.CLIENT)
public static boolean shouldDrawInnerFace(BlockState state, BlockRenderView view, BlockPos pos, int quad_index, int theme_index) {
if ( !(state.getBlock() instanceof ReFramedBlock frame_block)
|| !(view.getBlockEntity(pos) instanceof ThemeableBlockEntity frame_entity)
) return true;
CullElement key = new CullElement(frame_block, frame_block.getModelCacheKey(state), theme_index);
if (!INNER_CULL_MAP.asMap().containsKey(key)) return true;
// needs to be Integer object because array is initialized with null not 0
Integer cull_theme = Objects.requireNonNull(INNER_CULL_MAP.getIfPresent(key))[quad_index];
if (cull_theme == null) return true; // no culling possible
BlockState self_theme = frame_entity.getTheme(theme_index);
BlockState other_theme = frame_entity.getTheme(cull_theme);
if (self_theme.isSideInvisible(other_theme, null)) return false;
return !self_theme.isOpaque() || !other_theme.isOpaque();
}
// Doing this method from scratch as it is simpler to do than injecting everywhere
@Environment(EnvType.CLIENT)
public static boolean shouldDrawSide(BlockState self_state, BlockView world, BlockPos pos, Direction side, BlockPos other_pos, int theme_index) {
ThemeableBlockEntity self = world.getBlockEntity(pos) instanceof ThemeableBlockEntity e ? e : null;
ThemeableBlockEntity other = world.getBlockEntity(other_pos) instanceof ThemeableBlockEntity e ? e : null;
BlockState other_state = world.getBlockState(other_pos);
// normal behaviour
if (self == null && other == null) return Block.shouldDrawSide(self_state, world, pos, side, other_pos);
// self is a normal Block
if (self == null && other_state.getBlock() instanceof ReFramedBlock other_block) {
VoxelShape self_shape = self_state.getCullingShape(world, pos);
if (self_shape.isEmpty()) return true;
int i = 0;
VoxelShape other_shape = VoxelShapes.empty();
for (BlockState s: other.getThemes()) {
i++;
if (self_state.isSideInvisible(s, side) || s.isOpaque())
other_shape = combine(
other_shape,
other_block
.getShape(other_state, i)
.getFace(side.getOpposite()),
BooleanBiFunction.OR
);
}
// determine if side needs to be rendered
return VoxelShapes.matchesAnywhere(self_shape, other_shape, BooleanBiFunction.ONLY_FIRST);
}
BlockState self_theme = self.getTheme(theme_index);
// other is normal Block
if (other == null && self_state.getBlock() instanceof ReFramedBlock self_block) {
// Transparent is simple if self and the neighbor are invisible don't render side (like default)
if (self_theme.isSideInvisible(other_state, side)) return false;
// Opaque is also simple as each model are rendered one by one
if (other_state.isOpaque()) {
// no cache section :( because it differs between each instance of the frame
VoxelShape self_shape = self_block.getShape(self_state, theme_index).getFace(side);
if (self_shape.isEmpty()) return true;
VoxelShape other_shape = other_state.getCullingFace(world, other_pos, side.getOpposite());
// determine if side needs to be rendered
return VoxelShapes.matchesAnywhere(self_shape, other_shape, BooleanBiFunction.ONLY_FIRST);
}
return true;
}
// Both are frames
// here both are computed in the same zone as there will necessarily a shape comparison
if (self_state.getBlock() instanceof ReFramedBlock self_block && other_state.getBlock() instanceof ReFramedBlock other_block) {
VoxelShape self_shape = self_block.getShape(self_state, theme_index).getFace(side);
if (self_shape.isEmpty()) return true;
int i = 0;
VoxelShape other_shape = VoxelShapes.empty();
for (BlockState s: other.getThemes()) {
i++;
if (self_theme.isSideInvisible(s, side) || s.isOpaque())
other_shape = combine(
other_shape,
other_block
.getShape(other_state, i)
.getFace(side.getOpposite()),
BooleanBiFunction.OR
);
}
// determine if side needs to be rendered
return VoxelShapes.matchesAnywhere(self_shape, other_shape, BooleanBiFunction.ONLY_FIRST);
}
return true;
}
public static boolean cursorMatchesFace(VoxelShape shape, Vec3d pos) {
Map<Direction.Axis, Double> axes = Arrays.stream(Direction.Axis.values())
.collect(Collectors.toMap(

View File

@@ -37,6 +37,18 @@ public enum Corner implements StringIdentifiable {
return asString();
}
public Direction getFirstDirection() {
return first_direction;
}
public Direction getSecondDirection() {
return second_direction;
}
public Direction getThirdDirection() {
return third_direction;
}
public boolean hasDirection(Direction direction) {
return this.first_direction.equals(direction)
|| this.second_direction.equals(direction)
@@ -94,4 +106,17 @@ public enum Corner implements StringIdentifiable {
Direction other_2 = second_direction == direction || first_direction == direction ? third_direction : second_direction;
return getByDirections(direction, other_1.getOpposite(), other_2.getOpposite());
}
public Edge getEdge(Direction direction) {
return Edge.getByDirections(
first_direction == direction ? second_direction : first_direction,
second_direction == direction || first_direction == direction ? third_direction : second_direction
);
}
public Direction getOtherDirection(Edge edge) {
if (edge.getFirstDirection() != second_direction && edge.getSecondDirection() != second_direction) return second_direction;
if (edge.getFirstDirection() != third_direction && edge.getSecondDirection() != third_direction) return third_direction;
return first_direction;
}
}

View File

@@ -49,18 +49,10 @@ public enum Edge implements StringIdentifiable {
return second_direction;
}
public Direction getRightDirection() {
return switch (axis) {
case X -> Direction.WEST;
case Y -> Direction.DOWN;
case Z -> Direction.SOUTH;
};
return Direction.from(axis, Direction.AxisDirection.NEGATIVE);
}
public Direction getLeftDirection() {
return switch (axis) {
case X -> Direction.EAST;
case Y -> Direction.UP;
case Z -> Direction.NORTH;
};
return Direction.from(axis, Direction.AxisDirection.POSITIVE);
}
public boolean hasDirection(Direction direction) {
@@ -68,16 +60,32 @@ public enum Edge implements StringIdentifiable {
|| this.second_direction.equals(direction);
}
public Direction.Axis getAxis() {
return this.axis;
}
public int getID() {
return this.ID;
}
public Edge opposite() {
return getByDirections(first_direction.getOpposite(), second_direction.getOpposite());
}
public static Edge getByDirections(Direction direction_1, Direction direction_2) {
return Arrays.stream(Edge.values())
.filter(value -> value.hasDirection(direction_1) && value.hasDirection(direction_2))
.findFirst().orElse(Edge.NORTH_DOWN);
}
public boolean isSide(Direction side) {
return getRightDirection() == side || getLeftDirection() == side;
}
public Direction getOtherDirection(Direction direction) {
return first_direction == direction ? second_direction : first_direction;
}
public static Edge fromId(int id) {
return Arrays.stream(Edge.values())
.filter(value -> value.getID() == id)

View File

@@ -0,0 +1,21 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [4, 0, 4],
"to": [12, 16, 12],
"faces": {
"north": {"uv": [4, 0, 12, 16], "texture": "#side"},
"east": {"uv": [4, 0, 12, 16], "texture": "#side"},
"south": {"uv": [4, 0, 12, 16], "texture": "#side"},
"west": {"uv": [4, 0, 12, 16], "texture": "#side"},
"up": {"uv": [4, 4, 12, 12], "texture": "#top", "cullface": "up"},
"down": {"uv": [4, 4, 12, 12], "texture": "#bottom", "cullface": "down"}
}
}
]
}

View File

@@ -0,0 +1,35 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [4, 0, 4],
"to": [5, 14, 5],
"faces": {
"north": {"uv": [11, 2, 12, 16], "texture": "#side"},
"west": {"uv": [4, 2, 5, 16], "texture": "#side"},
"down": {"uv": [4, 11, 5, 12], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 0, 4],
"to": [11, 14, 5],
"faces": {
"north": {"uv": [5, 2, 11, 16], "texture": "#side"},
"down": {"uv": [5, 11, 11, 12], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [4, 14, 4],
"to": [11, 16, 5],
"faces": {
"north": {"uv": [5, 0, 12, 2], "texture": "#side"},
"west": {"uv": [4, 0, 5, 2], "texture": "#side"},
"up": {"uv": [5, 4, 12, 5], "texture": "#top", "cullface": "up"}
}
}
]
}

View File

@@ -0,0 +1,28 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [4, 0, 4],
"to": [5, 16, 5],
"faces": {
"north": {"uv": [11, 0, 12, 16], "texture": "#side"},
"west": {"uv": [4, 0, 5, 16], "texture": "#side"},
"up": {"uv": [4, 4, 5, 5], "texture": "#top", "cullface": "up"},
"down": {"uv": [4, 11, 5, 12], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 0, 4],
"to": [11, 16, 5],
"faces": {
"north": {"uv": [5, 0, 11, 16], "texture": "#side"},
"up": {"uv": [5, 4, 11, 5], "texture": "#top", "cullface": "up"},
"down": {"uv": [5, 11, 11, 12], "texture": "#bottom", "cullface": "down"}
}
}
]
}

View File

@@ -0,0 +1,21 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [5, 0, 0],
"to": [11, 14, 4],
"faces": {
"north": {"uv": [5, 2, 11, 16], "texture": "#side", "cullface": "north"},
"east": {"uv": [12, 2, 16, 16], "texture": "#side"},
"south": {"uv": [5, 2, 11, 16], "texture": "#side"},
"west": {"uv": [0, 2, 4, 16], "texture": "#side"},
"up": {"uv": [5, 0, 11, 4], "texture": "#top"},
"down": {"uv": [5, 12, 11, 16], "texture": "#bottom", "cullface": "down"}
}
}
]
}

View File

@@ -0,0 +1,21 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [5, 0, 0],
"to": [11, 16, 4],
"faces": {
"north": {"uv": [5, 0, 11, 16], "texture": "#side", "cullface": "north"},
"east": {"uv": [12, 0, 16, 16], "texture": "#side"},
"south": {"uv": [5, 0, 11, 16], "texture": "#side"},
"west": {"uv": [0, 0, 4, 16], "texture": "#side"},
"up": {"uv": [5, 0, 11, 4], "texture": "#top", "cullface": "up"},
"down": {"uv": [5, 12, 11, 16], "texture": "#bottom", "cullface": "down"}
}
}
]
}

View File

@@ -0,0 +1,43 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [5, 0, 0],
"to": [11, 14, 4],
"faces": {
"north": {"uv": [5, 2, 11, 16], "texture": "#side", "cullface": "north"},
"east": {"uv": [12, 2, 16, 16], "texture": "#side"},
"west": {"uv": [0, 2, 4, 16], "texture": "#side"},
"up": {"uv": [5, 0, 11, 4], "texture": "#top"},
"down": {"uv": [5, 12, 11, 16], "texture": "#bottom"}
}
},
{
"from": [5, 0, 12],
"to": [11, 14, 16],
"faces": {
"east": {"uv": [0, 2, 4, 16], "texture": "#side"},
"south": {"uv": [5, 2, 11, 16], "texture": "#side", "cullface": "south"},
"west": {"uv": [12, 2, 16, 16], "texture": "#side"},
"up": {"uv": [5, 12, 11, 16], "texture": "#top"},
"down": {"uv": [5, 0, 11, 4], "texture": "#bottom"}
}
},
{
"from": [4, 0, 4],
"to": [12, 16, 12],
"faces": {
"north": {"uv": [4, 0, 12, 16], "texture": "#side"},
"east": {"uv": [4, 0, 12, 16], "texture": "#side"},
"south": {"uv": [4, 0, 12, 16], "texture": "#side", "cullface": "south"},
"west": {"uv": [4, 0, 12, 16], "texture": "#side"},
"up": {"uv": [4, 4, 12, 12], "texture": "#top"},
"down": {"uv": [4, 4, 12, 12], "texture": "#bottom"}
}
}
]
}

View File

@@ -0,0 +1,20 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [5, 0, 4],
"to": [11, 14, 8],
"faces": {
"east": {"uv": [8, 2, 12, 16], "texture": "#side"},
"south": {"uv": [5, 2, 11, 16], "texture": "#side"},
"west": {"uv": [4, 2, 8, 16], "texture": "#side"},
"up": {"uv": [5, 4, 11, 8], "texture": "#top"},
"down": {"uv": [5, 8, 11, 12], "texture": "#bottom", "cullface": "down"}
}
}
]
}

View File

@@ -0,0 +1,57 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [5, 0, 4],
"to": [11, 14, 5],
"faces": {
"east": {"uv": [11, 2, 12, 16], "texture": "#side"},
"west": {"uv": [4, 2, 5, 16], "texture": "#side"},
"up": {"uv": [5, 4, 11, 5], "texture": "#top"},
"down": {"uv": [5, 11, 11, 12], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [8, 0, 5],
"to": [11, 14, 8],
"faces": {
"east": {"uv": [8, 2, 11, 16], "texture": "#side"},
"south": {"uv": [8, 2, 11, 16], "texture": "#side"},
"up": {"uv": [8, 5, 11, 8], "texture": "#top"},
"down": {"uv": [8, 8, 11, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 0, 8],
"to": [8, 14, 11],
"faces": {
"east": {"uv": [5, 2, 8, 16], "texture": "#side"},
"south": {"uv": [5, 2, 8, 16], "texture": "#side"},
"up": {"uv": [5, 8, 8, 11], "texture": "#top"},
"down": {"uv": [5, 5, 8, 8], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 0, 5],
"to": [8, 14, 8],
"faces": {
"up": {"uv": [5, 5, 8, 8], "texture": "#top"},
"down": {"uv": [5, 8, 8, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [4, 0, 5],
"to": [5, 14, 11],
"faces": {
"north": {"uv": [11, 2, 12, 16], "texture": "#side"},
"south": {"uv": [4, 2, 5, 16], "texture": "#side"},
"up": {"uv": [4, 5, 5, 11], "texture": "#top"},
"down": {"uv": [4, 5, 5, 11], "texture": "#bottom", "cullface": "down"}
}
}
]
}

View File

@@ -0,0 +1,66 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [5, 0, 4],
"to": [11, 14, 5],
"faces": {
"east": {"uv": [11, 2, 12, 16], "texture": "#side"},
"west": {"uv": [4, 2, 5, 16], "texture": "#side"},
"up": {"uv": [5, 4, 11, 5], "texture": "#top"},
"down": {"uv": [5, 11, 11, 12], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [8, 0, 5],
"to": [11, 14, 11],
"faces": {
"south": {"uv": [8, 2, 11, 16], "texture": "#side"},
"up": {"uv": [8, 5, 11, 11], "texture": "#top"},
"down": {"uv": [8, 5, 11, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 14, 5],
"to": [8, 16, 11],
"faces": {
"north": {"uv": [8, 0, 11, 2], "texture": "#side"},
"east": {"uv": [5, 0, 11, 2], "texture": "#side"},
"south": {"uv": [5, 0, 8, 2], "texture": "#side"},
"up": {"uv": [5, 5, 8, 11], "texture": "#top", "cullface": "up"}
}
},
{
"from": [5, 0, 5],
"to": [8, 14, 11],
"faces": {
"south": {"uv": [5, 2, 8, 16], "texture": "#side"},
"down": {"uv": [5, 5, 8, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [11, 0, 5],
"to": [12, 14, 11],
"faces": {
"north": {"uv": [4, 2, 5, 16], "texture": "#side"},
"south": {"uv": [11, 2, 12, 16], "texture": "#side"},
"up": {"uv": [11, 5, 12, 11], "texture": "#top"},
"down": {"uv": [11, 5, 12, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [4, 0, 5],
"to": [5, 16, 11],
"faces": {
"north": {"uv": [11, 0, 12, 16], "texture": "#side"},
"south": {"uv": [4, 0, 5, 16], "texture": "#side"},
"up": {"uv": [4, 5, 5, 11], "texture": "#top", "cullface": "up"},
"down": {"uv": [4, 5, 5, 11], "texture": "#bottom", "cullface": "down"}
}
}
]
}

View File

@@ -0,0 +1,19 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [5, 0, 4],
"to": [11, 14, 12],
"faces": {
"east": {"uv": [4, 2, 12, 16], "texture": "#side"},
"west": {"uv": [4, 2, 12, 16], "texture": "#side"},
"up": {"uv": [5, 4, 11, 12], "texture": "#top"},
"down": {"uv": [5, 4, 11, 12], "texture": "#bottom", "cullface": "down"}
}
}
]
}

View File

@@ -0,0 +1,65 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [5, 0, 4],
"to": [11, 16, 5],
"faces": {
"east": {"uv": [11, 0, 12, 16], "texture": "#side"},
"west": {"uv": [4, 0, 5, 16], "texture": "#side"},
"up": {"uv": [5, 4, 11, 5], "texture": "#top", "cullface": "up"},
"down": {"uv": [5, 11, 11, 12], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 0, 8],
"to": [11, 14, 11],
"faces": {
"south": {"uv": [5, 2, 11, 16], "texture": "#side"},
"up": {"uv": [5, 8, 11, 11], "texture": "#top"},
"down": {"uv": [5, 5, 11, 8], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 14, 5],
"to": [11, 16, 8],
"faces": {
"east": {"uv": [8, 0, 11, 2], "texture": "#side"},
"south": {"uv": [5, 0, 11, 2], "texture": "#side"},
"west": {"uv": [5, 0, 8, 2], "texture": "#side"},
"up": {"uv": [5, 5, 11, 8], "texture": "#top", "cullface": "up"}
}
},
{
"from": [5, 0, 5],
"to": [11, 14, 8],
"faces": {
"down": {"uv": [5, 8, 11, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [4, 0, 5],
"to": [5, 14, 11],
"faces": {
"north": {"uv": [11, 2, 12, 16], "texture": "#side"},
"south": {"uv": [4, 2, 5, 16], "texture": "#side"},
"up": {"uv": [4, 5, 5, 11], "texture": "#top"},
"down": {"uv": [4, 5, 5, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [11, 0, 5],
"to": [12, 14, 11],
"faces": {
"north": {"uv": [4, 2, 5, 16], "texture": "#side"},
"south": {"uv": [11, 2, 12, 16], "texture": "#side"},
"up": {"uv": [11, 5, 12, 11], "texture": "#top"},
"down": {"uv": [11, 5, 12, 11], "texture": "#bottom", "cullface": "down"}
}
}
]
}

View File

@@ -0,0 +1,48 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [5, 0, 4],
"to": [11, 14, 5],
"faces": {
"east": {"uv": [11, 2, 12, 16], "texture": "#side"},
"west": {"uv": [4, 2, 5, 16], "texture": "#side"},
"up": {"uv": [5, 4, 11, 5], "texture": "#top"},
"down": {"uv": [5, 11, 11, 12], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 0, 5],
"to": [11, 14, 11],
"faces": {
"south": {"uv": [5, 2, 11, 16], "texture": "#side"},
"up": {"uv": [5, 5, 11, 11], "texture": "#top"},
"down": {"uv": [5, 5, 11, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [4, 0, 5],
"to": [5, 14, 11],
"faces": {
"north": {"uv": [11, 2, 12, 16], "texture": "#side"},
"south": {"uv": [4, 2, 5, 16], "texture": "#side"},
"up": {"uv": [4, 5, 5, 11], "texture": "#top"},
"down": {"uv": [4, 5, 5, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [11, 0, 5],
"to": [12, 14, 11],
"faces": {
"north": {"uv": [4, 2, 5, 16], "texture": "#side"},
"south": {"uv": [11, 2, 12, 16], "texture": "#side"},
"up": {"uv": [11, 5, 12, 11], "texture": "#top"},
"down": {"uv": [11, 5, 12, 11], "texture": "#bottom", "cullface": "down"}
}
}
]
}

View File

@@ -0,0 +1,65 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [5, 0, 4],
"to": [11, 14, 5],
"faces": {
"east": {"uv": [11, 2, 12, 16], "texture": "#side"},
"west": {"uv": [4, 2, 5, 16], "texture": "#side"},
"up": {"uv": [5, 4, 11, 5], "texture": "#top"},
"down": {"uv": [5, 11, 11, 12], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [8, 0, 5],
"to": [11, 14, 8],
"faces": {
"east": {"uv": [8, 2, 11, 16], "texture": "#side"},
"south": {"uv": [8, 2, 11, 16], "texture": "#side"},
"up": {"uv": [8, 5, 11, 8], "texture": "#top"},
"down": {"uv": [8, 8, 11, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 14, 5],
"to": [8, 16, 8],
"faces": {
"north": {"uv": [8, 0, 11, 2], "texture": "#side"},
"east": {"uv": [8, 0, 11, 2], "texture": "#side"},
"up": {"uv": [5, 5, 8, 8], "texture": "#top", "cullface": "up"}
}
},
{
"from": [5, 0, 8],
"to": [8, 16, 11],
"faces": {
"east": {"uv": [5, 0, 8, 16], "texture": "#side"},
"south": {"uv": [5, 0, 8, 16], "texture": "#side"},
"up": {"uv": [5, 8, 8, 11], "texture": "#top", "cullface": "up"},
"down": {"uv": [5, 5, 8, 8], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 0, 5],
"to": [8, 14, 8],
"faces": {
"down": {"uv": [5, 8, 8, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [4, 0, 5],
"to": [5, 16, 11],
"faces": {
"north": {"uv": [11, 0, 12, 16], "texture": "#side"},
"south": {"uv": [4, 0, 5, 16], "texture": "#side"},
"up": {"uv": [4, 5, 5, 11], "texture": "#top", "cullface": "up"},
"down": {"uv": [4, 5, 5, 11], "texture": "#bottom", "cullface": "down"}
}
}
]
}

View File

@@ -0,0 +1,88 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [5, 0, 4],
"to": [11, 16, 5],
"faces": {
"east": {"uv": [11, 0, 12, 16], "texture": "#side"},
"west": {"uv": [4, 0, 5, 16], "texture": "#side"},
"up": {"uv": [5, 4, 11, 5], "texture": "#top", "cullface": "up"},
"down": {"uv": [5, 11, 11, 12], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [8, 0, 8],
"to": [11, 14, 11],
"faces": {
"south": {"uv": [8, 2, 11, 16], "texture": "#side"},
"up": {"uv": [8, 8, 11, 11], "texture": "#top"},
"down": {"uv": [8, 5, 11, 8], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [8, 14, 5],
"to": [11, 16, 8],
"faces": {
"east": {"uv": [8, 0, 11, 2], "texture": "#side"},
"south": {"uv": [8, 0, 11, 2], "texture": "#side"},
"up": {"uv": [8, 5, 11, 8], "texture": "#top", "cullface": "up"}
}
},
{
"from": [5, 14, 8],
"to": [8, 16, 11],
"faces": {
"east": {"uv": [5, 0, 8, 2], "texture": "#side"},
"south": {"uv": [5, 0, 8, 2], "texture": "#side"},
"up": {"uv": [5, 8, 8, 11], "texture": "#top", "cullface": "up"}
}
},
{
"from": [5, 14, 5],
"to": [8, 16, 8],
"faces": {
"up": {"uv": [5, 5, 8, 8], "texture": "#top", "cullface": "up"}
}
},
{
"from": [5, 0, 5],
"to": [11, 14, 8],
"faces": {
"down": {"uv": [5, 8, 11, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 0, 8],
"to": [8, 14, 11],
"faces": {
"south": {"uv": [5, 2, 8, 16], "texture": "#side"},
"down": {"uv": [5, 5, 8, 8], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [4, 0, 5],
"to": [5, 16, 11],
"faces": {
"north": {"uv": [11, 0, 12, 16], "texture": "#side"},
"south": {"uv": [4, 0, 5, 16], "texture": "#side"},
"up": {"uv": [4, 5, 5, 11], "texture": "#top", "cullface": "up"},
"down": {"uv": [4, 5, 5, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [11, 0, 5],
"to": [12, 14, 11],
"faces": {
"north": {"uv": [4, 2, 5, 16], "texture": "#side"},
"south": {"uv": [11, 2, 12, 16], "texture": "#side"},
"up": {"uv": [11, 5, 12, 11], "texture": "#top"},
"down": {"uv": [11, 5, 12, 11], "texture": "#bottom", "cullface": "down"}
}
}
]
}

View File

@@ -0,0 +1,38 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [5, 0, 4],
"to": [11, 14, 8],
"faces": {
"east": {"uv": [8, 2, 12, 16], "texture": "#side"},
"west": {"uv": [4, 2, 8, 16], "texture": "#side"},
"up": {"uv": [5, 4, 11, 8], "texture": "#top"},
"down": {"uv": [5, 8, 11, 12], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 14, 8],
"to": [11, 16, 12],
"faces": {
"north": {"uv": [5, 0, 11, 2], "texture": "#side"},
"east": {"uv": [4, 0, 8, 2], "texture": "#side"},
"west": {"uv": [8, 0, 12, 2], "texture": "#side"},
"up": {"uv": [5, 8, 11, 12], "texture": "#top", "cullface": "up"}
}
},
{
"from": [5, 0, 8],
"to": [11, 14, 12],
"faces": {
"east": {"uv": [4, 2, 8, 16], "texture": "#side"},
"west": {"uv": [8, 2, 12, 16], "texture": "#side"},
"down": {"uv": [5, 4, 11, 8], "texture": "#bottom", "cullface": "down"}
}
}
]
}

View File

@@ -0,0 +1,57 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [5, 0, 4],
"to": [11, 14, 5],
"faces": {
"east": {"uv": [11, 2, 12, 16], "texture": "#side"},
"west": {"uv": [4, 2, 5, 16], "texture": "#side"},
"up": {"uv": [5, 4, 11, 5], "texture": "#top"},
"down": {"uv": [5, 11, 11, 12], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 0, 11],
"to": [11, 14, 12],
"faces": {
"east": {"uv": [4, 2, 5, 16], "texture": "#side"},
"west": {"uv": [11, 2, 12, 16], "texture": "#side"},
"up": {"uv": [5, 11, 11, 12], "texture": "#top"},
"down": {"uv": [5, 4, 11, 5], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [5, 0, 5],
"to": [11, 14, 11],
"faces": {
"up": {"uv": [5, 5, 11, 11], "texture": "#top"},
"down": {"uv": [5, 5, 11, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [4, 0, 5],
"to": [5, 14, 11],
"faces": {
"north": {"uv": [11, 2, 12, 16], "texture": "#side"},
"south": {"uv": [4, 2, 5, 16], "texture": "#side"},
"up": {"uv": [4, 5, 5, 11], "texture": "#top"},
"down": {"uv": [4, 5, 5, 11], "texture": "#bottom", "cullface": "down"}
}
},
{
"from": [11, 0, 5],
"to": [12, 14, 11],
"faces": {
"north": {"uv": [4, 2, 5, 16], "texture": "#side"},
"south": {"uv": [11, 2, 12, 16], "texture": "#side"},
"up": {"uv": [11, 5, 12, 11], "texture": "#top"},
"down": {"uv": [11, 5, 12, 11], "texture": "#bottom", "cullface": "down"}
}
}
]
}

Some files were not shown because too many files have changed in this diff Show More