🎉 Trading starts!

This commit is contained in:
2023-08-15 21:30:14 +02:00
commit 51814b9f5d
76 changed files with 4585 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
package com.oierbravo.trading_station;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mojang.logging.LogUtils;
import com.oierbravo.trading_station.foundation.util.ModLang;
import com.oierbravo.trading_station.registrate.*;
import com.tterrag.registrate.Registrate;
import net.minecraftforge.common.util.Lazy;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.slf4j.Logger;
// The value here should match an entry in the META-INF/mods.toml file
@Mod("trading_station")
public class TradingStation
{
// Directly reference a slf4j logger
public static final Logger LOGGER = LogUtils.getLogger();
public static final String MODID = "trading_station";
public static final String DISPLAY_NAME = "Trading Station";
public static IEventBus modEventBus;
private static final Lazy<Registrate> REGISTRATE = Lazy.of(() -> Registrate.create(MODID));
public static final boolean withCreate = ModList.get().isLoaded("create");
public static final Gson GSON = new GsonBuilder().setPrettyPrinting()
.disableHtmlEscaping()
.create();
public TradingStation()
{
modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
// Register ourselves for server and other game events we are interested in
MinecraftForge.EVENT_BUS.register(this);
ModCreativeTab modTab = new ModCreativeTab();
ModBlocks.register();
ModBlockEntities.register();
ModRecipes.register(modEventBus);
ModMessages.register();
ModMenus.register();
Config.register();
registrate().addRawLang("itemGroup.trading_station:main", "Trading Station");
registrate().addRawLang(ModLang.key("block.display"), "Trading Station");
registrate().addRawLang(ModLang.key("recipe"), "Trading recipe");
registrate().addRawLang(ModLang.key("tooltip.progress"), "Progress: %d%%");
registrate().addRawLang(ModLang.key("select_target.title"), "Select an output target");
registrate().addRawLang(ModLang.key("select_target.button"), "Select target");
registrate().addRawLang(ModLang.key("select_target.clear"), "Clear");
registrate().addRawLang("config.jade.plugin_trading_station.trading_station_data", "Trading Station data");
}
public static Registrate registrate() {
return REGISTRATE.get();
}
public static ResourceLocation asResource(String path) {
return new ResourceLocation(MODID, path);
}
}

View File

@@ -0,0 +1,35 @@
package com.oierbravo.trading_station.compat.crafttweaker;
import com.blamejared.crafttweaker.api.recipe.component.IDecomposedRecipe;
import com.blamejared.crafttweaker.api.recipe.handler.IRecipeHandler;
import com.blamejared.crafttweaker.api.recipe.manager.base.IRecipeManager;
import com.oierbravo.trading_station.content.trading_station.TradingRecipe;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.crafting.Recipe;
import java.util.Optional;
@IRecipeHandler.For(TradingRecipe.class)
public class TradingRecipeHandler implements IRecipeHandler<TradingRecipe>{
@Override
public String dumpToCommandString(IRecipeManager<? super TradingRecipe> manager, TradingRecipe recipe) {
return manager.getCommandString() + recipe.toString() + recipe.getOutput() + "[" + recipe.getIngredient() + "]";
}
@Override
public <U extends Recipe<?>> boolean doesConflict(IRecipeManager<? super TradingRecipe> manager, TradingRecipe firstRecipe, U secondRecipe) {
return false;
}
@Override
public Optional<IDecomposedRecipe> decompose(IRecipeManager<? super TradingRecipe> manager, TradingRecipe recipe) {
return Optional.empty();
}
@Override
public Optional<TradingRecipe> recompose(IRecipeManager<? super TradingRecipe> manager, ResourceLocation name, IDecomposedRecipe recipe) {
return Optional.empty();
}
}

View File

@@ -0,0 +1,46 @@
package com.oierbravo.trading_station.compat.crafttweaker;
import com.blamejared.crafttweaker.api.CraftTweakerAPI;
import com.blamejared.crafttweaker.api.action.recipe.ActionAddRecipe;
import com.blamejared.crafttweaker.api.annotation.ZenRegister;
import com.blamejared.crafttweaker.api.fluid.IFluidStack;
import com.blamejared.crafttweaker.api.ingredient.IIngredient;
import com.blamejared.crafttweaker.api.recipe.manager.base.IRecipeManager;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingRecipe;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.crafting.RecipeType;
import org.openzen.zencode.java.ZenCodeType;
@ZenRegister
@ZenCodeType.Name("mods.trading_station.TradingManager")
//@Document("mods/trading_station/melting")
public class TradingRecipeManager implements IRecipeManager<TradingRecipe> {
/**
* Adds a Trading recipe.
*
* @param name The name of the recipe
* @param output The output fluidStack of the recipe.
* @param input The input of the recipe.
* @param processingTime The duration of the recipe (default 100 ticks)
* @param heatLevel Minimum heat level
*
* @docParam name "meltDown"
* @docParam output <fluid:minecraft:lava> * 100
* @docParam input <item:minecraft:dirt>
* @docParam duration 200
* @docParam heatLevel 2
*/
@ZenCodeType.Method
public void addRecipe(String name, IFluidStack output, IIngredient input, int processingTime, int heatLevel ){
name = fixRecipeName(name);
ResourceLocation resourceLocation = new ResourceLocation(TradingStation.MODID, name);
CraftTweakerAPI.apply(new ActionAddRecipe<>( this, new TradingRecipe(resourceLocation, output.getInternal(), input.asVanillaIngredient(), processingTime, heatLevel)));
}
@Override
public RecipeType<TradingRecipe> getRecipeType() {
return TradingRecipe.Type.INSTANCE;
}
}

View File

@@ -0,0 +1,45 @@
package com.oierbravo.trading_station.compat.jade;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import snownee.jade.api.BlockAccessor;
import snownee.jade.api.IBlockComponentProvider;
import snownee.jade.api.IServerDataProvider;
import snownee.jade.api.ITooltip;
import snownee.jade.api.config.IPluginConfig;
import snownee.jade.api.ui.IElementHelper;
import snownee.jade.api.ui.IProgressStyle;
public class ProgressComponentProvider implements IBlockComponentProvider, IServerDataProvider<BlockEntity> {
@Override
public void appendTooltip(ITooltip tooltip, BlockAccessor accessor, IPluginConfig config) {
//CompoundTag serverData = accessor.getServerData();
if (accessor.getServerData().contains("trading_station.progress")) {
int progress = accessor.getServerData().getInt("trading_station.progress");
IElementHelper elementHelper = tooltip.getElementHelper();
IProgressStyle progressStyle = elementHelper.progressStyle();
if(progress > 0)
tooltip.add(elementHelper.progress((float)progress / 100, Component.translatable("trading_station.tooltip.progress", progress), progressStyle,elementHelper.borderStyle()));
}
}
@Override
public void appendServerData(CompoundTag compoundTag, ServerPlayer serverPlayer, Level level, BlockEntity blockEntity, boolean b) {
if(blockEntity instanceof TradingStationBlockEntity){
TradingStationBlockEntity trading_station = (TradingStationBlockEntity) blockEntity;
compoundTag.putInt("trading_station.progress",trading_station.getProgressPercent());
}
}
@Override
public ResourceLocation getUid() {
return TradingStationPlugin.TRADING_STATION_DATA;
}
}

View File

@@ -0,0 +1,22 @@
package com.oierbravo.trading_station.compat.jade;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlock;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import net.minecraft.resources.ResourceLocation;
import snownee.jade.api.*;
@WailaPlugin
public class TradingStationPlugin implements IWailaPlugin {
public static final ResourceLocation TRADING_STATION_DATA = TradingStation.asResource("trading_station_data");
@Override
public void register(IWailaCommonRegistration registration) {
registration.registerBlockDataProvider(new ProgressComponentProvider(), TradingStationBlockEntity.class);
}
@Override
public void registerClient(IWailaClientRegistration registration) {
registration.registerBlockComponent(new ProgressComponentProvider(), TradingStationBlock.class);
}
}

View File

@@ -0,0 +1,49 @@
package com.oierbravo.trading_station.compat.jei;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingRecipe;
import com.oierbravo.trading_station.content.trading_station.TradingStationScreen;
import com.oierbravo.trading_station.registrate.ModBlocks;
import mezz.jei.api.IModPlugin;
import mezz.jei.api.JeiPlugin;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.registration.IGuiHandlerRegistration;
import mezz.jei.api.registration.IRecipeCatalystRegistration;
import mezz.jei.api.registration.IRecipeCategoryRegistration;
import mezz.jei.api.registration.IRecipeRegistration;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeManager;
import java.util.List;
import java.util.Objects;
@JeiPlugin
public class JEIPlugin implements IModPlugin {
@Override
public ResourceLocation getPluginUid() {
return new ResourceLocation(TradingStation.MODID, "jei_plugin");
}
@Override
public void registerCategories(IRecipeCategoryRegistration registration) {
registration.addRecipeCategories(new
TradingRecipeCategory(registration.getJeiHelpers().getGuiHelper()));
}
@Override
public void registerRecipeCatalysts(IRecipeCatalystRegistration registration) {
registration.addRecipeCatalyst(new ItemStack(ModBlocks.TRADING_STATION.get()),new RecipeType<>(TradingRecipeCategory.UID, TradingRecipe.class));
}
@Override
public void registerRecipes(IRecipeRegistration registration) {
RecipeManager rm = Objects.requireNonNull(Minecraft.getInstance().level).getRecipeManager();
List<TradingRecipe> tradingRecipes = rm.getAllRecipesFor(TradingRecipe.Type.INSTANCE);
registration.addRecipes(new RecipeType<>(TradingRecipeCategory.UID, TradingRecipe.class), tradingRecipes);
}
}

View File

@@ -0,0 +1,128 @@
package com.oierbravo.trading_station.compat.jei;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.mojang.blaze3d.vertex.PoseStack;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingRecipe;
import com.oierbravo.trading_station.foundation.util.ModLang;
import com.oierbravo.trading_station.registrate.ModBlocks;
import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder;
import mezz.jei.api.gui.drawable.IDrawable;
import mezz.jei.api.gui.drawable.IDrawableAnimated;
import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
import mezz.jei.api.helpers.IGuiHelper;
import mezz.jei.api.recipe.IFocusGroup;
import mezz.jei.api.recipe.RecipeIngredientRole;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.category.IRecipeCategory;
import mezz.jei.common.Constants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.core.NonNullList;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import javax.annotation.Nonnull;
import java.util.Arrays;
public class TradingRecipeCategory implements IRecipeCategory<TradingRecipe> {
public final static ResourceLocation UID = new ResourceLocation(TradingStation.MODID, "trading");
private final LoadingCache<Integer, IDrawableAnimated> cachedArrows;
private final IDrawable background;
private final IDrawable icon;
public TradingRecipeCategory(IGuiHelper helper) {
this.cachedArrows = CacheBuilder.newBuilder()
.maximumSize(25)
.build(new CacheLoader<>() {
@Override
public IDrawableAnimated load(Integer cookTime) {
return helper.drawableBuilder(Constants.RECIPE_GUI_VANILLA, 82, 128, 24, 17)
.buildAnimated(cookTime, IDrawableAnimated.StartDirection.LEFT, false);
}
});
this.background = new IDrawable() {
@Override
public int getWidth() {
return 176;
}
@Override
public int getHeight() {
return 45;
}
@Override
public void draw(PoseStack poseStack, int xOffset, int yOffset) {
}
};
this.icon = helper.createDrawableIngredient(VanillaTypes.ITEM_STACK, new ItemStack(ModBlocks.TRADING_STATION.get()));
}
protected IDrawableAnimated getArrow() {
return this.cachedArrows.getUnchecked(50);
}
@Override
public RecipeType<TradingRecipe> getRecipeType() {
return RecipeType.create("trading_station","trading", TradingRecipe.class);
}
@Override
public Component getTitle() {
return ModLang.translate("trading.recipe");
}
@Override
public IDrawable getBackground() {
return this.background;
}
@Override
public IDrawable getIcon() {
return this.icon;
}
@Override
public void setRecipe(@Nonnull IRecipeLayoutBuilder builder, @Nonnull TradingRecipe recipe, @Nonnull IFocusGroup focusGroup) {
NonNullList<Ingredient> ingredients = recipe.getIngredients();
for(int index = 0; index < ingredients.size(); index++) {
Ingredient ing = ingredients.get(index);
builder.addSlot(RecipeIngredientRole.INPUT, 41 + index * 18, 11)
.addIngredients(ingredients.get(index));
//.addItemStacks(Arrays.asList(ingredients.get(0).getItems()));
}
builder.addSlot(RecipeIngredientRole.OUTPUT, 113, 11)
.addItemStack(recipe.getResultItem());
}
@Override
public void draw(TradingRecipe recipe, IRecipeSlotsView recipeSlotsView, PoseStack stack, double mouseX, double mouseY) {
IRecipeCategory.super.draw(recipe, recipeSlotsView, stack, mouseX, mouseY);
IDrawableAnimated arrow = getArrow();
arrow.draw(stack, 75, 14);
drawProcessingTime(recipe, stack, 81,4);
}
protected void drawProcessingTime(TradingRecipe recipe, PoseStack poseStack, int x, int y) {
int processingTime = recipe.getProcessingTime();
if (processingTime > 0) {
int cookTimeSeconds = processingTime / 20;
MutableComponent timeString = Component.translatable("gui.jei.category.smelting.time.seconds", cookTimeSeconds);
Minecraft minecraft = Minecraft.getInstance();
Font fontRenderer = minecraft.font;
fontRenderer.draw(poseStack, timeString, x, y, 0xFF808080);
}
}
}

