Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by Alpvax

  1. If you are new to modding, I would suggest starting with 1.15, not 1.16. 1.16 has only just been released, so there are still bugs and issues being worked out. You need to subscribe to one of the render events, and render your text inside the event listener, in the same way you would in any other GUI.
  2. When I was starting to use DataGenerators, I found that Lex's mod CobbleForDays helped me understand.
  3. I don't agree with that logic. Yes, 1 bucket of a fluid is 1 block of the fluid (although it actually doesn't quite reach the top, so you could argue that is not true), but there is nothing saying 1 solid block is equivalent to 1 bucket of that material melted down. Liquid doesn't have ingots or nuggets, so those solid conversions do not need to apply to them. If we keep it as 1 block of a solid becomes a bucket-and-a-bit, all it means is that you don't fit an even number of blocks into your tanks. But I don't see why that is an issue, because once you have converted it to a fluid, whatever you're using it for (machines?) probably doesn't care about the solid amount. If you want to transfer exact amounts, use the blocks. They are probably easier to transport anyway (there is a vanilla mechanic for it, and you can usually carry 64 per inventory slot as opposed to the 1 in a bucket).
  4. I don't see how that is true at all. Why does 1 block have to fit in 1 bucket? If we just accept that 1 block is 1296mb, everything works. I don't see why we have to add the restriction that 1 bucket is 1 (solid) block. We can just accept that melting it makes it less dense, therefore bigger.
  5. Bear in mind that more players use metric systems than imperial (according to minecraft server statistics, and the fact that there are few countries which still use the imperial system). It is far easier for users to understand that half a bucket is 500mb, than it is for them to see 648 "atoms" (If that is the approach, I would prefer to use something like "voxellites" which has no real-world bearing than "atoms" which could cause huge confusion for users of chemical mods). And to the next argument that you would just display it as "3 1/2 buckets" or 3 1/1296 buckets", that is hugely unnatural for me (and presumably many others). I'm not sure what the issue with 144mb/ingot is. Why does a melted compound have to fit in the same space as a solid one? It doesn't in real life. And as far as cauldrons, I think it's fair enough to just lose 1mb in a cauldron. Who cares about 1/1000 of a bucket of an infinite resource? And for those mods which have finite supplies of water, they usually add their own mechanisms for collecting/storing it, so the cauldron issue is moot.
  6. Do you just mean with spawn eggs? Or do commands not work either? Vanilla spawn eggs (I believe) have the entity set when they are created, so if you override the entity, I think you also need to override the spawn egg to make it work. Disclaimer: I've not actually done it myself, but I believe that is the case.
  7. I don't believe that is the case. Look at the subclasses of JSONReloadListener (recipes, loot tables, advancements etc.). You don't care which files exist, just try to load all of them.
  8. You create a new (empty) set, then loop through it. Twice. Neither of your loops will do anything, as they are both always going to be empty when the loop is run. I would suggest including your modid in the path, to stop there being conflicts. I would also not limit it to "supported" mods. That way support for third party mods can be added by datapacks (or even included in those mods if your mod becomes popular enough). I would recommend using a path such as data/<datapackid>/<your mod id>/entities/<modid>/<mobname>.json That would mean that your zombie definition would be at data/<your mod id>/<your mod id>/entities/minecraft/zombie.json It means your modid is duplicated, but there is no risk of another mod using the entities path and causing your mod to crash.
  9. As the Optional annotation has now disappeared in favour of capabilities, there is now no way to add optional features to non-TileEntity blocks. An example use case would be proper fluid handling for vanilla cauldrons, or handling of different blocks' "heat" values. It would have to return a function (BlockState, IWorldReader) -> custom capability instance. And couldn't be cached without more work. The capability would also not be able to be serialisable to NBT (obviously non-TEs don't have NBT). It would effectively be a mapping of blockstate -> capability. If we restricted it to readonly capabilities there would be no issues with modders caching the capability and modifying something they shouldn't, but it would for example allow extraction from cauldrons, but not insertion. The optimum solution would be for the capabilities to be cached when first accessed (Probably by calling World/Chunk#getBlockCapability(Capability, BlockPos)) which would then be returned every time afterwards (until the position was unloaded). It would allow ModB to support ModA's X system, without having to inherit from an API which may not exist at runtime. This post is intended as the starting point of a discussion, if it is an idea that no-one is interested in, that is fine. The alternative is to just ship ModA's API with ModB, or at least the interfaces you are implementing in your block, but that has no way of adding capabilities to blocks which you don't own (e.g. vanilla cauldrons, torches).
  10. I'm not exactly sure that is true, but the chunk is already loaded, so the modder can always cancel the loading screen themselves if that is not the case.
  11. Because the chunk in the other dimension is already loaded, just like when you move from one chunk to the next in the same dimension, or use the teleport command to move to a loaded chunk.
  12. I understand that (I also understand how to use DistExecutor, and use it when I need to call client side methods). My question is is it safe for me to use it as a marker, just something to double check when I'm calling my methods so I know not to call them from the wrong side. Or would javadoc be better? Apologies for somewhat hijacking the thread, I won't reply again.
  13. I have a follow up question: I have a world capability, and one of the method returns is Optional (or could be @Nullable). The LazyOptional#map argument is a NonNullFunction, and ideally I would return empty from the calling function rather than null. //Capability.class public Optional<INetworkNode> getNode(BlockPos pos) { return Optional.ofNullable(nodes.get(pos)); } //Utility class (I'm happy to change the return type to LazyOptional) public <T> Optional<T> ifNetworkNode(Function<INetworkNode, T> callback, BlockPos pos) { return getWorld().getCapability(Capabilities.NETWORK_CAPABILITY).map(graph -> graph.getNode(pos) .map(callback) .orElse(null) //<-- How can I unbox this Optional and return (Lazy)Optional.empty from the method instead of null? ); ); } Am I doing something wrong? Have I missed something obvious again? EDIT: yes I was. I just needed to call orElseThrow on the LazyOptional return getWorld().getCapability(Capabilities.NETWORK_GRAPH_CAPABILITY).map(graph -> graph.getNode(getPos()).map(callback) ).orElseThrow(() -> new NullPointerException("World %s did not have network capability attached"));
  14. How true is this? Does it do nothing, or are the methods stripped during build/run? I have used it in the past as a marker for methods which I know must only be used on the client. Does this have a functional use or is it safe to use as a marker?
  15. Look into multipart blockstate json files on the minecraft wiki, they do (almost) everything forge blockstates used to do (forge blockstates no longer exist).
  16. Because many of the vanilla methods which I'm overriding have return values... I'm dropping this thread now, Lex answered my question, and it seems you're never going to understand what I was attempting to achieve Draco.
  17. But I know it does, because I just called isPresent. I would expect it to return null/throw an NPE (either would be acceptable). Except that you cannot return anything from the second approach, which was the entire reasoning behind this query.
  18. Yes, but I'm about to use the value, so it will be calculated anyway. Either way, the issue is solved, thanks.
  19. Except the normal optional also has the value() method public, saving the orElse call. Yes, the example was in fact bad, and that was helpful, thank you. I didn't even thing of doing all the processing inside the Map function, I have always tried to make them as simple as possible.
  20. Yes, I am aware of that method. But you cannot return a value from it. (scope is now lambda scope). I was also asking about the isPresent method, not ifPresent.
  21. Is it just me, or is the LazyOptional very awkward to use? The isPresent() function seems virtually useless, what does it offer over doing .orElse(null), followed by a null check, because you cannot get the value without using orElse anyway? It seems that there is no easy way to return a value from a capability that may not be present. For example: interface CapabilitySample { int amount(); int amountMultiplier(); } //In another class: public int getAmount(ICapabilityProvider obj) { LazyOptional<CapabilitySample> cap = obj.getCapability(Capability_Instance); //************** Option 1 ************** // Works if you only need a single method from the capability return cap.map(CapabilitySample::amount).orElse(0); //But what if you need multiple methods? The following (mapping the capability twice) seems like a bad idea: return cap.map(CapabilitySample::amount).orElse(0) * cap.map(CapabilitySample::amountMultiplier).orElse(1); //************** Option 2 ************** if (cap.isPresent()) { //How do I return cap.amount() from here? There is no way to retrieve the cap.value(). //Do I really have to do the following? CapabilitySample value = cap.orElseThrow(()-> new Exception("Pointless exception which can never happen!")); return value.amount() * value.amountModifier(); } else { return 0; } //************** Option 3 ************** //Requires an entire implementation to be written with dummy methods! CapabilitySample value = cap.orElse(dummyCapabilitySample); return return value.amount() * value.amountModifier(); } Am I missing something, or is this a big oversight? Am I using capabilities wrong? Am I not supposed to return values from them, and just go all-in functional? As an unrelated aside, I also find the capability default implementation factory impossible to use, because invariably I want to use the object I am attaching to to set up the capability.
  22. Yes, but with that approach being a supplier, I am correct in thinking that it won't? Would using the delegate fix it, or is a RegistryObject the correct approach?
  • Create New...

Important Information

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