TheGreyGhost
Members-
Posts
3280 -
Joined
-
Last visited
-
Days Won
8
Everything posted by TheGreyGhost
-
Ah. It sounds like your projection matrix is being messed up. I had a look at the vanilla code and found these lines this.mc.getProfiler().endStartSection("forge_render_last"); net.minecraftforge.client.ForgeHooksClient.dispatchRenderLast(this.mc.worldRenderer, matrixStackIn, partialTicks, matrix4f, finishTimeNano); this.mc.getProfiler().endStartSection("hand"); if (this.renderHand) { RenderSystem.clear(256, Minecraft.IS_RUNNING_ON_MAC); this.renderHand(matrixStackIn, activerenderinfo, partialTicks); } private void renderHand(MatrixStack matrixStackIn, ActiveRenderInfo activeRenderInfoIn, float partialTicks) { if (!this.debugView) { this.resetProjectionMatrix(this.getProjectionMatrix(activeRenderInfoIn, partialTicks, false)); which makes me think that you might need to add this to the start of your RenderWorldLast event: this.resetProjectionMatrix(this.getProjectionMatrix(activeRenderInfoIn, partialTicks, false)); Disclaimer: I haven't tried it yet myself so no guarantee it will work. -TGG
-
Howdy You might be interested in the code here; I think it does exactly what you want https://github.com/TheGreyGhost/MinecraftByExample/blob/working1-16-3/src/main/java/minecraftbyexample/usefultools/debugging/DebugBlockVoxelShapeHighlighter.java -TGG
-
[1.16.1]how can I make a custom crating block?
TheGreyGhost replied to 20ChenM's topic in Modder Support
Hi Try this example, it is quite close to what you want. If you then look at the vanilla crafting block, you should be able to figure the rest out. https://github.com/TheGreyGhost/MinecraftByExample/tree/master/src/main/java/minecraftbyexample/mbe31_inventory_furnace Cheers TGG -
How to Register Entities using the Deferred Register?
TheGreyGhost replied to kiou.23's topic in Modder Support
Howdy >Additionnaly, is there a Data Generator to generate Entity models? Try BlockBench, it is quite awesome https://blockbench.net/ I don't know about DeferredRegister for Entities; but this method should work for what you're trying to do: // register our entity types @SubscribeEvent public static void onEntityTypeRegistration(RegistryEvent.Register<EntityType<?>> entityTypeRegisterEvent) { emojiEntityType = EntityType.Builder.<EmojiEntity>create(EmojiEntity::new, EntityClassification.MISC) .size(0.25F, 0.25F) .build("minecraftbyexample:mbe81a_emoji_type_registry_name"); emojiEntityType.setRegistryName("minecraftbyexample:mbe81a_emoji_type_registry_name"); entityTypeRegisterEvent.getRegistry().register(emojiEntityType); } /** * Created by TGG on 24/06/2020. * * Heavily based on the vanilla SnowballEntity */ public class EmojiEntity extends ProjectileItemEntity { public EmojiEntity(EntityType<? extends EmojiEntity> entityType, World world) { super(entityType, world); } public EmojiEntity(World world, LivingEntity livingEntity) { super(StartupCommon.emojiEntityType, livingEntity, world); } public EmojiEntity(World world, double x, double y, double z) { super(StartupCommon.emojiEntityType, x, y, z, world); } // If you forget to override this method, the default vanilla method will be called. // This sends a vanilla spawn packet, which is then silently discarded when it reaches the client. // Your entity will be present on the server and can cause effects, but the client will not have a copy of the entity // and hence it will not render. @Nonnull @Override public IPacket<?> createSpawnPacket() { return NetworkHooks.getEntitySpawningPacket(this); } // ProjectileItemEntity::setItem uses this to save storage space. It only stores the itemStack if the itemStack is not // the default item. @Override protected Item getDefaultItem() { return StartupCommon.emojiItemHappy; } // We hit something (entity or block). @Override protected void onImpact(RayTraceResult rayTraceResult) { // if we hit an entity, apply an effect to it depending on the emoji mood if (rayTraceResult.getType() == RayTraceResult.Type.ENTITY) { EntityRayTraceResult entityRayTraceResult = (EntityRayTraceResult)rayTraceResult; Entity entity = entityRayTraceResult.getEntity(); if (entity instanceof LivingEntity) { LivingEntity livingEntity = (LivingEntity)entity; Optional<EmojiItem.EmojiMood> mood = getMoodFromMyItem(); if (mood.isPresent()) { EffectInstance effect = (mood.get() == EmojiItem.EmojiMood.HAPPY) ? new EffectInstance(Effects.REGENERATION, 100, 1) : new EffectInstance(Effects.POISON, 10, 0); livingEntity.addPotionEffect(effect); } } } if (!this.world.isRemote) { this.world.setEntityState(this, VANILLA_IMPACT_STATUS_ID); // calls handleStatusUpdate which tells the client to render particles this.remove(); } } // not needed here, but can be useful as a breakpoint location to check whether the entity was spawned properly, and to debug the behaviour / lifetime @Override public void tick() { super.tick(); } private static final byte VANILLA_IMPACT_STATUS_ID = 3; /* see https://wiki.vg/Entity_statuses make a cloud of particles at the impact point */ @Override public void handleStatusUpdate(byte statusID) { if (statusID == VANILLA_IMPACT_STATUS_ID) { IParticleData particleData = this.makeParticle(); for(int i = 0; i < 8; ++i) { this.world.addParticle(particleData, this.getPosX(), this.getPosY(), this.getPosZ(), 0.0D, 0.0D, 0.0D); } } } private IParticleData makeParticle() { Optional<EmojiItem.EmojiMood> mood = getMoodFromMyItem(); if (!mood.isPresent()) return ParticleTypes.SNEEZE; return (mood.get() == EmojiItem.EmojiMood.HAPPY) ? ParticleTypes.HEART : ParticleTypes.ANGRY_VILLAGER; } /** Look at the ItemStack stored by this entity and determine its mood * @return The mood, or empty if no mood defined (for some unknown reason...) */ private Optional<EmojiItem.EmojiMood> getMoodFromMyItem() { ItemStack itemStackForThisEntity = this.func_213882_k(); // returns air if the entity is storing the default item (HAPPY in this case) Item item = itemStackForThisEntity.isEmpty() ? getDefaultItem() : itemStackForThisEntity.getItem(); if (item instanceof EmojiItem) { EmojiItem.EmojiMood mood = ((EmojiItem) item).getEmojiMood(); return Optional.of(mood); } return Optional.empty(); } } -TGG -
Hi Every time the Minecraft version updates, there are a lot of changes to functions; sometimes it's just the names, other times the signatures changes, and sometimes whole classes and groups of classes are refactored to work differently. The best way to fix these problems during an update is 1) Find a vanilla class that uses the method in (eg) 1.15.2 2) Find the same vanilla class in 1.16.3, browse through the code until you find the code that calls the same method and see what it has changed to. 90% of the time you'll find it within a minute. -TGG
-
You might also find this sample code useful (in 1.15.2; requires minor tweaks to 1.16.3) https://github.com/TheGreyGhost/MinecraftByExample/blob/1-15-2-final/src/main/java/minecraftbyexample/usefultools/debugging/DebugBlockVoxelShapeHighlighter.java It makes blocks outline like this The lines behind blocks are hidden, but you can make them see through X-ray style by changing the render type -TGG
-
Any Updated 1.16.x good sources on modding?
TheGreyGhost replied to kiou.23's topic in Modder Support
Hi You could try this tutorial project; it has a lot of working examples. I'm just updating it from 1.15.2 to 1.16.3 at the moment, about 90% updated. https://github.com/TheGreyGhost/MinecraftByExample http://greyminecraftcoder.blogspot.com/2020/05/minecraft-by-example.html Cheers TGG- 1 reply
-
- 1
-
Hi What's the reason you want those coordinates in screen space? You might not need them, depending on what you want to do. Otherwise, the approach taken in that code sample looks like the necessary approach but you will need to spend quite a bit of effort, trial and error to get it to work properly. If you don't have a good understanding of 3D graphics, projections, viewports etc then it is going to be a very steep learning curve. Unfortunately I don't have anything more suitable/specific to help. -TGG
-
Howdy You might find this working example useful; it has some troubleshooting hints about bright/dark and also various examples of using TileEntityRenderers to render objects with different brightnesses, including a wavefront model. https://github.com/TheGreyGhost/MinecraftByExample/tree/master/src/main/java/minecraftbyexample/mbe21_tileentityrenderer Also some background info on lighting: https://greyminecraftcoder.blogspot.com/2020/04/lighting-1144.html -TGG
-
Howdy You might find this tutorial useful It works in 1.16.3 see example mbe45... https://github.com/TheGreyGhost/MinecraftByExample/tree/master/src/main/java/minecraftbyexample/mbe45_commands http://greyminecraftcoder.blogspot.com/2020/05/minecraft-by-example.html Cheers Richard
-
Howdy Your code should work fine as you've posted it above, if you get the parameters correct. The custom furnace I've written uses these: // draw the cook progress bar double cookProgress = containerFurnace.fractionOfCookTimeComplete(); // from 0.0 to 1.0 blit(guiLeft + COOK_BAR_XPOS, guiTop + COOK_BAR_YPOS, COOK_BAR_ICON_U, COOK_BAR_ICON_V, (int)(cookProgress * COOK_BAR_WIDTH), COOK_BAR_HEIGHT); // draw the fuel burn-time-left icon double burnRemaining = containerFurnace.fractionOfFuelRemaining(i); int yOffset = (int)((1.0 - burnRemaining) * FLAME_HEIGHT); blit(guiLeft + FLAME_XPOS + FLAME_X_SPACING * i, guiTop + FLAME_YPOS + yOffset, FLAME_ICON_U, FLAME_ICON_V + yOffset, FLAME_WIDTH, FLAME_HEIGHT - yOffset); -TGG
-
Howdy You might find this tutorial project useful, it has a couple of working examples of loading block models and various ways of animating blocks and tileentities. http://greyminecraftcoder.blogspot.com/2020/05/minecraft-by-example.html The examples for mbe04 (manipulation of baked models), mbe05 (animated texture) and mbe21 (tile entity rendering including block models) are probably the most relevant. https://github.com/TheGreyGhost/MinecraftByExample Cheers TGG
-
You might find this working example useful https://github.com/TheGreyGhost/MinecraftByExample/tree/master/src/main/java/minecraftbyexample/mbe60_network_messages The relevant bit is StartupCommon.simpleChannel.sendToServer(airstrikeMessageToServer); in ItemAirStrike class and for sending to clients // This message is called from the Server thread. // It spawns a random number of the given projectile at a position above the target location static void processMessage(AirstrikeMessageToServer message, ServerPlayerEntity sendingPlayer) { // 1) First send a message to all other clients who are in the same dimension, to tell them to render a "target" // effect on the ground // There are a number of other PacketDistributor types defined for other cases, for example // Sending to one player // simpleChannel.send(PacketDistributor.PLAYER.with(playerMP), new MyMessage()); // // Send to all players tracking this chunk // simpleChannel.send(PacketDistributor.TRACKING_CHUNK.with(chunk), new MyMessage()); // // Sending to all connected players // simpleChannel.send(PacketDistributor.ALL.noArg(), new MyMessage()); TargetEffectMessageToClient msg = new TargetEffectMessageToClient(message.getTargetCoordinates()); RegistryKey<World> playerDimension = sendingPlayer.func_241141_L_(); // func_241141_L_ is getPlayerDimension StartupCommon.simpleChannel.send(PacketDistributor.DIMENSION.with(() -> playerDimension), msg); -TGG
-
Ah, that makes more sense. I guess that will allow the serialisation of object instances to be coded in a much more high-level (and error-proof) way, rather than hard-coding (eg nbtCompound.putInt(xxx) etc) for each type of serialisation you want. Sounds like a good idea to me.. It looks like they have written a platform for it and are just dipping their toe in the water for refactoring the existing code, which explains why some of the defined codecs don't appear to be used anywhere yet. thx for the tip TGG
-
[1.16.1] New Lantern Not Supporting Transparency
TheGreyGhost replied to Matt Wild's topic in Modder Support
Hi You might find this working example of transparent models useful, just by coincidence it's also a lantern...! https://github.com/TheGreyGhost/MinecraftByExample/tree/master/src/main/java/minecraftbyexample/mbe05_block_advanced_models https://greyminecraftcoder.blogspot.com/2020/05/minecraft-by-example.html (mbe05) Cheers TGG -
Howdy folks While converting particles I've run into the Minecraft Codec. It appears to be a convenient way to serialise and deserialise objects without having to hard code a readNBT() and writeNBT()? But I don't understand why Particles have both Codec and DESERIALIZER as well, whereas in 1.15.3 there was no Codec. Likewise, ItemStack has both a Codec and write(CompoundNBT), but they are different- capability info in NBT but not in Codec. And the Codec appears to write .tag but to construct with .capNBT Is this just a work-in-progress thing? (i.e. eventually Codecs will replace NBT?) Or is there some difference in usage I'm not seeing? The Codecs are bristling with so many lambdas and wrappers I haven't been able to track down where they are actually used / what they're actually used for. Google has been surprisingly silent on the topic. Cheers TGG public static final Codec<ItemStack> field_234691_a_ = RecordCodecBuilder.create((p_234698_0_) -> { return p_234698_0_.group(Registry.ITEM.fieldOf("id").forGetter((p_234706_0_) -> { return p_234706_0_.item; }), Codec.INT.fieldOf("Count").forGetter((p_234705_0_) -> { return p_234705_0_.count; }), CompoundNBT.field_240597_a_.optionalFieldOf("tag").forGetter((p_234704_0_) -> { return Optional.ofNullable(p_234704_0_.tag); })).apply(p_234698_0_, ItemStack::new); }); public ItemStack(IItemProvider itemIn, int count, @Nullable CompoundNBT capNBT) { // doesn't appear to properly match the Codec? i.e. tag vs capNBT? ... etc ... } /** * Write the stack fields to a NBT object. Return the new NBT object. */ public CompoundNBT write(CompoundNBT nbt) { ResourceLocation resourcelocation = Registry.ITEM.getKey(this.getItem()); nbt.putString("id", resourcelocation == null ? "minecraft:air" : resourcelocation.toString()); nbt.putByte("Count", (byte)this.count); if (this.tag != null) { nbt.put("tag", this.tag.copy()); } CompoundNBT cnbt = this.serializeCaps(); if (cnbt != null && !cnbt.isEmpty()) { nbt.put("ForgeCaps", cnbt); } return nbt; }
-
You need block cutout render type. See here for example (3a: i.e. the sign) https://github.com/TheGreyGhost/MinecraftByExample/tree/master/src/main/java/minecraftbyexample/mbe03_block_variants https://greyminecraftcoder.blogspot.com/2020/05/minecraft-by-example.html -TGG
-
Thanks dudes, that's a big help Cheers TGG
-
No you don't need a utility class, it's a matter of preference only. You can create an object and register it on the event bus, or you can register a utility class instead (for its static methods), Forge supports both methods, eg both of these work: ServerLifeCycleEvents serverLifeCycleEvents = new ServerLifeCycleEvents(); MOD_EVENT_BUS.register(serverLifeCycleEvents); public class ServerLifecycleEvents { @SubscribeEvent public void onServerStartingEvent(FMLServerStartingEvent event) { } } ///------- or ------------ MOD_EVENT_BUS.register(ServerLifeCycleEvents.class); public class ServerLifecycleEvents { @SubscribeEvent public static void onServerStartingEvent(FMLServerStartingEvent event) { } //static here } I personally prefer the utility class for setup code because I only ever need a singleton and they are so simple I never need to write a test harness for it, so creating an object just adds a bit of extra overhead. I also like the imperative style of explicitly adding to registries. Or do you mean- can you just add registration methods to the objects themselves? (eg create a new Block and have it register itself?, or perhaps using a static initialiser inside the Block class) In that case - the answer is "no" because the objects must be registered with vanilla at the correct time, which is not guaranteed unless you use the forge initialisation events. Many folks like to eliminate utility classes as much as possible by using static initialiser assignment of a DeferredRegister, eg * private static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, MODID); * * public static final RegistryObject<Block> ROCK_BLOCK = BLOCKS.register("rock", () -> new Block(Block.Properties.create(Material.ROCK))); * * public ExampleMod() { * BLOCKS.register(FMLJavaModLoadingContext.get().getModEventBus()); * } Again I think that's a matter of personal preference although some people do hold strong opinions about the right way to do it (TM).
-
You might find this tutorial project useful: https://github.com/TheGreyGhost/MinecraftByExample In order to find the code for Nether portals, you need to know a bit about the objects and datastructures used by Minecraft; that's where the various tutorials around the web can be a big help. The source code itself is generally poorly documented (very few comments in vanilla code, and somewhat patchy comments for the Forge code) and often the names of methods can be misleading or even wrong, because the code has been decompiled and then manually deobfuscated by crowdsourcing. So for example for NetherPortals, the relevant code is in NetherPortalBlock and PortalSize, but it will be difficult to understand what's going on. You might be better off with BedBlock or DoorBlock but even those are likely to be hard work until you have a number of the key concepts around blocks and blockstates under your belt. -TGG
-
Howdy folks Are there any guidelines I should follow to ensure that my mod code is not going to cause multithreading problems? Most of the time it is obvious because I know whether my code is in a render thread, client tick thread, server thread etc, and the method I'm overriding or implementing gives me the (thread-safe) object I need. But I think there are some other places where there might be risk of concurrent threads colliding if I call vanilla objects; especially static registration methods of vanilla classes during mod initialisation. Are ModEventBus events called concurrently if multiple mods are present? If so, any calls I make to vanilla code from a ModEventBus event is likely to be risky I think. I hear rumours that DeferredWordQueue::enqueueWork is the method to ensure that registrations using vanilla classes are executed single-threaded, is this the intended method? What about the server thread, client thread? Eg are there ever concurrent server threads which may cause my mod to access non-thread-safe objects or methods? I know there are multiple render threads, which is perfectly safe provided I stick to the objects provided in the calling method or event and don't try to access server or client objects via 'sneaky' methods. What assumptions is it safe to make? The worst bugs I've ever had to deal with have all been caused by multithread collisions or race conditions so I'm very keen to understand where the high risk areas are... Cheers TGG
-
By crikey that's a decent upgrade guide all by itself, thanks dude! A few of those pointers will be saving me a couple of days of stuffing around I reckon! Cheers TGG
-
Howdy Does anyone know of a decent update guide from 1.15 to 1.16? i.e. similar to williewillus' from 1.14 to 1.15 https://gist.github.com/williewillus/30d7e3f775fe93c503bddf054ef3f93e - he saved me a ton of frustration with that guide! Cheers TGG
-
[1.15.2] Applying random textures to the block model
TheGreyGhost replied to Ragna Aarok's topic in Modder Support
Howdy You could perhaps use a multipart block, similar to this https://github.com/TheGreyGhost/MinecraftByExample/blob/master/src/main/resources/assets/minecraftbyexample/blockstates/mbe03b_block_3dweb_registry_name.json One multipart for each side, always true (so that all four sides show), with a random block model for each side. If multipart lets you use random models for each part, that will probably give you what you want. If that doesn't work, you could use a dynamic blockmodel eg working examples here (but much more complicated than just using blockstate) https://github.com/TheGreyGhost/MinecraftByExample/tree/master/src/main/java/minecraftbyexample/mbe04_block_dynamic_block_models -TGG -
If you make a TileEntity you can tell it to render anywhere even when out of view See BeaconTileEntityRenderer, in particular isGlobalRenderer() -TGG