View File

@@ -0,0 +1,12 @@
package com.oierbravo.trading_station.compat.kubejs;
import com.oierbravo.trading_station.content.trading_station.TradingRecipe;
import dev.latvian.mods.kubejs.recipe.schema.RegisterRecipeSchemasEvent;
public class KubeJSPlugin extends dev.latvian.mods.kubejs.KubeJSPlugin {
@Override
public void registerRecipeSchemas(RegisterRecipeSchemasEvent event) {
event.register(TradingRecipe.Serializer.ID, TradingRecipeSchema.SCHEMA);
}
}

View File

@@ -0,0 +1,29 @@
package com.oierbravo.trading_station.compat.kubejs;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import dev.latvian.mods.kubejs.item.InputItem;
import dev.latvian.mods.kubejs.item.OutputItem;
import dev.latvian.mods.kubejs.recipe.RecipeJS;
import dev.latvian.mods.kubejs.recipe.RecipeKey;
import dev.latvian.mods.kubejs.recipe.component.ItemComponents;
import dev.latvian.mods.kubejs.recipe.component.NumberComponent;
import dev.latvian.mods.kubejs.recipe.schema.RecipeSchema;
public interface TradingRecipeSchema {
RecipeKey<InputItem[]> INGREDIENTS = ItemComponents.INPUT_ARRAY.key("ingredients");
RecipeKey<OutputItem> RESULT = ItemComponents.OUTPUT.key("result");
RecipeKey<Integer> PROCESSING_TIME = NumberComponent.INT.key("processingTime").optional(1);
public class TradingRecipeJS extends RecipeJS{
@Override
public JsonElement writeInputItem(InputItem value) {
JsonObject json = super.writeInputItem(value).getAsJsonObject();
if(value.count > 1){
json.addProperty("count", value.count);
}
return (JsonElement) json;
}
}
RecipeSchema SCHEMA = new RecipeSchema(TradingRecipeJS.class, TradingRecipeJS::new, RESULT, INGREDIENTS, PROCESSING_TIME);
}

View File

@@ -0,0 +1,416 @@
package com.oierbravo.trading_station.content.trading_station;
import com.oierbravo.trading_station.foundation.util.ModLang;
import com.oierbravo.trading_station.network.packets.ItemStackSyncS2CPacket;
import com.oierbravo.trading_station.registrate.ModMessages;
import com.oierbravo.trading_station.registrate.ModRecipes;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Containers;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nonnull;
import java.util.Optional;
public abstract class AbstractTradingStationBlockEntity extends BlockEntity {
private CompoundTag updateTag;
public final ItemStackHandler inputItems = createInputItemHandler();
public final ItemStackHandler outputItems = createOutputItemHandler();
public final ItemStackHandler targetItemHandler = createTargetItemHandler();
private final LazyOptional<IItemHandler> inputItemHandler = LazyOptional.of(() -> inputItems);
private final LazyOptional<IItemHandler> outputItemHandler = LazyOptional.of(() -> outputItems);
public int progress = 0;
public int maxProgress = 1;
private BlockState lastBlockState;
protected final ContainerData containerData;
private Item preferedItem;
public AbstractTradingStationBlockEntity(BlockEntityType<?> pType, BlockPos pWorldPosition, BlockState pBlockState) {
super(pType, pWorldPosition, pBlockState);
updateTag = getPersistentData();
lastBlockState = this.getBlockState();
preferedItem = ItemStack.EMPTY.getItem();
containerData = AbstractTradingStationBlockEntity.createContainerData(this);
}
public static ContainerData createContainerData(AbstractTradingStationBlockEntity pBlockEntity){
return new ContainerData(){
@Override
public int get(int pIndex){
return switch (pIndex) {
case 0 -> pBlockEntity.progress;
case 1 -> pBlockEntity.maxProgress;
default -> 0;
};
}
@Override
public void set(int pIndex, int pValue) {
switch (pIndex) {
case 0 -> pBlockEntity.progress = pValue;
case 1 -> pBlockEntity.maxProgress = pValue;
}
}
@Override
public int getCount() {
return 2;
}
};
}
@NotNull
@Nonnull
private ItemStackHandler createTargetItemHandler() {
return new ItemStackHandler(1) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if(!level.isClientSide()) {
ModMessages.sendToClients(new ItemStackSyncS2CPacket(slot,this.getStackInSlot(0), worldPosition, ItemStackSyncS2CPacket.SlotType.TARGET));
}
if(!level.isClientSide()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
// clientSync();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return true;
//return canProcess(stack) && super.isItemValid(slot, stack);
}
@Override
public @NotNull ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate) {
return ItemStack.EMPTY;
}
@Override
public @NotNull ItemStack extractItem(int slot, int amount, boolean simulate) {
return ItemStack.EMPTY;
}
};
}
private ItemStackHandler createInputItemHandler() {
return new ItemStackHandler(2) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if(!level.isClientSide()) {
ModMessages.sendToClients(new ItemStackSyncS2CPacket(slot,this.getStackInSlot(0), worldPosition, ItemStackSyncS2CPacket.SlotType.INPUT));
}
if(!level.isClientSide()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
// clientSync();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return true;
//return canProcess(stack) && super.isItemValid(slot, stack);
}
};
}
@NotNull
@Nonnull
private ItemStackHandler createOutputItemHandler() {
return new ItemStackHandler(1) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if(!level.isClientSide()) {
ModMessages.sendToClients(new ItemStackSyncS2CPacket(slot, this.getStackInSlot(slot), worldPosition, ItemStackSyncS2CPacket.SlotType.OUTPUT));
}
if(!level.isClientSide()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
// clientSync();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return canProcess(stack) && super.isItemValid(slot, stack);
//return false;
}
};
}
@Override
public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
if (cap == ForgeCapabilities.ITEM_HANDLER) {
return inputItemHandler.cast();
}
return super.getCapability(cap, side);
}
@Override
public void setRemoved() {
super.setRemoved();
inputItemHandler.invalidate();
outputItemHandler.invalidate();
}
public LazyOptional<IItemHandler> getInputItemHandler(){
return inputItemHandler;
}
public LazyOptional<IItemHandler> getOutputItemHandler(){
return outputItemHandler;
}
@Override
public void onLoad() {
super.onLoad();
}
@Override
public void invalidateCaps() {
super.invalidateCaps();
inputItemHandler.invalidate();
outputItemHandler.invalidate();
}
@Override
protected void saveAdditional(@NotNull CompoundTag tag) {
super.saveAdditional(tag);
tag.put("input", inputItems.serializeNBT());
tag.put("output", outputItems.serializeNBT());
tag.put("target", targetItemHandler.serializeNBT());
tag.putInt("trading_station.progress", progress);
tag.putInt("trading_station.maxProgress", maxProgress);
String preferedItemString = ForgeRegistries.ITEMS.getKey(preferedItem).toString();
}
@Override
public void load(CompoundTag tag) {
super.load(tag);
inputItems.deserializeNBT(tag.getCompound("input"));
outputItems.deserializeNBT(tag.getCompound("output"));
targetItemHandler.deserializeNBT(tag.getCompound("target"));
progress = tag.getInt("trading_station.progress");
maxProgress = tag.getInt("trading_station.maxProgress");
String preferedItemString = tag.getString("trading_station.preferedItem");
preferedItem = ForgeRegistries.ITEMS.getValue( ResourceLocation.tryParse(preferedItemString));
}
public void drops() {
SimpleContainer inventory = new SimpleContainer(inputItems.getSlots() + 1);
for (int i = 0; i < inputItems.getSlots(); i++) {
inventory.setItem(i, inputItems.getStackInSlot(i));
}
inventory.setItem(inputItems.getSlots(), inputItems.getStackInSlot(0));
Containers.dropContents(this.level, this.worldPosition, inventory);
}
public void resetProgress() {
this.progress = 0;
this.maxProgress = 1;
}
protected static Optional<TradingRecipe> getRecipe(AbstractTradingStationBlockEntity pBlockEntity){
Level level = pBlockEntity.getLevel();
SimpleContainer inputInventory = getInputInventory(pBlockEntity);
if(!pBlockEntity.targetItemHandler.getStackInSlot(0).isEmpty())
return ModRecipes.findByOutput(level,pBlockEntity.targetItemHandler.getStackInSlot(0));
return ModRecipes.find(inputInventory,level);
// return level.getRecipeManager().getRecipeFor(TradingRecipe.Type.INSTANCE, inputInventory, level);
}
protected int getProcessingTime(AbstractTradingStationBlockEntity pBlockEntity) {
return getRecipe(pBlockEntity).map(TradingRecipe::getProcessingTime).orElse(1);
}
public static void tick(Level pLevel, BlockPos pPos, BlockState pState, AbstractTradingStationBlockEntity pBlockEntity) {
if(pLevel.isClientSide()) {
return;
}
if(!isPowered(pBlockEntity))
return;
if (canCraftItem(pBlockEntity)) {
pBlockEntity.progress += 1;
BlockEntity.setChanged(pLevel, pPos, pState);
pBlockEntity.maxProgress = pBlockEntity.getProcessingTime(pBlockEntity);
if (pBlockEntity.progress > pBlockEntity.maxProgress) {
AbstractTradingStationBlockEntity.craftItem(pBlockEntity);
}
BlockEntity.setChanged(pLevel, pPos, pState);
} else {
pBlockEntity.resetProgress();
BlockEntity.setChanged(pLevel, pPos, pState);
}
}
protected static void updateProgress(AbstractTradingStationBlockEntity pBlockEntity){
pBlockEntity.progress += 1;
}
private static boolean isPowered(AbstractTradingStationBlockEntity pBlockEntity){
return pBlockEntity.getLevel().getBlockState(pBlockEntity.getBlockPos())
.getValue(BlockStateProperties.POWERED);
}
private static SimpleContainer getInputInventory(AbstractTradingStationBlockEntity pBlockEntity){
int containerSize = 0;
for(int index = 0; index < pBlockEntity.inputItems.getSlots(); index++) {
if (!pBlockEntity.inputItems.getStackInSlot(index).isEmpty())
containerSize++;
}
SimpleContainer inputInventory = new SimpleContainer(containerSize);
pBlockEntity.inputItemHandler.ifPresent(iItemHandler -> {
for(int slot = 0; slot < iItemHandler.getSlots(); slot++) {
if(!iItemHandler.getStackInSlot(slot).isEmpty()){
inputInventory.addItem(iItemHandler.getStackInSlot(slot));
}
}
});
return inputInventory;
}
private static void craftItem(AbstractTradingStationBlockEntity pBlockEntity) {
Level level = pBlockEntity.getLevel();
SimpleContainer inputInventory = getInputInventory(pBlockEntity);
Optional<TradingRecipe> recipe = getRecipe(pBlockEntity);
if(recipe.isPresent()){
for (int i = 0; i < recipe.get().getIngredients().size(); i++) {
Ingredient ingredient = recipe.get().getIngredients().get(i);
for (int slot = 0; slot < pBlockEntity.inputItems.getSlots(); slot++) {
ItemStack itemStack = pBlockEntity.inputItems.getStackInSlot(slot);
if(ingredient.test(itemStack)){
pBlockEntity.inputItems.extractItem(slot,ingredient.getItems()[0].getCount(),false);
inputInventory.setChanged();
}
}
}
pBlockEntity.outputItems.insertItem(0, recipe.get().getResultItem(), false);
}
pBlockEntity.resetProgress();
pBlockEntity.setChanged();
}
static boolean canCraftItem(AbstractTradingStationBlockEntity pBlockEntity) {
Level level = pBlockEntity.getLevel();
if(level == null)
return false;
SimpleContainer inputInventory = getInputInventory(pBlockEntity);
Optional<TradingRecipe> match = getRecipe(pBlockEntity);
if(match.isEmpty()) {
return false;
}
//return false;
return match.isPresent()
&& AbstractTradingStationBlockEntity.hasEnoughInputItems(inputInventory,match.get().getIngredients())
&& AbstractTradingStationBlockEntity.hasEnoughOutputSpace(pBlockEntity.outputItems,match.get().getResultItem());
}
private boolean canProcess(ItemStack stack) {
return getRecipe(this).isPresent();
}
protected static boolean hasEnoughInputItems(SimpleContainer inventory, NonNullList<Ingredient> ingredients){
int enough = 0;
for(int ingredientIndex = 0; ingredientIndex < ingredients.size();ingredientIndex ++){
Ingredient ingredient = ingredients.get(ingredientIndex);
for(int slot = 0; slot < inventory.getContainerSize(); slot++){
if(ingredient.test(inventory.getItem(slot))){
if(inventory.getItem(slot).getCount() >= ingredient.getItems()[0].getCount() )
enough++;
}
}
}
return ingredients.size() == enough;
}
protected static boolean hasEnoughOutputSpace(ItemStackHandler stackHandler,ItemStack resultItemStack){
return stackHandler.getStackInSlot(0).isEmpty() || stackHandler.getStackInSlot(0).is(resultItemStack.getItem()) && stackHandler.getStackInSlot(0).getMaxStackSize() - stackHandler.getStackInSlot(0).getCount() >= resultItemStack.getCount() ;
}
@Override
public CompoundTag getUpdateTag() {
this.saveAdditional(updateTag);
return updateTag;
}
@Nullable
@Override
public ClientboundBlockEntityDataPacket getUpdatePacket() {
return ClientboundBlockEntityDataPacket.create(this);
}
@Override
public void handleUpdateTag(CompoundTag tag) {
this.load(tag);
}
@Override
public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) {
this.load(pkt.getTag());
}
public int getProgressPercent() {
return this.progress * 100 / this.maxProgress;
}
public void setItemStack(int slot, ItemStack itemStack,ItemStackSyncS2CPacket.SlotType slotType) {
if(slotType == ItemStackSyncS2CPacket.SlotType.INPUT)
inputItems.setStackInSlot(slot,itemStack);
else if (slotType == ItemStackSyncS2CPacket.SlotType.OUTPUT)
outputItems.setStackInSlot(slot,itemStack);
else if (slotType == ItemStackSyncS2CPacket.SlotType.TARGET)
targetItemHandler.setStackInSlot(slot,itemStack);
}
public void setPreferedItem(ItemStack itemStack) {
this.targetItemHandler.setStackInSlot(0,itemStack);
}
public ItemStack getPreferedItemStack() {
return targetItemHandler.getStackInSlot(0);
}
public ItemStackHandler getTargetItemHandler(){
return targetItemHandler;
}
}

