
Toasterkid
Members-
Posts
26 -
Joined
-
Last visited
Everything posted by Toasterkid
-
Also doubting if my usage of awardStat is correct. It just looks like this right now: player.awardStat(SampleModRegistry.FIREWORK_BOOSTS_USED.getId()); but there are places vanilla Minecraft uses the function like this: .awardStat(Stats.CUSTOM.get(Stats.DAMAGE_BLOCKED_BY_SHIELD)
-
What does NetworkHooks.openScreen(player, blockEntity, pPos) do?
-
At an attempt at answering my first question I thought I might be able to change the code to this public class SampleModStatisticsRegistry { public static final DeferredRegister<StatType<?>> STATISTICS = DeferredRegister.create(ForgeRegistries.STAT_TYPES, SampleMod.MODID); public static final RegistryObject<StatType<?>> FIREWORK_BOOSTS_USED = STATISTICS.register("firework_boosts_used", () -> new StatType<>(ForgeRegistries.STAT_TYPES, Component.literal("firework_boosts"))); } or to this public class SampleModStatisticsRegistry { public static final DeferredRegister<StatType<?>> STATISTICS = DeferredRegister.create(ForgeRegistries.STAT_TYPES, SampleMod.MODID); public static final RegistryObject<StatType<?>> FIREWORK_BOOSTS_USED = STATISTICS.register("firework_boosts_used", () -> new StatType<>(BuiltInRegistries.STAT_TYPE, Component.literal("firework_boosts"))); } but for the first code snippet the StatType constructor requires a Registry not an IForgeRegistry and for the second code snippet we run into the same NPE issue from above.
-
I am attempting to create a mod that adds custom statistics to Minecraft. I've had some help from LexManos on the Discord server, but posting a lot of what I posted in the #mod-dev-support-1.20 channel here to have a more permanent spot for discussion. --- Minecraft creates their stats like this: and some of the registries in the code above are located in BuiltInRegistries.java like this: and the ForgeRegistries#STAT_TYPES looks like this: So, attempting to follow that and the forge documentation on registries I arrived at this: Clearly, registering a stat twice in a row is the wrong way to do it, but the makeRegistryStatType function was used as it does give the correct return type for the code I had come up with so far. --- At this point the game crashes upon trying to use Player#awardStat, because of a NPE that occurs in Stat#locationToKey. Which happens in the 2nd Stat#locationToKey in the Stat#buildName function. The .getRegistry returns the this.registry class variable with a value of {MappedRegistry@#####} "Registry[ResourceKey[minecraft:root / minecraft:custom_stat] (Stable)]" The value passed into .getKey is "samplemod:fireworks_boosts_used" but the reference found is null. So Lex's conclusion was that "[I'm] passing in null because the registry doesnt have an entry for your custom stat instance. So.. register your custom stat instance in that registry." --- So I suppose at this point my questions are 1. How can I create a supplier that returns a Supplier<? extends StatType<?>> to replace the () -> makeRegistryStatType("firework_boosts_used", BuiltInRegistries.CUSTOM_STAT) line of code. 2. Is my registry entry public static final RegistryObject<StatType<?>> FIREWORK_BOOSTS_USED the correct type? 3. Do I need to do anything additional, like create my own StatType<> or my own Stat<> ?
-
(1.20) Beginner having issue with making a crafting recipe
Toasterkid replied to Evanski's topic in Modder Support
Pretty sure you get that error because ShapelessRecipe is only for recipes that are crafted using a grid, and don't need to be arranged in a certain way. You have to use AbstractCookingRecipe for any recipe that uses the [smeltable item - fuel item - result item] combination. But I don't think you really need to be messing with code here for recipes. You should just be able to copy what the minecraft\recipes\iron_ingot_from_smelting_raw_iron.json does and replace the ingredient item and your result item: { "type": "minecraft:smelting", "category": "misc", "cookingtime": 200, "experience": 0.7, "group": "iron_ingot", "ingredient": { "item": "minecraft:raw_iron" }, "result": "minecraft:iron_ingot" } or just add the block to the logs_that_burn_tag since the Minecraft recipe for charcoal uses that: { "type": "minecraft:smelting", "category": "misc", "cookingtime": 200, "experience": 0.15, "ingredient": { "tag": "minecraft:logs_that_burn" }, "result": "minecraft:charcoal" } -
If you don't want an item to have a recipe then simply don't create the .json file for it in the `your_mod/recipes/` directory.
-
[1.20.1] Custom Crop - Disallow vanilla farmland block
Toasterkid replied to Sinsei's topic in Modder Support
Have you checked if you need to override Block#canSustainPlant ? It has this line of code in it: if (net.minecraftforge.common.PlantType.CROP.equals(type)) { return state.is(Blocks.FARMLAND); } which would be relevant since StemBlock.java has this in it: @Override public net.minecraftforge.common.PlantType getPlantType(BlockGetter world, BlockPos pos) { return net.minecraftforge.common.PlantType.CROP; } -
If you look at the Minecraft wiki, you can see that there already exists one block that unlocks without needing any other blocks, which is the crafting table. https://minecraft.fandom.com/wiki/Recipe_book#Unlocking So if you find the file: \data\minecraft\advancements\recipes\decorations\crafting_table.json You can see that it uses a "unlock_right_away" criteria to do the job. { "parent": "minecraft:recipes/root", "criteria": { "has_the_recipe": { "conditions": { "recipe": "minecraft:crafting_table" }, "trigger": "minecraft:recipe_unlocked" }, "unlock_right_away": { "trigger": "minecraft:tick" } }, "requirements": [ [ "has_the_recipe", "unlock_right_away" ] ], "rewards": { "recipes": [ "minecraft:crafting_table" ] }, "sends_telemetry_event": false }
-
How do I make a custom skybox for my custom dimension?
Toasterkid replied to SlayerOfDragons's topic in Modder Support
For fog you would probably start with making a listener to the EntityViewRenderEvent like this public class ClientListener { @SubscribeEvent public void onRenderFog(EntityViewRenderEvent.FogDensity event) { // your code } } Note that you can also access other stuff, such as FogColors, from the EntityViewRenderEvent.- 2 replies
-
- 1.20.1
- dimensions
-
(and 1 more)
Tagged with:
-
[1.20.1] How to change the scale of a particle?
Toasterkid replied to A tired guy's topic in Modder Support
Is Particle#scale(float) not available to use? It just calls Particle.setSize(float, float) -
probably something like this ? Effects.DIG_SLOWDOWN.getDisplayName()
-
How can I prevent blocks with no light value and/or not a part of the height map from being rendered to the camera/player? Especially when they are capable of seeing through solid blocks while underground, such as in spectator mode. Realizing this was just a version of anti-xray stuff, I found this mod: https://github.com/DrexHD/AntiXray/tree/1.20.4 which seems to prevent x-raying by handling chunk rendering, specifically the ClientboundLevelChunkWithLightPacket. Would this be the correct method to handle my problem? If so, is there a part of this mod's code that I should start with trying to implement to prevent blocks without light value being rendered?
-
I would like to setup a test that makes sure an animation completes, however this animation can be a couple of seconds long. Are there any examples of using a GameTestSequence created from GameTestHelper#startSequence to wait until a certain function in the code is reached or finished?
-
Maybe you can try getting the blocks by getting the relative position of blocks from other blocks, based on the direction the player is looking. public boolean mineBlock(...) { // get the blocks you want to break BlockPos middle = blockPos; BlockPos topMiddle = middle.above(); BlockPos topLeft = topMiddle.relative(playerEntity.getDirection().getCounterClockWise()); BlockPos topRight = topMiddle.relative(playerEntity.getDirection().getClockWise()); BlockPos bottomMiddle = middle.below(); // add the rest of the blocks here } // maybe call your own function to break those blocks if (this.breakAndDrop(world, playerEntity, stack, topMiddle)) { // you could do something or count something here idk } // which could look something like this private void breakAndDrop(World world, PlayerEntity player, ItemStack itemStack, BlockPos pos) { Block.dropResources(world.getBlockState(pos), world, pos, null, player, itemStack); world.destroyBlock(pos, false, player); }
-
From an entity I can set the world to raining via entity.level.getLevelData().setRaining(true); but how do I make thunder with that? From level I can also see entity.level.setThunderLevel(float value) and entity.level.setRainLevel(float value) but I can't find a description on what those do.
-
I'm assuming its in the wrong class because of this line ? Which would make it Client side ? @Mod.EventBusSubscriber(modid = MyMod.MODID, bus = Bus.MOD, value = Dist.CLIENT) Would removing this and setting up the MyMod.java like this be correct? I ask because I see other examples use the public static final RegistryObject<> in the same class that they setup the public static final DeferredRegister<>, and not for just particles. public MyMod() { // Register the setup method for modloading IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus(); ParticleRegistration.PARTICLES_TYPES.register(bus); } Or do I need to make further changes to the registration then? Such as moving the registerParticleFactory() to a ClientStartup/ClientProxy ?
-
Any help or advice would be appreciated. I'm trying to learn how to add particles to a mod, using a tutorial from TheGreyGhost. Trying to get the particle to appear in the Entity's tick() method. The vanilla FLAME particle appears but not my particle. @Override public void tick() { if(entity == null) return; try { // Adds a particle to every entity while in the overworld! //this.level.addParticle(ParticleTypes.FLAME, this.getX(), this.getY() + 1, this.getZ(), 0, 0.04, 0); // Try to add a custom particle to every entity in the overworld. Color tint = Color.CYAN; // does this do anything if the particle texture is already colored? double diameter = this.getEntityScale(); FlameParticleData flameParticleData = new FlameParticleData(tint, diameter); this.level.addParticle(flameParticleData, this.getX(), this.getY() + 2, this.getZ(), 0, 0.05, 0); } catch (Exception e) { The other code I have setting up the Particle Registration, the FlameParticle, the FlameParticleData, the FlameParticleFactory, and the FlameParticleType: ParticleRegistration.java. I also have a flame_particle.json that references the flame.png that I want to use. @Mod.EventBusSubscriber(modid = MyMod.MODID, bus = Bus.MOD, value = Dist.CLIENT) public class ParticleRegistration { public static final DeferredRegister<ParticleType<?>> PARTICLES_TYPES = DeferredRegister.create( ForgeRegistries.PARTICLE_TYPES, MyMod.MODID); // This sets the FlameParticleType to use the textures specified in flame_particle.json. public static final RegistryObject<ParticleType<FlameParticleData>> FLAME_PARTICLE = PARTICLES_TYPES.register( "flame_particle", FlameParticleType::new); // Is this necessary? public static ParticleType<FlameParticleData> flameParticleType = new FlameParticleType(); @SuppressWarnings("resource") @SubscribeEvent public static void registerParticleFactory(ParticleFactoryRegisterEvent event) { Minecraft.getInstance().particleEngine.register(ParticleRegistration.FLAME_PARTICLE.get(), FlameParticleFactory::new); } } FlameParticle.java /** * Based on TheGreyGhost's MinecraftByExample * Custom Particle to illustrate how to add a Particle with your own texture and movement/animation behaviour * */ public class FlameParticle extends SpriteTexturedParticle { /** * Construct a new FlameParticle at the given [x,y,z] position, with the given initial velocity, the given color, and the * given diameter. * We also supply sprites so that you can change the sprite texture in the tick() method (although not needed for this example) */ public FlameParticle(ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ, Color tint, double diameter, IAnimatedSprite sprites) { super(world, x, y, z, velocityX, velocityY, velocityZ); this.sprites = sprites; setColor(tint.getRed()/255.0F, tint.getGreen()/255.0F, tint.getBlue()/255.0F); setSize((float)diameter, (float)diameter); // the size (width, height) of the collision box. final float PARTICLE_SCALE_FOR_ONE_METRE = 0.5F; // if the particleScale is 0.5, the texture will be rendered as 1 metre high // sets the rendering size of the particle for a TexturedParticle. this.scale(PARTICLE_SCALE_FOR_ONE_METRE * (float)diameter); //maxAge = 100; // lifetime in ticks: 100 ticks = 5 seconds this.lifetime = 100; final float ALPHA_VALUE = 1.0F; this.alpha = ALPHA_VALUE; //the vanilla Particle constructor added random variation to our starting velocity. Undo it! this.xd = velocityX; this.yd = velocityY; this.zd = velocityZ; // the move() method will check for collisions with scenery this.hasPhysics = true; // I think hasPhysics replaces canCollide } // Comments from TheGreyGhost // ---- methods used by TexturedParticle.renderParticle() method to find out how to render your particle // the base method just renders a quad, rotated to directly face the player // can be used to change the skylight+blocklight brightness of the rendered Particle. @Override public int getLightColor(float partialTick) // previously protected int getBrightnessForRender(float partialTick) { final int BLOCK_LIGHT = 15; // maximum brightness final int SKY_LIGHT = 15; // maximum brightness final int FULL_BRIGHTNESS_VALUE = LightTexture.pack(BLOCK_LIGHT, SKY_LIGHT); // .pack replaces .packLight return FULL_BRIGHTNESS_VALUE; // if you want the brightness to be the local illumination (from block light and sky light) you can just use // the Particle.getBrightnessForRender() base method, which contains: // BlockPos blockPos = new BlockPos(this.posX, this.posY, this.posZ); // return this.world.isBlockLoaded(blockPos) ? WorldRenderer.getCombinedLight(this.world, blockPos) : 0; } // Choose the appropriate render type for your particles: // There are several useful predefined types: // PARTICLE_SHEET_TRANSLUCENT semi-transparent (translucent) particles // PARTICLE_SHEET_OPAQUE opaque particles // TERRAIN_SHEET particles drawn from block or item textures // PARTICLE_SHEET_LIT appears to be the same as OPAQUE. Not sure of the difference. In previous versions of minecraft, // "lit" particles changed brightness depending on world lighting i.e. block light + sky light public IParticleRenderType getRenderType() { return IParticleRenderType.PARTICLE_SHEET_TRANSLUCENT; } /** * call once per tick to update the Particle position, calculate collisions, remove when max lifetime is reached, etc */ @Override public void tick() { // if you want to change the texture as the particle gets older, you can use //setSpriteFromAge(sprites); // not sure whether this should be uncommented yet this.xo = x; // previously prevPosX and posX this.yo = y; // previously prevPosY and posY this.xo = z; // previously prevPosZ and posZ move(xd, yd, zd); // simple linear motion. You can change speed by changing xd, yd, // zd every tick. For example - you can make the particle accelerate downwards due to gravity by // final double GRAVITY_ACCELERATION_PER_TICK = -0.02; // yd += GRAVITY_ACCELERATION_PER_TICK; // calling move() also calculates collisions with other objects // collision with a block makes the ball disappear. But does not collide with entities if (onGround) { // onGround is only true if the particle collides while it is moving downwards... this.remove(); // this.setExpired() is probably this.remove() } if (yo == y && yd > 0) { // detect a collision while moving upwards (can't move up at all) this.remove(); } if (this.age++ >= this.lifetime) { // this.maxAge becomes this.lifetime this.remove(); } } private final IAnimatedSprite sprites; // contains a list of textures; choose one using either // newParticle.selectSpriteRandomly(sprites); or newParticle.selectSpriteWithAge(sprites); } FlameParticleData.java /** * Based on TheGreyGhost's MinecraftByExample * The particle has two pieces of information which are used to customise it: * * 1) The colour (tint) which is used to change the hue of the particle * 2) The diameter of the particle * * This class is used to * 1) store this information, and * 2) transmit it between server and client (write and read methods), and * 3) parse it from a command string i.e. the /particle params */ public class FlameParticleData implements IParticleData { public FlameParticleData(Color tint, double diameter) { this.tint = tint; this.diameter = constrainDiameterToValidRange(diameter); } public Color getTint() { return tint; } /** * @return get diameter of particle in metres */ public double getDiameter() { return diameter; } @Nonnull @Override public ParticleType<FlameParticleData> getType() { return ParticleRegistration.flameParticleType; } // write the particle information to a PacketBuffer, ready for transmission to a client @Override public void writeToNetwork(PacketBuffer buf) { buf.writeInt(tint.getRed()); buf.writeInt(tint.getGreen()); buf.writeInt(tint.getBlue()); buf.writeDouble(diameter); } // used for debugging I think; prints the data in human-readable format @Nonnull @Override public String writeToString() { return String.format(Locale.ROOT, "%s %.2f %i %i %i", this.getType().getRegistryName(), diameter, tint.getRed(), tint.getGreen(), tint.getBlue()); } private static double constrainDiameterToValidRange(double diameter) { final double MIN_DIAMETER = 0.05; final double MAX_DIAMETER = 1.0; return MathHelper.clamp(diameter, MIN_DIAMETER, MAX_DIAMETER); } private Color tint; private double diameter; // Comments from the TheGreyGhost // --------- these remaining methods are used to serialize the Particle Data. // I'm not yet sure what the Codec is used for, given that the DESERIALIZER already deserializes using read. // Perhaps it will be used to replace the manual read methods in the future. // The CODEC is a convenience to make it much easier to serialise and deserialise your objects. // Using the builder below, you construct a serialiser and deserialiser in one go, using lambda functions. // eg for the FlameParticleData CODEC: // a) In order to serialise it, it reads the 'tint' member variable (type: INT) and the 'diameter' member variable (type: DOUBLE) // b) In order to deserialise it, call the matching constructor FlameParticleData(INT, DOUBLE) public static final Codec<FlameParticleData> CODEC = RecordCodecBuilder.create( instance -> instance.group( Codec.INT.fieldOf("tint").forGetter(d -> d.tint.getRGB()), Codec.DOUBLE.fieldOf("diameter").forGetter(d -> d.diameter) ).apply(instance, FlameParticleData::new) ); private FlameParticleData(int tintRGB, double diameter) { this.tint = new Color(tintRGB); this.diameter = constrainDiameterToValidRange(diameter); } // The DESERIALIZER is used to construct FlameParticleData from either command line parameters or from a network packet public static final IDeserializer<FlameParticleData> DESERIALIZER = new IDeserializer<FlameParticleData>() { // parse the parameters for this particle from a /particle command @Nonnull @Override public FlameParticleData fromCommand(@Nonnull ParticleType<FlameParticleData> type, @Nonnull StringReader reader) throws CommandSyntaxException { reader.expect(' '); double diameter = constrainDiameterToValidRange(reader.readDouble()); final int MIN_COLOUR = 0; final int MAX_COLOUR = 255; reader.expect(' '); int red = MathHelper.clamp(reader.readInt(), MIN_COLOUR, MAX_COLOUR); reader.expect(' '); int green = MathHelper.clamp(reader.readInt(), MIN_COLOUR, MAX_COLOUR); reader.expect(' '); int blue = MathHelper.clamp(reader.readInt(), MIN_COLOUR, MAX_COLOUR); Color color = new Color(red, green, blue); return new FlameParticleData(color, diameter); } // read the particle information from a PacketBuffer after the client has received it from the server @Override public FlameParticleData fromNetwork(@Nonnull ParticleType<FlameParticleData> type, PacketBuffer buf) { // warning! never trust the data read in from a packet buffer. final int MIN_COLOUR = 0; final int MAX_COLOUR = 255; int red = MathHelper.clamp(buf.readInt(), MIN_COLOUR, MAX_COLOUR); int green = MathHelper.clamp(buf.readInt(), MIN_COLOUR, MAX_COLOUR); int blue = MathHelper.clamp(buf.readInt(), MIN_COLOUR, MAX_COLOUR); Color color = new Color(red, green, blue); double diameter = constrainDiameterToValidRange(buf.readDouble()); return new FlameParticleData(color, diameter); } }; } FlameParticleFactory.java /** * Based on TheGreyGhost's MinecraftByExample * On the client side: * When the client wants to spawn a Particle, it gives the FlameParticleData to this factory method * The factory selects an appropriate Particle class and instantiates it * */ public class FlameParticleFactory implements IParticleFactory<FlameParticleData> { //IParticleFactory private final IAnimatedSprite sprites; // contains a list of textures; choose one using either // not sure if i still need this // newParticle.selectSpriteRandomly(sprites); or newParticle.selectSpriteWithAge(sprites); // this method is needed for proper registration of your Factory: // The ParticleManager.register method creates a Sprite and passes it to your factory for subsequent use when rendering, then // populates it with the textures from your textures/particle/xxx.json public FlameParticleFactory(IAnimatedSprite sprite) { this.sprites = sprite; } @Nullable @Override public Particle createParticle(FlameParticleData flameParticleData, ClientWorld world, double xPos, double yPos, double zPos, double xVelocity, double yVelocity, double zVelocity) { FlameParticle newParticle = new FlameParticle(world, xPos, yPos, zPos, xVelocity, yVelocity, zVelocity, flameParticleData.getTint(), flameParticleData.getDiameter(), sprites); newParticle.pickSprite(sprites); // not quite the newParticle.selectSpriteRandomly(sprites) that was used. return newParticle; } // This is private to prevent you accidentally registering the Factory using the default constructor. // ParticleManager has two register methods, and if you use the wrong one the game will enter an infinite loop private FlameParticleFactory() { throw new UnsupportedOperationException("Use the FlameParticleFactory(IAnimatedSprite sprite) constructor"); } } FlameParticleType.java /** * Based on TheGreyGhost's MinecraftByExample * Simple class used to describe the Particle */ public class FlameParticleType extends ParticleType<FlameParticleData> { private static boolean ALWAYS_SHOW_REGARDLESS_OF_DISTANCE_FROM_PLAYER = false; public FlameParticleType() { super(ALWAYS_SHOW_REGARDLESS_OF_DISTANCE_FROM_PLAYER, FlameParticleData.DESERIALIZER); } // get the Codec used to // a) convert a FlameParticleData to a serialised format // b) construct a FlameParticleData object from the serialised format public Codec<FlameParticleData> codec() { return FlameParticleData.CODEC; } } The flame_particle.json, which is located in resources/asset.MyMod/particles, that references the flame.png, located in resources/asset.MyMod/particles/textures/particles { "textures": [ "MyMod:flame" ] }