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
This commit is contained in:
@@ -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,15 +23,12 @@ 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 ?
|
||||
*/
|
||||
@@ -39,6 +37,10 @@ public class ReFramed implements ModInitializer {
|
||||
|
||||
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 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 +50,24 @@ 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)));
|
||||
|
||||
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 +88,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 +106,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);
|
||||
|
||||
@@ -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,10 +43,9 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,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(); }
|
||||
|
||||
@@ -70,6 +70,7 @@ public class ReFramedModelProvider implements ModelResourceProvider, ModelVarian
|
||||
}
|
||||
|
||||
public void dumpCache() {
|
||||
CamoAppearanceManager.dumpCahe();
|
||||
appearanceManager = null; //volatile write
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,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 +65,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;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -15,5 +15,8 @@ public class GRecipe extends FabricRecipeProvider {
|
||||
ReFramed.BLOCKS.forEach(block -> {
|
||||
if (block instanceof RecipeSetter provider) provider.setRecipe(exporter);
|
||||
});
|
||||
ReFramed.ITEMS.forEach(item -> {
|
||||
if (item instanceof RecipeSetter provider) provider.setRecipe(exporter);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package fr.adrien1106.reframed.item;
|
||||
|
||||
import fr.adrien1106.reframed.ReFramed;
|
||||
import fr.adrien1106.reframed.block.ReFramedEntity;
|
||||
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemUsageContext;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.recipe.book.RecipeCategory;
|
||||
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 implements RecipeSetter {
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecipe(RecipeExporter exporter) {
|
||||
ShapedRecipeJsonBuilder
|
||||
.create(RecipeCategory.BUILDING_BLOCKS, this, 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(this), FabricRecipeProvider.conditionsFromItem(this))
|
||||
.offerTo(exporter);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package fr.adrien1106.reframed.item;
|
||||
|
||||
import fr.adrien1106.reframed.ReFramed;
|
||||
import fr.adrien1106.reframed.block.ReFramedDoubleBlock;
|
||||
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemUsageContext;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.recipe.book.RecipeCategory;
|
||||
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 implements RecipeSetter {
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecipe(RecipeExporter exporter) {
|
||||
ShapedRecipeJsonBuilder
|
||||
.create(RecipeCategory.BUILDING_BLOCKS, this)
|
||||
.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(this), FabricRecipeProvider.conditionsFromItem(this))
|
||||
.offerTo(exporter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package fr.adrien1106.reframed.item;
|
||||
|
||||
import fr.adrien1106.reframed.ReFramed;
|
||||
import fr.adrien1106.reframed.block.ReFramedDoubleBlock;
|
||||
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemUsageContext;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.recipe.book.RecipeCategory;
|
||||
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 implements RecipeSetter {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecipe(RecipeExporter exporter) {
|
||||
ShapedRecipeJsonBuilder
|
||||
.create(RecipeCategory.BUILDING_BLOCKS, this)
|
||||
.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(this), FabricRecipeProvider.conditionsFromItem(this))
|
||||
.offerTo(exporter);
|
||||
}
|
||||
}
|
||||
@@ -167,8 +167,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));
|
||||
|
||||
Reference in New Issue
Block a user