View File

@@ -0,0 +1,149 @@
package com.oierbravo.trading_station.content.trading_station;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.platform.Lighting;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.item.ItemStack;
/**
* This class can be used to render a 2D ItemStack to the screen with optional transparency. The item being rendered
* doesn't need to represent a real ItemStack held in an inventory or container.
*/
@SuppressWarnings("unused")
public class FakeItemRenderer {
private static final Minecraft MINECRAFT = Minecraft.getInstance();
private static final ItemRenderer ITEM_RENDERER = MINECRAFT.getItemRenderer();
private static final TextureManager TEXTURE_MANAGER = MINECRAFT.getTextureManager();
public static void renderFakeItem(ItemStack pItemStack, int pX, int pY) {
renderFakeItem(pItemStack, pX, pY, 1.0F);
}
public static void renderFakeItem(ItemStack pItemStack, int pX, int pY, float pAlpha) {
if (!pItemStack.isEmpty()) {
BakedModel model = getBakedModel(pItemStack);
TEXTURE_MANAGER.getTexture(InventoryMenu.BLOCK_ATLAS).setFilter(true, false);
RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
RenderSystem.enableBlend();
PoseStack modelViewStack = RenderSystem.getModelViewStack();
modelViewStack.pushPose();
modelViewStack.translate(pX + 8.0D, pY + 8.0D, 0F);
modelViewStack.scale(16.0F, -16.0F, 16.0F);
RenderSystem.applyModelViewMatrix();
if (!model.usesBlockLight()) {
Lighting.setupForFlatItems();
}
MultiBufferSource.BufferSource bufferSource = MINECRAFT.renderBuffers().bufferSource();
ITEM_RENDERER.render(pItemStack,
ItemTransforms.TransformType.GUI,
false,
new PoseStack(),
getWrappedBuffer(bufferSource, pAlpha),
LightTexture.FULL_BRIGHT,
OverlayTexture.NO_OVERLAY,
model);
bufferSource.endBatch();
RenderSystem.enableDepthTest();
if (!model.usesBlockLight()) {
Lighting.setupFor3DItems();
}
modelViewStack.popPose();
RenderSystem.applyModelViewMatrix();
}
}
private static MultiBufferSource getWrappedBuffer(MultiBufferSource pBufferSource, float pAlpha) {
return pRenderType -> new WrappedVertexConsumer(pBufferSource.getBuffer(RenderType.entityTranslucent(InventoryMenu.BLOCK_ATLAS)), 1F, 1F, 1F, pAlpha);
}
private static BakedModel getBakedModel(ItemStack pItemStack) {
return ITEM_RENDERER.getModel(pItemStack, null, MINECRAFT.player, 0);
}
}
class WrappedVertexConsumer implements VertexConsumer {
protected final VertexConsumer consumer;
protected final float red;
protected final float green;
protected final float blue;
protected final float alpha;
public WrappedVertexConsumer(VertexConsumer pConsumer, float pRed, float pGreen, float pBlue, float pAlpha) {
this.consumer = pConsumer;
this.red = pRed;
this.green = pGreen;
this.blue = pBlue;
this.alpha = pAlpha;
}
@Override
public VertexConsumer vertex(double pX, double pY, double pZ) {
return consumer.vertex(pX, pY, pZ);
}
@Override
public VertexConsumer color(int pRed, int pGreen, int pBlue, int pAlpha) {
return consumer.color((int)(pRed * red), (int)(pGreen * green), (int)(pBlue * blue), (int)(pAlpha * alpha));
}
@Override
public VertexConsumer uv(float pU, float pV) {
return consumer.uv(pU, pV);
}
@Override
public VertexConsumer overlayCoords(int pU, int pV) {
return consumer.overlayCoords(pU, pV);
}
@Override
public VertexConsumer uv2(int pU, int pV) {
return consumer.uv2(pU, pV);
}
@Override
public VertexConsumer normal(float pX, float pY, float pZ) {
return consumer.normal(pX, pY, pZ);
}
@Override
public void endVertex() {
consumer.endVertex();
}
@Override
public void defaultColor(int pDefaultR, int pDefaultG, int pDefaultB, int pDefaultA) {
consumer.defaultColor(pDefaultR, pDefaultG, pDefaultB, pDefaultA);
}
@Override
public void unsetDefaultColor() {
consumer.unsetDefaultColor();
}
}

View File

@@ -0,0 +1,181 @@
package com.oierbravo.trading_station.content.trading_station;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingRecipeBuilder.TradingRecipeParams;
import net.minecraft.core.NonNullList;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.*;
import net.minecraft.world.level.Level;
public class TradingRecipe implements Recipe<SimpleContainer> {
private final ResourceLocation id;
private final NonNullList<Ingredient> itemIngredients;
private final ItemStack result;
private final int processingTime;
public TradingRecipe(TradingRecipeParams params) {
this.id = params.id;
this.result = params.result;
this.itemIngredients = params.itemIngredients;
this.processingTime = params.processingTime;
}
@Override
public boolean matches(SimpleContainer pContainer, Level pLevel) {
if(pLevel.isClientSide)
return false;
if(pContainer.getContainerSize() != itemIngredients.size())
return false;
int matchedIngredients = 0;
for (int i = 0; i < itemIngredients.size(); i++) {
Ingredient ingredient = itemIngredients.get(i);
for (int slot = 0; slot < pContainer.getContainerSize(); slot++) {
ItemStack itemStack = pContainer.getItem(slot);
if(ingredient.test(pContainer.getItem(slot))){
matchedIngredients++;
}
}
return matchedIngredients == itemIngredients.size();
}
return false;
}
public boolean matches(SimpleContainer pContainer, Level pLevel, ItemStack preferedOutput){
return false;
}
public boolean matchesOutput(ItemStack targetItemStack){
return result.sameItem(targetItemStack);
}
@Override
public NonNullList<Ingredient> getIngredients() {
return itemIngredients;
}
@Override
public ItemStack assemble(SimpleContainer pContainer) {
return result.copy();
}
@Override
public boolean canCraftInDimensions(int pWidth, int pHeight) {
return true;
}
@Override
public ItemStack getResultItem() {
return result.copy();
}
public ItemStack getResult(){
return result.copy();
}
@Override
public ResourceLocation getId() {
return id;
}
@Override
public RecipeSerializer<?> getSerializer() {
return Serializer.INSTANCE;
}
@Override
public RecipeType<?> getType() {
return Type.INSTANCE;
}
public static class Type implements RecipeType<TradingRecipe> {
private Type() { }
public static final Type INSTANCE = new Type();
public static final String ID = "trading";
}
public static class Serializer implements RecipeSerializer<TradingRecipe> {
public static final Serializer INSTANCE = new Serializer();
public static final ResourceLocation ID =
new ResourceLocation(TradingStation.MODID,"trading");
@Override
public TradingRecipe fromJson(ResourceLocation id, JsonObject json) {
TradingRecipeBuilder builder = new TradingRecipeBuilder(id);
NonNullList<Ingredient> itemIngredients = NonNullList.create();
int processingTime = 1;
for (JsonElement je : GsonHelper.getAsJsonArray(json, "ingredients")) {
JsonObject jsonObject = je.getAsJsonObject();
Ingredient ingredient = Ingredient.fromJson(jsonObject);
if(jsonObject.has("count")){
ItemStack itemStack = ingredient.getItems()[0];
itemStack.setCount(jsonObject.get("count").getAsInt());
}
itemIngredients.add(ingredient);
}
ItemStack result = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "result"));
if(GsonHelper.isValidNode(json,"processingTime")){
processingTime = GsonHelper.getAsInt(json,"processingTime");
}
builder.withItemIngredients(itemIngredients)
.withSingleItemOutput(result)
.processingTime(processingTime);
return builder.build();
}
@Override
public TradingRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) {
TradingRecipeBuilder builder = new TradingRecipeBuilder(id);
NonNullList<Ingredient> itemIngredients = NonNullList.create();
int processingTime = 1;
int size = buffer.readVarInt();
for (int i = 0; i < size; i++)
itemIngredients.add(Ingredient.fromNetwork(buffer));
ItemStack result = buffer.readItem();
processingTime = buffer.readInt();
builder.withItemIngredients(itemIngredients)
.withSingleItemOutput(result)
.processingTime(processingTime);
return builder.build();
}
@Override
public void toNetwork(FriendlyByteBuf buffer, TradingRecipe recipe) {
NonNullList<Ingredient> itemIngredients = recipe.itemIngredients;
int processingTime = recipe.getProcessingTime();
buffer.writeVarInt(itemIngredients.size());
itemIngredients.forEach(i -> i.toNetwork(buffer));
buffer.writeItem(recipe.getResultItem());
buffer.writeInt(processingTime);
}
}
public int getProcessingTime() {
return processingTime;
}
}

View File

@@ -0,0 +1,66 @@
package com.oierbravo.trading_station.content.trading_station;
import net.minecraft.core.NonNullList;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraftforge.common.crafting.conditions.ICondition;
import java.util.ArrayList;
import java.util.List;
public class TradingRecipeBuilder {
protected TradingRecipeParams params;
protected List<ICondition> recipeConditions;
public TradingRecipeBuilder(ResourceLocation recipeId) {
params = new TradingRecipeParams(recipeId);
recipeConditions = new ArrayList<>();
}
public TradingRecipeBuilder withItemIngredients(Ingredient... itemIngredients) {
return withItemIngredients(NonNullList.of(Ingredient.EMPTY, itemIngredients));
}
public TradingRecipeBuilder withItemIngredients(NonNullList<Ingredient> itemIngredients) {
params.itemIngredients = itemIngredients;
return this;
}
public TradingRecipeBuilder withSingleItemOutput(ItemStack output) {
params.result = output;
return this;
}
public TradingRecipeBuilder processingTime(int time) {
params.processingTime = time;
return this;
}
public TradingRecipe build(){
return new TradingRecipe(params);
}
public static class TradingRecipeParams {
protected ResourceLocation id;
protected NonNullList<Ingredient> itemIngredients;
protected ItemStack result;
protected int fuelConsumed;
protected int processingTime;
protected TradingRecipeParams(ResourceLocation id) {
this.id = id;
itemIngredients = NonNullList.create();
result = ItemStack.EMPTY;
fuelConsumed = 0;
processingTime = 1;
}
}
}

