Jump to content

Thorius

Members
  • Posts

    54
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by Thorius

  1. Well if you (Tatuck) want to know more about the subject, look into trigonometry. (in case you're not familiar with it) I think you can find many good explanations on the internet, maybe videos will be helpfull. I think you can learn the basics of trigonometry pretty fast and then you can do so much more with 3D coordinates.
  2. I wrote this in 1.15.2. The angle is given in radians. In any case you should test this solution whether or not it creates some errors in some special cases.
  3. @SubscribeEvent public static void soundAngle(PlaySoundEvent e){ ClientPlayerEntity player = Minecraft.getInstance().player; if(player != null) { //the event also triggers in the main menu, so this avoids crash ISound sound = e.getResultSound(); double x = sound.getX() - player.getPosX(); //gets the position relative to the player double y = sound.getZ() - player.getPosZ(); double angle = Math.atan2(y, x); //converts two sides of a rectangle to an angle given in radians player.sendChatMessage(String.valueOf(angle)); } } Something like this should work. In this code you get the angle relative to the world and not the player.
  4. Sorry for the delayed response, but i still have issues. I managed to render the face, however, what I get is a collection of all the textures. Changing the texture location (for the material) does nothing and although i could display my texture with some magic numbers, it would be a terrible and unstable solution. So my question is, how do i get the texture dependent UV coordinates or in case the texture is bound the wrong way, how do i do it correctly? My code: @SuppressWarnings("deprecation") public class CrucibleRenderer extends TileEntityRenderer<CrucibleTileEntity>{ //vanilla texture for testing purposes public static final Material MOLTEN_METAL_TEXTURE = new Material(AtlasTexture.LOCATION_BLOCKS_TEXTURE, new ResourceLocation("block/stone")); public CrucibleRenderer(TileEntityRendererDispatcher rendererDispatcherIn) { super(rendererDispatcherIn); } @Override public void render(CrucibleTileEntity tileEntityIn, float partialTicks, MatrixStack matrixStackIn, IRenderTypeBuffer bufferIn, int combinedLightIn, int combinedOverlayIn) { //The issue is here int fluid = tileEntityIn.getFluid(); if(fluid > 0) { float f = 0.375f + fluid * 0.015f; Matrix4f matrix4f = matrixStackIn.getLast().getMatrix(); IVertexBuilder vertexBuilder = MOLTEN_METAL_TEXTURE.getBuffer(bufferIn, RenderType::getEntitySolid); this.renderFace(tileEntityIn, f, combinedOverlayIn, combinedLightIn, matrix4f, vertexBuilder); } //Some other rendering stuff (hopefully) unrelated to the issue ItemStack item = tileEntityIn.getItem(); if(!item.isEmpty()) { matrixStackIn.push(); matrixStackIn.scale(0.5f, 0.5f, 0.5f); double height = 1.5D; if(item.getItem() instanceof BlockItem) height = 1.0D; height += fluid * 0.025D; matrixStackIn.translate(1.0D, height, 1.0D); //Animation matrixStackIn.rotate(Vector3f.YP.rotationDegrees(90.f)); //Rendering renderItem(item, matrixStackIn, bufferIn, combinedLightIn, combinedOverlayIn); matrixStackIn.pop(); } } private void renderFace(CrucibleTileEntity tileEntityIn, float height, int combinedOverlayIn, int combinedLightIn, Matrix4f matrix, IVertexBuilder iVertexBuilder) { this.renderFace(matrix, iVertexBuilder, 0.25F, 0.75F, height, 0.25F, 0.75F, 1.f, 1.f, 1.f, combinedOverlayIn, combinedLightIn); } private void renderFace(Matrix4f matrix, IVertexBuilder vertexBuilder, float minX, float maxX, float height, float minZ, float maxZ, float red, float green, float blue, int combinedOverlayIn, int combinedLightIn) { //Right now i use some testing values fo the UV coordinates vertexBuilder.pos(matrix, minX, height, maxZ).color(red, green, blue, 1.0F).tex(0.5f, 0.40f) .overlay(combinedOverlayIn).lightmap(combinedLightIn).normal(0.f, 1.f, 0.f).endVertex(); vertexBuilder.pos(matrix, maxX, height, maxZ).color(red, green, blue, 1.0F).tex(0.5f, 0.5f) .overlay(combinedOverlayIn).lightmap(combinedLightIn).normal(0.f, 1.f, 0.f).endVertex(); vertexBuilder.pos(matrix, maxX, height, minZ).color(red, green, blue, 1.0F).tex(0.40f, 0.5f) .overlay(combinedOverlayIn).lightmap(combinedLightIn).normal(0.f, 1.f, 0.f).endVertex(); vertexBuilder.pos(matrix, minX, height, minZ).color(red, green, blue, 1.0F).tex(0.40f, 0.40f) .overlay(combinedOverlayIn).lightmap(combinedLightIn).normal(0.f, 1.f, 0.f).endVertex(); } private void renderItem(ItemStack stack, MatrixStack matrixStackIn, IRenderTypeBuffer bufferIn, int combinedLightIn, int combinedOverlayIn) { Minecraft.getInstance().getItemRenderer().renderItem(stack, TransformType.FIXED, combinedLightIn, combinedOverlayIn, matrixStackIn, bufferIn); } }
  5. Hello, actually i would like to know two things about TER. My first issue is that unless i use a VoxelShape that is not a full block, the models that i render are dark. I tried many things to solve the problem, but none of them worked. In any case, it would be better if didn't have to change the VoxelShape of the block. My other issue is that i don't know how to attach a texture to a face drawn with the vertex builder. I can't find any good examples. Thanks in advance!
  6. You have to run the forge jar and not the minecraft_server one.
  7. For the client you have to select the location of your minecraft installation, .minecraft
  8. The place where you installed the server with forge should have a folder named mods propably. Put your mods in there.
  9. To spawn arrows, something like this would work: @Override public void onUsingTick(ItemStack stack, LivingEntity player, int count) { if (!(player instanceof PlayerEntity)) { return; } PlayerEntity playerEntity = (PlayerEntity)player; World worldIn = player.world; if (!worldIn.isRemote) { AbstractArrowEntity abstractarrowentity = new ArrowEntity(worldIn, playerEntity); abstractarrowentity.shoot(playerEntity, playerEntity.rotationPitch, playerEntity.rotationYaw, 0.0F, 10.0F, 1.0F); abstractarrowentity.setIsCritical(true); abstractarrowentity.setDamage(10.D); abstractarrowentity.setKnockbackStrength(1); abstractarrowentity.setFire(100); stack.damageItem(1, playerEntity, (p_220009_1_) -> { p_220009_1_.sendBreakAnimation(playerEntity.getActiveHand()); }); abstractarrowentity.pickupStatus = AbstractArrowEntity.PickupStatus.CREATIVE_ONLY; worldIn.addEntity(abstractarrowentity); } You dont even need your own arrow class for this. But creating a custom bullet would also have its benefits and would look better with less unused functionality.
  10. You have to create a new bullet entity class but you can use the snowball as a template. In kinematics there's not much difference between a snowball and a bullet. If it looks and hurts like a bullet then it's a bullet. But you have to register it as a new entity.
  11. The snowball entity class is actually very good as a template for bullets. You just have to add damage and change its skin. I don't think you have any advantages if you use the arrow class.
  12. It could look like this: package com.thoriuslight.professionsmod.item; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.SnowballEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvents; import net.minecraft.world.World; public class BOWTEST extends Item{ public BOWTEST(Properties builder) { super(builder); } @Override public ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) { playerIn.setActiveHand(handIn); return ActionResult.resultPass(playerIn.getHeldItem(handIn)); } @Override public int getUseDuration(ItemStack stack) { return 20; } @Override public void onUsingTick(ItemStack stack, LivingEntity player, int count) { if (!(player instanceof PlayerEntity)) { return; } World worldIn = player.world; worldIn.playSound((PlayerEntity)null, player.getPosX(), player.getPosY(), player.getPosZ(), SoundEvents.ENTITY_SNOWBALL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (random.nextFloat() * 0.4F + 0.8F)); if (!worldIn.isRemote) { SnowballEntity snowballentity = new SnowballEntity(worldIn, player); snowballentity.setItem(new ItemStack(Items.DIAMOND)); snowballentity.shoot(player, player.rotationPitch, player.rotationYaw, 0.0F, 1.F, 1.0F); worldIn.addEntity(snowballentity); } } } After getUseDuration ticks there will be a small pause but it's not that noticeable. You have to set the active hand to be the item.
  13. Hello, I want to apply bonus damage to my weapon if the attacked entity meets the criteria. However, onLeftClickEntity(ItemStack stack, PlayerEntity player, Entity entity) disables the normal attack damage because of the invulnerability after taking damage. Maybe i could get this working but what would be the best and least ugly way to implement this feature? I really appreciate any help you can provide.
  14. Also, giving the arrow a way too high velocity might cause problems because of engine limitations, so alternatively you could create new bullet entity and change its damage there.
  15. For higher fire rate you can also use the onUsingTick(ItemStack stack, LivingEntity player, int count).
  16. I think you should look at the vanilla SnowballItem and change it so that it uses ammo instead of itself. In summary, you should use onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn)
  17. You can register it like this: public static final RegistryObject<Item> BOWTEST = ITEMS.register("bowtest", () -> new BowItem(new Item.Properties().maxDamage(500).group(AnItemGroup))); Instead of the vanilla BowItem you can also use your own class. But seeing your other posts, you already did this with other items, so i don't understand your problem.
  18. Thanks for your reply, it seems i made the wrong assumptions because of some mistakes on my part. The function is called properly but i wrote print instead of println and it is also fine for another function to return null. So the remaining problems are unrelated to this topic and i can manage them by myself.
  19. RecipeInit: package com.thoriuslight.professionsmod.init; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.SpecialRecipeSerializer; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import com.thoriuslight.professionsmod.ProfessionsMod; import com.thoriuslight.professionsmod.item.crafting.DoughRecipe; import com.thoriuslight.professionsmod.item.crafting.SmithChainArmorRecipe; import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; @Mod.EventBusSubscriber(modid = ProfessionsMod.MODID, bus = Bus.MOD) public class RecipeInit { public static final IRecipeSerializer<DoughRecipe> DOUGH_CRAFTING = null; public static final IRecipeSerializer<SmithChainArmorRecipe> CHAINMAIL_CRAFTING = null; @SubscribeEvent public static void registerRecipes(final RegistryEvent.Register<IRecipeSerializer<?>> event) { System.out.println("RECIPE_INITIALIZATION"); event.getRegistry().register(new SpecialRecipeSerializer<>(DoughRecipe::new).setRegistryName(ProfessionsMod.MODID, "dough_crafting")); event.getRegistry().register(new SpecialRecipeSerializer<>(SmithChainArmorRecipe::new).setRegistryName(ProfessionsMod.MODID, "chainmail_crafting")); } } DoughRecipe is the normal SpecialRecipe SmithChainArmorRecipe: (kind of a mess right now, because i'm focusing on getting it to work) package com.thoriuslight.professionsmod.item.crafting; import java.util.List; import com.google.common.collect.Lists; import com.thoriuslight.professionsmod.init.ItemInit; import com.thoriuslight.professionsmod.init.RecipeInit; import com.thoriuslight.professionsmod.init.SkillInit; import com.thoriuslight.professionsmod.item.ButtedChainArmorItem; import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; public class SmithChainArmorRecipe implements ISmithRecipe{ private final ItemStack recipeOutput; private final ResourceLocation id; private final int requiredSkills; public SmithChainArmorRecipe(ResourceLocation id){ this.id = id; this.requiredSkills = SkillInit.WEAK_CHAIN_ARMOR.getId(); this.recipeOutput = new ItemStack(ItemInit.COPPER_BUTTED_CHAIN_BOOTS.get()); } @Override public boolean matches(CraftingInventory inv, World worldIn) { System.out.print("its working"); List<ItemStack> list = Lists.newArrayList(); boolean chainArmor = false; boolean chain = false; for(int i = 0; i < inv.getSizeInventory(); ++i) { ItemStack itemstack = inv.getStackInSlot(i); if (!itemstack.isEmpty()) { list.add(itemstack); if(itemstack.getItem() instanceof ButtedChainArmorItem) chainArmor = true; if(itemstack.getItem() == ItemInit.COPPER_CHAIN.get()) chain = true; } } if (list.size() == 2 && chain && chainArmor) { ItemStack stack = null; for(int j = 0; j < 2; ++j) { if(list.get(j).getItem() instanceof ButtedChainArmorItem) { stack = list.get(j); break; } } if(stack != null) { if(stack.getDamage() != 0) return true; } } return false; } @Override public boolean isUnlocked(int skillList) { skillList &= this.requiredSkills; return skillList == this.requiredSkills; } @Override public ItemStack getCraftingResult(CraftingInventory inv) { return this.recipeOutput.copy(); } @Override public boolean canFit(int width, int height) { return width * height >= 2; } @Override public ItemStack getRecipeOutput() { return ItemStack.EMPTY; } @Override public ResourceLocation getId() { return this.id; } @Override public IRecipeSerializer<?> getSerializer() { return RecipeInit.CHAINMAIL_CRAFTING; } @Override public Ingredient getInput() { return null; } @Override public NonNullList<Ingredient> getIngredients() { return null; } public int getRequirements() { return this.requiredSkills; } @Override public boolean isDynamic() { return true; } } ISmithRecipe: package com.thoriuslight.professionsmod.item.crafting; import javax.annotation.Nonnull; import com.thoriuslight.professionsmod.ProfessionsMod; import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipeType; import net.minecraft.item.crafting.Ingredient; import net.minecraft.util.ResourceLocation; import net.minecraft.util.registry.Registry; public interface ISmithRecipe extends IRecipe<CraftingInventory>{ ResourceLocation RECIPE_TYPE_ID = new ResourceLocation(ProfessionsMod.MODID, "smith"); @Nonnull @Override default IRecipeType<?> getType() { return Registry.RECIPE_TYPE.getValue(RECIPE_TYPE_ID).get(); } @Override default boolean canFit(int width, int height) { return false; } Ingredient getInput(); boolean isUnlocked(int skillList); } Other SmithRecipes specified elsewhere with json files are working fine.
  20. Hi, i'm trying to create a special recipe for a custom recipe type. The problem is that while the recipe exists, the recipe doesn't seem to have any information stored. I made it so that the function matches(CraftingInventory inv, World worldIn) outputs a text to the console if it is called. The recipe is registered the same way as a SpecialRecipe, which works fine for me. However, even though the recipe is in the RecipeManager and it does extend my recipe class, calling matches(CraftingInventory inv, World worldIn) manually does not output anything to the console. I can't find the root of this behaviour, because i checked explicitly that the recipe extends my class. The only thing i can think of are the Sides. Maybe the server side doesn't get the required data. But then again it works for the SpecialRecipe and the SpecialRecipeSerializer is defined for IRecipe, which my custom recipe also implements. So is it inevitable to create a new recipeSerializer or does the problem lie elsewhere? Thanks in advance
  21. The input gets duplicated. However i found the problem. I extended the CraftResultSlot for debug reasons and i noticed that it uses IRecipeType.CRAFTING to get the ingredients. After changing it to my type it works fine. Thanks for the help anyways.
  22. Hello, i created a special crafting table and recipe. If i craft something, then the ingredients get decreased by one, but then they double themselves. For example: a stack has initally 3 items, then after a single craft it becomes 4, then 6, 10, 18 and so on. If the recipeType is changed to the normal vanilla one in the container, then it functions properly. Consequently it is probably the custom recipe responsible for the error. This, however, contradicts my findings, the CraftingResultSlot should be responsible for handling the ingredients slots. But as i said, the container class works fine with the vanilla recipes and i didn't find anything related in the classes responsible for the recipes. Container class: package com.thoriuslight.professionsmod.inventory.container; import java.util.Optional; import com.thoriuslight.professionsmod.init.BlockInit; import com.thoriuslight.professionsmod.init.ModContainerTypes; import com.thoriuslight.professionsmod.init.RecipeSerializerInit; import com.thoriuslight.professionsmod.item.crafting.ISmithRecipe; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.CraftResultInventory; import net.minecraft.inventory.CraftingInventory; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.container.CraftingResultSlot; import net.minecraft.inventory.container.RecipeBookContainer; import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.RecipeItemHelper; import net.minecraft.network.PacketBuffer; import net.minecraft.network.play.server.SSetSlotPacket; import net.minecraft.util.IWorldPosCallable; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; public class SmithCraftingContainer extends RecipeBookContainer<CraftingInventory>{ private final CraftingInventory craftMatrix = new CraftingInventory(this, 3, 3); private final CraftResultInventory craftResult = new CraftResultInventory(); private final IWorldPosCallable canInteractWithCallable; private final PlayerEntity player; public SmithCraftingContainer(int windowId, final PlayerInventory playerInventory, final PacketBuffer data) { this(windowId, playerInventory, IWorldPosCallable.DUMMY); } public SmithCraftingContainer(int windowId, final PlayerInventory playerInventory) { this(windowId, playerInventory, IWorldPosCallable.DUMMY); } public SmithCraftingContainer(int windowId, final PlayerInventory playerInventory, IWorldPosCallable worldPosCallable) { super(ModContainerTypes.SMITH_CRAFTING.get(), windowId); this.canInteractWithCallable = worldPosCallable; this.player = playerInventory.player; this.addSlot(new CraftingResultSlot(playerInventory.player, this.craftMatrix, this.craftResult, 0, 124, 35)); for(int i = 0; i < 3; ++i) { for(int j = 0; j < 3; ++j) { this.addSlot(new Slot(this.craftMatrix, j + i * 3, 30 + j * 18, 17 + i * 18)); } } for(int k = 0; k < 3; ++k) { for(int i1 = 0; i1 < 9; ++i1) { this.addSlot(new Slot(playerInventory, i1 + k * 9 + 9, 8 + i1 * 18, 84 + k * 18)); } } for(int l = 0; l < 9; ++l) { this.addSlot(new Slot(playerInventory, l, 8 + l * 18, 142)); } } protected static void func_217066_a(int p_217066_0_, World world, PlayerEntity p_217066_2_, CraftingInventory craftInv, CraftResultInventory p_217066_4_) { if (!world.isRemote) { ServerPlayerEntity serverplayerentity = (ServerPlayerEntity)p_217066_2_; ItemStack itemstack = ItemStack.EMPTY; Optional<ISmithRecipe> optional = world.getServer().getRecipeManager().getRecipe(RecipeSerializerInit.SMITH_TYPE, craftInv, world); if (optional.isPresent()) { ISmithRecipe ismithrecipe = optional.get(); if (p_217066_4_.canUseRecipe(world, serverplayerentity, ismithrecipe)) { itemstack = ismithrecipe.getCraftingResult(craftInv); } } p_217066_4_.setInventorySlotContents(0, itemstack); serverplayerentity.connection.sendPacket(new SSetSlotPacket(p_217066_0_, 0, itemstack)); } } @Override public void onCraftMatrixChanged(IInventory inventoryIn) { this.canInteractWithCallable.consume((world, p_217069_2_) -> { func_217066_a(this.windowId, world, this.player, this.craftMatrix, this.craftResult); }); } @Override public void fillStackedContents(RecipeItemHelper itemHelperIn) { this.craftMatrix.fillStackedContents(itemHelperIn); } @Override public void clear() { this.craftMatrix.clear(); this.craftResult.clear(); } @Override public boolean matches(IRecipe<? super CraftingInventory> recipeIn) { return recipeIn.matches(this.craftMatrix, this.player.world); } @Override public void onContainerClosed(PlayerEntity playerIn) { super.onContainerClosed(playerIn); this.canInteractWithCallable.consume((p_217068_2_, p_217068_3_) -> { this.clearContainer(playerIn, p_217068_2_, this.craftMatrix); }); } @Override public boolean canInteractWith(PlayerEntity playerIn) { return isWithinUsableDistance(this.canInteractWithCallable, playerIn, BlockInit.SMITHCRAFTINGTABLE_BLOCK.get()); } @Override public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) { ItemStack itemstack = ItemStack.EMPTY; Slot slot = this.inventorySlots.get(index); if (slot != null && slot.getHasStack()) { ItemStack itemstack1 = slot.getStack(); itemstack = itemstack1.copy(); if (index == 0) { this.canInteractWithCallable.consume((p_217067_2_, p_217067_3_) -> { itemstack1.getItem().onCreated(itemstack1, p_217067_2_, playerIn); }); if (!this.mergeItemStack(itemstack1, 10, 46, true)) { return ItemStack.EMPTY; } slot.onSlotChange(itemstack1, itemstack); } else if (index >= 10 && index < 46) { if (!this.mergeItemStack(itemstack1, 1, 10, false)) { if (index < 37) { if (!this.mergeItemStack(itemstack1, 37, 46, false)) { return ItemStack.EMPTY; } } else if (!this.mergeItemStack(itemstack1, 10, 37, false)) { return ItemStack.EMPTY; } } } else if (!this.mergeItemStack(itemstack1, 10, 46, false)) { return ItemStack.EMPTY; } if (itemstack1.isEmpty()) { slot.putStack(ItemStack.EMPTY); } else { slot.onSlotChanged(); } if (itemstack1.getCount() == itemstack.getCount()) { return ItemStack.EMPTY; } ItemStack itemstack2 = slot.onTake(playerIn, itemstack1); if (index == 0) { playerIn.dropItem(itemstack2, false); } } return itemstack; } @Override public boolean canMergeSlot(ItemStack stack, Slot slotIn) { return slotIn.inventory != this.craftResult && super.canMergeSlot(stack, slotIn); } @Override public int getOutputSlot() { return 0; } @Override public int getWidth() { return this.craftMatrix.getWidth(); } @Override public int getHeight() { return this.craftMatrix.getHeight(); } @OnlyIn(Dist.CLIENT) @Override public int getSize() { return 10; } } Recipe class: package com.thoriuslight.professionsmod.item.crafting; import com.thoriuslight.professionsmod.init.RecipeSerializerInit; import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; public class SmithRecipe implements ISmithRecipe{ private final int recipeWidth; private final int recipeHeight; private final NonNullList<Ingredient> recipeItems; private final ItemStack recipeOutput; private final ResourceLocation id; public SmithRecipe(ResourceLocation id, int recipeWidthIn, int recipeHeightIn, NonNullList<Ingredient> recipeItemsIn, ItemStack output){ this.recipeWidth = recipeWidthIn; this.recipeHeight = recipeHeightIn; this.id = id; this.recipeItems = recipeItemsIn; this.recipeOutput = output; } @Override public boolean matches(CraftingInventory inv, World worldIn) { //Horizontal shift for(int x = 0; x <= inv.getWidth() - this.recipeWidth; ++x) { //Vertical shift for(int y = 0; y <= inv.getHeight() - this.recipeHeight; ++y) { if (this.checkMatch(inv, x, y, true)) { return true; } if (this.checkMatch(inv, x, y, false)) { return true; } } } return false; } private boolean checkMatch(CraftingInventory craftingInventory, int p_77573_2_, int p_77573_3_, boolean p_77573_4_) { for(int i = 0; i < craftingInventory.getWidth(); ++i) { for(int j = 0; j < craftingInventory.getHeight(); ++j) { int k = i - p_77573_2_; int l = j - p_77573_3_; Ingredient ingredient = Ingredient.EMPTY; if (k >= 0 && l >= 0 && k < this.recipeWidth && l < this.recipeHeight) { if (p_77573_4_) { ingredient = this.recipeItems.get(this.recipeWidth - k - 1 + l * this.recipeWidth); } else { ingredient = this.recipeItems.get(k + l * this.recipeWidth); } } if (!ingredient.test(craftingInventory.getStackInSlot(i + j * craftingInventory.getWidth()))) { return false; } } } return true; } @Override public ItemStack getCraftingResult(CraftingInventory inv) { return this.recipeOutput.copy(); } @Override public boolean canFit(int width, int height) { return width >= this.recipeWidth && height >= this.recipeHeight; } @Override public ItemStack getRecipeOutput() { return this.recipeOutput; } @Override public ResourceLocation getId() { return this.id; } @Override public IRecipeSerializer<?> getSerializer() { return RecipeSerializerInit.SMITH_SERIALIZER.get(); } @Override public Ingredient getInput() { return null; } public int getRecipeHeight() { return this.recipeHeight; } public int getRecipeWidth() { return this.recipeWidth; } @Override public NonNullList<Ingredient> getIngredients() { return this.recipeItems; } } IRecipe class: package com.thoriuslight.professionsmod.item.crafting; import javax.annotation.Nonnull; import com.thoriuslight.professionsmod.ProfessionsMod; import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipeType; import net.minecraft.item.crafting.Ingredient; import net.minecraft.util.ResourceLocation; import net.minecraft.util.registry.Registry; public interface ISmithRecipe extends IRecipe<CraftingInventory>{ ResourceLocation RECIPE_TYPE_ID = new ResourceLocation(ProfessionsMod.MODID, "smith"); @Nonnull @Override default IRecipeType<?> getType() { return Registry.RECIPE_TYPE.getValue(RECIPE_TYPE_ID).get(); } @Override default boolean canFit(int width, int height) { return false; } Ingredient getInput(); } RecipeSerializer class: package com.thoriuslight.professionsmod.item.crafting; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; import net.minecraft.network.PacketBuffer; import net.minecraft.util.JSONUtils; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.crafting.CraftingHelper; import net.minecraftforge.registries.ForgeRegistryEntry; public class SmithRecipeSerializer extends ForgeRegistryEntry<IRecipeSerializer<?>> implements IRecipeSerializer<SmithRecipe>{ @Override public SmithRecipe read(ResourceLocation recipeId, JsonObject json) { Map<String, Ingredient> map = SmithRecipeSerializer.deserializeKey(JSONUtils.getJsonObject(json, "key")); String[] astring = SmithRecipeSerializer.shrink(SmithRecipeSerializer.patternFromJson(JSONUtils.getJsonArray(json, "pattern"))); int i = astring[0].length(); int j = astring.length; NonNullList<Ingredient> input = deserializeIngredients(astring, map, i, j); ItemStack ouput = CraftingHelper.getItemStack(JSONUtils.getJsonObject(json, "result"), true); return new SmithRecipe(recipeId, i, j, input, ouput); } private static NonNullList<Ingredient> deserializeIngredients(String[] pattern, Map<String, Ingredient> keys, int patternWidth, int patternHeight) { NonNullList<Ingredient> nonnulllist = NonNullList.withSize(patternWidth * patternHeight, Ingredient.EMPTY); Set<String> set = Sets.newHashSet(keys.keySet()); set.remove(" "); for(int i = 0; i < pattern.length; ++i) { for(int j = 0; j < pattern[i].length(); ++j) { String s = pattern[i].substring(j, j + 1); Ingredient ingredient = keys.get(s); if (ingredient == null) { throw new JsonSyntaxException("Pattern references symbol '" + s + "' but it's not defined in the key"); } set.remove(s); nonnulllist.set(j + patternWidth * i, ingredient); } } if (!set.isEmpty()) { throw new JsonSyntaxException("Key defines symbols that aren't used in pattern: " + set); } else { return nonnulllist; } } private static Map<String, Ingredient> deserializeKey(JsonObject json) { Map<String, Ingredient> map = Maps.newHashMap(); for(Entry<String, JsonElement> entry : json.entrySet()) { if (entry.getKey().length() != 1) { throw new JsonSyntaxException("Invalid key entry: '" + (String)entry.getKey() + "' is an invalid symbol (must be 1 character only)."); } if (" ".equals(entry.getKey())) { throw new JsonSyntaxException("Invalid key entry: ' ' is a reserved symbol."); } map.put(entry.getKey(), Ingredient.deserialize(entry.getValue())); } map.put(" ", Ingredient.EMPTY); return map; } @VisibleForTesting static String[] shrink(String... toShrink) { int i = Integer.MAX_VALUE; int j = 0; int k = 0; int l = 0; for(int i1 = 0; i1 < toShrink.length; ++i1) { String s = toShrink[i1]; i = Math.min(i, firstNonSpace(s)); int j1 = lastNonSpace(s); j = Math.max(j, j1); if (j1 < 0) { if (k == i1) { ++k; } ++l; } else { l = 0; } } if (toShrink.length == l) { return new String[0]; } else { String[] astring = new String[toShrink.length - l - k]; for(int k1 = 0; k1 < astring.length; ++k1) { astring[k1] = toShrink[k1 + k].substring(i, j + 1); } return astring; } } private static int firstNonSpace(String str) { int i; for(i = 0; i < str.length() && str.charAt(i) == ' '; ++i) { ; } return i; } private static int lastNonSpace(String str) { int i; for(i = str.length() - 1; i >= 0 && str.charAt(i) == ' '; --i) { ; } return i; } private static String[] patternFromJson(JsonArray jsonArr) { String[] astring = new String[jsonArr.size()]; if (astring.length > 3) { throw new JsonSyntaxException("Invalid pattern: too many rows, " + 3 + " is maximum"); } else if (astring.length == 0) { throw new JsonSyntaxException("Invalid pattern: empty pattern not allowed"); } else { for(int i = 0; i < astring.length; ++i) { String s = JSONUtils.getString(jsonArr.get(i), "pattern[" + i + "]"); if (s.length() > 3) { throw new JsonSyntaxException("Invalid pattern: too many columns, " + 3 + " is maximum"); } if (i > 0 && astring[0].length() != s.length()) { throw new JsonSyntaxException("Invalid pattern: each row must be the same width"); } astring[i] = s; } return astring; } } @Override public SmithRecipe read(ResourceLocation recipeId, PacketBuffer buffer) { int i = buffer.readVarInt(); int j = buffer.readVarInt(); NonNullList<Ingredient> nonnulllist = NonNullList.withSize(i * j, Ingredient.EMPTY); for(int k = 0; k < nonnulllist.size(); ++k) { nonnulllist.set(k, Ingredient.read(buffer)); } ItemStack itemstack = buffer.readItemStack(); return new SmithRecipe(recipeId, i, j, nonnulllist, itemstack); } @Override public void write(PacketBuffer buffer, SmithRecipe recipe) { buffer.writeVarInt(recipe.getRecipeWidth()); buffer.writeVarInt(recipe.getRecipeHeight()); for(Ingredient ingredient : recipe.getIngredients()) { ingredient.write(buffer); } buffer.writeItemStack(recipe.getRecipeOutput()); } } Recipe Init class: package com.thoriuslight.professionsmod.init; import com.thoriuslight.professionsmod.ProfessionsMod; import com.thoriuslight.professionsmod.item.crafting.ISmithRecipe; import com.thoriuslight.professionsmod.item.crafting.SmithRecipe; import com.thoriuslight.professionsmod.item.crafting.SmithRecipeSerializer; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.IRecipeType; import net.minecraft.util.ResourceLocation; import net.minecraft.util.registry.Registry; import net.minecraftforge.fml.RegistryObject; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; public class RecipeSerializerInit { public static final IRecipeSerializer<SmithRecipe> SMITH_RECIPE_SERIALIZER = new SmithRecipeSerializer(); public static final IRecipeType<ISmithRecipe> SMITH_TYPE = registerType(ISmithRecipe.RECIPE_TYPE_ID); public static final DeferredRegister<IRecipeSerializer<?>> RECIPE_SERIALIZERS = new DeferredRegister<>(ForgeRegistries.RECIPE_SERIALIZERS, ProfessionsMod.MODID); public static final RegistryObject<IRecipeSerializer<?>> SMITH_SERIALIZER = RECIPE_SERIALIZERS.register("smith", () -> SMITH_RECIPE_SERIALIZER); private static IRecipeType<ISmithRecipe> registerType(ResourceLocation recipeTypeId) { return Registry.register(Registry.RECIPE_TYPE, recipeTypeId, new RecipeType<>()); } private static class RecipeType<T extends IRecipe<?>> implements IRecipeType<T> { @Override public String toString() { return Registry.RECIPE_TYPE.getKey(this).toString(); } } } Thank you for taking your time to help. I really appreciate it.
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.