Jump to content

desht

Members
  • Posts

    244
  • Joined

  • Last visited

  • Days Won

    13

Posts posted by desht

  1. You should be able to use Minecraft.getMinecraft().timer.renderPartialTicks in your InputUpdateEvent handler to determine how long it's been since the last tick (that number is a float between 0.0f and 1.0f).  Use this to interpolate; interpolation is calculating a value between two values, e.g. 

    float interpolated = oldVal + (newVal - oldVal) * partialTicks;

    Obviously that means storing the old value as a copy of the latest value each tick.

  2. Yes, you should override your block's onReplaced() method and drop any contained items there.  Note that dropping the contents of a tile entity's inventory is a different operation from dropping the tile entity's own block (which should be done by a loot table in 1.14).

     

    Please don't make your tile entity a subclass of LockableLootTileEntity, which uses the vanilla IInventory system.  Instead use Forge capabilities, and store your items in an IItemHandler implementation (most likely ItemStackHandler or a subclass of that).  If you insist on using vanilla IInventory, don't be surprised when people complain that your block's inventory is not accessible by any other mods...

  3. SoundHandler doesn't exist on the server, because the server has, of course, no concept of how to play a sound (or even what a sound is, other than some symbol in a registry).

     

    If you want to control the playback/pause/stop of client-side sound playing from the server, you'll need to send custom packets to any interested clients.  This doesn't necessarily need to be an explicit play/pause/stop packet; you could control playback from a client-side entity or tile entity, for example, and there are already ways of sync'ing information to those.

  4. Take a look through AbstractSkeletonEntity, and RangedBowAttackGoalRangedBowAttackGoal has the strafing code (in its tick() implementation).

     

    What you'll need to do is remove that goal for the skeleton and replace it with a goal that lacks the strafe code.  Fortunately, it looks like that shouldn't be too hard, since the skel's combat code is set up via AbstractSkeletonEntity#setCombatTask(), which gets called when the skel is created (whether via spawn or restoration from NBT), and when its held weapon changes.  You should be able to hook entity spawning to call your own code to add your own ranged attack goal.  Not sure offhand about hooking equipment changes, though.

    • Like 2
  5. Container and GUI creation is very different in 1.14.x compared with 1.12.2.  I wrote a post about it here while figuring it out: 

    I hope you're developing in 1.14.x and not the dead-end that is 1.13.x.

    And the reason you're not finding any GuiXXXX classes in vanilla is that they've all been renamed to xxxScreen (e.g. HopperScreen).

    • Thanks 2
  6. There's also a minecraft:fences tag, which includes all wooden fences plus the nether brick fence.  That sounds like a suitable place to add your metal fence.

     

    To add your block to that tag, create a file src/main/resources/data/minecraft/tags/blocks/fences.json in your project, and add something like:

    {
      "replace": false,
      "values": [
        "yourmod:your_fence_block"
      ]
    }

    substituting in the correct block ID, of course.

    The "replace": false part there indicates that you're appending your block to the minecraft:fences tag, rather than overwriting it.

     

    If you want to browse all existing (vanilla) tags from your IDE, look for the external library "net.minecraft:client:extra:1.14.3" in your project dependencies tab (at least for IntelliJ, don't ask me about Eclipse).  Under there you'll see all the assets and data resources from vanilla, which can be a very useful reference.

    • Thanks 1
  7. Also, consider very carefully whether you should be using NBT here, or whether it would be better to have 3 separate Blocks (poor/medium/rich).  Have a read of https://gist.github.com/williewillus/353c872bcf1a6ace9921189f6100d09a#dealing-with-item-metadata, in particular the points about abusing NBT to replace metadata.  Remember that the number of blocks & items you can have is (for all intents and purposes) unlimited in 1.13+.

  8. 56 minutes ago, TehStoneMan said:

    Here:

    
    package io.github.tehstoneman.betterstorage.common.tileentity;
    
    import net.minecraft.tileentity.TileEntityType;
    
    public final class BetterStorageTileEntityTypes
    {
    	public static TileEntityType< TileEntityCrate >				CRATE;
    	public static TileEntityType< TileEntityReinforcedChest >	REINFORCED_CHEST;
    	public static TileEntityType< TileEntityLocker >			LOCKER;
    	public static TileEntityType< TileEntityReinforcedLocker >	REINFORCED_LOCKER;
    }

    I guess @ObjectHolder is something new to me - I have not seen it before.

    Nope, @ObjectHolder is not new - it's been around since 1.10.  Read https://mcforge.readthedocs.io/en/latest/concepts/registries/ (although it's written for 1.12.2, the concepts still apply in 1.14+).

     

    Learn it, use it - it's the Right Way to do things with Forge, especially in 1.14 where so many more things are in registries.

  9. 2 minutes ago, Oscarita25 said:

    its post if you want to draw after the ElementType that you check for if i am correct (not sure tho) 

    Yes, that is correct.  It's probably only important if you want to draw specifically over or under an existing element.  If drawing on a separate area of the screen, either should be fine (and of course the Pre event is cancelable, while the Post event is not).

  10. RenderGameOverlayEvent.Pre (or possibly Post) is the right place, but to just draw something on the screen, I don't see the need to extend Screen (which is what GuiScreen is now called in 1.14).  Just draw on the main screen, having checked the element type you want to draw before or after.

     

    drawTexturedModalRect() and the various related methods are now all called blit() (overloaded by the parameters they take, which are the same as in 1.12.2 so a direct method rename should be possible), and can be found in AbstractGui.  There is a blit() overload which takes a TextureAtlasSprite, so that should work for you.

     

    Tessellator/TextureAtlasSprite code hasn't really changed since 1.12.2 as far as I'm aware. Get your sprite from a TextureStitchEvent.Pre event handler as normal.

     

    As for 1.13?  It's a dead-end.  Active development is on 1.14.2 now, and even it's a bit rough right now, it will inevitably improve.

    • Like 1
  11. 14 hours ago, diesieben07 said:

    Blocks use loot tables now. You can set it by overriding getLootTable in your block class or it will default to [modid]:blocks/[block registry name]. This translates to the following location of the loot table: /assets/[modid]/loot_tables/blocks/[block registry name].json.

    Shouldn't that be /data/[modid]/loot_tables/blocks/[block registry name].json ?

     

    Also, @NickDerMitHut I believe modded loot tables require a "name" field (in the pool itself, not just the entries).  This is in contrast to vanilla loot tables which don't.  The name should be something unique, so prefix it with your mod id (e.g. "cockmod:somepoolname").

  12. No worries.  One other thing, regarding my point about one-to-one container->GUI mappings...

     

    If you have one container object but you want several different GUIs (my use case: Modular Routers modules nearly all use the same container object - a 9-slot inventory for filtering - but several modules have extra GUI controls for configuring module-specific properties), then:

    • A separate container type will need to be registered for each GUI type, but you can use the same subclass of Container each time, just with a different ContainerType parameter.
    • Then you can associate each container type with its corresponding GUI using ScreenManager.registerFactory() as normal

     

    • Thanks 1
  13. Bit of follow up since I understand a bit more now....

    • To get extra data passed across to the client (like a TE blockpos, for example), Forge 26.0.16 adds an extra PacketBuffer parameter to the NetworkHooks.openGui() calls, and a corresponding parameter to the container factory constructor.
    • Looks like NetworkHooks.openGui() remains the way to go for modded - I guess player.openContainer() is really for vanilla only?
    • Update: player.openContainer() should be fine to use if you're just creating a GUI purely to display some container slots (and don't need direct access to the clientside tile entity), like a chest GUI for example. 
    • Typically, you'll have two or more constructors in your container objects - one "factory" constructor which is called by Minecraft client-side when a GUI is opened (and when the container type is registered during init), and one or more constructors of your choosing which create a container with any data you need to initialize them with.
    • Those extra constructors would be called server-side from your INamedContainerProvider implementation, and client-side from your "factory" constructor, having extracted information from the extraData PacketBuffer.

     

    • Thanks 4
  14. As anyone who's started porting to 1.14.2 is probably aware by now, container and GUI creation has changed... quite a bit.  To summarise what I've gathered so far:

    • Containers (more accurately: container types) are now registry objects and must be registered in a RegistryEvent.Register<ContainerType<?>> event handler.
    • Container objects themselves must provide a constructor of the form MyContainer(int windowId, PlayerInventory inv, PacketBuffer extraData).  This will be used to instantiate the client-side container.
    • Your container's constructor must call the super Container constructor with your registered container type and the windowId parameter (this int parameter is not used in any other way - just pass it along to the superclass constructor and forget about it)
    • You can use the extraData parameter to pass... extra data! to your container.  This PacketBuffer parameter is built server-side when you call NetworkHooks.openGui(); see below.
    • Typically, your container will have (at least) two constructors; the factory constructor described above which is used for client-side construction, and a constructor taking whatever parameters you need to pass to set up your server-side container object.
    • Container-based GUI's are now associated with a container type with the ScreenManager.registerFactory() method, which takes a registered ContainerType and a ScreenManager.IFactory to construct your GUI object. Call that in your client-side init code.
      • ExtensionPoint.GUIFACTORY is gone, no longer needed, as is the old IGuiHandler system.  ScreenManager does all that work now.
      • While there must be a one-to-one mapping from ContainerType to each GUI, also remember that you can happily re-use the same container class for multiple container types if you need to; just pass the container type as a parameter to your constructor and up along to the Container constructor.
    • All container-based GUI's must provide a constructor taking(T, PlayerInventory, ITextComponent), where the generic T is the type of your container object.
      • Container-based GUI objects are now generified (is that a word?) on the container's class, e.g. public class MyGui extends ContainerScreen<MyContainer>
    • IInteractionObject is gone; instead your tile entity should implement INamedContainerProvider: the createMenu() method is where you create and return your server-side container object. (I believe getDisplayName() is only used to initialize the title field of your GUI object).
      • To open a container-based GUI on the tile entity (server-side), call NetworkHooks.OpenGui(player, myTileEntity, pos) or player.openContainer(myTileEntity)
        • That would typically be called from Block#onBlockActivated()
      • If you want to create a container-based GUI for an item, create a class implementing INamedContainerProvider (a static inner class of the item makes sense, or perhaps an anonymous implementation), implementing createMenu() and getDisplayName() to create and return the container object as above. 
        • That would typically be called as something like NetworkHooks.OpenGui(player, new MyItemContainerProvider(stack), pos)  or player.openContainer(new MyItemContainerProvider(stack)) from Item#onItemRightClick() or Item#onItemUse()
    • player.openContainer() can be used if you have no need to pass any extra data to the client, e.g. your GUI is just displaying container slots, like a chest.  But if your client GUI needs access to the client-side tile entity, use NetworkHooks.openGui() and pass at least the tile entity's blockpos so the client container can get the GUI object. 
    • Syncing any necessary TE data to the client-side TE needs to be done separately by whatever means you choose.
    • Note that NetworkHooks.openGui() has a couple of variants to allow extra data to be passed to the client-side container object: a simple pos argument if you just need to pass the blockpos of your TE, or a more flexible Consumer<PacketBuffer> if you have more complex data to pass to the client.  The simple pos variant just calls the full-blooded Consumer<PacketBuffer> variant in any case.  It's this packet buffer that is received by the client-side container constructor.

     

    • Like 6
    • Thanks 5
    • Haha 1
  15. 5 hours ago, ImANoobApperntly said:

    but I cant seem to get the events to trigger when joining a server and Minecraft#player is always null :/ 

    Further to what everyone else has said - use the EntityJoinWorldEvent#getEntity() method, checking if it's instanceof EntityPlayer.

    Attempting to use the Minecraft class server side will crash your game when run on a dedicated server, because Minecraft doesn't exist server-side.  So drop that idea now, it's a non-starter.

    • Thanks 1
  16. On 6/5/2019 at 12:35 AM, Draco18s said:

    A little offtopic (sorry), but is there a particular reason you're calling markDirty() in getCapability()?  Bearing in mind that markDirty() calls World#updateComparatorOutputLevel() which can do a potentially non-trivial amount of work (calling Block#onNeighborChange() on all your block's neighbors, and possibly even some of their neighbors too).

×
×
  • Create New...

Important Information

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