
MatNX
Members-
Posts
15 -
Joined
-
Last visited
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
MatNX's Achievements

Tree Puncher (2/8)
0
Reputation
-
MatNX started following Worldgen not working and Implementing custom ModelBlockRenderer for block.
-
I'm working with this really cool mod called MCGLTF, that allows the importing of GLTF/GLB models into Minecraft, and it works beautifully, thus far I have managed to replace ItemRenderers, BlockEntityRenderers, and EntityRenderers. What I find a bit more difficult, however, is replacing simple Blocks. They are all rendered through the BlockRenderDispatcher, and don't really get implementations for custom ModelLoaders. I tried mixin, though that doesn't work as the GLTF-Model seems to need to be registered alongside the Renderer. Does anyone have experience with this?
-
Hi. I have added a new ConfiguredFeature JSON, a new PlacedFeature JSON and a new BiomeModifier JSON, and in 1.20.4, those should be enough to generate my feature in the world. When I try to generate a world, however, I get this error: ResourceKey[minecraft:root / minecraft:worldgen/configured_feature]: Unbound values in registry ResourceKey[minecraft:root / minecraft:worldgen/configured_feature]: [dungeons:disk_tumblestone] Any idea what could cause this? For reference, this is my ConfiguredFeature: { "type": "minecraft:disk", "config": { "state_provider": { "fallback": { "type": "minecraft:simple_state_provider", "state": { "Name": "dungeons:tumblestone" } }, "rules": [] }, "target": { "type": "minecraft:matching_blocks", "blocks": [ "minecraft:dirt", "minecraft:clay" ] }, "radius": { "type": "minecraft:uniform", "min_inclusive": 2, "max_inclusive": 3 }, "half_height": 1 } } This is my PlacedFeature: { "feature": "dungeons:disk_tumblestone", "placement": [ { "type": "minecraft:in_square" }, { "type": "minecraft:heightmap", "heightmap": "OCEAN_FLOOR_WG" }, { "type": "minecraft:block_predicate_filter", "predicate": { "type": "minecraft:matching_fluids", "fluids": "minecraft:water" } }, { "type": "minecraft:biome" } ] } and this is my biome_modifier { "type": "forge:add_features", "biomes": "#minecraft:is_overworld", "features": "dungeons:disk_tumblestone", "step": "surface_features" }
-
I have a LevelChunk Capability that allows me to paint blocks. It works by saving a capability storing colors and blockpos arrays to the level. It works well, and I have a rightclickevent that dyes the blocks. As there are mainly visual alterations, I need to sync it to the client using this code: if (event.getEntity() instanceof ServerPlayer sPlayer) { sPlayer.connection.send(new ClientboundLevelChunkWithLightPacket(event.getLevel().getChunkAt(event.getPos()), event.getLevel().getLightEngine(), new BitSet(), new BitSet())); } This works for the righclickevent, but not upon loading the chunk. The data, mind you, is still there, anything that happens on the server, such as not allowing already painted blocks to be repainted, still work. Anyone got any idea what the issue could be? Here is my rightclick: @SubscribeEvent public static void rightClickEvent(PlayerInteractEvent.RightClickBlock event) { ItemStack stack = event.getItemStack(); if (!(stack.getItem() instanceof DyeItem) && !(stack.getItem() instanceof PotionItem && PotionUtils.getPotion(stack) == Potions.WATER)) { return; } ColorCapability colorCapability = event.getLevel().getChunkAt(event.getPos()).getCapability(ColorCapabilityProvider.COLOR_CAPABILITY).orElse(null); if(stack.getItem() instanceof DyeItem item) { int colorint = item.getDyeColor().getTextColor(); int index = colorCapability.containsPos(event.getPos()); if (index != -1) { if (colorCapability.getColor(index) == colorint) { return; } colorCapability.setColor(colorint, index); } else { colorCapability.addColor(colorint); colorCapability.addPos(event.getPos()); } event.getLevel().playSound((Player) null, event.getPos(), SoundEvents.DYE_USE, SoundSource.BLOCKS, 1.0F, 1.0F); event.getEntity().awardStat(Stats.ITEM_USED.get(stack.getItem())); if (!event.getEntity().getAbilities().instabuild) { stack.shrink(1); } } else if (stack.getItem() instanceof PotionItem potion && PotionUtils.getPotion(stack) == Potions.WATER) { if (colorCapability.containsPos(event.getPos()) != -1) { event.getLevel().playSound((Player) null, event.getPos(), SoundEvents.GENERIC_SPLASH, SoundSource.BLOCKS, 1.0F, 1.0F); event.getEntity().setItemInHand(event.getHand(), ItemUtils.createFilledResult(stack, event.getEntity(), new ItemStack(Items.GLASS_BOTTLE))); event.getEntity().awardStat(Stats.ITEM_USED.get(stack.getItem())); if (!event.getLevel().isClientSide) { ServerLevel $$6 = (ServerLevel) event.getLevel(); for (int $$7 = 0; $$7 < 5; ++$$7) { $$6.sendParticles(ParticleTypes.SPLASH, (double) event.getPos().getX() + event.getLevel().random.nextDouble(), (double) (event.getPos().getY() + 1), (double) event.getPos().getZ() + event.getLevel().random.nextDouble(), 1, 0.0, 0.0, 0.0, 1.0); } } event.getLevel().playSound((Player) null, event.getPos(), SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F); event.getLevel().gameEvent((Entity) null, GameEvent.FLUID_PLACE, event.getPos()); colorCapability.removeColor(colorCapability.containsPos(event.getPos())); colorCapability.removePos(colorCapability.containsPos(event.getPos())); } } if (event.getEntity() instanceof ServerPlayer sPlayer) { CriteriaTriggers.CONSUME_ITEM.trigger(sPlayer, stack); sPlayer.connection.send(new ClientboundLevelChunkWithLightPacket(event.getLevel().getChunkAt(event.getPos()), event.getLevel().getLightEngine(), new BitSet(), new BitSet())); } event.getLevel().getChunkAt(event.getPos()).setUnsaved(true); }
-
Update: I got it! It was a really stupid problem: blockpos.toshortstring concatenates using , . I was checking for ,. I just missed the space. A stupid mistake, but thanks for your help anyway.
-
The saveNBTData and loadNBTData both fires, and, when loading a world, I can see the data in the field while debugging. However, here is where it gets interesting: Save and load both get called 3 times, and they only have the data one the first load/save. It seems that the subsequent 2 calls override my color and pos fields. It seems like a Client/Server issue.
-
Provider is fairly straightforward, here you go. Thanks for the fast response and the tip! package com.matnx.masonry.multiblock.capability; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.capabilities.CapabilityToken; import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.util.INBTSerializable; import net.minecraftforge.common.util.LazyOptional; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class ColorCapabilityProvider implements ICapabilityProvider, INBTSerializable<CompoundTag> { public static Capability<ColorCapability> COLOR_CAPABILITY = CapabilityManager.get(new CapabilityToken<>() { }); private ColorCapability colorCapability = null; private final LazyOptional<ColorCapability> optional = LazyOptional.of(this::createColor); private @NotNull ColorCapability createColor() { if (this.colorCapability == null) { this.colorCapability = new ColorCapability(); } return this.colorCapability; } @Override public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) { if (cap == COLOR_CAPABILITY) { return optional.cast(); } return LazyOptional.empty(); } @Override public CompoundTag serializeNBT() { CompoundTag nbt = new CompoundTag(); createColor().saveNBTData(nbt); return nbt; } @Override public void deserializeNBT(CompoundTag nbt) { createColor().loadNBTData(nbt); } }
-
i have created a Level Capability to store data to the level, allowing for blocks to be painted by the player. The basic implementation works, i can right click a block and it gets a tint as defined. However, when I close the game and reopen it, all painted areas are gone, that is, it seems to either not save or reload the capabilties to or from disk. I have made a similar cabability for blockentities, and those save fine, so it seems to be related to the level. Perhaps a server/client issue? Either way, I'm not sure where to go, so any help would be greatly appreciated. package com.matnx.masonry.multiblock.capability; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraftforge.common.capabilities.AutoRegisterCapability; import org.checkerframework.checker.units.qual.A; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @AutoRegisterCapability public class ColorCapability { private List<Integer> color = new ArrayList<>(); private List<BlockPos> pos = new ArrayList<>(); public int getColor(int i) { if (color.size() > i) { return color.get(i); } else { return -1; } } public void setColor(int p_18944_, int i) { color.set(i, p_18944_); } public void addColor(int p_18944_) { color.add(p_18944_); } public BlockPos getPos(int i) { if (pos.size() > i) { return pos.get(i); } else { return new BlockPos(0, -500, 0); } } public int containsPos(BlockPos posit) { return pos.indexOf(posit); } public void addPos(BlockPos p_18944_) { pos.add(p_18944_); } public void setPos(BlockPos p_18944_, int i) { pos.set(i, p_18944_); } public void saveNBTData(CompoundTag nbt) { String[] stringArray = pos.stream() .map(BlockPos::toShortString) .toArray(String[]::new); String concatenatedString = String.join(";", stringArray); byte[] byteArray = concatenatedString.getBytes(StandardCharsets.UTF_8); nbt.putByteArray("pos", byteArray); nbt.putIntArray("color", color); } public void loadNBTData(CompoundTag nbt) { byte[] byteArray = nbt.getByteArray("pos"); String restoredString = new String(byteArray, StandardCharsets.UTF_8); String[] restoredArray = restoredString.split(";"); pos = Arrays.stream(restoredArray).map(s -> { String[] parts = s.split(","); return new BlockPos(Integer.valueOf(parts[0]), Integer.valueOf(parts[1]), Integer.valueOf(parts[2])); }).collect(Collectors.toList()); color = Arrays.stream(nbt.getIntArray("color")) .boxed() .collect(Collectors.toList()); } }
-
I have a mod that adds a custom slime variant. I stuck closely to the methods the normal slime is using, and made a pretty similar renderer, as well as an outer layer. Now, this works, I get a slime with opaque organs and a transparent hull. Looking through the hull, however, all blocks and entities that are also translucent simply stop rendering, and i really dont know why. This is my slime-renderer: package com.matnx.earth.entity.render; import com.matnx.earth.Earth; import com.matnx.earth.entity.classes.TropicalSlime; import com.matnx.earth.entity.model.TropicalSlimeCore; import com.matnx.earth.entity.model.TropicalSlimeModel; import com.matnx.earth.entity.model.TropicalSlimeShell; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.*; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import net.minecraft.world.entity.monster.Slime; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) public class TropicalSlimeRender extends MobRenderer<TropicalSlime, TropicalSlimeModel<TropicalSlime>> { private static final ResourceLocation SLIME_LOCATION = new ResourceLocation(Earth.MODID, "textures/entity/slime/tropical_slime.png"); public TropicalSlimeRender(EntityRendererProvider.Context p_174391_) { super(p_174391_, new TropicalSlimeModel<>(p_174391_.bakeLayer(TropicalSlimeModel.LAYER_LOCATION)), 0.25F); this.addLayer(new TropicalSlimeShell<>(this, p_174391_.getModelSet())); this.addLayer(new TropicalSlimeCore(this, p_174391_.getModelSet())); } public void render(TropicalSlime p_115976_, float p_115977_, float p_115978_, PoseStack p_115979_, MultiBufferSource p_115980_, int p_115981_) { this.shadowRadius = 0.25F; super.render(p_115976_, p_115977_, p_115978_, p_115979_, p_115980_, p_115981_); } protected void scale(TropicalSlime p_115983_, PoseStack p_115984_, float p_115985_) { float f = 0.999F; p_115984_.scale(0.999F, 0.999F, 0.999F); p_115984_.translate(0.0D, (double)0.001F, 0.0D); float f1 = 2; float f2 = Mth.lerp(p_115985_, p_115983_.oSquish, p_115983_.squish) / (f1 * 0.5F + 1.0F); float f3 = 1.0F / (f2 + 1.0F); p_115984_.scale(f3 * f1, 1.0F / f3 * f1, f3 * f1); } public ResourceLocation getTextureLocation(TropicalSlime p_115974_) { return SLIME_LOCATION; } } This is my OuterLayer package com.matnx.earth.entity.model; import com.matnx.earth.Earth; import com.matnx.earth.ModRenderTypes; import com.matnx.earth.entity.classes.SkeletonWolf; import com.matnx.earth.entity.classes.TropicalSlime; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Matrix3f; import com.mojang.math.Matrix4f; import com.mojang.math.Vector3f; import net.minecraft.client.Minecraft; import net.minecraft.client.animation.AnimationChannel; import net.minecraft.client.animation.AnimationDefinition; import net.minecraft.client.animation.Keyframe; import net.minecraft.client.animation.KeyframeAnimations; import net.minecraft.client.model.EntityModel; import net.minecraft.client.model.HierarchicalModel; import net.minecraft.client.model.SlimeModel; import net.minecraft.client.model.geom.*; import net.minecraft.client.model.geom.builders.CubeListBuilder; import net.minecraft.client.model.geom.builders.LayerDefinition; import net.minecraft.client.model.geom.builders.MeshDefinition; import net.minecraft.client.model.geom.builders.PartDefinition; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.LivingEntityRenderer; import net.minecraft.client.renderer.entity.RenderLayerParent; import net.minecraft.client.renderer.entity.layers.RenderLayer; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import net.minecraft.world.entity.ExperienceOrb; import net.minecraft.world.entity.LivingEntity; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) public class TropicalSlimeShell<T extends LivingEntity> extends RenderLayer<T, TropicalSlimeModel<T>> { private final EntityModel<T> model; public TropicalSlimeShell(RenderLayerParent<T, TropicalSlimeModel<T>> p_174536_, EntityModelSet p_174537_) { super(p_174536_); this.model = new TropicalSlimeModel<>(p_174537_.bakeLayer(TropicalSlimeModel.SHELL_LOCATION)); } public void render(PoseStack p_117470_, MultiBufferSource p_117471_, int p_117472_, T p_117473_, float p_117474_, float p_117475_, float p_117476_, float p_117477_, float p_117478_, float p_117479_) { Minecraft minecraft = Minecraft.getInstance(); boolean flag = minecraft.shouldEntityAppearGlowing(p_117473_) && p_117473_.isInvisible(); if (!p_117473_.isInvisible() || flag) { VertexConsumer vertexconsumer; if (flag) { vertexconsumer = p_117471_.getBuffer(RenderType.outline(this.getTextureLocation(p_117473_))); } else { vertexconsumer = p_117471_.getBuffer(RenderType.entityTranslucent(this.getTextureLocation(p_117473_))); } this.getParentModel().copyPropertiesTo(this.model); this.model.prepareMobModel(p_117473_, p_117474_, p_117475_, p_117476_); this.model.setupAnim(p_117473_, p_117474_, p_117475_, p_117477_, p_117478_, p_117479_); this.model.renderToBuffer(p_117470_, vertexconsumer, p_117472_, LivingEntityRenderer.getOverlayCoords(p_117473_, 0.0F), 1.0F, 1.0F, 1.0F, 1.0F); } } }
-
My mod adds a cow variant, which is purely cosmetic, but still needs to be a separate entity. I want it to be able to breed with vanilla cows. Is there a specific goal or event I can use? I don't want to override vanilla classes.
-
I'm relatively new to Forge Modding and am currently working on my first "real" Mod. It adds different grass types, and each of them can randomly turn into a "drained" variant. While this works fine for my custom blocks, I'd like regular grass to also turn into a custom variant, basically adding a randomTick event to the block. However, most tutorials I've found for this are for older forge versions. So, I'd appreciate some help.
-
Thank you, this is exactly what I needed! I'll test it first with a simple mod that will only "change" 1 block on a server, to see if it is possible to trick a server in the given timeframe of 1 tick, and to alter the packets without it causing issues/the server noticing. You seem to really know your stuff, though, so I'll trust your judgement and keep it small for now, to not have invested too much time into something that isn't likely to succeed.
-
I mentioned it, I'm planning to store the locations of the custom items locally, and simply testing, whenever I get a block-update, or if I change chunks, if the block is still there. Something similar is done with drops and items in my inventory. The items will get lost if put into a foreign inventory, but that doesn't matter in that case, because the blocks are cheaply made, and you can still customize the default doors. I have solved most of these issues, my only problem in that department is actually just how to craft the blocks without changing the crafting ingredients. (For example charred wood by putting wood and flint and steel in a table, and leaving the flint and steel in the grid. The server would not see a difference, and would not know if I actually crafted or just cancelled the crafting). I have also looked up the Minecraft TCP Protocols, and I know what I need to send to the Server to trick it, I just don't know how to block the standard outgoing transmissions, and how to send the fake requests upon my events. (I'm not sure how to access the established channel from the outside, Mods and Plugins use a separate Channel to communicate with Servers, and I need access to the "Vanilla Protocols")
-
MatNX joined the community
-
I'm working on a simple mod that allows you to craft custom doors, you have a door frame and can insert both sticks and planks to alter the appearance. You also get charred and bleached wood, which gives it more color variation. I will save the custom items locally, while letting the Server think it is dealing with regular items. For example, if I craft charred wood, I now have 2 different items, normal planks and charred planks in my inventory, and I want the Server to think they are just 2 different stacks of planks. I have figured out how to make the crafting work, by simply giving the input and output the same amounts of material and letting the Server think I simply cancellec a crafting request, but what I don't know is how to trick the server in the first place. I think, to put it differently, how do I send false information to a Server?