Jump to content

Adil Yilan

Members
  • Posts

    73
  • Joined

  • Last visited

Everything posted by Adil Yilan

  1. @warjort Hmm, but I could use LivingTickEvent and access ServerPlayerGameMode from there? I could check if isDestroyingBlock property is set to true, and then access block state based on destroyPos property to check if destroyed block is the one that I am trying to implement => damage player if it is. Would this be a good approach?
  2. @Luis_ST I have found this in Minecraft protocol: https://wiki.vg/Protocol#Player_Action I presume this is how ticks that you have linked are sent to server, since server eventually has to know whether player has completed or canceled digging? Do you think it would be a good idea to listen for this packet and react on it or it would be an overkill? EDIT: Nvm this, it still does not solve "ticking" idea of damage. I will go with your proposal @Luis_ST as it seems to be only viable solution for now. Thank you!
  3. @Luis_ST I am trying to have damage to be consistent during mining process. If it takes 10 seconds to mine it, I would like to reduce health by 1 hit point for every second of mining. So if player starts to mine, after 1 second it should already show that 1/2 of heart is lost. If player decides to stop mining after 4 seconds, he should still end up with 2 hearts lost, even though block was not mined at the end. I don't think that is possible with your solution or did I miss something?
  4. General idea is to create a block that inflicts damage to player when player is mining it. If it takes 10 seconds to mine the block, player might receive 10 hit points of damage (5 hearts) until block is mined. To implement this, I need some kind of event that "ticks" as long as player is breaking the block. I have tried with PlayerInteractEvent.LeftClickBlock and BlockEvent.BreakEvent but these two only provide information when mining starts and ends, but not that it is still in progress. Is there any way to do this with existing events? Thanks!
  5. Never mind this, I have recreated the model and issue went away... Whatever caused this will remain a mistery.
  6. I have created 3D armor model in Blockbench without adding any anymations whatsoever. However I have noticed some strange behavior when Steve is standing and idling: So as you can see, armor on the left side moves up/down. When I equip regular armor such as diamond armor this movement does not happen. Any idea what this could be? I am not sure whether this is something that GeckoLib adds, or this is normal behavior that somehow should be handled or ... ? Total weirdness...
  7. Thanks @diesieben07 and @Luis_ST, you've helped me a lot as usual. It works great now with this code: @Override public InteractionResult use(BlockState blockState, Level level, BlockPos blockPos, Player player, InteractionHand hand, BlockHitResult blockHitResult) { // IF: Code is executing on logical client. if(level.isClientSide) { // Do nothing. return InteractionResult.SUCCESS; } // Get block entity at the block location. BlockEntity blockEntity = level.getBlockEntity(blockPos); // IF: block entity is matching. if (blockEntity instanceof VikingChestBlockEntity) { // Cast player to ServerPlayer. ServerPlayer serverPlayer = (ServerPlayer) player; // Cast block entity to VikingChestBlockEntity. VikingChestBlockEntity vikingChestBlockEntity = (VikingChestBlockEntity)blockEntity; // Open menu. NetworkHooks.openScreen(serverPlayer, vikingChestBlockEntity, blockPos); } return InteractionResult.CONSUME; }
  8. This is the use method on VikingChestBlock class: @Override public InteractionResult use(BlockState blockState, Level level, BlockPos blockPos, Player player, InteractionHand hand, BlockHitResult blockHitResult) { // IF: Code is executing on logical client. if(level.isClientSide) { // Do nothing. return InteractionResult.SUCCESS; } // Get block entity at the position where block was used. BlockEntity blockEntity = level.getBlockEntity(blockPos); if (blockEntity instanceof VikingChestBlockEntity) { // Open menu. player.openMenu((VikingChestBlockEntity)blockEntity); } return InteractionResult.CONSUME; } I also used this, but didn't work either: @Override public InteractionResult use(BlockState blockState, Level level, BlockPos blockPos, Player player, InteractionHand hand, BlockHitResult blockHitResult) { // IF: Code is executing on logical client. if(level.isClientSide) { // Do nothing. return InteractionResult.SUCCESS; } // Get menu provider reference. MenuProvider menuprovider = this.getMenuProvider(blockState, level, blockPos); // IF: Menu provider is defined. if (menuprovider != null) { // Open menu. player.openMenu(menuprovider); } return InteractionResult.CONSUME; }
  9. Hi, I have implemented custom chest, but I am getting a very strange error when the menu should appear. This is how menu is registered: public final class ContainerMenuTypes { private ContainerMenuTypes() {} public static final DeferredRegister<MenuType<?>> REGISTRY = DeferredRegister.create(ForgeRegistries.MENU_TYPES, ExperimentalMod.MODID); public static final RegistryObject<MenuType<VikingChestMenu>> VIKING_CHEST = REGISTRY.register("viking_chest", () -> IForgeMenuType.create(VikingChestMenu::new)); } And this is how constructor looks like: // This constructor is required by forge to register menu type. public VikingChestMenu(int containerId, Inventory inventory, FriendlyByteBuf buff) { this(containerId, inventory, inventory.player.level.getBlockEntity(buff.readBlockPos())); } So when I click on the chest, this error occurs: [15:31:15] [Render thread/ERROR] [minecraft/BlockableEventLoop]: Error executing task on Client java.lang.NullPointerException: Cannot invoke "net.minecraft.network.FriendlyByteBuf.readBlockPos()" because "buff" is null at ba.appimpact.minecraft.experimental.common.menu.container.VikingChestMenu.<init>(VikingChestMenu.java:83) ~[%23186!/:?] {re:classloading} at net.minecraftforge.network.IContainerFactory.create(IContainerFactory.java:20) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23180%23187!/:?] {re:classloading} at net.minecraft.world.inventory.MenuType.create(MenuType.java:44) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading,pl:accesstransformer:B} at net.minecraft.client.gui.screens.MenuScreens$ScreenConstructor.fromPacket(MenuScreens.java:115) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A} at net.minecraft.client.gui.screens.MenuScreens.lambda$create$0(MenuScreens.java:43) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A} at java.util.Optional.ifPresent(Optional.java:178) ~[?:?] {} at net.minecraft.client.gui.screens.MenuScreens.create(MenuScreens.java:43) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A} at net.minecraft.client.multiplayer.ClientPacketListener.handleOpenScreen(ClientPacketListener.java:979) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A} at net.minecraft.network.protocol.game.ClientboundOpenScreenPacket.handle(ClientboundOpenScreenPacket.java:37) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading} at net.minecraft.network.protocol.game.ClientboundOpenScreenPacket.handle(ClientboundOpenScreenPacket.java:11) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading} at net.minecraft.network.protocol.PacketUtils.lambda$ensureRunningOnSameThread$0(PacketUtils.java:22) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading} at net.minecraft.util.thread.BlockableEventLoop.doRunTask(BlockableEventLoop.java:157) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading,pl:accesstransformer:B} at net.minecraft.util.thread.ReentrantBlockableEventLoop.doRunTask(ReentrantBlockableEventLoop.java:23) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading} at net.minecraft.util.thread.BlockableEventLoop.pollTask(BlockableEventLoop.java:131) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading,pl:accesstransformer:B} at net.minecraft.util.thread.BlockableEventLoop.runAllTasks(BlockableEventLoop.java:116) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading,pl:accesstransformer:B} at net.minecraft.client.Minecraft.runTick(Minecraft.java:1041) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A} at net.minecraft.client.Minecraft.run(Minecraft.java:669) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A} at net.minecraft.client.main.Main.main(Main.java:206) ~[forge-1.19-41.0.110_mapped_parchment_1.18.2-2022.07.17-1.19.jar%23181!/:?] {re:classloading,pl:runtimedistcleaner:A} at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] {} at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?] {} at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] {} at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?] {} at net.minecraftforge.fml.loading.targets.ForgeClientUserdevLaunchHandler.lambda$launchService$0(ForgeClientUserdevLaunchHandler.java:25) ~[fmlloader-1.19-41.0.110.jar%2394!/:?] {} at cpw.mods.modlauncher.LaunchServiceHandlerDecorator.launch(LaunchServiceHandlerDecorator.java:30) [modlauncher-10.0.8.jar%23106!/:?] {} at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:53) [modlauncher-10.0.8.jar%23106!/:?] {} at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:71) [modlauncher-10.0.8.jar%23106!/:?] {} at cpw.mods.modlauncher.Launcher.run(Launcher.java:106) [modlauncher-10.0.8.jar%23106!/:?] {} at cpw.mods.modlauncher.Launcher.main(Launcher.java:77) [modlauncher-10.0.8.jar%23106!/:?] {} at cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:26) [modlauncher-10.0.8.jar%23106!/:?] {} at cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:23) [modlauncher-10.0.8.jar%23106!/:?] {} at cpw.mods.bootstraplauncher.BootstrapLauncher.main(BootstrapLauncher.java:141) [bootstraplauncher-1.1.2.jar:?] {} For some reason, FriendlyByteBuf buff is null in constructor and I need it to access block entity so that rest of the code can execute. Any ideas what could be wrong here?
  10. Worked like a charm: @Mod.EventBusSubscriber(modid = ExperimentalMod.MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public final class ClientSetupEventHandler { private static ResourceLocation BLOCKING_PROPERTY_RESLOC = new ResourceLocation(ExperimentalMod.MODID, "blocking"); @SubscribeEvent public static void onClientSetup(final FMLClientSetupEvent event) { event.enqueueWork(() -> { ItemProperties.register(WeaponItems.VIKING_SHIELD.get(), BLOCKING_PROPERTY_RESLOC, ($itemStack, $level, $entity, $seed) -> { return $entity != null && $entity.isUsingItem() && $entity.getUseItem() == $itemStack ? 1.0F : 0.0F; }); }); } } With this correction in model file: "overrides": [ { "predicate": { "experimentalmod:blocking": 1 }, "model": "experimentalmod:item/viking_shield_blocking" } ] Thanks @Luis_ST !
  11. @Luis_ST Both models were created in Blockbench and then exported as JSON files. So I guess you are referring to this: register(Items.SHIELD, new ResourceLocation("blocking"), (p_174590_, p_174591_, p_174592_, p_174593_) -> { return p_174592_ != null && p_174592_.isUsingItem() && p_174592_.getUseItem() == p_174590_ ? 1.0F : 0.0F; }); So even though I do inherit from ShieldItem, I have to create my own custom blocking property, which would probably end up being "experimentalmod:blocking" instead of regular "blocking" ? I will try to add this now, but regardless of that, is this like a "hack" or proper way to do it for every item property? Thanks
  12. I have created custom shield by extending existing ShieldItem: public final class VikingShieldItem extends ShieldItem { public VikingShieldItem() { super(createProperties()); } private static Properties createProperties() { Properties properties = new Properties(); properties.tab(CreativeModeTab.TAB_COMBAT); properties.durability(672); return properties; } @Override public boolean isValidRepairItem(ItemStack repairedItemStack, ItemStack repairItemStack) { return repairItemStack.is(OreItems.TITANIUM_INGOT.get()); } } I have also created two Blockbench model, one regular, and the other one when shield is blocking, and saved them as viking_shield.json and viking_shield_blocking.json. In viking_shield.json I have this addition: "overrides": [ { "predicate": { "blocking": 1 }, "model": "experimentalmod:item/viking_shield_blocking" } ] However, when I start the game, shield is properly loaded, it blocks, everything works ok, but use animation is not working - it hides and restores to same default look, although it should be tilted. Is there anything else that must be configured for alternate model to be loaded? Thanks!
  13. @Luis_ST @warjort Thank you both for your answers! This is final version of code, in case someone else ends up looking for the same thing: @EventBusSubscriber(modid = ExperimentalMod.MODID, bus = Bus.FORGE) public final class AllowDespawnEventHandler { @SubscribeEvent() public static void onAllowDespawn(final AllowDespawn event) { // IF: Code is executing on the logical client. if(event.getLevel().isClientSide()) { // Do not change anything, do regular behavior. event.setResult(Result.DEFAULT); return; } // Get reference to entity that is about to despawn. Mob mob = event.getEntity(); // IF: Entity is instance of GoblinEntity class. if(mob instanceof GoblinEntity) { // Prevent Goblins from despawning. event.setResult(Result.DENY); // Stop execution. return; } // For other entities, we don't want to change regular logic, so we set result to be DEFAULT which means // whatever should happen otherwise, continue with it. event.setResult(Result.DEFAULT); } } It works as expected.
  14. Thanks @Luis_ST ! I did check event comments but is still not entirely clear what to do with this check: /** * This event is fired for a {@link Mob} that can despawn <i>each mob tick</i>. * This event only fires if a mob can be allowed to despawn and will not * otherwise fire if a despawn is certain. * <p> * This event is not {@linkplain Cancelable cancellable}, but does {@linkplain HasResult have a result}. * {@link Result#DEFAULT} indicates that default despawn mechanics should be used. * {@link Result#ALLOW} indicates that the mob should forcefully despawn. * {@link Result#DENY} indicates that the mob should forcefully stay spawned. * <p> * This event is fired on the {@linkplain MinecraftForge#EVENT_BUS main Forge event bus}, * only on the {@linkplain LogicalSide#SERVER logical server}. * * @see LivingEntity#checkDespawn() * @author cpw */ Comment mentiona that event is fired only on the LogicalSide.SERVER. Is .isClientSide() check then necessary if Forge ensures that event is never fired on logical client? This is what I have now in code: // IF: Code is executing on the logical client. if(event.getLevel().isClientSide()) { // Do not change anything, do regular behavior. event.setResult(Result.DEFAULT); return; } Should I: 1) Set result to DEFAUT? 2) Don't set result at all? 3) Regarding the comment, just remove isClientSide() check entirely? Thanks again!
  15. I want to prevent monster from despawning. Idea is to use AllowDespawn event from Forge. However, since event requires for Result to be set, I am not sure what result to set when code is executing on logical client side... To fix that, I thought that I might set event handler to Dist.DEDICATED_SERVER but I am not really sure if that is proper way: // Option 1: Set Dist.DEDICATED.SERVER? But what will then happen in single player? @EventBusSubscriber(modid = ExperimentalMod.MODID, bus = Bus.MOD, value = Dist.DEDICATED_SERVER) public class AllowDespawnEventHandler { @SubscribeEvent() public static void onAllowDespawn(final AllowDespawn event) { // Option 2: Check if it is logical client side in event handler. if(event.getLevel().isClientSide()) { // But I don't know what to set for event.setResult(...) ? return; } } } So the question is what should I use to avoid duplicate code execution / messing up the single player mode: 1) Use Dist.DEDICATED_SERVER 2) Use level.isClientSide() 3) Use something else? I hope code snippet above illustrates my doubts / question. Thanks for any assistance.
  16. @Luis_ST, thank you for the quick reply. I was just worried that I might be using Forge mechanics the wrong way by creating multiple registries of same type, but if it is safe to do, I will stick with that than.
  17. I have a lot of blocks so I have decided to create multiple registries to keep things more clear: public final class FruitBlocks { private FruitBlocks() {} public static final DeferredRegister<Block> REGISTRY = DeferredRegister.create(ForgeRegistries.BLOCKS, ExperimentalMod.MODID); public static final RegistryObject<FruitPlantBlock> ORANGE_PLANT = REGISTRY.register("orange_plant", () -> new OrangePlantBlock()); /// ... More fruit blocks are registered here } This is another registry but for different group of blocks: public final class MachineBlocks { private MachineBlocks() {} public static final DeferredRegister<Block> REGISTRY = DeferredRegister.create(ForgeRegistries.BLOCKS, ExperimentalMod.MODID); public static final RegistryObject<Block> TERRAFORMER = REGISTRY.register("terraformer", () -> new TerraformerBlock()); /// ... More machine blocks are registered here } Everything is working as expected, but I am not sure if this is safe thing to do? Is there a smarter/better way to separate groups of blocks/items/entities?
  18. @diesieben07 Ok thank you, good to know that.
  19. @diesieben07 Adding data generator for this is def something I had in plan, but I am not sure if this is most optimized JSON output, regardless if it is manual or auto generated. Can it be improved / regrouped in a way I have envisioned to have multiple variants point to same model?
  20. I have a crop that has AGE property that changes from 0 to 29. There are 5 different block models: Stage 0 - AGE from 0 to 5 Stage 1 - AGE from 6 to 11 Stage 2 - AGE from 12 to 17 Stage 3 - AGE from 18 to 23 Stage 4 - AGE from 24 to 29 For every stage there is a different model. My blockstate JSON file looks like this: { "variants":{ "age=0" : { "model" : "experimentalmod:block/fruit_plant_stage_0" }, "age=1" : { "model" : "experimentalmod:block/fruit_plant_stage_0" }, "age=2" : { "model" : "experimentalmod:block/fruit_plant_stage_0" }, "age=3" : { "model" : "experimentalmod:block/fruit_plant_stage_0" }, "age=4" : { "model" : "experimentalmod:block/fruit_plant_stage_0" }, "age=5" : { "model" : "experimentalmod:block/fruit_plant_stage_0" }, "age=6" : { "model" : "experimentalmod:block/fruit_plant_stage_1" }, "age=7" : { "model" : "experimentalmod:block/fruit_plant_stage_1" }, "age=8" : { "model" : "experimentalmod:block/fruit_plant_stage_1" }, "age=9" : { "model" : "experimentalmod:block/fruit_plant_stage_1" }, "age=10" : { "model" : "experimentalmod:block/fruit_plant_stage_1" }, "age=11" : { "model" : "experimentalmod:block/fruit_plant_stage_1" }, ... } } Although this works, I find it terrible from the code quality perspective. I have searched for any clues on how to use same model for different variants but without success. Is there a way to say: For AGE values from 0 to 5 use model fruit_plant_stage_0 For AGE values from 6 to 11 use model fruit_plant_stage_1 ...etc Thanks
  21. Ah ok, so it is related to client optimization if I understand correctly? Client will remove the entity from memory if it is outside of the tracking range?
  22. Hi, I have created several entities that work properly but there are few things that I am not sure I understand correctly when it comes to EntityType.Builder. One of those things is how to set clientTrackingRange to adequate value. I have checked Forge documentation, various tutorials, looked for usage in Minecraft source code, but can't really find anything that would give me 100% sure explanation on how to set value properly. Fox, Cat, Bee have it set to 8, but Cow, Sheep, Wolf and Pig have it set to 10... Is it because they can be tamed and follow the player? Why is Zombie set to 10 but Skeleton to 8? I would really like to get proper understanding of this parameter, so any hints are really welcomed, including articles that I can read on my own. Thanks!
  23. @MFMods thank you for so many hints I will dig into the methods that you have mentioned and experiment a bit. Hopefully I will not end up bald. I am still new to a lot of concepts in Forge/Minecraft, but it's still fun and challenging to make stuff on your own. After all, it is one fine working TV as you can see.
  24. I have a TV block that is 48 wide and 16 high. As you can see on the video above, I have an issue where player can put any other block on extra space of TV and I can't figure out how to stop that from happening. SHAPE is defined like this: private static final VoxelShape SHAPE = Block.box(-16.0D, 0.0D, 0.0D, 32.0D, 16.0D, 16.0D); I have overridden all possible methods to return this shape but issue is still there: @Override public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { return SHAPE; } @Override public VoxelShape getOcclusionShape(BlockState pState, BlockGetter pLevel, BlockPos pPos) { return SHAPE; } @Override public VoxelShape getBlockSupportShape(BlockState pState, BlockGetter pReader, BlockPos pPos) { return SHAPE; } @Override public VoxelShape getInteractionShape(BlockState pState, BlockGetter pLevel, BlockPos pPos) { return SHAPE; } @Override public VoxelShape getCollisionShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { return SHAPE; } @Override public VoxelShape getVisualShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { return SHAPE; } Any hints/ideas on how to fix this? Thanks!
  25. @DePhoegon To create an instance of BlockTagsProvider, I would have to pass in DataGenerator. I need to get list of all blocks in runtime, not when data is generating. Apart from seeing the map of tags and blocks, I don't see how could I use that while the mod is running.
×
×
  • Create New...

Important Information

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