View File

@@ -0,0 +1,135 @@
package com.oierbravo.trading_station.content.trading_station;
import com.oierbravo.trading_station.registrate.ModBlockEntities;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.network.NetworkHooks;
import org.jetbrains.annotations.Nullable;
import static net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING;
public class TradingStationBlock extends BaseEntityBlock {
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
private static final VoxelShape RENDER_SHAPE = Shapes.box(0, 0, 0, 1, 1, 1);
//public static final BooleanProperty BOTTOM = BlockStateProperties.BOTTOM;
@SuppressWarnings("deprecation")
@Override
public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
return RENDER_SHAPE;
}
@Override
public VoxelShape getCollisionShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
return RENDER_SHAPE;
}
public TradingStationBlock(Properties pProperties) {
super(pProperties);
registerDefaultState(getStateDefinition().any().setValue(HORIZONTAL_FACING, Direction.NORTH).setValue(POWERED,false));
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{
if (!context.getLevel().getBlockState(context.getClickedPos().above()).canBeReplaced(context))
return null;
return super.getStateForPlacement(context)
.setValue(HORIZONTAL_FACING, context.getHorizontalDirection().getOpposite())
.setValue(POWERED, context.getLevel().hasNeighborSignal(context.getClickedPos()));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(HORIZONTAL_FACING).add(POWERED);
}
@Override
public RenderShape getRenderShape(BlockState pState) {
return RenderShape.MODEL;
}
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) {
return ModBlockEntities.TRADING_STATION.create(pPos, pState);
}
@Override
public void tick(BlockState state, ServerLevel worldIn, BlockPos pos, RandomSource r) {
boolean previouslyPowered = state.getValue(POWERED);
if (previouslyPowered != worldIn.hasNeighborSignal(pos))
worldIn.setBlock(pos, state.cycle(POWERED), 2);
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level pLevel, BlockState pState, BlockEntityType<T> pBlockEntityType) {
return createTickerHelper(pBlockEntityType, ModBlockEntities.TRADING_STATION.get(),
TradingStationBlockEntity::tick);
}
@Override
public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos,
boolean isMoving) {
super.neighborChanged(state, worldIn, pos, blockIn, fromPos, isMoving);
if (worldIn.isClientSide)
return;
if (!worldIn.getBlockTicks()
.willTickThisTick(pos, this))
worldIn.scheduleTick(pos, this, 0);
}
@Override
public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) {
if (pState.getBlock() != pNewState.getBlock()) {
BlockEntity blockEntity = pLevel.getBlockEntity(pPos);
if (blockEntity instanceof TradingStationBlockEntity) {
((TradingStationBlockEntity) blockEntity).drops();
}
}
super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving);
}
@Override
public InteractionResult use(BlockState state, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand handIn, BlockHitResult hit) {
if (!pLevel.isClientSide()) {
BlockEntity blockEntity = pLevel.getBlockEntity(pPos);
if(blockEntity instanceof TradingStationBlockEntity) {
NetworkHooks.openScreen(((ServerPlayer)pPlayer), (TradingStationBlockEntity)blockEntity, pPos);
} else {
throw new IllegalStateException("Our Container provider is missing!");
}
}
return InteractionResult.sidedSuccess(pLevel.isClientSide());
}
}

View File

@@ -0,0 +1,434 @@
package com.oierbravo.trading_station.content.trading_station;
import com.oierbravo.trading_station.foundation.util.ModLang;
import com.oierbravo.trading_station.network.packets.ItemStackSyncS2CPacket;
import com.oierbravo.trading_station.registrate.ModMessages;
import com.oierbravo.trading_station.registrate.ModRecipes;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Containers;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.ShapelessRecipe;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class TradingStationBlockEntity extends BlockEntity implements MenuProvider {
//private final int FLUID_CAPACITY = TradingStationConfig.trading_station_CAPACITY.get();
//private static final int FLIUD_PER_TICK = TradingStationConfig.trading_statio_FLUID_PER_TICK.get();
private CompoundTag updateTag;
public final ItemStackHandler inputItems = createInputItemHandler();
public final ItemStackHandler outputItems = createOutputItemHandler();
public final ItemStackHandler targetItemHandler = createTargetItemHandler();
private final LazyOptional<IItemHandler> inputItemHandler = LazyOptional.of(() -> inputItems);
private final LazyOptional<IItemHandler> outputItemHandler = LazyOptional.of(() -> outputItems);
public int progress = 0;
public int maxProgress = 1;
private BlockState lastBlockState;
protected final ContainerData containerData;
private Item preferedItem;
public TradingStationBlockEntity(BlockEntityType<?> pType, BlockPos pWorldPosition, BlockState pBlockState) {
super(pType, pWorldPosition, pBlockState);
updateTag = getPersistentData();
lastBlockState = this.getBlockState();
preferedItem = ItemStack.EMPTY.getItem();
containerData = TradingStationBlockEntity.createContainerData(this);
}
public static ContainerData createContainerData(TradingStationBlockEntity pBlockEntity){
return new ContainerData(){
@Override
public int get(int pIndex){
return switch (pIndex) {
case 0 -> pBlockEntity.progress;
case 1 -> pBlockEntity.maxProgress;
default -> 0;
};
}
@Override
public void set(int pIndex, int pValue) {
switch (pIndex) {
case 0 -> pBlockEntity.progress = pValue;
case 1 -> pBlockEntity.maxProgress = pValue;
}
}
@Override
public int getCount() {
return 2;
}
};
}
@NotNull
@Nonnull
private ItemStackHandler createTargetItemHandler() {
return new ItemStackHandler(1) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if(!level.isClientSide()) {
ModMessages.sendToClients(new ItemStackSyncS2CPacket(slot,this.getStackInSlot(0), worldPosition, ItemStackSyncS2CPacket.SlotType.TARGET));
}
if(!level.isClientSide()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
// clientSync();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return true;
//return canProcess(stack) && super.isItemValid(slot, stack);
}
@Override
public @NotNull ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate) {
return ItemStack.EMPTY;
}
@Override
public @NotNull ItemStack extractItem(int slot, int amount, boolean simulate) {
return ItemStack.EMPTY;
}
};
}
private ItemStackHandler createInputItemHandler() {
return new ItemStackHandler(2) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if(!level.isClientSide()) {
ModMessages.sendToClients(new ItemStackSyncS2CPacket(slot,this.getStackInSlot(0), worldPosition, ItemStackSyncS2CPacket.SlotType.INPUT));
}
if(!level.isClientSide()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
// clientSync();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return true;
//return canProcess(stack) && super.isItemValid(slot, stack);
}
};
}
@NotNull
@Nonnull
private ItemStackHandler createOutputItemHandler() {
return new ItemStackHandler(1) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if(!level.isClientSide()) {
ModMessages.sendToClients(new ItemStackSyncS2CPacket(slot, this.getStackInSlot(slot), worldPosition, ItemStackSyncS2CPacket.SlotType.OUTPUT));
}
if(!level.isClientSide()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
// clientSync();
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
return canProcess(stack) && super.isItemValid(slot, stack);
//return false;
}
};
}
@Override
public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
if (cap == ForgeCapabilities.ITEM_HANDLER) {
return inputItemHandler.cast();
}
return super.getCapability(cap, side);
}
@Override
public void setRemoved() {
super.setRemoved();
inputItemHandler.invalidate();
outputItemHandler.invalidate();
}
public LazyOptional<IItemHandler> getInputItemHandler(){
return inputItemHandler;
}
public LazyOptional<IItemHandler> getOutputItemHandler(){
return outputItemHandler;
}
@Override
public void onLoad() {
super.onLoad();
}
@Override
public void invalidateCaps() {
super.invalidateCaps();
inputItemHandler.invalidate();
outputItemHandler.invalidate();
}
@Override
protected void saveAdditional(@NotNull CompoundTag tag) {
super.saveAdditional(tag);
tag.put("input", inputItems.serializeNBT());
tag.put("output", outputItems.serializeNBT());
tag.put("target", targetItemHandler.serializeNBT());
tag.putInt("trading_station.progress", progress);
tag.putInt("trading_station.maxProgress", maxProgress);
String preferedItemString = ForgeRegistries.ITEMS.getKey(preferedItem).toString();
}
@Override
public void load(CompoundTag tag) {
super.load(tag);
inputItems.deserializeNBT(tag.getCompound("input"));
outputItems.deserializeNBT(tag.getCompound("output"));
targetItemHandler.deserializeNBT(tag.getCompound("target"));
progress = tag.getInt("trading_station.progress");
maxProgress = tag.getInt("trading_station.maxProgress");
String preferedItemString = tag.getString("trading_station.preferedItem");
preferedItem = ForgeRegistries.ITEMS.getValue( ResourceLocation.tryParse(preferedItemString));
}
public void drops() {
SimpleContainer inventory = new SimpleContainer(inputItems.getSlots() + 1);
for (int i = 0; i < inputItems.getSlots(); i++) {
inventory.setItem(i, inputItems.getStackInSlot(i));
}
inventory.setItem(inputItems.getSlots(), inputItems.getStackInSlot(0));
Containers.dropContents(this.level, this.worldPosition, inventory);
}
public void resetProgress() {
this.progress = 0;
this.maxProgress = 1;
}
protected static Optional<TradingRecipe> getRecipe(TradingStationBlockEntity pBlockEntity){
Level level = pBlockEntity.getLevel();
SimpleContainer inputInventory = getInputInventory(pBlockEntity);
if(!pBlockEntity.targetItemHandler.getStackInSlot(0).isEmpty())
return ModRecipes.findByOutput(level,pBlockEntity.targetItemHandler.getStackInSlot(0));
return ModRecipes.find(inputInventory,level);
// return level.getRecipeManager().getRecipeFor(TradingRecipe.Type.INSTANCE, inputInventory, level);
}
protected int getProcessingTime(TradingStationBlockEntity pBlockEntity) {
return getRecipe(pBlockEntity).map(TradingRecipe::getProcessingTime).orElse(1);
}
public static void tick(Level pLevel, BlockPos pPos, BlockState pState, TradingStationBlockEntity pBlockEntity) {
if(pLevel.isClientSide()) {
return;
}
if(!isPowered(pBlockEntity))
return;
if (canCraftItem(pBlockEntity)) {
pBlockEntity.progress += 1;
BlockEntity.setChanged(pLevel, pPos, pState);
pBlockEntity.maxProgress = pBlockEntity.getProcessingTime(pBlockEntity);
if (pBlockEntity.progress > pBlockEntity.maxProgress) {
TradingStationBlockEntity.craftItem(pBlockEntity);
}
BlockEntity.setChanged(pLevel, pPos, pState);
} else {
pBlockEntity.resetProgress();
BlockEntity.setChanged(pLevel, pPos, pState);
}
}
protected static void updateProgress(TradingStationBlockEntity pBlockEntity){
pBlockEntity.progress += 1;
}
private static boolean isPowered(TradingStationBlockEntity pBlockEntity){
return pBlockEntity.getLevel().getBlockState(pBlockEntity.getBlockPos())
.getValue(BlockStateProperties.POWERED);
}
private static SimpleContainer getInputInventory(TradingStationBlockEntity pBlockEntity){
int containerSize = 0;
for(int index = 0; index < pBlockEntity.inputItems.getSlots(); index++) {
if (!pBlockEntity.inputItems.getStackInSlot(index).isEmpty())
containerSize++;
}
SimpleContainer inputInventory = new SimpleContainer(containerSize);
pBlockEntity.inputItemHandler.ifPresent(iItemHandler -> {
for(int slot = 0; slot < iItemHandler.getSlots(); slot++) {
if(!iItemHandler.getStackInSlot(slot).isEmpty()){
inputInventory.addItem(iItemHandler.getStackInSlot(slot));
}
}
});
return inputInventory;
}
private static void craftItem(TradingStationBlockEntity pBlockEntity) {
Level level = pBlockEntity.getLevel();
SimpleContainer inputInventory = getInputInventory(pBlockEntity);
Optional<TradingRecipe> recipe = getRecipe(pBlockEntity);
if(recipe.isPresent()){
for (int i = 0; i < recipe.get().getIngredients().size(); i++) {
Ingredient ingredient = recipe.get().getIngredients().get(i);
for (int slot = 0; slot < pBlockEntity.inputItems.getSlots(); slot++) {
ItemStack itemStack = pBlockEntity.inputItems.getStackInSlot(slot);
if(ingredient.test(itemStack)){
pBlockEntity.inputItems.extractItem(slot,ingredient.getItems()[0].getCount(),false);
inputInventory.setChanged();
}
}
}
pBlockEntity.outputItems.insertItem(0, recipe.get().getResultItem(), false);
}
pBlockEntity.resetProgress();
pBlockEntity.setChanged();
}
static boolean canCraftItem(TradingStationBlockEntity pBlockEntity) {
Level level = pBlockEntity.getLevel();
if(level == null)
return false;
SimpleContainer inputInventory = getInputInventory(pBlockEntity);
Optional<TradingRecipe> match = getRecipe(pBlockEntity);
if(match.isEmpty()) {
return false;
}
//return false;
return match.isPresent()
&& TradingStationBlockEntity.hasEnoughInputItems(inputInventory,match.get().getIngredients())
&& TradingStationBlockEntity.hasEnoughOutputSpace(pBlockEntity.outputItems,match.get().getResultItem());
}
private boolean canProcess(ItemStack stack) {
return getRecipe(this).isPresent();
}
protected static boolean hasEnoughInputItems(SimpleContainer inventory, NonNullList<Ingredient> ingredients){
int enough = 0;
for(int ingredientIndex = 0; ingredientIndex < ingredients.size();ingredientIndex ++){
Ingredient ingredient = ingredients.get(ingredientIndex);
for(int slot = 0; slot < inventory.getContainerSize(); slot++){
if(ingredient.test(inventory.getItem(slot))){
if(inventory.getItem(slot).getCount() >= ingredient.getItems()[0].getCount() )
enough++;
}
}
}
return ingredients.size() == enough;
}
protected static boolean hasEnoughOutputSpace(ItemStackHandler stackHandler,ItemStack resultItemStack){
return stackHandler.getStackInSlot(0).isEmpty() || stackHandler.getStackInSlot(0).is(resultItemStack.getItem()) && stackHandler.getStackInSlot(0).getMaxStackSize() - stackHandler.getStackInSlot(0).getCount() >= resultItemStack.getCount() ;
}
@Override
public CompoundTag getUpdateTag() {
this.saveAdditional(updateTag);
return updateTag;
}
@Nullable
@Override
public ClientboundBlockEntityDataPacket getUpdatePacket() {
return ClientboundBlockEntityDataPacket.create(this);
}
@Override
public void handleUpdateTag(CompoundTag tag) {
this.load(tag);
}
@Override
public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) {
this.load(pkt.getTag());
}
public int getProgressPercent() {
return this.progress * 100 / this.maxProgress;
}
public void setItemStack(int slot, ItemStack itemStack,ItemStackSyncS2CPacket.SlotType slotType) {
if(slotType == ItemStackSyncS2CPacket.SlotType.INPUT)
inputItems.setStackInSlot(slot,itemStack);
else if (slotType == ItemStackSyncS2CPacket.SlotType.OUTPUT)
outputItems.setStackInSlot(slot,itemStack);
else if (slotType == ItemStackSyncS2CPacket.SlotType.TARGET)
targetItemHandler.setStackInSlot(slot,itemStack);
}
@Override
public Component getDisplayName() {
return ModLang.translate("block.display");
}
@Nullable
@Override
public AbstractContainerMenu createMenu(int pContainerId, Inventory pPlayerInventory, Player pPlayer) {
return new TradingStationMenu(pContainerId, pPlayerInventory, this, this.containerData);
}
public void setPreferedItem(ItemStack itemStack) {
this.targetItemHandler.setStackInSlot(0,itemStack);
}
public ItemStack getPreferedItemStack() {
return targetItemHandler.getStackInSlot(0);
}
public ItemStackHandler getTargetItemHandler(){
return targetItemHandler;
}
}

