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:
2024-03-15 23:30:10 +01:00
parent 08bde119b2
commit 5c064176b2
23 changed files with 613 additions and 56 deletions

View File

@@ -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);
}
}

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,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);
}
}

View File

@@ -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);
}
}