NeoForge icon indicating copy to clipboard operation
NeoForge copied to clipboard

FluidResource and ItemResource proof of concept

Open Technici4n opened this issue 3 months ago • 6 comments

Currently throwing ideas around...

FluidStack and ItemStack are very convenient, but they are also mutable. There are cases where we want to prevent mutation of fluid and item stacks. There are also many use cases where we would really like an immutable and count-less stack, for example for filtering, recipe ingredients, or other logic that should not depend on the count/amount.

This proof of concept is motivated by the move of ItemStack (and FluidStack) from NBT to data components. Data components are immutable. This makes exposing an immutable abstraction of a stack very practical, as we just need to expose 1) the item or fluid, 2) the count or amount and 3) an immutable data component map.

The goal is to provide the necessary abstractions in this PR for modder that want to move to immutable stack handling.

Right now this PR adds:

  • FluidResource: immutable fluid and component map. Can be seen as a countless immutable FluidStack.
  • ItemResource: immutable item and component map. Can be seen as a countless immutable ItemStack.
  • IResource is a supertype of these two, in preparation for more generic handling of resources.
  • ResourceAmount is a simple record of a resource and an amount. This can be used as an immutable stack.

Note that thanks to stacks being shallow-copied, stack copies have become cheap. Calling stack.copy() will allocate exactly two objects regardless of the stored components. The backing component map is only copied lazily if one of the stacks is mutated.

Conversions:

  • From stack to resource: FluidResource.of(fluidStack).
  • From resource + amount to stack: fluidResource.toStack(amount).
  • From ResourceAmount to resource: resourceAmount.resource().
  • From resource + amount to ResourceAmount: new ResourceAmount<>(resource, amount).
  • From stack to ResourceAmount: stack.immutable().
  • From ResourceAmount to stack: FluidStack.of(resourceAmount).

Technici4n avatar Mar 15 '24 16:03 Technici4n

  • [x] Publish PR to GitHub Packages

Last commit published: 5e560876876237b60e9cda4cbc9dbdba71061c61.

PR Publishing

The artifacts published by this PR:

Repository Declaration

In order to use the artifacts published by the PR, add the following repository to your buildscript:

repositories {
    maven {
        name 'Maven for PR #715' // https://github.com/neoforged/NeoForge/pull/715
        url 'https://prmaven.neoforged.net/NeoForge/pr715'
        content {
            includeModule('net.neoforged', 'neoforge')
        }
    }
}

MDK installation

In order to setup a MDK using the latest PR version, run the following commands in a terminal.
The script works on both *nix and Windows as long as you have the JDK bin folder on the path.
The script will clone the MDK in a folder named NeoForge-pr715.
On Powershell you will need to remove the -L flag from the curl invocation.

mkdir NeoForge-pr715
cd NeoForge-pr715
curl -L https://prmaven.neoforged.net/NeoForge/pr715/net/neoforged/neoforge/20.5.0-alpha.24w11a.20240318.171240/mdk-pr715.zip -o mdk.zip
jar xf mdk.zip
rm mdk.zip || del mdk.zip

To test a production environment, you can download the installer from here.

Can you add methods like toImmutable() to ItemStack and FluidStack, you know, java doesn't have extension methods and it's a pain to use these factories.

vfyjxf avatar Mar 17 '24 14:03 vfyjxf

toResource/getResource is probably a better name

KnightMiner avatar Mar 17 '24 17:03 KnightMiner

toResource/getResource is probably a better name

Yeah, that's what I meant.

vfyjxf avatar Mar 17 '24 17:03 vfyjxf

Updated with more codecs, and convenience methods.

While we are not there yet, here is what I think that a good objective would be. You should be able to replace the following ItemStack code:

ItemStack stack = getStack();
stack.shrink(16);
stack.set(COMPONENT_1, someComponent);
stack.remove(COMPONENT_2);
// No need to call setStack(stack) because we are mutating the stack directly...

by the following code based on immutable resources:

ResourceAmount<ItemResource> stack = getStack();
stack = stack.shrink(16);
stack = stack.with(resource -> resource
        .set(COMPONENT_1, someComponent)
        .remove(COMPONENT_2));
setStack(stack);
     

Technici4n avatar Mar 18 '24 17:03 Technici4n

@Technici4n isBlank -> isEmpty in IResource?

Spinoscythe avatar Mar 20 '24 20:03 Spinoscythe