View File

@@ -0,0 +1,31 @@
package com.oierbravo.trading_station.content.trading_station;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.block.model.ItemTransforms;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.NotNull;
public class TradingStationBlockRenderer implements BlockEntityRenderer<TradingStationBlockEntity> {
public TradingStationBlockRenderer(BlockEntityRendererProvider.Context context) {
}
@Override
public void render(TradingStationBlockEntity pBlockEntity, float pPartialTick, @NotNull PoseStack pPoseStack, @NotNull MultiBufferSource pBufferSource, int pPackedLight, int pPackedOverlay) {
if(!pBlockEntity.getPreferedItemStack().isEmpty()){
pPoseStack.pushPose();
pPoseStack.translate(0.5d, 1.1d, 0.5d);
renderBlock(pPoseStack,pBufferSource, LightTexture.FULL_BRIGHT,pPackedOverlay,pBlockEntity.getPreferedItemStack());
pPoseStack.popPose();
}
}
protected void renderBlock(PoseStack ms, MultiBufferSource buffer, int light, int overlay, ItemStack stack) {
Minecraft.getInstance()
.getItemRenderer()
.renderStatic(stack, ItemTransforms.TransformType.GROUND, light, overlay, ms, buffer, 0);
}
}

View File

@@ -0,0 +1,19 @@
package com.oierbravo.trading_station.content.trading_station;
import net.minecraftforge.common.ForgeConfigSpec;
public class TradingStationConfig {
//public static ForgeConfigSpec.IntValue MELTER_CAPACITY;
//public static ForgeConfigSpec.IntValue MELTER_FLUID_PER_TICK;
public static void registerServerConfig(ForgeConfigSpec.Builder COMMON_BUILDER) {
/* SERVER_BUILDER.comment("Settings for the trading_station").push("trading_station");
MELTER_CAPACITY = SERVER_BUILDER
.comment("How much liquid fits into the trading_station, in mB")
.defineInRange("capacity", 1000, 1, Integer.MAX_VALUE);
MELTER_FLUID_PER_TICK = SERVER_BUILDER
.comment("How much liquid generates per tick, in mB")
.defineInRange("liquidPerTick", 2, 1, Integer.MAX_VALUE);
SERVER_BUILDER.pop();*/
}
}

View File

@@ -0,0 +1,142 @@
package com.oierbravo.trading_station.content.trading_station;
import com.oierbravo.trading_station.registrate.ModBlocks;
import com.oierbravo.trading_station.registrate.ModMenus;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.*;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.SlotItemHandler;
import org.jetbrains.annotations.Nullable;
public class TradingStationMenu extends AbstractContainerMenu {
public final TradingStationBlockEntity blockEntity;
public final Inventory inventory;
private final Level level;
private final ContainerData containerData;
public ItemStackHandler ghostInventory;
public TradingStationMenu(int pContainerId, Inventory inv, FriendlyByteBuf extraData){
this(pContainerId, inv, inv.player.level.getBlockEntity(extraData.readBlockPos()), new SimpleContainerData(2));
}
public TradingStationMenu(int pContainerId, Inventory pInv, BlockEntity pBlockEntity, ContainerData pData){
super(ModMenus.TRADING_STATION.get(), pContainerId);
checkContainerSize(pInv, 3);
blockEntity = (TradingStationBlockEntity) pBlockEntity;
this.level = pInv.player.getLevel();
this.containerData = pData;
this.inventory = pInv;
addPlayerHotbar(pInv);
addPlayerInventory(pInv);
this.addDataSlots(pData);
//this.blockEntity.inputItems
this.blockEntity.getInputItemHandler().ifPresent(itemHandler -> {
this.addSlot(new SlotItemHandler(itemHandler,0,TradingStationScreen.inputSlotX[0],TradingStationScreen.inputSlotY));
this.addSlot(new SlotItemHandler(itemHandler,1,TradingStationScreen.inputSlotX[1],TradingStationScreen.inputSlotY));
});
this.blockEntity.getOutputItemHandler().ifPresent(itemHandler -> {
this.addSlot(new SlotItemHandler(itemHandler,0,TradingStationScreen.outputSlotX,TradingStationScreen.outputSlotY));
});
this.addSlot(new SlotItemHandler(this.blockEntity.getTargetItemHandler(),0,87,28));
}
public TradingStationMenu(int pContainerId, Inventory pInventory, BlockPos sourcePos) {
this(pContainerId, pInventory, Minecraft.getInstance().level.getBlockEntity(sourcePos), TradingStationBlockEntity.createContainerData((TradingStationBlockEntity) Minecraft.getInstance().level.getBlockEntity(sourcePos)));
}
public static TradingStationMenu factory(@Nullable MenuType<TradingStationMenu> pMenuType, int pContainerId, Inventory inventory, FriendlyByteBuf buf) {
return new TradingStationMenu(pContainerId, inventory, buf);
}
public int getScaledProgress() {
int progress = this.containerData.get(0);
int maxProgress = this.containerData.get(1); // Max Progress
int progressArrowSize = 34; // This is the height in pixels of your arrow
return maxProgress != 0 && progress != 0 ? progress * progressArrowSize / maxProgress : 0;
}
public boolean isCrafting() {
return containerData.get(0) > 0;
}
private static final int HOTBAR_SLOT_COUNT = 9;
private static final int PLAYER_INVENTORY_ROW_COUNT = 3;
private static final int PLAYER_INVENTORY_COLUMN_COUNT = 9;
private static final int PLAYER_INVENTORY_SLOT_COUNT = PLAYER_INVENTORY_COLUMN_COUNT * PLAYER_INVENTORY_ROW_COUNT;
private static final int VANILLA_SLOT_COUNT = HOTBAR_SLOT_COUNT + PLAYER_INVENTORY_SLOT_COUNT;
private static final int VANILLA_FIRST_SLOT_INDEX = 0;
private static final int TE_INVENTORY_FIRST_SLOT_INDEX = VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT;
// THIS YOU HAVE TO DEFINE!
private static final int TE_INVENTORY_SLOT_COUNT = 2; // must be the number of slots you have!
@Override
public ItemStack quickMoveStack(Player playerIn, int pIndex) {
Slot sourceSlot = slots.get(pIndex);
if (sourceSlot == null || !sourceSlot.hasItem()) return ItemStack.EMPTY; //EMPTY_ITEM
ItemStack sourceStack = sourceSlot.getItem();
ItemStack copyOfSourceStack = sourceStack.copy();
// Check if the slot clicked is one of the vanilla container slots
if (pIndex < VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT) {
// This is a vanilla container slot so merge the stack into the tile inventory
if (!moveItemStackTo(sourceStack, TE_INVENTORY_FIRST_SLOT_INDEX, TE_INVENTORY_FIRST_SLOT_INDEX
+ TE_INVENTORY_SLOT_COUNT, false)) {
return ItemStack.EMPTY; // EMPTY_ITEM
}
} else if (pIndex < TE_INVENTORY_FIRST_SLOT_INDEX + TE_INVENTORY_SLOT_COUNT) {
// This is a TE slot so merge the stack into the players inventory
if (!moveItemStackTo(sourceStack, VANILLA_FIRST_SLOT_INDEX, VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT, false)) {
return ItemStack.EMPTY;
}
} else if (pIndex == TE_INVENTORY_FIRST_SLOT_INDEX + TE_INVENTORY_SLOT_COUNT) {
// This is a TE Outpu slot so merge the stack into the players inventory
if (!moveItemStackTo(sourceStack, VANILLA_FIRST_SLOT_INDEX, VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT, false)) {
return ItemStack.EMPTY;
}
} else {
System.out.println("Invalid slotIndex:" + pIndex);
return ItemStack.EMPTY;
}
// If stack size == 0 (the entire stack was moved) set slot contents to null
if (sourceStack.getCount() == 0) {
sourceSlot.set(ItemStack.EMPTY);
} else {
sourceSlot.setChanged();
}
sourceSlot.onTake(playerIn, sourceStack);
return copyOfSourceStack;
}
@Override
public boolean stillValid(Player pPlayer) {
return stillValid(ContainerLevelAccess.create(level, blockEntity.getBlockPos()), pPlayer, ModBlocks.TRADING_STATION.get());
}
private static final int PLAYER_INVENTORY_Y = 64;
private void addPlayerInventory(Inventory playerInventory) {
for (int i = 0; i < 3; ++i) {
for (int l = 0; l < 9; ++l) {
this.addSlot(new Slot(playerInventory, l + i * 9 + 9, 8 + l * 18, PLAYER_INVENTORY_Y + i * 18));
}
}
}
private static final int HOTBAR_Y = 122;
private void addPlayerHotbar(Inventory playerInventory) {
for (int i = 0; i < 9; ++i) {
this.addSlot(new Slot(playerInventory, i, 8 + i * 18, HOTBAR_Y));
}
}
}

