PneumaticCraft: Repressurized

PneumaticCraft: Repressurized

50M Downloads

[Feature Request] Fluidstack NBT Support in the TPP, Refinery & Fluid Mixer

HipHopHuman opened this issue ยท 14 comments

commented

I think it's worth having this as it's own issue :)

This would lay the groundwork for some possible future features but also be immensely useful for pack devs. With this I think it'd even be possible for me to build the ice cream / resource multiplying ideas into a pack using KubeJS to test how it'd work

commented

Wanted to circle back on this one, since I can't quite remember where we left it :)

NBT support is in now for fluid ingredients & outputs (just specify NBT in the same way as you would for item ingredients & outputs). Do you recall what else was needed? Maybe it's worth trying some experimental recipes in the TPP/Refinery/Fluid Mixer and seeing what breaks. If the required fixes aren't too radical, I can probably get them in before the 1.18 port...

commented

I can't really give you a technical answer to this question, since I have very little experience with coding mods. What I can do is fire up a test bed instance with PNCR+KubeJS and see what's possible. I think if I attempt to add a more basic version of the ice cream idea, it should shed some light on what's missing and I'll report those findings in this issue. It'll take a while though.

commented

@desht I got to the point where I'm implementing the actual Ice Cream in the fluid mixer, with a default NBT { "flavor": "Regular" }.

It's not working. This is the "datapack" (actually done via KubeJS):

event.custom({
  type: "pneumaticcraft:fluid_mixer",
  pressure: 3,
  time: 300,
  input1: {
    type: "pneumaticcraft:fluid",
    fluid: "kubejs:nitrogen",
    amount: 1000
  },
  input2: {
    type: "pneumaticcraft:fluid",
    fluid: "kubejs:sweetened_milk",
    amount: 1000
  },
  fluid_output: {
    fluid: "kubejs:liquid_ice_cream",
    nbt: `{"flavor":"Regular"}`,
    amount: 1250
  }
})

I have already tried adding type: "forge:nbt" to the fluid_output section, but it didn't work. When the Ice Cream is crafted, it comes out as just a plain Ice Cream fluid with no attached NBT data. Am I missing something?

commented

Those look like backquotes there, which isn't valid JSON syntax. Correct would be:

"fluid_output": {
    "fluid": "kubejs:liquid_ice_cream",
    "nbt": "{\"flavor\":\"Regular\"}",
    "amount": 1250
}

JSON requires double-quoted strings, and any embedded quotes must be escaped with a backslash \.

commented

(This comment is a WIP)

TPP Changes

Item NBT

The TPP needs dynamic NBT support on inputs and outputs, with the ability to specify a relationship between them. One should be able to determine the quantity of output based on the quantity of input. This is needed to facilitate a use case like that of an Air Canister's stored air producing a relative amount of Liquified Air in the TPP. Supporting this isn't even possible with KubeJS right now, and the integration with the Holding enchant makes determining a theoretical maximum more complicated.

Max Fluid Output Quantity

I toyed with the idea of allowing Reinforced Canisters - at the same ratio as the basic ones, the output amount equates to about 20,000ml. The TPP's internal tank does not support any more than 16kmb, even with volume upgrades, so any output value larger than 16kmb "stalls" the TPP.


Refinery Changes (optional for now)

