diff --git a/common/src/main/java/dev/ryanhcode/sable/physics/config/FloatingBlockMaterialProvider.java b/common/src/main/java/dev/ryanhcode/sable/physics/config/FloatingBlockMaterialProvider.java new file mode 100644 index 000000000..22edb859b --- /dev/null +++ b/common/src/main/java/dev/ryanhcode/sable/physics/config/FloatingBlockMaterialProvider.java @@ -0,0 +1,118 @@ +package dev.ryanhcode.sable.physics.config; + +import dev.ryanhcode.sable.physics.floating_block.FloatingBlockMaterial; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.data.CachedOutput; +import net.minecraft.data.DataProvider; +import net.minecraft.data.PackOutput; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; +import java.util.function.Supplier; + +public abstract class FloatingBlockMaterialProvider implements DataProvider { + protected final PackOutput.PathProvider pathProvider; + private final CompletableFuture registries; + protected final String modId; + private final Map definitions = new HashMap<>(); + + public FloatingBlockMaterialProvider(PackOutput packOutput, CompletableFuture registries, String modId) { + this.pathProvider = packOutput.createPathProvider(PackOutput.Target.DATA_PACK, "floating_block_material"); + this.registries = registries; + this.modId = modId; + } + + protected abstract void addProperties(HolderLookup.Provider holderLookup); + + public final CompletableFuture run(CachedOutput output) { + return this.registries.thenCompose((provider) -> { + final Set> list = new HashSet<>(); + this.addProperties(provider); + this.definitions.forEach((id, definition) -> { + list.add(DataProvider.saveStable(output, provider, FloatingBlockMaterial.CODEC, definition, this.pathProvider.json(id))); + }); + return CompletableFuture.allOf(list.toArray(CompletableFuture[]::new)); + }); + } + + public final FloatingBlockMaterial define(final Supplier block, double liftStrength, final Function builderFunction) { + return this.define(BuiltInRegistries.BLOCK.getKey(block.get()), liftStrength, builderFunction); + } + + public final FloatingBlockMaterial define(final ResourceLocation id, double liftStrength, final Function builderFunction) { + return this.definitions.computeIfAbsent(id, (k) -> builderFunction.apply(new Builder(liftStrength)).build()); + } + + @Override + public @NotNull String getName() { + return "Floating Block Material Properties for " + this.modId; + } + + public static class Builder { + boolean preventSelfLift = false; + boolean scaleWithPressure = false; + boolean scaleWithGravity = false; + final double liftStrength; + double transitionSpeed = 0.0d; + double slowVerticalFriction = 0.0d; + double fastVerticalFriction = 0.0d; + double slowHorizontalFriction = 0.0d; + double fastHorizontalFriction = 0.0d; + + public Builder(double liftStrength) { + this.liftStrength = liftStrength; + } + + public Builder preventSelfLift() { + this.preventSelfLift = true; + return this; + } + + public Builder scaleWithPressure() { + this.scaleWithPressure = true; + return this; + } + + public Builder scaleWithGravity() { + this.scaleWithGravity = true; + return this; + } + + public Builder transitionSpeed(double transitionSpeed) { + this.transitionSpeed = transitionSpeed; + return this; + } + + public Builder slowVerticalFriction(double slowVerticalFriction) { + this.slowVerticalFriction = slowVerticalFriction; + return this; + } + + public Builder fastVerticalFriction(double fastVerticalFriction) { + this.fastVerticalFriction = fastVerticalFriction; + return this; + } + + public Builder slowHorizontalFriction(double slowHorizontalFriction) { + this.slowHorizontalFriction = slowHorizontalFriction; + return this; + } + + public Builder fastHorizontalFriction(double fastHorizontalFriction) { + this.fastHorizontalFriction = fastHorizontalFriction; + return this; + } + + public FloatingBlockMaterial build() { + return new FloatingBlockMaterial(this.preventSelfLift, this.scaleWithPressure, this.scaleWithGravity, this.liftStrength, this.transitionSpeed, this.slowVerticalFriction, this.fastVerticalFriction, this.slowHorizontalFriction, this.fastHorizontalFriction); + } + } +} diff --git a/common/src/main/java/dev/ryanhcode/sable/physics/config/block_properties/BlockPhysicsPropertiesProvider.java b/common/src/main/java/dev/ryanhcode/sable/physics/config/block_properties/BlockPhysicsPropertiesProvider.java new file mode 100644 index 000000000..815f5c4af --- /dev/null +++ b/common/src/main/java/dev/ryanhcode/sable/physics/config/block_properties/BlockPhysicsPropertiesProvider.java @@ -0,0 +1,159 @@ +package dev.ryanhcode.sable.physics.config.block_properties; + +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.data.CachedOutput; +import net.minecraft.data.DataProvider; +import net.minecraft.data.PackOutput; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.util.ExtraCodecs; +import net.minecraft.world.level.block.Block; +import org.jetbrains.annotations.NotNull; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; +import java.util.function.Supplier; + +public abstract class BlockPhysicsPropertiesProvider implements DataProvider { + protected final PackOutput.PathProvider pathProvider; + private final CompletableFuture registries; + protected final String modId; + private final Map definitions = new HashMap<>(); + + public BlockPhysicsPropertiesProvider(PackOutput packOutput, CompletableFuture registries, String modId) { + this.pathProvider = packOutput.createPathProvider(PackOutput.Target.DATA_PACK, "physics_block_properties"); + this.registries = registries; + this.modId = modId; + } + + protected abstract void addProperties(HolderLookup.Provider holderLookup); + + public final CompletableFuture run(CachedOutput output) { + return this.registries.thenCompose((provider) -> { + final Set> list = new HashSet<>(); + this.addProperties(provider); + this.definitions.forEach((id, definition) -> { + list.add(DataProvider.saveStable(output, provider, PhysicsBlockPropertiesDefinition.CODEC, definition, this.pathProvider.json(id))); + }); + return CompletableFuture.allOf(list.toArray(CompletableFuture[]::new)); + }); + } + + public final PhysicsBlockPropertiesDefinition define(final TagKey key, final Function builderFunction) { + return this.define(key.location(), true, builderFunction); + } + + public final PhysicsBlockPropertiesDefinition define(final Supplier block, final Function builderFunction) { + return this.define(BuiltInRegistries.BLOCK.getKey(block.get()), false, builderFunction); + } + + public final PhysicsBlockPropertiesDefinition define(final ResourceLocation id, boolean tag, final Function builderFunction) { + return this.definitions.computeIfAbsent(id, (k) -> builderFunction.apply(new Builder(k, tag)).build()); + } + + @Override + public @NotNull String getName() { + return "Block Physics Properties for " + this.modId; + } + + public static class Builder { + final ExtraCodecs.TagOrElementLocation selector; + int priority = 1000; + Map properties = new HashMap<>(); + Map> overrides = null; + + public Builder(ResourceLocation id, boolean tag) { + this.selector = new ExtraCodecs.TagOrElementLocation(id, tag); + } + + /** + * Sets the priority of the properties + * @param priority the priority + * @return this + */ + public Builder priority(int priority) { + this.priority = priority; + return this; + } + + /** + * @param properties function to apply multiple properties in one place + * @return this + * @see PhysicsBlockPropertyTypes + */ + public Builder properties(Function properties) { + this.properties.putAll(properties.apply(new PropertyBuilder()).getProperties()); + return this; + } + + /** + * @param type the physics property type + * @param value the value to set + * @return this + * @see PhysicsBlockPropertyTypes + */ + public Builder property(PhysicsBlockPropertyTypes.PhysicsBlockPropertyType type, T value) { + this.properties.put(PhysicsBlockPropertyTypes.REGISTRY.getKey(type), value); + return this; + } + + /** + * @param type the physics property type + * @param value the value to set + * @return this + * @see PhysicsBlockPropertyTypes + */ + public Builder property(Supplier> type, T value) { + this.properties.put(PhysicsBlockPropertyTypes.REGISTRY.getKey(type.get()), value); + return this; + } + + /** + * @param conditions conditions that must be met for these properties + * @param properties function to assign override properties + * @return this + * @see BlockStateConditionSet.Builder + */ + public Builder override(BlockStateConditionSet conditions, Function properties) { + if (this.overrides == null) this.overrides = new HashMap<>(); + this.overrides.put(conditions, properties.apply(new PropertyBuilder()).getProperties()); + return this; + } + + public PhysicsBlockPropertiesDefinition build() { + return new PhysicsBlockPropertiesDefinition(this.selector, this.priority, this.properties, Optional.ofNullable(this.overrides)); + } + + public static class PropertyBuilder { + Map properties = new HashMap<>(); + + /** + * @param type the physics property type + * @param value the value to set + * @return this + * @see PhysicsBlockPropertyTypes + */ + public PropertyBuilder property(PhysicsBlockPropertyTypes.PhysicsBlockPropertyType type, T value) { + this.properties.put(PhysicsBlockPropertyTypes.REGISTRY.getKey(type), value); + return this; + } + + /** + * @param type the physics property type + * @param value the value to set + * @return this + * @see PhysicsBlockPropertyTypes + */ + public PropertyBuilder property(Supplier> type, T value) { + this.properties.put(PhysicsBlockPropertyTypes.REGISTRY.getKey(type.get()), value); + return this; + } + + public Map getProperties() { + return this.properties; + } + } + } +} diff --git a/common/src/main/java/dev/ryanhcode/sable/physics/config/block_properties/BlockStateConditionSet.java b/common/src/main/java/dev/ryanhcode/sable/physics/config/block_properties/BlockStateConditionSet.java index 8c3766eb9..69366c30e 100644 --- a/common/src/main/java/dev/ryanhcode/sable/physics/config/block_properties/BlockStateConditionSet.java +++ b/common/src/main/java/dev/ryanhcode/sable/physics/config/block_properties/BlockStateConditionSet.java @@ -66,4 +66,27 @@ public String toString() { } } + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + List conditions = new ArrayList<>(); + + public Builder expect(String property, String value) { + this.conditions.add(new BlockStateCondition(property, value)); + return this; + } + + public > Builder expect(Property property, T value) { + return this.expect(property.getName(), property.getName(value)); + } + + public BlockStateConditionSet build() { + if (this.conditions.isEmpty()) { + throw new IllegalStateException("conditions must not be empty"); + } + return new BlockStateConditionSet(this.conditions); + } + } } diff --git a/common/src/main/java/dev/ryanhcode/sable/physics/config/block_properties/PhysicsBlockPropertyTypes.java b/common/src/main/java/dev/ryanhcode/sable/physics/config/block_properties/PhysicsBlockPropertyTypes.java index f1bb82d60..9d01c8190 100644 --- a/common/src/main/java/dev/ryanhcode/sable/physics/config/block_properties/PhysicsBlockPropertyTypes.java +++ b/common/src/main/java/dev/ryanhcode/sable/physics/config/block_properties/PhysicsBlockPropertyTypes.java @@ -15,7 +15,7 @@ public class PhysicsBlockPropertyTypes { public static final ResourceKey>> REGISTRY_KEY = ResourceKey.createRegistryKey(Sable.sablePath("physics_block_properties")); private static final RegistrationProvider> VANILLA_PROVIDER; - private static final Registry> REGISTRY; + protected static final Registry> REGISTRY; static { VANILLA_PROVIDER = RegistrationProvider.get(REGISTRY_KEY, Sable.MOD_ID); diff --git a/common/src/main/java/dev/ryanhcode/sable/physics/config/dimension_physics/BezierResourceFunction.java b/common/src/main/java/dev/ryanhcode/sable/physics/config/dimension_physics/BezierResourceFunction.java index 6e7b7267b..bfcba7607 100644 --- a/common/src/main/java/dev/ryanhcode/sable/physics/config/dimension_physics/BezierResourceFunction.java +++ b/common/src/main/java/dev/ryanhcode/sable/physics/config/dimension_physics/BezierResourceFunction.java @@ -90,4 +90,21 @@ public record BezierPoint(double altitude, double value, double slope) { BezierPoint::new ); } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + List points = new ArrayList<>(); + + public Builder addPoint(double altitude, double value, double slope) { + this.points.add(new BezierPoint(altitude, value, slope)); + return this; + } + + public BezierResourceFunction build() { + return new BezierResourceFunction(this.points); + } + } } diff --git a/common/src/main/java/dev/ryanhcode/sable/physics/config/dimension_physics/DimensionPhysicsProvider.java b/common/src/main/java/dev/ryanhcode/sable/physics/config/dimension_physics/DimensionPhysicsProvider.java new file mode 100644 index 000000000..d318afdba --- /dev/null +++ b/common/src/main/java/dev/ryanhcode/sable/physics/config/dimension_physics/DimensionPhysicsProvider.java @@ -0,0 +1,134 @@ +package dev.ryanhcode.sable.physics.config.dimension_physics; + +import net.minecraft.core.HolderLookup; +import net.minecraft.data.CachedOutput; +import net.minecraft.data.DataProvider; +import net.minecraft.data.PackOutput; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; +import org.joml.Vector3f; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + +public abstract class DimensionPhysicsProvider implements DataProvider { + protected final PackOutput.PathProvider pathProvider; + private final CompletableFuture registries; + protected final String modId; + private final Map definitions = new HashMap<>(); + + public DimensionPhysicsProvider(PackOutput packOutput, CompletableFuture registries, String modId) { + this.pathProvider = packOutput.createPathProvider(PackOutput.Target.DATA_PACK, "dimension_physics"); + this.registries = registries; + this.modId = modId; + } + + protected abstract void addProperties(HolderLookup.Provider holderLookup); + + public final CompletableFuture run(CachedOutput output) { + return this.registries.thenCompose((provider) -> { + final Set> list = new HashSet<>(); + this.addProperties(provider); + this.definitions.forEach((id, definition) -> { + list.add(DataProvider.saveStable(output, provider, DimensionPhysics.CODEC, definition, this.pathProvider.json(id))); + }); + return CompletableFuture.allOf(list.toArray(CompletableFuture[]::new)); + }); + } + + public final DimensionPhysics define(final ResourceKey key, final Function builderFunction) { + return this.definitions.computeIfAbsent(key.location(), (k) -> builderFunction.apply(new Builder(k)).build()); + } + + public final DimensionPhysics define(final ResourceLocation id, final Function builderFunction) { + return this.definitions.computeIfAbsent(id, (k) -> builderFunction.apply(new Builder(k)).build()); + } + + @Override + public @NotNull String getName() { + return "Dimension Physics Properties for " + this.modId; + } + + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + public static class Builder { + final ResourceLocation dimension; + int priority = 1000; + Optional universalDrag = Optional.empty(); + Optional baseGravity = Optional.empty(); + Optional basePressure = Optional.empty(); + Optional pressureFunction = Optional.empty(); + Optional magneticNorth = Optional.empty(); + boolean ignoreChunks = false; + + public Builder(ResourceLocation dimension) { + this.dimension = dimension; + } + + /** + * @param priority the priority of the file, higher values will override + * @return this + */ + public Builder priority(int priority) { + this.priority = priority; + return this; + } + + /** + * @param drag universal drag of the dimension + * @return this + */ + public Builder drag(float drag) { + this.universalDrag = Optional.of(drag); + return this; + } + + /** + * @param gravity base gravity of the dimension + * @return this + */ + public Builder gravity(Vector3f gravity) { + this.baseGravity = Optional.of(gravity); + return this; + } + + /** + * @param pressure base pressure of the dimension + * @return this + */ + public Builder pressure(double pressure) { + this.basePressure = Optional.of(pressure); + return this; + } + + /** + * @param builder pressure function builder + * @return this + * @see BezierResourceFunction.Builder + */ + public Builder pressureFunc(Function builder) { + this.pressureFunction = Optional.of(builder.apply(new BezierResourceFunction.Builder()).build()); + return this; + } + + /** + * @param north magnetic north of the dimension + * @return this + */ + public Builder north(Vector3f north) { + this.magneticNorth = Optional.of(north); + return this; + } + + public Builder ignoreChunks() { + this.ignoreChunks = true; + return this; + } + + public DimensionPhysics build() { + return new DimensionPhysics(this.dimension, this.priority, this.universalDrag, this.baseGravity, this.basePressure, this.pressureFunction, this.magneticNorth, this.ignoreChunks); + } + } +}