View File

@@ -0,0 +1,91 @@
package com.oierbravo.trading_station.content.trading_station;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.foundation.util.ModLang;
import com.oierbravo.trading_station.registrate.ModRecipes;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraftforge.client.gui.widget.ExtendedButton;
import java.util.ArrayList;
import java.util.Optional;
public class TradingStationScreen extends AbstractContainerScreen<TradingStationMenu> {
private static final ResourceLocation TEXTURE = TradingStation.asResource("textures/gui/trading_station.png");
private int progressArrowX = 79;
private int progressArrowY = 47;
private int targetSelectButtonX = 131;
private int targetSelectButtonY = 18;
public static int inputSlotX[] = {19,42};
public static int inputSlotY = 38;
public static int outputSlotX = 131;
public static int outputSlotY = 38;
@Override
protected void init() {
super.init();
this.titleLabelX = 4;
this.titleLabelY = 4;
this.inventoryLabelY = 100000;
this.addRenderableWidget(new ExtendedButton(leftPos + targetSelectButtonX,topPos + targetSelectButtonY,16,16, ModLang.translate("select_target.button"), btn ->{
TradingStationTargetSelectScreen screen = new TradingStationTargetSelectScreen( this.menu.blockEntity);
Minecraft.getInstance().pushGuiLayer(screen);
}));
}
public TradingStationScreen(TradingStationMenu pMenu, Inventory pPlayerInventory, Component pTitle) {
super(pMenu, pPlayerInventory, pTitle);
}
@Override
protected void renderBg(PoseStack pPoseStack, float pPartialTick, int pMouseX, int pMouseY) {
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
RenderSystem.setShaderTexture(0, TEXTURE);
this.fillGradient(pPoseStack, 0, 0, this.width, this.height, -1072689136, -804253680);
int x = (width - imageWidth) / 2;
int y = (height - imageHeight) / 2;
this.blit(pPoseStack, x, y, 0, 0, imageWidth, imageHeight);
if (menu.isCrafting()) {
this.blit(pPoseStack, x + progressArrowX, y + progressArrowY, 179, 0, menu.getScaledProgress(), 7);
}
if(!menu.blockEntity.getPreferedItemStack().isEmpty()){
Optional<TradingRecipe> recipe = ModRecipes.findByOutput(menu.blockEntity.getLevel(),menu.blockEntity.getPreferedItemStack());
if(recipe.isPresent()){
renderFakeRecipe(recipe.get(), pPoseStack);
}
}
}
private void renderFakeRecipe(TradingRecipe recipe, PoseStack pPoseStack){
for(int index = 0; index < recipe.getIngredients().size(); index++){
Ingredient ingredient = recipe.getIngredients().get(index);
if(!ingredient.isEmpty())
FakeItemRenderer.renderFakeItem(ingredient.getItems()[0],getGuiLeft() + TradingStationScreen.inputSlotX[index],getGuiTop() + TradingStationScreen.inputSlotY, .5f);
}
FakeItemRenderer.renderFakeItem(recipe.getResultItem(),getGuiLeft() + TradingStationScreen.outputSlotX,getGuiTop() + TradingStationScreen.outputSlotY, .5f);
}
@Override
public void render(PoseStack pPoseStack, int pMouseX, int pMouseY, float pPartialTick) {
super.render(pPoseStack, pMouseX, pMouseY, pPartialTick);
}
}

View File

@@ -0,0 +1,246 @@
package com.oierbravo.trading_station.content.trading_station;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.foundation.util.ModLang;
import com.oierbravo.trading_station.network.packets.GhostItemSyncC2SPacket;
import com.oierbravo.trading_station.registrate.ModMessages;
import com.oierbravo.trading_station.registrate.ModRecipes;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemStack;
import java.util.LinkedList;
import java.util.List;
/**
* Scroll code and loop adapted from Alchemistry/src/main/java/com/smashingmods/alchemistry/client/container/RecipeSelectorScreen.java
*/
public class TradingStationTargetSelectScreen extends Screen {
private static final ResourceLocation TEXTURE = TradingStation.asResource("textures/gui/trade_select.png");
private TradingStationBlockEntity blockEntity;
private List<ItemStack> allPossibleOutputs;
private LinkedList<ItemStack> displayedItemStacks = new LinkedList<>();
private float scrollOffset;
private boolean scrolling;
private int startIndex;
private static int MAX_DISPLAYED_RECIPES = 24;
private static final int COLUMNS = 8;
private static final int TARGET_BOX_SIZE = 17;
private int targetBoxLeftPosOffset = 7;
private int targetBoxTopPosOffset = 19;
private int scrollBarXOffset = 148;
private int scrollBarYOffset = 22;
protected int titleLabelX;
protected int titleLabelY;
protected int imageWidth = 165;
protected int imageHeight = 83;
protected int leftPos;
protected int topPos;
protected TradingStationTargetSelectScreen(Component pTitle) {
super(pTitle);
}
public TradingStationTargetSelectScreen(TradingStationBlockEntity pBlockEntity) {
this(ModLang.translate("select_target.title"));
this.blockEntity = pBlockEntity;
this.allPossibleOutputs = ModRecipes.getAllOutputs(pBlockEntity.getLevel());
resetDisplayedTargets();
}
@Override
protected void init() {
super.init();
this.titleLabelX = 4;
this.titleLabelY = 4;
this.leftPos = (this.width - this.imageWidth) / 2;
this.topPos = (this.height - this.imageHeight) / 2;
addRenderableWidget(new Button(getGuiLeft() - 25, getGuiTop() + 1, 25, 20, Component.literal("<--"), (button) -> {
Minecraft.getInstance().popGuiLayer();
}));
addRenderableWidget(new Button(getGuiLeft() - 25, getGuiTop() + 30, 25, 20, ModLang.translate("select_target.clear"), (button) -> {
ModMessages.sendToServer(new GhostItemSyncC2SPacket(ItemStack.EMPTY,this.blockEntity.getBlockPos()));
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_STONECUTTER_SELECT_RECIPE, 1.0f));
Minecraft.getInstance().popGuiLayer();
}));
}
public int getGuiLeft() { return leftPos; }
public int getGuiTop() { return topPos; }
@Override
public void tick() {
if (displayedItemStacks.size() < MAX_DISPLAYED_RECIPES) {
mouseScrolled(0, 0, 0);
scrollOffset = 0.0f;
}
if (displayedItemStacks.size() <= MAX_DISPLAYED_RECIPES) {
startIndex = 0;
scrollOffset = 0;
}
super.tick();
}
@Override
public void render(PoseStack pPoseStack, int pMouseX, int pMouseY, float pPartialTick) {
renderBackground(pPoseStack);
int lastDisplayedIndex = startIndex + MAX_DISPLAYED_RECIPES;
renderScrollbar(pPoseStack);
renderSelectedTarget(pPoseStack, pMouseX, pMouseY, lastDisplayedIndex);
renderTargetItems(pPoseStack, pMouseX, pMouseY, lastDisplayedIndex);
renderLabels(pPoseStack, pMouseX, pMouseY);
super.render(pPoseStack, pMouseX, pMouseY, pPartialTick);
}
protected void renderLabels(PoseStack pPoseStack, int pMouseX, int pMouseY) {
this.font.draw(pPoseStack, this.title, (float)this.titleLabelX + getGuiLeft(), (float)this.titleLabelY + getGuiTop(), 4210752);
}
private void renderSelectedTarget(PoseStack pPoseStack, int pMouseX, int pMouseY, int pLastDisplayedIndex) {
LinkedList<ItemStack> displayedRecipes = getDisplayedItemStacks();
ItemStack selectedTarget = this.blockEntity.getTargetItemHandler().getStackInSlot(0);
for (int index = startIndex; index >= 0 && index < pLastDisplayedIndex && index < displayedRecipes.size(); index++) {
int firstDisplayedIndex = index - startIndex;
ItemStack target = allPossibleOutputs.get(index);
int xStart = getGuiLeft() + targetBoxLeftPosOffset + firstDisplayedIndex % COLUMNS * TARGET_BOX_SIZE + 1;
int yStart = getGuiTop() + targetBoxTopPosOffset + (firstDisplayedIndex / COLUMNS) * TARGET_BOX_SIZE + 3;
if(target.sameItem(selectedTarget))
blit(pPoseStack, xStart, yStart, 0, imageHeight + 19, TARGET_BOX_SIZE, TARGET_BOX_SIZE);
}
}
private void renderTargetItems(PoseStack pPoseStack, int pMouseX, int pMouseY, int pLastDisplayedIndex) {
LinkedList<ItemStack> displayedRecipes = getDisplayedItemStacks();
for (int index = startIndex; index >= 0 && index < pLastDisplayedIndex && index < displayedRecipes.size(); index++) {
int firstDisplayedIndex = index - startIndex;
ItemStack target = allPossibleOutputs.get(index);
int xStart = getGuiLeft() + targetBoxLeftPosOffset + firstDisplayedIndex % COLUMNS * TARGET_BOX_SIZE + 1;
int yStart = getGuiTop() + targetBoxTopPosOffset + (firstDisplayedIndex / COLUMNS) * TARGET_BOX_SIZE + 3;
renderFloatingItem(target, xStart, yStart);
if (pMouseX >= xStart - 1 && pMouseX <= xStart + 16 && pMouseY >= yStart - 1 && pMouseY <= yStart + 16) {
renderTooltip(pPoseStack, target, pMouseX, pMouseY);
}
}
}
private LinkedList<ItemStack> getDisplayedItemStacks() {
return displayedItemStacks;
}
private void renderFloatingItem(ItemStack pItemStack, int pX, int pY) {
RenderSystem.applyModelViewMatrix();
setBlitOffset(2000);
itemRenderer.blitOffset = 2000.0f;
itemRenderer.renderAndDecorateItem(pItemStack, pX, pY);
itemRenderer.renderGuiItemDecorations(font, pItemStack, pX, pY, "");
setBlitOffset(0);
itemRenderer.blitOffset = 0.0f;
}
@Override
public void renderBackground(PoseStack pPoseStack) {
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
RenderSystem.setShaderTexture(0, TEXTURE);
this.fillGradient(pPoseStack, 0, 0, this.width, this.height, -1072689136, -804253680);
this.blit(pPoseStack, getGuiLeft(), getGuiTop(), 0, 0, imageWidth, imageHeight);
}
private void renderScrollbar(PoseStack pPoseStack) {
int scrollPosition = (int) (43.0f * scrollOffset);
blit(pPoseStack, getGuiLeft() + scrollBarXOffset, getGuiTop() + scrollBarYOffset + scrollPosition, 0, imageHeight + 1 + (isScrollBarActive() ? 0 : 9), 7, 9);
}
@Override
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
scrolling = false;
int lastDisplayedIndex = startIndex + MAX_DISPLAYED_RECIPES;
for (int index = startIndex; index < lastDisplayedIndex; index++) {
int currentIndex = index - startIndex;
double boxX = pMouseX - (double)(getGuiLeft() + targetBoxLeftPosOffset + currentIndex % COLUMNS * TARGET_BOX_SIZE);
double boxY = pMouseY - (double)(getGuiTop() + targetBoxTopPosOffset + currentIndex / COLUMNS * TARGET_BOX_SIZE);
if (boxX > 0 && boxX <= TARGET_BOX_SIZE + 1 && boxY > 0 && boxY <= TARGET_BOX_SIZE + 1 && isValidRecipeIndex(index)) {
ItemStack itemStack = getDisplayedItemStacks().get(index);
ModMessages.sendToServer(new GhostItemSyncC2SPacket(itemStack,this.blockEntity.getBlockPos()));
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_STONECUTTER_SELECT_RECIPE, 1.0f));
Minecraft.getInstance().popGuiLayer();
return true;
}
int scrollMinX = leftPos + 148;
int scrollMinY = topPos + 9;
int scrollMaxX = scrollMinX + 6;
int scrollMaxY = scrollMinY + 60;
if (pMouseX >= scrollMinX && pMouseX < scrollMaxX && pMouseY >= scrollMinY && pMouseY < scrollMaxY) {
scrolling = true;
}
}
return super.mouseClicked(pMouseX, pMouseY, pButton);
}
private boolean isValidRecipeIndex(int pSlot) {
return pSlot >= 0 && pSlot < getDisplayedItemStacks().size();
}
@Override
public boolean isPauseScreen() {
return false;
}
public void resetDisplayedTargets() {
this.displayedItemStacks.clear();
this.displayedItemStacks.addAll(allPossibleOutputs);
}
@Override
public boolean mouseDragged(double pMouseX, double pMouseY, int pButton, double pDragX, double pDragY) {
if (scrolling && isScrollBarActive()) {
int scrollbarTopPos = getGuiTop() + 9;
int scrollbarBottomPos = scrollbarTopPos + 51;
scrollOffset = ((float) pMouseY - (float) scrollbarTopPos - 7.5f) / ((float) (scrollbarBottomPos - scrollbarTopPos) - 9.0f);
scrollOffset = Mth.clamp(scrollOffset, 0.0f, 1.0f);
startIndex = (int) ((double) (scrollOffset * (float) getOffscreenRows()) + 0.5d) * COLUMNS;
return true;
} else {
return super.mouseDragged(pMouseX, pMouseY, pButton, pDragX, pDragY);
}
}
@Override
public boolean mouseScrolled(double pMouseX, double pMouseY, double pDelta) {
if (pMouseX >= leftPos && pMouseX < leftPos + imageWidth && pMouseY >= topPos && pMouseY < topPos + imageHeight && isScrollBarActive()) {
scrollOffset = Mth.clamp(scrollOffset - (float) pDelta / (float) getOffscreenRows(), 0.0f, 1.0f);
startIndex = (int) ((double) (scrollOffset * (float) getOffscreenRows()) + 0.5d) * COLUMNS;
}
return true;
}
private int getOffscreenRows() {
return (displayedItemStacks.size() + 6 - 1) / 6 - 3;
}
private boolean isScrollBarActive() {
return displayedItemStacks.size() > MAX_DISPLAYED_RECIPES;
}
}