I experimented with separating Liquified Air into its constituent gases. It was really hard to get an accurate real-life representation of the percentage distribution (which I'm assuming is due to fractional limitations with the millibucket unit) so some "hand-wavium" (as you call it) had to be used and it produces a little too much CO2 (not that I have a use in mind for that at all, just wanted to see what working with the Refinery datapack format was like).

I think an improvement could be made here - allow for much higher numbers (even exceeding 16000mb), but add a new field "increment" to both the input and output fields to control the speed at which the fluid "refines". This way, one could get a percentage distribution like 78%, 21%, 0.9%, 0.1% (which is closer to but not quite as accurate as real life). Then have the information that renders in JEI be determined by the increment, rather than the input amount. This way, more accurate distributions can be made and JEI can still render them within reason.

commented

@desht that's not the issue, this isn't JSON, it's JavaScript. Backticks are valid - I use them in several other scripts. KubeJS converts this JS Object into the correct JSON representation. I use them to avoid having ugly escape characters and they're more distinguishable from single quotes

commented

Ah, ok. I think I need to get a copy of the kubejs config you're using so I can test where it's going wrong...

commented

Sure thing. Once you've installed KubeJS:

Make a .js file (filename doesn't matter) in the <instance>/kubejs/startup_scripts folder, and paste this in:

onEvent('fluid.registry', event => {
  // add a liquid air fluid
  event.create('liquified_air')
      .textureThin(0xa1c2f7)
      .bucketColor(0xa1c2f7)
      .displayName('Liquified Air');

    // add a liquid nitrogen fluid
  event.create('nitrogen')
      .textureThin(0xe9f4f5)
      .bucketColor(0xe9f4f5)
      .displayName('Nitrogen');

    // add a liquid oxygen fluid
  event.create('oxygen')
      .textureThin(0xa1f7ee)
      .bucketColor(0xa1f7ee)
      .displayName('Oxygen');

    // add an Argon fluid
  event.create('argon')
      .textureThin(0xc5c8e3)
      .bucketColor(0xc5c8e3)
      .displayName('Argon');

    // add a Co2 fluid
  event.create('co2')
      .textureThin(0xdbb13d)
      .bucketColor(0xdbb13d)
      .displayName('CO2');

    // add a Sweetened Milk fluid
  event.create('sweetened_milk')
      .textureThin(0xffffff)
      .bucketColor(0xffffff)
      .displayName('Sweetened Milk');

    // add an Ice Cream fluid
    event.create('liquid_ice_cream')
      .textureThick(0xfafaeb)
      .bucketColor(0xfafaeb)
      .displayName('Ice Cream');
})

Then, make a .js file in the <instance>/kubejs/server_scripts folder, and paste this in:

onEvent('recipes', event => {
  // liquified air from air canisters in TPP
  event.custom({
    type: 'pneumaticcraft:thermo_plant',
    exothermic: false,
    speed: 0.2,
    item_input: {
      type: 'forge:nbt',
      item: 'pneumaticcraft:air_canister',
      nbt: `{"pneumaticcraft:air": 30000}`
    },
    temperature: {
      max_temp: 77.15,
      min_temp: 67.15
    },
    fluid_output: {
      fluid: 'kubejs:liquified_air',
      amount: 5000
    },
    item_output: {
      item: 'pneumaticcraft:air_canister'
    }
  }).id('air_canister_to_liquid_air');

  event.custom({
    type: "pneumaticcraft:thermo_plant",
    exothermic: false,
    speed: 0.6,
    item_input: {
      type: 'forge:nbt',
      item: 'pneumaticcraft:reinforced_air_canister',
      nbt: `{"pneumaticcraft:air": 120000}`
    },
    temperature: {
      max_temp: 77.15,
      min_temp: 67.15
    },
    fluid_output: {
      fluid: 'kubejs:liquified_air',
      amount: 16000
    },
    item_output: {
      item: 'pneumaticcraft:reinforced_air_canister'
    }
  }).id('reinforced_canister_to_liquid_air')

  // sweetened milk
  event.custom({
    type: "pneumaticcraft:thermo_plant",
    exothermic: true,
    speed: 0.2,
    pressure: 2,
    temperature: {
      min_temp: 345.15
    },
    item_input: {
      item: "minecraft:sugar",
      amount: 1
    },
    fluid_input: {
      type: 'pneumaticcraft:fluid',
      fluid: 'minecraft:milk',
      amount: 1000
    },
    fluid_output: {
      fluid: 'kubejs:sweetened_milk',
      amount: 1000
    }
  })

  // liquid air components
  event.custom({
    type: "pneumaticcraft:refinery",
    temperature: {
      max_temp: 73.15
    },
    input: {
      type: "pneumaticcraft:fluid",
      fluid: "kubejs:liquified_air",
      amount: 10
    },
    results: [
      { fluid: "kubejs:nitrogen", amount: 4 },
      { fluid: "kubejs:oxygen", amount: 3 },
      { fluid: "kubejs:argon", amount: 2 },
      { fluid: "kubejs:co2", amount: 1 }
    ]
  }).id('liquid_air_to_constituents')

  // ice cream!
  event.custom({
    type: "pneumaticcraft:fluid_mixer",
    pressure: 3,
    time: 300,
    input1: {
      type: "pneumaticcraft:fluid",
      fluid: "kubejs:nitrogen",
      amount: 1000
    },
    input2: {
      type: "pneumaticcraft:fluid",
      fluid: "kubejs:sweetened_milk",
      amount: 1000
    },
    fluid_output: {
      fluid: "kubejs:liquid_ice_cream",
      nbt: `{"flavor":"Regular"}`,
      amount: 1250
    }
  })
})

Some helpful things to know as you make changes with KubeJS:

  • typing /kubejs hand will give you the NBT/Item data for the item you're holding
  • typing /kubejs reload <argument> allows you to reload startup, server, and client scripts, as well as textures (so you don't have to restart the game all the time)
  • if those fail, you have the vanilla /reload command for reloading server stuff, as well as F3+T for reloading clientside stuff
  • if all that fails, restart the game (might be needed if you change any fluid properties)
  • warning/error logs can be found in the <instance>/logs/kubejs folder
commented

Thanks. Already somewhat familiar with KubeJS (it's in my dev world already for testing purposes, need to be sure dynamic recipe management works as expected...)

commented

Other question: what did you check to determine that the output fluid from the Fluid Mixer recipe was missing the NBT data?

commented

Just tested, the Fluid Mixer output tank is definitely getting a fluid with the right NBT - here's a screenshot from the debug session I'm running now:

image

commented

Note, extracting that fluid with a bucket will not preserve the NBT, because NBT-preserving behaviour is not part of vanilla/Forge bucket handling by default. To preserve NBT, the custom fluid (i.e. your Ice Cream) would need to override FluidAttributes#getBucket() to store the fluidstack NBT in the bucket itemstack (an example of a mod that does this is Immersive Engineering and its buckets of potion fluid). I'm not sure if KubeJS allows that level of customisability...

Also, for this to work sensibly, the FluidStack class (a Forge class) would need a method to add tooltip text similar to the ItemStack#getTooltipLines() method. Such a method doesn't exist, so there's no way of adding tooltip data in the GUI based on the the fluid's NBT.

At this point, I'm thinking you're really going to need a separate fluid for each flavour...

commented

That bucket thing explains it then - I was under the impression that NBT data was preserved as long as the fluid was in a bucket or container, and only lost NBT when placed in the world, because I read that somewhere on the KubeJS Discord history. I'll have to look into it - KubeJS may not have anything to preserve NBT data on bucket items built in, but it does give me the ability to create custom items with NBT as well as the ability to override right-click actions and hooks into the underlying mod's API (I can theoretically check which fluids are stored in a machine), so it'll be tedious, but should be possible.

As for overriding tooltips, I actually requested that be a feature of KubeJS a while ago, with different text based on NBT (for my custom Tool Belt in my PNC pack) and it was implemented by Lat rather quickly - KubeJS can absolutely handle giving items custom tooltip text based on NBT and even overriding existing tooltip lines with custom colors. I'm not sure it would work inside a machine GUI though, but worth a try.

commented

The tooltip thing probably would need a bit of support from me in code (my fluid tank widget would need a line to retrieve the tooltip data from the fluidstack somehow and display it, which it doesn't do right now)