Basic grid functionality and rotation
This commit is contained in:
parent
13c489cda0
commit
2197c69f0f
@ -16,6 +16,8 @@ repositories {
|
||||
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
||||
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
||||
// for more information about repositories.
|
||||
|
||||
maven { url 'https://maven.nucleoid.xyz' }
|
||||
}
|
||||
|
||||
loom {
|
||||
@ -38,7 +40,11 @@ dependencies {
|
||||
|
||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
|
||||
|
||||
modImplementation include("eu.pb4:polymer-core:${project.polymer_version}")
|
||||
modImplementation include("eu.pb4:polymer-blocks:${project.polymer_version}")
|
||||
modImplementation include("eu.pb4:polymer-resource-pack:${project.polymer_version}")
|
||||
modImplementation include("eu.pb4:sgui:${project.sgui_version}")
|
||||
}
|
||||
|
||||
processResources {
|
||||
|
@ -14,4 +14,6 @@ maven_group=net.sys42.dakedres.grafting
|
||||
archives_base_name=grafting
|
||||
|
||||
# Dependencies
|
||||
fabric_version=0.115.4+1.21.1
|
||||
fabric_version=0.115.4+1.21.1
|
||||
polymer_version=0.9.18+1.21.1
|
||||
sgui_version=1.6.1+1.21.1
|
@ -1,10 +0,0 @@
|
||||
package net.sys42.dakedres.grafting;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
|
||||
public class GraftingClient implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
// This entrypoint is suitable for setting up client-specific logic, such as rendering.
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package net.sys42.dakedres.grafting.mixin.client;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(MinecraftClient.class)
|
||||
public class ExampleClientMixin {
|
||||
@Inject(at = @At("HEAD"), method = "run")
|
||||
private void init(CallbackInfo info) {
|
||||
// This code is injected into the start of MinecraftClient.run()V
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "net.sys42.dakedres.grafting.mixin.client",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"client": [
|
||||
"ExampleClientMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
@ -1,7 +1,24 @@
|
||||
package net.sys42.dakedres.grafting;
|
||||
|
||||
import eu.pb4.polymer.core.api.block.PolymerBlockUtils;
|
||||
import eu.pb4.polymer.resourcepack.api.PolymerModelData;
|
||||
import eu.pb4.polymer.resourcepack.api.PolymerResourcePackUtils;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.sound.BlockSoundGroup;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.sys42.dakedres.grafting.blocks.Workbench;
|
||||
import net.sys42.dakedres.grafting.blocks.WorkbenchBlockEntity;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -13,6 +30,21 @@ public class Grafting implements ModInitializer {
|
||||
// That way, it's clear which mod wrote info, warnings, and errors.
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
||||
|
||||
public static final Identifier WORKBENCH_ID = Identifier.of(Grafting.MOD_ID, "workbench");
|
||||
public static final Block WORKBENCH = Registry.register(
|
||||
Registries.BLOCK, WORKBENCH_ID,
|
||||
new Workbench(AbstractBlock.Settings.create().sounds(BlockSoundGroup.WOOD))
|
||||
);
|
||||
public static final BlockEntityType<WorkbenchBlockEntity> WORKBENCH_BLOCK_ENTITY_TYPE = Registry.register(
|
||||
Registries.BLOCK_ENTITY_TYPE,
|
||||
WORKBENCH_ID,
|
||||
FabricBlockEntityTypeBuilder.create(WorkbenchBlockEntity::new, WORKBENCH).build()
|
||||
);
|
||||
public static final BlockItem WORKBENCH_ITEM = Registry.register(
|
||||
Registries.ITEM, WORKBENCH_ID,
|
||||
new Workbench.WorkbenchItem(WORKBENCH, new Item.Settings())
|
||||
);
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
// This code runs as soon as Minecraft is in a mod-load-ready state.
|
||||
@ -20,5 +52,14 @@ public class Grafting implements ModInitializer {
|
||||
// Proceed with mild caution.
|
||||
|
||||
LOGGER.info("Hello Fabric world!");
|
||||
|
||||
PolymerBlockUtils.registerBlockEntity(WORKBENCH_BLOCK_ENTITY_TYPE);
|
||||
|
||||
if (PolymerResourcePackUtils.addModAssets(MOD_ID)) {
|
||||
LOGGER.info("Successfully added mod assets for " + MOD_ID);
|
||||
} else {
|
||||
LOGGER.error("Failed to add mod assets for " + MOD_ID);
|
||||
}
|
||||
PolymerResourcePackUtils.markAsRequired();
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package net.sys42.dakedres.grafting;
|
||||
|
||||
public class PlacementMatrixUtils {
|
||||
public static final int[][] ROTATION_MATRICES = {
|
||||
{ 0,1,2,3,4,5,6,7,8 },
|
||||
{ 1,2,5,0,4,8,3,6,7 },
|
||||
{ 2,5,8,1,4,7,0,3,6 },
|
||||
{ 5,8,7,2,4,6,1,0,3 },
|
||||
{ 8,7,6,5,4,3,2,1,0 },
|
||||
{ 7,6,3,8,4,0,5,2,1 },
|
||||
{ 6,3,0,7,4,1,8,5,2 },
|
||||
{ 3,0,1,6,4,2,7,8,5 }
|
||||
};
|
||||
|
||||
|
||||
// public static DefaultedList<ItemStack> rotate(DefaultedList<ItemStack> grid, int direction) {
|
||||
// DefaultedList<ItemStack> o = DefaultedList.ofSize(grid.size(), ItemStack.EMPTY);
|
||||
// int[] rotationMatrix = ROTATION_MATRICES[(direction < 0 ? 8 - direction : direction) % 8];
|
||||
//
|
||||
// for(int i = 0; i < grid.size(); i++) {
|
||||
// o.set(rotationMatrix[i], grid.get(i));
|
||||
// }
|
||||
//
|
||||
// return o;
|
||||
// }
|
||||
|
||||
public static int clampRotation(int rotation) {
|
||||
return (rotation < 0 ? 8 + rotation : rotation) % 8;
|
||||
}
|
||||
|
||||
public static int[] getRotationMatrix(int rotation) {
|
||||
return ROTATION_MATRICES[clampRotation(rotation)];
|
||||
}
|
||||
|
||||
public static int[] rotate(int[] matrix, int rotation) {
|
||||
int[] o = new int[matrix.length];
|
||||
int[] rotationMatrix = ROTATION_MATRICES[rotation];
|
||||
|
||||
for(int i = 0; i < matrix.length; i++) {
|
||||
o[rotationMatrix[i]] = matrix[i];
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
public static int[] getPlacements() {
|
||||
int[] placements = {
|
||||
2,0,8,
|
||||
1,3,4,
|
||||
7,6,5
|
||||
};
|
||||
int[] out = new int[9];
|
||||
|
||||
for(int i = 0; i < 9; i++) {
|
||||
out[placements[i]] = i;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package net.sys42.dakedres.grafting.blocks;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import eu.pb4.polymer.core.api.block.PolymerBlock;
|
||||
import eu.pb4.polymer.core.api.item.PolymerItem;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.BlockWithEntity;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.sys42.dakedres.grafting.Grafting;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class Workbench extends BlockWithEntity implements PolymerBlock {
|
||||
private final DefaultedList<ItemStack> stacks = DefaultedList.ofSize(9, ItemStack.EMPTY);
|
||||
|
||||
public Workbench(Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MapCodec<? extends BlockWithEntity> getCodec() {
|
||||
return createCodec(Workbench::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new WorkbenchBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getPolymerBlockState(BlockState blockState) {
|
||||
return Blocks.CRAFTING_TABLE.getDefaultState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) {
|
||||
if(!player.isSneaking() && world.getBlockEntity(pos) instanceof WorkbenchBlockEntity blockEntity) {
|
||||
blockEntity.openMenu((ServerPlayerEntity) player);
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
|
||||
return super.onUse(state, world, pos, player, hit);
|
||||
}
|
||||
|
||||
public static final class WorkbenchItem extends BlockItem implements PolymerItem {
|
||||
public WorkbenchItem(Block block, Settings settings) {
|
||||
super(block, settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity serverPlayerEntity) {
|
||||
return Items.CRAFTING_TABLE;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,404 @@
|
||||
package net.sys42.dakedres.grafting.blocks;
|
||||
|
||||
import eu.pb4.polymer.resourcepack.api.PolymerModelData;
|
||||
import eu.pb4.sgui.api.ClickType;
|
||||
import eu.pb4.sgui.api.elements.GuiElement;
|
||||
import eu.pb4.sgui.api.elements.GuiElementInterface;
|
||||
import eu.pb4.sgui.api.gui.SimpleGui;
|
||||
import eu.pb4.sgui.virtual.inventory.VirtualSlot;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.CrafterBlock;
|
||||
import net.minecraft.block.entity.LockableContainerBlockEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.inventory.CraftingResultInventory;
|
||||
import net.minecraft.inventory.Inventories;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.inventory.RecipeInputInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.recipe.RecipeMatcher;
|
||||
import net.minecraft.recipe.input.CraftingRecipeInput;
|
||||
import net.minecraft.registry.RegistryWrapper;
|
||||
import net.minecraft.screen.NamedScreenHandlerFactory;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.screen.slot.CraftingResultSlot;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import net.minecraft.screen.slot.SlotActionType;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.sys42.dakedres.grafting.Grafting;
|
||||
import net.sys42.dakedres.grafting.PlacementMatrixUtils;
|
||||
import net.sys42.dakedres.grafting.ui.Icons;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class WorkbenchBlockEntity extends LockableContainerBlockEntity implements RecipeInputInventory {
|
||||
|
||||
public static final String NBT_GRID_ROTATION_KEY = "GridRotation";
|
||||
public static final int GRID_SIZE = 9;
|
||||
public static final int GRID_WIDTH = 3;
|
||||
|
||||
private DefaultedList<ItemStack> grid = DefaultedList.ofSize(GRID_SIZE, ItemStack.EMPTY);
|
||||
private int gridRotation = 0;
|
||||
private final ArrayList<Gui> guis = new ArrayList<>();
|
||||
public WorkbenchBlockEntity(BlockPos blockPos, BlockState blockState) {
|
||||
super(Grafting.WORKBENCH_BLOCK_ENTITY_TYPE, blockPos, blockState);
|
||||
}
|
||||
|
||||
public void openMenu(ServerPlayerEntity playerEntity) {
|
||||
playerEntity.openHandledScreen(new NamedScreenHandlerFactory() {
|
||||
@Override
|
||||
public Text getDisplayName() {
|
||||
return WorkbenchBlockEntity.this.getDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) {
|
||||
return WorkbenchBlockEntity.this.createScreenHandler(syncId, playerInventory);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
|
||||
super.readNbt(nbt, registryLookup);
|
||||
this.gridRotation = nbt.getByte(NBT_GRID_ROTATION_KEY);
|
||||
this.grid = DefaultedList.ofSize(this.size(), ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) {
|
||||
super.writeNbt(nbt, registryLookup);
|
||||
nbt.putByte(NBT_GRID_ROTATION_KEY, (byte) gridRotation);
|
||||
Inventories.writeNbt(nbt, this.grid, registryLookup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Text getContainerName() {
|
||||
// TODO: localize
|
||||
return Text.of("Workbench");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return GRID_WIDTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return GRID_WIDTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultedList<ItemStack> getHeldStacks() {
|
||||
return this.grid;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setHeldStacks(DefaultedList<ItemStack> inventory) {
|
||||
this.grid = inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScreenHandler createScreenHandler(int syncId, PlayerInventory playerInventory) {
|
||||
return createScreenHandler(syncId, playerInventory, playerInventory.player);
|
||||
}
|
||||
|
||||
protected ScreenHandler createScreenHandler(int syncId, PlayerInventory playerInventory, PlayerEntity player) {
|
||||
return new Gui((ServerPlayerEntity) player).openAsScreenHandler(syncId, playerInventory, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return GRID_SIZE;
|
||||
}
|
||||
|
||||
public boolean hasEmptySlots() {
|
||||
for(ItemStack itemStack : grid) {
|
||||
if (itemStack.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int[] getPlacementMatrix() {
|
||||
return PlacementMatrixUtils.rotate(PlacementMatrixUtils.getPlacements(), gridRotation);
|
||||
}
|
||||
|
||||
public void placeStack(ItemStack stack) {
|
||||
int[] placements = getPlacementMatrix();
|
||||
|
||||
for(int i = 0; i < GRID_SIZE; i++) {
|
||||
int p = placements[i];
|
||||
if(getStack(p).isEmpty()) {
|
||||
setStack(p, stack);
|
||||
distributeStack(stack, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void distributeStack(ItemStack stack) {
|
||||
distributeStack(stack, stack.getCount());
|
||||
}
|
||||
|
||||
public void distributeStack(ItemStack stack, int count) {
|
||||
ArrayList<ItemStack> candidates = new ArrayList<>();
|
||||
int totalCount = count;
|
||||
int maxTotalCount = 0;
|
||||
int[] placements = getPlacementMatrix();
|
||||
|
||||
for(int i = 0; i < GRID_SIZE; i++) {
|
||||
int p = placements[i];
|
||||
ItemStack ps = getStack(p);
|
||||
if(!ps.isEmpty() && ItemStack.areItemsAndComponentsEqual(ps, stack)) {
|
||||
totalCount += ps.getCount();
|
||||
maxTotalCount += ps.getMaxCount();
|
||||
ps.setCount(0);
|
||||
candidates.add(ps);
|
||||
}
|
||||
}
|
||||
|
||||
int remainder = 0;
|
||||
if(totalCount > maxTotalCount) {
|
||||
remainder = totalCount - maxTotalCount;
|
||||
totalCount = maxTotalCount;
|
||||
}
|
||||
int i = 0;
|
||||
while(totalCount > 0) {
|
||||
candidates.get(i % candidates.size()).increment(1);
|
||||
totalCount--;
|
||||
i++;
|
||||
}
|
||||
|
||||
stack.decrement(count - remainder);
|
||||
markDirty();
|
||||
}
|
||||
|
||||
protected int lastPriorityIndexAlike(ItemStack stack) {
|
||||
int[] placements = getPlacementMatrix();
|
||||
|
||||
for(int i = placements.length - 1; i >= 0; i--) {
|
||||
int p = placements[i];
|
||||
ItemStack ps = getStack(p);
|
||||
if(ItemStack.areItemsAndComponentsEqual(ps, stack)) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public ItemStack removeStack(ItemStack stack, int amount) {
|
||||
int index = lastPriorityIndexAlike(stack);
|
||||
|
||||
if(index >= 0) {
|
||||
ItemStack o = removeStack(index, amount);
|
||||
distributeStack(o, 0);
|
||||
return o;
|
||||
}
|
||||
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
public boolean hasItemsLike(ItemStack stack) {
|
||||
for(ItemStack itemStack : grid) {
|
||||
if(ItemStack.areItemsAndComponentsEqual(itemStack, stack)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Based on CrafterScreenHandler#updateResult
|
||||
public ItemStack getResult(ServerPlayerEntity player) {
|
||||
World world = player.getWorld();
|
||||
CraftingRecipeInput craftingRecipeInput = createRecipeInput();
|
||||
return CrafterBlock.getCraftingRecipe(world, craftingRecipeInput)
|
||||
.map(recipe -> recipe.value()
|
||||
.craft(craftingRecipeInput, world.getRegistryManager())
|
||||
)
|
||||
.orElse(ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDirty() {
|
||||
for(Gui gui : guis) {
|
||||
gui.updateResult();
|
||||
}
|
||||
super.markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provideRecipeInputs(RecipeMatcher finder) {
|
||||
|
||||
}
|
||||
|
||||
// TODO: Reimplement. Need to prevent any possible desync between the orientation as manipulated here, and the one in getPlacements
|
||||
public void rotate(int direction) {
|
||||
gridRotation = PlacementMatrixUtils.clampRotation(gridRotation + direction);
|
||||
int[] rotationMatrix = PlacementMatrixUtils.ROTATION_MATRICES[PlacementMatrixUtils.clampRotation(direction)];
|
||||
DefaultedList<ItemStack> newGrid = DefaultedList.ofSize(grid.size(), ItemStack.EMPTY);
|
||||
|
||||
for(int i = 0; i < grid.size(); i++) {
|
||||
newGrid.set(rotationMatrix[i], grid.get(i));
|
||||
}
|
||||
|
||||
setHeldStacks(newGrid);
|
||||
markDirty();
|
||||
}
|
||||
|
||||
public class Gui extends SimpleGui {
|
||||
private static final int BUTTONS_LEFT = 1;
|
||||
private static final int GRID_LEFT = BUTTONS_LEFT + 1;
|
||||
private static final int RESULT_LEFT = GRID_LEFT + GRID_WIDTH + 2;
|
||||
|
||||
private final CraftingResultInventory resultInventory = new CraftingResultInventory();
|
||||
public Gui(ServerPlayerEntity player) {
|
||||
super(ScreenHandlerType.GENERIC_9X3, player, false);
|
||||
guis.add(this);
|
||||
|
||||
this.setTitle(WorkbenchBlockEntity.this.getDisplayName());
|
||||
setSlot(BUTTONS_LEFT, new RotateGridButton(Icons.ROTATE_CLOCKWISE,1));
|
||||
setSlot(BUTTONS_LEFT + 9, new RotateGridButton(Icons.ROTATE_COUNTER_CLOCKWISE, -1));
|
||||
setSlotRedirect(
|
||||
RESULT_LEFT + 9,
|
||||
new CraftingResultSlot(player, WorkbenchBlockEntity.this, resultInventory, 0, 0, 0)
|
||||
);
|
||||
for(int i = 0; i < GRID_SIZE; i++) {
|
||||
int row = (i / GRID_WIDTH);
|
||||
setSlotRedirect(
|
||||
GRID_LEFT + (i % GRID_WIDTH) + (row * 9),
|
||||
new GridSlot(i)
|
||||
);
|
||||
}
|
||||
|
||||
updateResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
guis.remove(this);
|
||||
super.close();
|
||||
}
|
||||
|
||||
protected void updateResult() {
|
||||
resultInventory.setStack(0, getResult(player));
|
||||
}
|
||||
|
||||
/*
|
||||
According to ScreenHandler#internalOnSlotClick, quickMove is continually called
|
||||
while it returns a non-empty ItemStack that matches the original slot
|
||||
*/
|
||||
@Override
|
||||
public ItemStack quickMove(int index) {
|
||||
ItemStack returnStack = ItemStack.EMPTY;
|
||||
Slot slot = this.getSlotRedirectOrPlayer(index);
|
||||
|
||||
if(slot != null && slot.hasStack() && !(slot instanceof VirtualSlot)) {
|
||||
ItemStack operatingStack = slot.getStack();
|
||||
returnStack = operatingStack.copy();
|
||||
|
||||
if(index < this.getVirtualSize()) {
|
||||
int i = -1;
|
||||
|
||||
if(slot instanceof GridSlot) {
|
||||
i = lastPriorityIndexAlike(operatingStack);
|
||||
operatingStack = i == -1 ? ItemStack.EMPTY : removeStack(i);
|
||||
|
||||
if (!this.insertItem(operatingStack, this.getVirtualSize(), this.getVirtualSize() + 36, true)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.insertItem(operatingStack, this.getVirtualSize(), this.getVirtualSize() + 36, true)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
if(slot.getIndex() == i) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else {
|
||||
if(hasItemsLike(operatingStack)) {
|
||||
distributeStack(operatingStack);
|
||||
return ItemStack.EMPTY;
|
||||
} else if(hasEmptySlots()) {
|
||||
placeStack(operatingStack);
|
||||
slot.setStack(ItemStack.EMPTY);
|
||||
} else {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
if (operatingStack.isEmpty()) {
|
||||
slot.setStack(ItemStack.EMPTY);
|
||||
} else {
|
||||
slot.markDirty();
|
||||
}
|
||||
} else if (slot instanceof VirtualSlot) {
|
||||
return slot.getStack();
|
||||
}
|
||||
|
||||
return returnStack;
|
||||
}
|
||||
|
||||
// - Inserting single items changes the shape
|
||||
// - Inserting a full stack will attempt to distribute the stack, or insert if that stack isn't in the workbench
|
||||
public class GridSlot extends Slot {
|
||||
public GridSlot(int index) {
|
||||
super(WorkbenchBlockEntity.this, index, index, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack insertStack(ItemStack stack, int count) {
|
||||
|
||||
if(stack.isEmpty()) {
|
||||
return stack;
|
||||
}
|
||||
|
||||
int allowedCount = Math.min(count, stack.getCount());
|
||||
if(
|
||||
(!hasItemsLike(stack) || count == 1) &&
|
||||
WorkbenchBlockEntity.this.hasEmptySlots()
|
||||
) {
|
||||
placeStack(stack.split(allowedCount));
|
||||
} else {
|
||||
distributeStack(stack, allowedCount);
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack takeStack(int amount) {
|
||||
return removeStack(this.getStack(), amount);
|
||||
}
|
||||
}
|
||||
|
||||
public class RotateGridButton extends GuiElement {
|
||||
public RotateGridButton(PolymerModelData model, int bias) {
|
||||
super(
|
||||
Icons.getStack(model),
|
||||
new GuiElementInterface.ItemClickCallback() {
|
||||
@Override
|
||||
public void click(int i, ClickType clickType, SlotActionType slotActionType) {
|
||||
switch(clickType) {
|
||||
case ClickType.MOUSE_LEFT -> rotate(bias);
|
||||
case ClickType.MOUSE_RIGHT -> rotate(bias * -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package net.sys42.dakedres.grafting.item;
|
||||
|
||||
import eu.pb4.polymer.core.api.item.PolymerItem;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.item.*;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class WorkbenchItem extends BlockItem implements PolymerItem {
|
||||
public WorkbenchItem(Block block, Settings settings, String modelId) {
|
||||
super(block, settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity serverPlayerEntity) {
|
||||
return Items.CRAFTING_TABLE;
|
||||
}
|
||||
|
||||
// Thank you Mykhailo!
|
||||
// copied from:
|
||||
// https://github.com/MykhailoOpryshok/Borukva-Food/blob/master/src/main/java/com/opryshok/block/TexturedPolyBlockItem.java#L18
|
||||
// @Override
|
||||
// public ActionResult useOnBlock(ItemUsageContext context) {
|
||||
// var x = super.useOnBlock(context);
|
||||
// if (x == ActionResult.CONSUME) {
|
||||
// if (context.getPlayer() instanceof ServerPlayerEntity player) {
|
||||
// var pos = Vec3d.ofCenter(context.getBlockPos().offset(context.getSide()));
|
||||
// var blockSoundGroup = this.getBlock().getDefaultState().getSoundGroup();
|
||||
// player.networkHandler.sendPacket(new PlaySoundS2CPacket(Registries.SOUND_EVENT.getEntry(this.getPlaceSound(this.getBlock().getDefaultState())), SoundCategory.BLOCKS, pos.x, pos.y, pos.z, (blockSoundGroup.getVolume() + 1.0F) / 2.0F, blockSoundGroup.getPitch() * 0.8F, context.getPlayer().getRandom().nextLong()));
|
||||
// }
|
||||
// return ActionResult.SUCCESS;
|
||||
// }
|
||||
// return x;
|
||||
// }
|
||||
|
||||
}
|
30
src/main/java/net/sys42/dakedres/grafting/ui/Icons.java
Normal file
30
src/main/java/net/sys42/dakedres/grafting/ui/Icons.java
Normal file
@ -0,0 +1,30 @@
|
||||
package net.sys42.dakedres.grafting.ui;
|
||||
|
||||
import eu.pb4.polymer.resourcepack.api.PolymerModelData;
|
||||
import eu.pb4.polymer.resourcepack.api.PolymerResourcePackUtils;
|
||||
import net.minecraft.component.ComponentType;
|
||||
import net.minecraft.component.DataComponentTypes;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.Unit;
|
||||
import net.sys42.dakedres.grafting.Grafting;
|
||||
|
||||
public class Icons {
|
||||
public static final Item BASE_ITEM = Items.BREEZE_ROD;
|
||||
|
||||
public static final PolymerModelData ROTATE_CLOCKWISE = uiElementModel("icons/rotate_clockwise.png");
|
||||
public static final PolymerModelData ROTATE_COUNTER_CLOCKWISE = uiElementModel("icons/rotate_counter_clockwise.png");
|
||||
|
||||
private static PolymerModelData uiElementModel(String path) {
|
||||
return PolymerResourcePackUtils.requestModel(BASE_ITEM, Identifier.of(Grafting.MOD_ID + path));
|
||||
}
|
||||
|
||||
public static ItemStack getStack(PolymerModelData model) {
|
||||
ItemStack stack = Icons.ROTATE_CLOCKWISE.asStack();
|
||||
stack.set(DataComponentTypes.HIDE_TOOLTIP, Unit.INSTANCE);
|
||||
|
||||
return stack;
|
||||
}
|
||||
}
|
121
src/main/resources/assets/grafting/models/block/workbench.json
Normal file
121
src/main/resources/assets/grafting/models/block/workbench.json
Normal file
@ -0,0 +1,121 @@
|
||||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"textures": {
|
||||
"4": "grafting:block/workbench_top",
|
||||
"5": "grafting:block/workbench_front",
|
||||
"6": "grafting:block/workbench_bottom",
|
||||
"7": "grafting:block/workbench_side",
|
||||
"particle": "grafting:block/workbench_top"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 12],
|
||||
"to": [4, 12, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [12, 5, 16, 16], "texture": "#5"},
|
||||
"east": {"uv": [0, 5, 4, 16], "texture": "#7"},
|
||||
"south": {"uv": [0, 5, 4, 16], "texture": "#5"},
|
||||
"west": {"uv": [12, 5, 16, 16], "texture": "#7"},
|
||||
"up": {"uv": [0, 0, 4, 4], "texture": "#missing"},
|
||||
"down": {"uv": [12, 12, 16, 16], "rotation": 180, "texture": "#6"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [4, 12, 4],
|
||||
"faces": {
|
||||
"north": {"uv": [12, 5, 16, 16], "texture": "#5"},
|
||||
"east": {"uv": [12, 5, 16, 16], "texture": "#7"},
|
||||
"south": {"uv": [0, 5, 4, 16], "texture": "#5"},
|
||||
"west": {"uv": [0, 5, 4, 16], "texture": "#7"},
|
||||
"up": {"uv": [0, 0, 4, 4], "rotation": 90, "texture": "#missing"},
|
||||
"down": {"uv": [12, 0, 16, 4], "rotation": 180, "texture": "#6"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [12, 0, 12],
|
||||
"to": [16, 12, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 5, 4, 16], "texture": "#5"},
|
||||
"east": {"uv": [0, 5, 4, 16], "texture": "#7"},
|
||||
"south": {"uv": [12, 5, 16, 16], "texture": "#5"},
|
||||
"west": {"uv": [12, 5, 16, 16], "texture": "#7"},
|
||||
"up": {"uv": [0, 0, 4, 4], "rotation": 270, "texture": "#missing"},
|
||||
"down": {"uv": [0, 12, 4, 16], "rotation": 180, "texture": "#6"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [12, 0, 0],
|
||||
"to": [16, 12, 4],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 5, 4, 16], "texture": "#5"},
|
||||
"east": {"uv": [12, 5, 16, 16], "texture": "#7"},
|
||||
"south": {"uv": [12, 5, 16, 16], "texture": "#5"},
|
||||
"west": {"uv": [0, 5, 4, 16], "texture": "#7"},
|
||||
"up": {"uv": [0, 0, 4, 4], "rotation": 180, "texture": "#missing"},
|
||||
"down": {"uv": [0, 0, 4, 4], "rotation": 180, "texture": "#6"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0, 12, 0],
|
||||
"to": [16, 16, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 16, 4], "texture": "#5"},
|
||||
"east": {"uv": [0, 0, 16, 4], "texture": "#7"},
|
||||
"south": {"uv": [0, 0, 16, 4], "texture": "#5"},
|
||||
"west": {"uv": [0, 0, 16, 4], "texture": "#7"},
|
||||
"up": {"uv": [0, 0, 16, 16], "texture": "#4"},
|
||||
"down": {"uv": [0, 0, 16, 16], "texture": "#6"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, 0, 16],
|
||||
"to": [12, 12, 16],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 6]},
|
||||
"faces": {
|
||||
"north": {"uv": [4, 4, 12, 16], "texture": "#5"},
|
||||
"south": {"uv": [4, 4, 12, 16], "texture": "#5"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, 0, 0],
|
||||
"to": [12, 12, 0],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 4, -10]},
|
||||
"faces": {
|
||||
"north": {"uv": [4, 4, 12, 16], "texture": "#5"},
|
||||
"south": {"uv": [4, 4, 12, 16], "texture": "#5"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"display": {
|
||||
"thirdperson_righthand": {
|
||||
"rotation": [75, 45, 0],
|
||||
"translation": [0, 2.5, 0],
|
||||
"scale": [0.375, 0.375, 0.375]
|
||||
},
|
||||
"thirdperson_lefthand": {
|
||||
"rotation": [75, 45, 0],
|
||||
"translation": [0, 2.5, 0],
|
||||
"scale": [0.375, 0.375, 0.375]
|
||||
},
|
||||
"firstperson_righthand": {
|
||||
"rotation": [0, 45, 0],
|
||||
"scale": [0.4, 0.4, 0.4]
|
||||
},
|
||||
"firstperson_lefthand": {
|
||||
"rotation": [0, 225, 0],
|
||||
"scale": [0.4, 0.4, 0.4]
|
||||
},
|
||||
"ground": {
|
||||
"translation": [0, 3, 0],
|
||||
"scale": [0.25, 0.25, 0.25]
|
||||
},
|
||||
"gui": {
|
||||
"rotation": [30, 225, 0],
|
||||
"scale": [0.625, 0.625, 0.625]
|
||||
},
|
||||
"fixed": {
|
||||
"scale": [0.5, 0.5, 0.5]
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 677 B |
Binary file not shown.
After Width: | Height: | Size: 670 B |
@ -17,17 +17,10 @@
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.sys42.dakedres.grafting.Grafting"
|
||||
],
|
||||
"client": [
|
||||
"net.sys42.dakedres.grafting.GraftingClient"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"grafting.mixins.json",
|
||||
{
|
||||
"config": "grafting.client.mixins.json",
|
||||
"environment": "client"
|
||||
}
|
||||
"grafting.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.16.13",
|
||||
|
Loading…
x
Reference in New Issue
Block a user