View File

@@ -0,0 +1,33 @@
package com.oierbravo.trading_station.content.trading_station.powered;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlock;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import com.oierbravo.trading_station.registrate.ModBlockEntities;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
public class PoweredTradingStationBlock extends TradingStationBlock {
public PoweredTradingStationBlock(Properties pProperties) {
super(pProperties);
}
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) {
return ModBlockEntities.POWERED_TRADING_STATION.create(pPos, pState);
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level pLevel, BlockState pState, BlockEntityType<T> pBlockEntityType) {
return createTickerHelper(pBlockEntityType, ModBlockEntities.POWERED_TRADING_STATION.get(),
TradingStationBlockEntity::tick);
}
}

View File

@@ -0,0 +1,12 @@
package com.oierbravo.trading_station.content.trading_station.powered;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
public class PoweredTradingStationBlockEntity extends TradingStationBlockEntity {
public PoweredTradingStationBlockEntity(BlockEntityType<?> pType, BlockPos pWorldPosition, BlockState pBlockState) {
super(pType, pWorldPosition, pBlockState);
}
}

View File

@@ -0,0 +1,18 @@
package com.oierbravo.trading_station.foundation.gui;
import com.oierbravo.trading_station.content.trading_station.TradingStationScreen;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.network.chat.Component;
import net.minecraftforge.client.gui.widget.ExtendedButton;
public class BackButton extends ExtendedButton {
public BackButton(int pX, int pY, int pWidth, int pHeight, Component pMessage, OnPress pOnPress) {
super(pX, pY, pWidth, pHeight, pMessage, pOnPress);
}
/* public BackButton(int pX, int pY, AbstractContainerScreen<TradingStationScreen> parentScreen){
this(pX,pY,16,16,Component.literal("Back"), btn->{
this.
})
}*/
}

View File

