Skip to content

Instantly share code, notes, and snippets.

@X-Niter
Last active December 20, 2022 22:36
Show Gist options
  • Save X-Niter/83ce88193e803249ebdec0e8e7c0b47e to your computer and use it in GitHub Desktop.
Save X-Niter/83ce88193e803249ebdec0e8e7c0b47e to your computer and use it in GitHub Desktop.
public class FluidRegistry {
private static final ResourceLocation OVERLAY = new ResourceLocation("block/water_overlay");
private static final ResourceLocation RENDER_OVERLAY = new ResourceLocation("textures/misc/underwater.png");
private static final ResourceLocation LIQUID = new ResourceLocation("block/water_still");
private static final ResourceLocation LIQUID_FLOW = new ResourceLocation("block/water_flow");
private final DeferredRegister<Fluid> FLUIDS;
private final DeferredRegister<FluidType> FLUID_TYPES;
private final DeferredRegister<Block> LIQUID_BLOCKS;
private final DeferredRegister<Item> BUCKETS;
private static final List<FluidProviderRegistryObject<? extends ChemlibFluidTypes, ?, ?, ?, ?>> allFluids = new ArrayList<>();
private final String modid;
public FluidRegistry(String modid) {
this.modid = modid;
FLUIDS = DeferredRegister.create(ForgeRegistries.FLUIDS, modid);
FLUID_TYPES = DeferredRegister.create(ForgeRegistries.Keys.FLUID_TYPES, modid);
LIQUID_BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, modid);
BUCKETS = DeferredRegister.create(ForgeRegistries.ITEMS, modid);
}
public DeferredRegister<FluidType> getFluidTypes() {
return this.FLUID_TYPES;
}
public FluidProviderRegistryObject<ChemlibFluidTypes, Source, Flowing, LiquidBlock, BucketItem> registerLiquidChemical(String name, int pColor) {
int density = Math.round(100);
return register(name, properties -> properties
.temperature(0)
.density(density)
.viscosity(density)
.lightLevel(0), renderProperties -> renderProperties
.tint(pColor)
);
}
public static FluidType.Properties getFluidTypeProperties() {
return FluidType.Properties.create()
.sound(SoundActions.BUCKET_FILL, SoundEvents.BUCKET_FILL)
.sound(SoundActions.BUCKET_EMPTY, SoundEvents.BUCKET_EMPTY);
}
public void registerElementalFluids() {
for (JsonElement jsonElement : ELEMENTS_JSON.getAsJsonArray("elements")) {
JsonObject object = jsonElement.getAsJsonObject();
String elementName = object.get("name").getAsString();
MatterState matterState = MatterState.valueOf(object.get("matter_state").getAsString().toUpperCase());
boolean artificial = object.has("artificial") && object.get("artificial").getAsBoolean();
String color = object.get("color").getAsString();
if (!artificial) {
switch (matterState) {
case LIQUID, GAS -> {
boolean hasFluid = object.has("has_fluid") && object.get("has_fluid").getAsBoolean();
if (!hasFluid) {
JsonObject properties = object.get("fluid_properties").getAsJsonObject();
int slopeFindDistance = properties.has("slope_find_distance") ? properties.get("slope_find_distance").getAsInt() : 4;
int decreasePerBlock = properties.has("decrease_per_block") ? properties.get("decrease_per_block").getAsInt() : 1;
register(
elementName,
fluidTypePropertiesFactory(properties, elementName),
renderProperties -> renderProperties
.tint((int) Long.parseLong(color, 16))
);
}
}
}
}
}
}
public void registerCompoundFluids() {// TODO ADD IN THE JSON COMPOUND DYNAMIC FLUID REGISTRATION SIMILAR TO THE ABOVE METHOD
}
public FluidProviderRegistryObject<ChemlibFluidTypes, Source, Flowing, LiquidBlock, BucketItem> register(String name, UnaryOperator<FluidTypeRenderProperties> renderProperties) {
return register(name, UnaryOperator.identity(), renderProperties);
}
public FluidProviderRegistryObject<ChemlibFluidTypes, Source, Flowing, LiquidBlock, BucketItem> register(
String name, UnaryOperator<FluidType.Properties> properties, UnaryOperator<FluidTypeRenderProperties> renderProperties) {
return register(name, BucketItem::new, properties, renderProperties);
}
public FluidProviderRegistryObject<ChemlibFluidTypes, Source, Flowing, LiquidBlock, BucketItem> register(
String name, FluidType.Properties properties, UnaryOperator<FluidTypeRenderProperties> renderProperties) {
return register(name, BucketItem::new, properties, renderProperties);
}
public <BUCKET extends BucketItem> FluidProviderRegistryObject<ChemlibFluidTypes, Source, Flowing, LiquidBlock, BUCKET> register(
String name, BucketCreator<BUCKET> bucketCreator, FluidType.Properties fluidProperties, UnaryOperator<FluidTypeRenderProperties> renderProperties) {
return register(name, fluidProperties, renderProperties.apply(FluidTypeRenderProperties.builder()), bucketCreator,
ChemlibFluidTypes::new);
}
public <BUCKET extends BucketItem> FluidProviderRegistryObject<ChemlibFluidTypes, Source, Flowing, LiquidBlock, BUCKET> register(
String name, BucketCreator<BUCKET> bucketCreator, UnaryOperator<FluidType.Properties> fluidProperties, UnaryOperator<FluidTypeRenderProperties> renderProperties) {
return register(name, fluidProperties.apply(getFluidTypeProperties()), renderProperties.apply(FluidTypeRenderProperties.builder()), bucketCreator,
ChemlibFluidTypes::new);
}
public <TYPE extends ChemlibFluidTypes, BUCKET extends BucketItem> FluidProviderRegistryObject<TYPE, Source, Flowing, LiquidBlock, BUCKET> register(
String pName, FluidType.Properties properties, FluidTypeRenderProperties renderProperties, BucketCreator<BUCKET> bucketCreator, BiFunction<FluidType.Properties, FluidTypeRenderProperties, TYPE> fluidTypeCreator) {
String fluidSource = pName + "_fluid";
String fluidFlowing = pName + "_flowing";
String bucket = pName + "_bucket";
//Set the translation string to the same as the block
//properties.descriptionId(Util.makeDescriptionId("block", new ResourceLocation(modid, pName)));
//Create the registry object and let the values init to null as before we actually call get on them, we will update the backing values
FluidProviderRegistryObject<TYPE, Source, Flowing, LiquidBlock, BUCKET> fluidRegistryObject = new FluidProviderRegistryObject<>();
//Pass in suppliers that are wrapped instead of direct references to the registry objects, so that when we update the registry object to
// point to a new object it gets updated properly.
ForgeFlowingFluid.Properties fluidProperties = new ForgeFlowingFluid.Properties(fluidRegistryObject::getFluidType, fluidRegistryObject::getStillFluid,
fluidRegistryObject::getFlowingFluid).bucket(fluidRegistryObject::getBucket).block(fluidRegistryObject::getBlock);
//Update the references to objects that are retrieved from the deferred registers
fluidRegistryObject.updateFluidType(FLUID_TYPES.register(pName, () ->
fluidTypeCreator.apply(properties, renderProperties)));
fluidRegistryObject.updateStill(FLUIDS.register(fluidSource, () ->
new Source(fluidProperties)));
fluidRegistryObject.updateFlowing(FLUIDS.register(fluidFlowing, () ->
new Flowing(fluidProperties)));
//Note: The block properties used here is a copy of the ones for water
fluidRegistryObject.updateBlock(LIQUID_BLOCKS.register(pName, () ->
new LiquidBlock(fluidRegistryObject::getStillFluid, BlockBehaviour.Properties.of(Material.WATER))));
fluidRegistryObject.updateBucket(BUCKETS.register(bucket, () ->
bucketCreator.create(fluidRegistryObject::getStillFluid, new Item.Properties().tab(ItemRegistry.MISC_TAB).stacksTo(1))));
allFluids.add(fluidRegistryObject);
return fluidRegistryObject;
}
public void register(IEventBus bus) {
// Fires the JSON OBJECT Elements to get registered as fluids first
registerElementalFluids();
// Register fluids as normal
FLUID_TYPES.register(bus);
FLUIDS.register(bus);
LIQUID_BLOCKS.register(bus);
BUCKETS.register(bus);
}
public List<FluidProviderRegistryObject<? extends ChemlibFluidTypes, ?, ?, ?, ?>> getAllFluids() {
return Collections.unmodifiableList(allFluids);
}
@FunctionalInterface
public interface BucketCreator<BUCKET extends BucketItem> {
BUCKET create(Supplier<? extends Fluid> supplier, Item.Properties builder);
}
public static class FluidTypeRenderProperties {
private ResourceLocation stillTexture = LIQUID;
private ResourceLocation flowingTexture = LIQUID_FLOW;
private ResourceLocation overlayTexture = OVERLAY;
private ResourceLocation renderOverlayTexture = RENDER_OVERLAY;
private int color = 0xFFFFFFFF;
private FluidTypeRenderProperties() {
}
public static FluidTypeRenderProperties builder() {
return new FluidTypeRenderProperties();
}
public FluidTypeRenderProperties texture(ResourceLocation still, ResourceLocation flowing) {
this.stillTexture = still;
this.flowingTexture = flowing;
return this;
}
public FluidTypeRenderProperties texture(ResourceLocation still, ResourceLocation flowing, ResourceLocation overlay) {
this.stillTexture = still;
this.flowingTexture = flowing;
this.overlayTexture = overlay;
return this;
}
public FluidTypeRenderProperties renderOverlay(ResourceLocation renderOverlay) {
this.renderOverlayTexture = renderOverlay;
return this;
}
public FluidTypeRenderProperties tint(int color) {
this.color = color;
return this;
}
}
public static class ChemlibFluidTypes extends FluidType {
private final ResourceLocation stillTexture;
private final ResourceLocation flowingTexture;
private final ResourceLocation overlayTexture;
private final ResourceLocation renderOverlayTexture;
private final int color;
public ChemlibFluidTypes(FluidType.Properties properties, FluidTypeRenderProperties renderProperties) {
super(properties);
this.stillTexture = renderProperties.stillTexture;
this.flowingTexture = renderProperties.flowingTexture;
this.overlayTexture = renderProperties.overlayTexture;
this.renderOverlayTexture = renderProperties.renderOverlayTexture;
this.color = renderProperties.color;
}
//For use in datagen
// TODO: Could this be the solution to solve JEI and Mek rendering our fluids invisible???
public ResourceLocation getStillTexture() {
return stillTexture;
}
@Override
public boolean isVaporizedOnPlacement(Level level, BlockPos pos, FluidStack stack) {
//TODO - I wonder if we can allow json object definition for if this fluid vaporizes? That would be cool
return false;
}
@Override
public void initializeClient(Consumer<IClientFluidTypeExtensions> consumer) {
consumer.accept(new IClientFluidTypeExtensions() {
@Override
public ResourceLocation getStillTexture() {
return stillTexture;
}
@Override
public ResourceLocation getFlowingTexture() {
return flowingTexture;
}
@Override
public ResourceLocation getOverlayTexture() {
return overlayTexture;
}
@Nullable
@Override
public ResourceLocation getRenderOverlayTexture(Minecraft mc) {
return renderOverlayTexture;
}
@Override
public int getTintColor() {
return color;
}
});
}
}
/*
This section defines helper methods for accessing fluids and fluid types from the registry.
The first set of helper methods provide streams of fluid objects.
*/
public Stream<Fluid> getFluidsAsStream() {
return FLUIDS.getEntries().stream().map(RegistryObject::get);
}
public Stream<FluidType> getFluidTypesAsStream() {
return getFluidsAsStream().map(Fluid::getFluidType);
}
public Stream<ForgeFlowingFluid.Source> getSourceFluidsAsStream() {
return getFluidsAsStream().filter(fluid -> fluid instanceof ForgeFlowingFluid.Source).map(fluid -> (ForgeFlowingFluid.Source) fluid);
}
public Stream<ForgeFlowingFluid.Source> getLiquidSourceFluidsAsStream() {
return getSourceFluidsAsStream().filter(source -> !source.getFluidType().isLighterThanAir());
}
public Stream<ForgeFlowingFluid.Source> getGasSourceFluidsAsStream() {
return getSourceFluidsAsStream().filter(source -> source.getFluidType().isLighterThanAir());
}
/*
This set of helper methods provide lists of fluid objects.
*/
public List<Fluid> getFluids() {
return getFluidsAsStream().collect(Collectors.toList());
}
public List<Fluid> getSourceFluids() {
return getSourceFluidsAsStream().collect(Collectors.toList());
}
public List<Fluid> getLiquidSourceFluids() {
return getLiquidSourceFluidsAsStream().collect(Collectors.toList());
}
public List<Fluid> getGasSourceFluids() {
return getGasSourceFluidsAsStream().collect(Collectors.toList());
}
/*
Get a single object by filtering a registry stream.
*/
public Optional<FluidType> getFluidTypeByName(String pName) {
return getFluidTypesAsStream().filter(fluidType -> Objects.requireNonNull(ForgeRegistries.FLUID_TYPES.get().getKey(fluidType)).getPath().equals(pName)).findFirst();
}
public Optional<ForgeFlowingFluid.Source> getSourceFluidByName(String pName) {
return getSourceFluidsAsStream().filter(source -> Objects.requireNonNull(ForgeRegistries.FLUID_TYPES.get().getKey(source.getFluidType())).getPath().equals(pName)).findFirst();
}
public Optional<ForgeFlowingFluid.Source> getLiquidSourceFluidByName(String pName) {
return getLiquidSourceFluidsAsStream().filter(source -> Objects.requireNonNull(ForgeRegistries.FLUID_TYPES.get().getKey(source.getFluidType())).getPath().equals(pName)).findFirst();
}
public Optional<ForgeFlowingFluid.Source> getGasSourceFluidByName(String pName) {
return getGasSourceFluidsAsStream().filter(source -> Objects.requireNonNull(ForgeRegistries.FLUID_TYPES.get().getKey(source.getFluidType())).getPath().equals(pName)).findFirst();
}
/*
This set of helpers define methods to get blocks and items from the fluid registry.
*/
public Stream<LiquidBlock> getLiquidBlocks() {
return LIQUID_BLOCKS.getEntries().stream().map(RegistryObject::get).map(block -> (LiquidBlock) block);
}
public Stream<BucketItem> getBuckets() {
return BUCKETS.getEntries().stream().map(RegistryObject::get).map(item -> (BucketItem) item);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment