dee12452
Members-
Posts
75 -
Joined
-
Last visited
-
Days Won
2
Everything posted by dee12452
-
Custom fishing rods with custom loot-table(s)
dee12452 replied to Viler_of_cool's topic in Modder Support
I'll assume you have some programming experience? If not you might want to start with some way of learning at least the basics of Java. However my first experience coding was actually in Minecraft modding so it's not necessary but it really does help. Any books or online resources can help, not up to date with anything myself to link useful things. Hell, ChatGPT might give you better ideas in this area than me. Ok with that out of the way, you could either start here if you want to read https://docs.minecraftforge.net/en/1.20.x/gettingstarted/ Or with Youtube tutorials potentially. I always recommend KaupenJoe's tutorials but there's a lot out there. If you want to get down and dirty quickly, you could easily follow a tutorial listed above to get your own custom items. Now loot modifiers are kinda their own beast. To do what you're asking, you'll need to make at least one custom GLM. The docs on that is here: https://docs.minecraftforge.net/en/1.20.x/resources/server/glm/ Pretty sure they have links to Github examples as well, but that's what I used to make my own GLM and it works great! Good luck! Hope this gives you a good starting point. -
You should just send a packet to the client over the network, and handle movement on the client when the packet is received https://docs.minecraftforge.net/en/latest/networking/
-
public static void sendEntityToLevel(ServerLevel otherDimensionLevel, LivingEntity entity, Vec3 location) { entity.teleportTo(otherDimensionLevel, location.x, location.y, location.z, new HashSet<>(), 0, 0 ); } This is what I'm using and it's worked fine
-
[1.20.4] Apply nausea wobble effect to the screen outside Nausea effect
dee12452 replied to chxr's topic in Modder Support
This honestly might just work for you @SubscribeEvent public static void onScreenRender(ScreenEvent.Render.Post event) { final var player = Minecraft.getInstance().player; final var options = Minecraft.getInstance().options; if(!hasMyEffect(player)) return; // TODO: You provide hasMyEffect float f = Mth.lerp(event.getPartialTick(), player.oSpinningEffectIntensity, player.spinningEffectIntensity); float f1 = ((Double)options.screenEffectScale().get()).floatValue(); if(f <= 0F || f1 >= 1F) return; float p_282656_ = f * (1.0F - f1); final var p_282460_ = event.getGuiGraphics(); int i = p_282460_.guiWidth(); int j = p_282460_.guiHeight(); p_282460_.pose().pushPose(); float f5 = Mth.lerp(p_282656_, 2.0F, 1.0F); p_282460_.pose().translate((float)i / 2.0F, (float)j / 2.0F, 0.0F); p_282460_.pose().scale(f5, f5, f5); p_282460_.pose().translate((float)(-i) / 2.0F, (float)(-j) / 2.0F, 0.0F); float f4 = 0.2F * p_282656_; float f2 = 0.4F * p_282656_; float f3 = 0.2F * p_282656_; RenderSystem.disableDepthTest(); RenderSystem.depthMask(false); RenderSystem.enableBlend(); RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE); p_282460_.setColor(f4, f2, f3, 1.0F); p_282460_.blit(new ResourceLocation("textures/misc/nausea.png"), 0, 0, -90, 0.0F, 0.0F, i, j, i, j); p_282460_.setColor(1.0F, 1.0F, 1.0F, 1.0F); RenderSystem.defaultBlendFunc(); RenderSystem.disableBlend(); RenderSystem.depthMask(true); RenderSystem.enableDepthTest(); p_282460_.pose().popPose(); } Note: Most of this is directly copied from GameRenderer as you pointed out you found. The only thing you'll have to likely do is update the `oSpinningEffectIntensity` + `spinningEffectIntensity` variables on the player when your effect is applied. Which values should be there? Not 100% sure, might be a game of guess and check, but `handleNetherPortalClient` in LocalPlayer has some hard coded you might be able to start with. -
Nice! Hopefully OP got their shit figured out too 👽
-
public class ParticleReboundRecipe implements Recipe<CraftingContainer> { private List<ParticleReboundIngredient> inputs; private ParticleReboundFuel fuel; private ItemStack output; public ParticleReboundRecipe(List<ParticleReboundIngredient> inputs, ParticleReboundFuel fuel, ItemStack output) { this.inputs = inputs; this.fuel = fuel; this.output = output; } // TODO: Implement interface ... // TODO: Move to separate file if desired public record ParticleReboundIngredient(Ingredient ingredient, int count) { public static final Codec<ParticleReboundIngredient> CODEC = RecordCodecBuilder.create( builder -> builder.group( Ingredient.CODEC.fieldOf("ingredient").forGetter((i) -> i.ingredient), Codec.INT.fieldOf("count").forGetter(i -> i.count) ).apply(builder, ParticleReboundIngredient::new) ); } // TODO: Move to separate file if desired public record ParticleReboundFuel(String tag) { public static final Codec<ParticleReboundFuel> CODEC = RecordCodecBuilder.create( builder -> builder.group(Codec.STRING.fieldOf("tag").forGetter(f -> f.tag)).apply(builder, ParticleReboundFuel::new) ); public boolean isFuel(ItemStack stack) { // TODO: Check if fuel item matches the tag } } public class Serializer implements RecipeSerializer<ParticleReboundRecipe> { public static final Codec<ParticleReboundRecipe> CODEC = RecordCodecBuilder.create( builder -> builder.group( ParticleReboundIngredient.CODEC.listOf().fieldOf("inputs").forGetter(r -> r.inputs), ParticleReboundFuel.CODEC.fieldOf("fuel").forGetter(r -> r.fuel), ItemStack.CODEC.fieldOf("output").forGetter(r -> r.output) ).apply(builder, ParticleReboundRecipe::new) ); @Override public @NotNull Codec<ParticleReboundRecipe> codec() { return CODEC; } // TODO: The rest ... } } ?
-
That looks pretty cool, nice! Sure, so looking at that JSON file I posted, I pretty much made a record class for each "custom" data type in that JSON. The Input is a good example of why ``` "inputs": [ { "ingredient": { "item": "relativedimensions:aberrant_shard" }, "count": 8 } ], ``` So here's the inputs, it's an array, which we can use the Codec builder's builder.listOf to define an array. Each Item is of some arbitrary object with keys "ingredient" (which we know is an Ingredient) and a "count" which is an int. You don't have to have an intermediate class to map this to necessarily but I found that it's just easier to see the data that way, hence the 'ParticleReboundIngredient' represents one of these inputs. Let me know if that makes sense or not.
-
@chxr Looks like you're making some sort of a crafting table / furnace hybrid? Are the inputs needing arranging like a shaped recipe, or is it shapeless? I'll assume it's shapeless since that just adds a lot more complexity. In that case I'd probably do something like this { "type": "relativedimensions:particle_rebound", "inputs": [ { "ingredient": { "item": "relativedimensions:aberrant_shard" }, "count": 8 } ], "fuel": { "tag": "relativedimensions:block/aberrant_fuel" }, "output": { "Count": 1, "id": "relativedimensions:aberrant_ingot" } } inputs: A list of ingredients and how many are needed. The count among each input adds up to 8. Since there's only 1 ingredient, the count is set to 8. fuel: Same thing as before but remove the list and just make it an object with a tag. output: Kept the same. In this case the Codec I would make is public record ParticleReboundIngredient(Ingredient ingredient, int count) { public static final Codec<ParticleReboundIngredient> CODEC = RecordCodecBuilder.create( builder -> builder.group( Ingredient.CODEC.fieldOf("ingredient").forGetter((i) -> i.ingredient), Codec.INT.fieldOf("count").forGetter(i -> i.count) ).apply(builder, ParticleReboundIngredient::new) ); } public record ParticleReboundFuel(String tag) { public static final Codec<ParticleReboundFuel> CODEC = RecordCodecBuilder.create( builder -> builder.group(Codec.STRING.fieldOf("tag").forGetter(f -> f.tag)).apply(builder, ParticleReboundFuel::new) ); public boolean isFuel(ItemStack stack) { // TODO: Check if fuel item matches the tag } } public record ParticleReboundRecipe(List<ParticleReboundIngredient> inputs, ParticleReboundFuel fuel, ItemStack output) { public static final Codec<ParticleReboundRecipe> CODEC = RecordCodecBuilder.create( builder -> builder.group( ParticleReboundIngredient.CODEC.listOf().fieldOf("inputs").forGetter(r -> r.inputs), ParticleReboundFuel.CODEC.fieldOf("fuel").forGetter(r -> r.fuel), ItemStack.CODEC.fieldOf("output").forGetter(r -> r.output) ).apply(builder, ParticleReboundRecipe::new) ); } There might be a more proper Codec for the fuel and the tag that's built into minecraft / forge, but I didn't look
-
Yeah CODECs are super funky the first time you start working with them, I definitely had a few woes in the beginning when moving to 1.20.2. What's the JSON structure of your recipe? I'm sure either I or ChatGPT can whip you up a CODEC for it pretty quickly lol.
-
@JacksStuff looks like at least one of your problems is your recipe JSON. ItemStack's CODEC isn't defined the way you're thinking it is. Try this instead { "type": "magic_overhaul:rune_inscribing", "base": { "item": "minecraft:stone" }, "template": { "item": "magic_overhaul:rune_template_acnar" }, "output": { "Count": 1, "id": "magic_overhaul:rune_acnar" } }
-
{ "type": "magic_overhaul:rune_inscribing", "base": { "item": "//base item" }, "template": { "item": "//template item" }, "output": { "count": 1, "item": "//output item" } } ^ Ok, where is your recipe JSON placed in your file structure? What's it called? And paste the actual JSON you're testing with, because it needs to be valid.
-
Sure, I'm sorry I couldn't be more helpful so far. Does this always return empty? List<RecipeHolder<RuneInscribingRecipe>> list = this.blockEntity.getLevel().getRecipeManager().getRecipesFor(RuneInscribingRecipe.RECIPE_TYPE, inventory, this.blockEntity.getLevel());
-
Hm yeah sorry, not seeing anything else that's sticking out, I'd need to debug myself probably. Do you have a github or bitbucket repo? I could poke around when I have time to see what the problem might be.
-
Ok yeah I think this might be where the problem starts. For starters, I think you can get rid of your RecipeType impl and make it a static constant instead. I'm not 100% sure this will fix it but it's posssible. RuneInscribingRecipe public class RuneInscribingRecipe implements Recipe<SimpleContainer> { public static final RecipeType<RuneInscribingRecipe> RECIPE_TYPE = new RecipeType<>(){}; // .... @Override public RecipeType<?> getType() { return RECIPE_TYPE; } // .... } RuneInscriberMenu private Optional<RecipeHolder<RuneInscribingRecipe>> getCurrentRecipe() { SimpleContainer inventory = new SimpleContainer(2); inventory.setItem(BASE_INPUT_SLOT, this.inventory.getStackInSlot(BASE_INPUT_SLOT)); inventory.setItem(TEMPLATE_INPUT_SLOT, this.inventory.getStackInSlot(TEMPLATE_INPUT_SLOT)); List<RecipeHolder<RuneInscribingRecipe>> list = this.blockEntity.getLevel().getRecipeManager().getRecipesFor(RuneInscribingRecipe.RECIPE_TYPE, inventory, this.blockEntity.getLevel()); if (list.isEmpty()) { return Optional.empty(); } return Optional.of(list.get(0)); } Also, this here is a little suspicious where you're getting the `this.inventory.getStackInSlot` calls. I'd try and make sure those are what you expect they are with either a Debug line in IDE or print statement SimpleContainer inventory = new SimpleContainer(2); inventory.setItem(BASE_INPUT_SLOT, this.inventory.getStackInSlot(BASE_INPUT_SLOT)); System.out.printf("CHECKING BASE INPUT OF RECIPE: %s\n", this.inventory.getStackInSlot(BASE_INPUT_SLOT)); inventory.setItem(TEMPLATE_INPUT_SLOT, this.inventory.getStackInSlot(TEMPLATE_INPUT_SLOT)); System.out.printf("CHECKING TEMPLATE INPUT OF RECIPE: %s\n", this.inventory.getStackInSlot(TEMPLATE_INPUT_SLOT)); ^ See what the result of those print statements are, make sure they're right
-
There's a couple of discrepancies between my 1.20.2 implementation that's working and yours here but nothing I'd imagine is directly causing an issue. What's the exact problem that's happening? Is there a crash? Are you using a custom crafting menu you made from scratch (i.e. a new class that likely extends AbstractContainerMenu + a screen to go along with it)?
-
Yeah this looks good, alright post all of `RuneInscribingRecipe`
-
I don't spot anything obvious. Can you post the code where you register the serializer?
-
1.20.4 Trident with Channeling and Riptide
dee12452 replied to StrangePerson's topic in Modder Support
You mean via an enchantment table? I mean final int enchantLevel = 3; tridentItemStack.enchant(Enchantments.RIPTIDE, enchantLevel); tridentItemStack.enchant(Enchantments.CHANNELING, enchantLevel); works in code, so if you can throw that in somewhere that'd work. -
Somebody can correct me if I’m wrong but pretty sure it’s just yHeadRot and xHeadRot
-
Variables change after every time I join the world
dee12452 replied to Exavior's topic in Modder Support
The problem I see you having is every time `addAdditionalSaveData` is called, a new item is randomly selected and saved. What you need to be doing here is saving what is already selected, as this is called every time the entity is saved (i.e. when the world is closed, hence your problem). What you can do instead is just save whatever's defined by your EntityDataAccessor in addAdditionalSaveData. -
A custom Capability is probably the way to go.
-
Well I can tell you the tutorial you’re following is probably not for 1.20.4 lol. You’re going to want to use GuiGraphics in 1.20.4
-
Try if(player.getItemInHand(InteractionHand.MAIN_HAND).getItem() == ItemInit.SOUL_POUCH_ARTIFACT.get()) { player.sendSystemMessage(Component.literal("Test")); }