@@ -0,0 +1,148 @@
package com.oierbravo.trading_station.foundation.render;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.oierbravo.trading_station.TradingStation;
import net.minecraft.client.renderer.RenderStateShard;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RegisterShadersEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import java.io.IOException;
// TODO 1.17: use custom shaders instead of vanilla ones
public class RenderTypes extends RenderStateShard {
public static final ShaderStateShard GLOWING_SHADER = new ShaderStateShard(() -> Shaders.glowingShader);
public static RenderType getOutlineTranslucent(ResourceLocation texture, boolean cull) {
return RenderType.create(createLayerName("outline_translucent" + (cull ? "_cull" : "")),
DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, false, true, RenderType.CompositeState.builder()
.setShaderState(cull ? RENDERTYPE_ENTITY_TRANSLUCENT_CULL_SHADER : RENDERTYPE_ENTITY_TRANSLUCENT_SHADER)
.setTextureState(new TextureStateShard(texture, false, false))
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setCullState(cull ? CULL : NO_CULL)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.setWriteMaskState(COLOR_WRITE)
.createCompositeState(false));
}
public static RenderType getGlowingSolid(ResourceLocation texture) {
return RenderType.create(createLayerName("glowing_solid"), DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256,
true, false, RenderType.CompositeState.builder()
.setShaderState(GLOWING_SHADER)
.setTextureState(new TextureStateShard(texture, false, false))
.setCullState(CULL)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
}
private static final RenderType GLOWING_SOLID_DEFAULT = getGlowingSolid(InventoryMenu.BLOCK_ATLAS);
public static RenderType getGlowingSolid() {
return GLOWING_SOLID_DEFAULT;
}
public static RenderType getGlowingTranslucent(ResourceLocation texture) {
return RenderType.create(createLayerName("glowing_translucent"), DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS,
256, true, true, RenderType.CompositeState.builder()
.setShaderState(GLOWING_SHADER)
.setTextureState(new TextureStateShard(texture, false, false))
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
}
private static final RenderType ADDITIVE = RenderType.create(createLayerName("additive"), DefaultVertexFormat.BLOCK,
VertexFormat.Mode.QUADS, 256, true, true, RenderType.CompositeState.builder()
.setShaderState(BLOCK_SHADER)
.setTextureState(new TextureStateShard(InventoryMenu.BLOCK_ATLAS, false, false))
.setTransparencyState(ADDITIVE_TRANSPARENCY)
.setCullState(NO_CULL)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
public static RenderType getAdditive() {
return ADDITIVE;
}
private static final RenderType GLOWING_TRANSLUCENT_DEFAULT = getGlowingTranslucent(InventoryMenu.BLOCK_ATLAS);
public static RenderType getGlowingTranslucent() {
return GLOWING_TRANSLUCENT_DEFAULT;
}
private static final RenderType ITEM_PARTIAL_SOLID =
RenderType.create(createLayerName("item_partial_solid"), DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, true,
false, RenderType.CompositeState.builder()
.setShaderState(RENDERTYPE_ENTITY_SOLID_SHADER)
.setTextureState(BLOCK_SHEET)
.setCullState(CULL)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
public static RenderType getItemPartialSolid() {
return ITEM_PARTIAL_SOLID;
}
private static final RenderType ITEM_PARTIAL_TRANSLUCENT = RenderType.create(createLayerName("item_partial_translucent"),
DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, true, true, RenderType.CompositeState.builder()
.setShaderState(RENDERTYPE_ENTITY_TRANSLUCENT_CULL_SHADER)
.setTextureState(BLOCK_SHEET)
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
public static RenderType getItemPartialTranslucent() {
return ITEM_PARTIAL_TRANSLUCENT;
}
private static final RenderType FLUID = RenderType.create(createLayerName("fluid"),
DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, false, true, RenderType.CompositeState.builder()
.setShaderState(RENDERTYPE_ENTITY_TRANSLUCENT_CULL_SHADER)
.setTextureState(BLOCK_SHEET_MIPPED)
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setLightmapState(LIGHTMAP)
.setOverlayState(OVERLAY)
.createCompositeState(true));
public static RenderType getFluid() {
return FLUID;
}
private static String createLayerName(String name) {
return TradingStation.MODID + ":" + name;
}
// Mmm gimme those protected fields
private RenderTypes() {
super(null, null, null);
}
@EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD)
private static class Shaders {
private static ShaderInstance glowingShader;
/*@SubscribeEvent
public static void onRegisterShaders(RegisterShadersEvent event) throws IOException {
ResourceManager resourceManager = event.getResourceManager();
event.registerShader(new ShaderInstance(resourceManager, TradingStation.asResource("glowing_shader"), DefaultVertexFormat.NEW_ENTITY), shader -> glowingShader = shader);
}*/
}
}

View File

@@ -0,0 +1,14 @@
package com.oierbravo.trading_station.foundation.util;
import com.oierbravo.trading_station.TradingStation;
import net.minecraft.network.chat.Component;
public class ModLang {
public static Component translate(String key){
return Component.translatable(TradingStation.MODID + '.' + key);
}
public static String key(String key){
return TradingStation.MODID + '.' + key;
}
}

View File

@@ -0,0 +1,56 @@
package com.oierbravo.trading_station.network.packets;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class GhostItemSyncC2SPacket {
private final ItemStack itemStack;
private final BlockPos pos;
public GhostItemSyncC2SPacket(ItemStack itemStack, BlockPos pos) {
this.itemStack = itemStack;
this.pos = pos;
}
public GhostItemSyncC2SPacket(FriendlyByteBuf buf) {
this.itemStack = buf.readItem();
this.pos = buf.readBlockPos();
}
public void toBytes(FriendlyByteBuf buf) {
buf.writeItem(itemStack);
buf.writeBlockPos(pos);
}
public static void handle(GhostItemSyncC2SPacket message, Supplier<NetworkEvent.Context> supplier) {
NetworkEvent.Context context = supplier.get();
context.enqueueWork(() -> {
ServerPlayer sender = context.getSender();
if (sender == null)
return;
AbstractContainerMenu container = sender.containerMenu;
if (container == null)
return;
if(sender.getLevel().getBlockEntity(message.pos) instanceof TradingStationBlockEntity blockEntity) {
blockEntity.setPreferedItem(message.itemStack);
//blockEntity.setChanged();
}
});
context.setPacketHandled(true);
}
}

View File

@@ -0,0 +1,54 @@
package com.oierbravo.trading_station.network.packets;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class ItemStackSyncS2CPacket {
private final int slot;
private final ItemStack itemStack;
private final BlockPos pos;
public enum SlotType {
INPUT, OUTPUT, TARGET;
}
private final SlotType slotType;
public ItemStackSyncS2CPacket(int slot, ItemStack itemStack, BlockPos pos,SlotType slotType) {
this.slot = slot;
this.itemStack = itemStack;
this.pos = pos;
this.slotType = slotType;
}
public ItemStackSyncS2CPacket(FriendlyByteBuf buf) {
this.slot = buf.readInt();
this.itemStack = buf.readItem();
this.pos = buf.readBlockPos();
this.slotType = SlotType.values()[buf.readInt()];
}
public void toBytes(FriendlyByteBuf buf) {
buf.writeInt(slot);
buf.writeItem(itemStack);
buf.writeBlockPos(pos);
buf.writeInt(slotType.ordinal());
}
public static boolean handle(ItemStackSyncS2CPacket message, Supplier<NetworkEvent.Context> supplier) {
NetworkEvent.Context context = supplier.get();
context.enqueueWork(() -> {
if(Minecraft.getInstance().level.getBlockEntity(message.pos) instanceof TradingStationBlockEntity blockEntity) {
blockEntity.setItemStack(message.slot,message.itemStack,message.slotType);
}
});
return true;
}
}

View File

@@ -0,0 +1,50 @@
package com.oierbravo.trading_station.network.packets;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import com.oierbravo.trading_station.content.trading_station.TradingStationMenu;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.SimpleMenuProvider;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraftforge.network.NetworkEvent;
import net.minecraftforge.network.NetworkHooks;
import java.util.function.Supplier;
public class OpenTargetSelectPacket {
private BlockPos sourcePos;
public OpenTargetSelectPacket(BlockPos pSourcePos){
this.sourcePos = pSourcePos;
}
public OpenTargetSelectPacket(FriendlyByteBuf buf){
this(buf.readBlockPos());
}
public void toBytes(FriendlyByteBuf buf) {
buf.writeBlockPos(sourcePos);
}
public static boolean handle(OpenTargetSelectPacket message, Supplier<NetworkEvent.Context> supplier) {
NetworkEvent.Context context = supplier.get();
context.enqueueWork(() -> {
ServerPlayer sender = context.getSender();
if (sender == null)
return;
TradingStationMenu container = (TradingStationMenu) sender.containerMenu;
if (container == null)
return;
/*NetworkHooks.openScreen(sender, new SimpleMenuProvider(
(windowId, playerInventory, playerEntity) -> new TradingTradeSelectMenu(windowId, message.sourcePos), Component.translatable("")), (buf -> {
buf.writeBlockPos(message.sourcePos);
}));*/
NetworkHooks.openScreen(((ServerPlayer)sender), (TradingStationBlockEntity)container.blockEntity, message.sourcePos);
});
return true;
}
}

View File

@@ -0,0 +1,52 @@
package com.oierbravo.trading_station.network.packets;
import com.oierbravo.trading_station.content.trading_station.TradingStationMenu;
import dev.latvian.mods.rhino.ast.Block;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.SimpleMenuProvider;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraftforge.network.NetworkEvent;
import net.minecraftforge.network.NetworkHooks;
import java.util.function.Supplier;
public class OpenTradingMenuPacket {
protected BlockPos sourcePos;
public OpenTradingMenuPacket(BlockPos pSourcePos){
this.sourcePos = pSourcePos;
}
public OpenTradingMenuPacket(FriendlyByteBuf buf){
this(buf.readBlockPos());
}
public void toBytes(FriendlyByteBuf buf) {
buf.writeBlockPos(sourcePos);
}
public BlockPos getSourcePos(){
return sourcePos;
}
public static boolean handle(OpenTradingMenuPacket message, Supplier<NetworkEvent.Context> supplier) {
NetworkEvent.Context context = supplier.get();
context.enqueueWork(() -> {
ServerPlayer sender = context.getSender();
if (sender == null)
return;
AbstractContainerMenu container = sender.containerMenu;
if (container == null)
return;
NetworkHooks.openScreen(sender, new SimpleMenuProvider(
(windowId, playerInventory, playerEntity) -> new TradingStationMenu(windowId,playerInventory,message.sourcePos), Component.translatable("trading_station.block.display")), (buf -> {
buf.writeBlockPos(message.sourcePos);
}));
});
return true;
}
}

View File

@@ -0,0 +1,30 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.content.trading_station.TradingStationConfig;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.config.ModConfig;
//From https://github.com/McJty/TutorialV3/blob/1.19/src/main/java/com/example/tutorialv3/setup/Config.java
public class Config {
public static void register() {
registerServerConfigs();
//registerCommonConfigs();
//registerClientConfigs();
}
private static void registerClientConfigs() {
ForgeConfigSpec.Builder CLIENT_BUILDER = new ForgeConfigSpec.Builder();
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, CLIENT_BUILDER.build());
}
private static void registerCommonConfigs() {
ForgeConfigSpec.Builder COMMON_BUILDER = new ForgeConfigSpec.Builder();
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, COMMON_BUILDER.build());
}
private static void registerServerConfigs() {
ForgeConfigSpec.Builder SERVER_BUILDER = new ForgeConfigSpec.Builder();
TradingStationConfig.registerServerConfig(SERVER_BUILDER);
ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, SERVER_BUILDER.build());
}
}

View File

@@ -0,0 +1,24 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockRenderer;
import com.oierbravo.trading_station.content.trading_station.powered.PoweredTradingStationBlockEntity;
import com.tterrag.registrate.util.entry.BlockEntityEntry;
public class ModBlockEntities {
public static final BlockEntityEntry<TradingStationBlockEntity> TRADING_STATION = TradingStation.registrate()
.blockEntity("trading_station", TradingStationBlockEntity::new)
.validBlocks(ModBlocks.TRADING_STATION)
.renderer(() -> TradingStationBlockRenderer::new)
.register();
public static final BlockEntityEntry<PoweredTradingStationBlockEntity> POWERED_TRADING_STATION = TradingStation.registrate()
.blockEntity("powered_trading_station", PoweredTradingStationBlockEntity::new)
.validBlocks(ModBlocks.POWERED_TRADING_STATION)
.renderer(() -> TradingStationBlockRenderer::new)
.register();
public static void register() {
}
}

View File

@@ -0,0 +1,55 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlock;
import com.oierbravo.trading_station.content.trading_station.powered.PoweredTradingStationBlock;
import com.oierbravo.trading_station.content.trading_station.TradingStationBlockEntity;
import com.oierbravo.trading_station.content.trading_station.powered.PoweredTradingStationBlockEntity;
import com.tterrag.registrate.Registrate;
import com.tterrag.registrate.util.entry.BlockEntry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraftforge.client.model.generators.ConfiguredModel;
public class ModBlocks {
private static final Registrate REGISTRATE = TradingStation.registrate()
.creativeModeTab(() -> ModCreativeTab.MAIN);
public static final BlockEntry<TradingStationBlock> TRADING_STATION = TradingStation.registrate()
.block("trading_station", TradingStationBlock::new)
.lang("Trading Station")
.blockstate((ctx, prov) ->
prov.getVariantBuilder(ctx.getEntry()).forAllStates(state -> {
String modelFileName = "trading_station:block/trading_station";
if(state.getValue(BlockStateProperties.POWERED))
modelFileName += "_powered";
return ConfiguredModel.builder().modelFile(prov.models().getExistingFile(ResourceLocation.tryParse(modelFileName)))
.rotationY(((int) state.getValue(BlockStateProperties.HORIZONTAL_FACING).toYRot() + 180) % 360).build();
})
)
.simpleItem()
.blockEntity(TradingStationBlockEntity::new)
.build()
.register();
public static final BlockEntry<PoweredTradingStationBlock> POWERED_TRADING_STATION = TradingStation.registrate()
.block("powered_trading_station", PoweredTradingStationBlock::new)
.lang("Powered Trading Station")
.blockstate((ctx, prov) ->
prov.getVariantBuilder(ctx.getEntry()).forAllStates(state -> {
String modelFileName = "trading_station:block/powered_trading_station";
if(state.getValue(BlockStateProperties.POWERED))
modelFileName += "_powered";
return ConfiguredModel.builder().modelFile(prov.models().getExistingFile(ResourceLocation.tryParse(modelFileName)))
.rotationY(((int) state.getValue(BlockStateProperties.HORIZONTAL_FACING).toYRot() + 180) % 360).build();
})
)
.simpleItem()
.blockEntity(PoweredTradingStationBlockEntity::new)
.build()
.register();
public static void register() {
}
}

View File

@@ -0,0 +1,21 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.TradingStation;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
public class ModCreativeTab extends CreativeModeTab {
public static ModCreativeTab MAIN;
public ModCreativeTab() {
super(TradingStation.DISPLAY_NAME);
MAIN = this;
}
@Override
public ItemStack makeIcon() {
return new ItemStack(ModBlocks.TRADING_STATION.get());
}
}

View File

@@ -0,0 +1,25 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingStationMenu;
import com.oierbravo.trading_station.content.trading_station.TradingStationScreen;
import com.tterrag.registrate.util.entry.MenuEntry;
import com.tterrag.registrate.util.entry.RegistryEntry;
import net.minecraft.client.gui.screens.inventory.ContainerScreen;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.inventory.ChestMenu;
import net.minecraft.world.inventory.MenuType;
public class ModMenus {
public static final MenuEntry<TradingStationMenu> TRADING_STATION = TradingStation.registrate()
.menu("trading_station",TradingStationMenu::factory, () -> TradingStationScreen::new)
.register();
public static final MenuEntry<TradingStationMenu> TRADING_STATION_TRADE_SELECT = TradingStation.registrate()
.menu("trading_station_trade_select",TradingStationMenu::factory, () -> TradingStationScreen::new)
.register();
public static void register() {
}
}

View File

@@ -0,0 +1,70 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.network.packets.GhostItemSyncC2SPacket;
import com.oierbravo.trading_station.network.packets.ItemStackSyncS2CPacket;
import com.oierbravo.trading_station.network.packets.OpenTargetSelectPacket;
import com.oierbravo.trading_station.network.packets.OpenTradingMenuPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkDirection;
import net.minecraftforge.network.NetworkRegistry;
import net.minecraftforge.network.PacketDistributor;
import net.minecraftforge.network.simple.SimpleChannel;
public class ModMessages {
private static SimpleChannel INSTANCE;
private static int packetId = 0;
private static int id() {
return packetId++;
}
public static void register() {
SimpleChannel net = NetworkRegistry.ChannelBuilder
.named(new ResourceLocation(TradingStation.MODID, "messages"))
.networkProtocolVersion(() -> "1.0")
.clientAcceptedVersions(s -> true)
.serverAcceptedVersions(s -> true)
.simpleChannel();
INSTANCE = net;
net.messageBuilder(ItemStackSyncS2CPacket.class, id(), NetworkDirection.PLAY_TO_CLIENT)
.decoder(ItemStackSyncS2CPacket::new)
.encoder(ItemStackSyncS2CPacket::toBytes)
.consumerMainThread(ItemStackSyncS2CPacket::handle)
.add();
net.messageBuilder(GhostItemSyncC2SPacket.class, id(), NetworkDirection.PLAY_TO_SERVER)
.decoder(GhostItemSyncC2SPacket::new)
.encoder(GhostItemSyncC2SPacket::toBytes)
.consumerMainThread(GhostItemSyncC2SPacket::handle)
.add();
net.messageBuilder(OpenTradingMenuPacket.class, id(), NetworkDirection.PLAY_TO_SERVER)
.decoder(OpenTradingMenuPacket::new)
.encoder(OpenTradingMenuPacket::toBytes)
.consumerMainThread(OpenTradingMenuPacket::handle)
.add();
net.messageBuilder(OpenTargetSelectPacket.class, id(), NetworkDirection.PLAY_TO_SERVER)
.decoder(OpenTargetSelectPacket::new)
.encoder(OpenTargetSelectPacket::toBytes)
.consumerMainThread(OpenTargetSelectPacket::handle)
.add();
}
public static <MSG> void sendToServer(MSG message) {
INSTANCE.sendToServer(message);
}
public static <MSG> void sendToPlayer(MSG message, ServerPlayer player) {
INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), message);
}
public static <MSG> void sendToClients(MSG message) {
INSTANCE.send(PacketDistributor.ALL.noArg(), message);
}
}

View File

@@ -0,0 +1,70 @@
package com.oierbravo.trading_station.registrate;
import com.oierbravo.trading_station.TradingStation;
import com.oierbravo.trading_station.content.trading_station.TradingRecipe;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.Level;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class ModRecipes {
public static final DeferredRegister<RecipeSerializer<?>> SERIALIZERS =
DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, TradingStation.MODID);
public static final DeferredRegister<RecipeType<?>> RECIPE_TYPES = DeferredRegister.create(ForgeRegistries.RECIPE_TYPES, TradingStation.MODID);
public static final RegistryObject<RecipeType<TradingRecipe>> TRADING_TYPE =
RECIPE_TYPES.register("trading",() -> TradingRecipe.Type.INSTANCE);
public static final RegistryObject<RecipeSerializer<TradingRecipe>> TRADING_SERIALIZER =
SERIALIZERS.register("trading", () -> TradingRecipe.Serializer.INSTANCE);
public static Optional<TradingRecipe> find(SimpleContainer pInv, Level pLevel) {
if(pLevel.isClientSide())
return Optional.empty();
return pLevel.getRecipeManager().getRecipeFor(TradingRecipe.Type.INSTANCE,pInv,pLevel);
}
/*public static List<ItemStack> getAllOutputs(Level pLevel){
List<ItemStack> allOutputs = pLevel.getRecipeManager().getAllRecipesFor(TradingRecipe.Type.INSTANCE).stream()
.map(TradingRecipe::getResult).toList();
allOutputs.add(ItemStack.EMPTY);
return allOutputs;
}*/
public static List<ItemStack> getAllOutputs(Level pLevel){
return pLevel.getRecipeManager().getAllRecipesFor(TradingRecipe.Type.INSTANCE).stream()
.map(TradingRecipe::getResult).toList();
}
public static Optional<TradingRecipe> findByOutput(Level pLevel,ItemStack targetedOutput){
//if(pLevel.isClientSide())
// return Optional.empty();
return pLevel.getRecipeManager().getAllRecipesFor(TradingRecipe.Type.INSTANCE).stream()
.filter(recipe -> recipe.matchesOutput(targetedOutput)).findFirst();
}
/*public static Optional<TradingRecipe> findWithPreferdOutput(SimpleContainer pInv, Level pLevel, ItemStack preferedOutput){
if(pLevel.isClientSide())
return Optional.empty();
List<TradingRecipe> allTradingRecipes = pLevel.getRecipeManager().getAllRecipesFor(TradingRecipe.Type.INSTANCE);
return allTradingRecipes.stream().filter(extrudingRecipe -> TradingRecipe.matches(tradingStation,tradingRecipe)).findFirst();
}*/
public static void register(IEventBus eventBus) {
SERIALIZERS.register(eventBus);
RECIPE_TYPES.register(eventBus);
}
}