Skip to content

Commit

Permalink
Add TagModifier System
Browse files Browse the repository at this point in the history
  • Loading branch information
FirstMegaGame4 committed Dec 10, 2023
1 parent d7dd7c8 commit f50a6d4
Show file tree
Hide file tree
Showing 12 changed files with 352 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.mmodding.mmodding_lib.interface_injections;

import com.mmodding.mmodding_lib.library.tags.modifiers.TagModifier;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Holder;
import org.quiltmc.qsl.base.api.util.InjectedInterface;

@InjectedInterface({Holder.class, AbstractBlock.AbstractBlockState.class, FluidState.class, ItemStack.class})
public interface TagRuntimeManagement<T> {

default boolean isIn(TagModifier<T> modifier) {
throw new AssertionError();
}

interface BlockStateTagRuntimeManagement extends TagRuntimeManagement<Block> {

/**
* BlockState version, avoiding unchecked cast warn.
*/
@Override
default boolean isIn(TagModifier<Block> modifier) {
throw new AssertionError();
}
}

interface FluidStateTagRuntimeManagement extends TagRuntimeManagement<Fluid> {

/**
* FluidState version, avoiding unchecked cast warn.
*/
@Override
default boolean isIn(TagModifier<Fluid> modifier) {
throw new AssertionError();
}
}

interface ItemStackTagRuntimeManagement extends TagRuntimeManagement<Item> {

/**
* ItemStack version, avoiding unchecked cast warn.
*/
@Override
default boolean isIn(TagModifier<Item> modifier) {
throw new AssertionError();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.mmodding.mmodding_lib.library.tags.modifiers;

import net.minecraft.tag.TagKey;
import org.quiltmc.qsl.base.api.util.TriState;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public final class AdvancedTagModifier<T> implements TagModifier<T> {

private final TagKey<T> tagKey;
private final Priority priority;
private final List<Function<T, Boolean>> additions;
private final List<Function<T, Boolean>> exclusions;

AdvancedTagModifier(TagKey<T> tagKey, Priority priority) {
this.tagKey = tagKey;
this.priority = priority;
this.additions = new ArrayList<>();
this.exclusions = new ArrayList<>();
}

private boolean process(List<Function<T, Boolean>> functions, T value) {
for (Function<T, Boolean> function : functions) {
if (function.apply(value)) {
return true;
}
}
return false;
}

@SafeVarargs
public final AdvancedTagModifier<T> append(Function<T, Boolean>... functions) {
this.additions.addAll(Arrays.asList(functions));
return this;
}

@SafeVarargs
public final AdvancedTagModifier<T> exclude(Function<T, Boolean>... functions) {
this.exclusions.addAll(Arrays.asList(functions));
return this;
}

@Override
public TriState status(T value) {
boolean addition = this.process(this.additions, value);
boolean exclusion = this.process(this.exclusions, value);
if (addition && exclusion) {
if (this.priority.equals(Priority.ADDITION)) {
return TriState.TRUE;
}
else if (this.priority.equals(Priority.EXCLUSION)) {
return TriState.FALSE;
}
else {
throw new RuntimeException("Unknown Enum Constant Of Priority");
}
}
else {
if (addition) {
return TriState.TRUE;
}
else if (exclusion) {
return TriState.FALSE;
}
else {
return TriState.DEFAULT;
}
}
}

@Override
public boolean result(T value, Function<TagKey<T>, Boolean> backup) {
return switch (this.status(value)) {
case TRUE -> true;
case FALSE -> false;
case DEFAULT -> backup.apply(this.tagKey);
};
}

@Override
public TagKey<T> getTagKey() {
return this.tagKey;
}

/**
* If a value is considered as an addition and an exclusion at the same time,
* this enumeration will determine what will be the final decision.
*/
public enum Priority {
ADDITION,
EXCLUSION
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.mmodding.mmodding_lib.library.tags.modifiers;

import net.minecraft.tag.TagKey;
import org.quiltmc.qsl.base.api.util.TriState;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

public final class SimpleTagModifier<T> implements TagModifier<T> {

private final TagKey<T> tagKey;
private final List<T> additions;
private final List<T> exclusions;

SimpleTagModifier(TagKey<T> tagKey) {
this.tagKey = tagKey;
this.additions = new ArrayList<>();
this.exclusions = new ArrayList<>();
}

private T check(T value) {
if (this.additions.contains(value)) {
throw new IllegalArgumentException("Value " + value + " is already an addition in this manager of " + this.tagKey);
}
else if (this.exclusions.contains(value)) {
throw new IllegalArgumentException("Value " + value + " is already an exclusion in this manager of " + this.tagKey);
}
else {
return value;
}
}

@SafeVarargs
public final SimpleTagModifier<T> append(T... values) {
for (T value : values) {
this.additions.add(this.check(value));
}
return this;
}

@SafeVarargs
public final SimpleTagModifier<T> exclude(T... values) {
for (T value : values) {
this.exclusions.add(this.check(value));
}
return this;
}

public TriState status(T value) {
if (this.additions.contains(value)) {
return TriState.TRUE;
}
else if (this.exclusions.contains(value)) {
return TriState.FALSE;
}
else {
return TriState.DEFAULT;
}
}

@Override
public boolean result(T value, Function<TagKey<T>, Boolean> backup) {
return switch (this.status(value)) {
case TRUE -> true;
case FALSE -> false;
case DEFAULT -> backup.apply(this.tagKey);
};
}

public TagKey<T> getTagKey() {
return this.tagKey;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.mmodding.mmodding_lib.library.tags.modifiers;

import net.minecraft.tag.TagKey;
import org.quiltmc.qsl.base.api.util.TriState;

import java.util.function.Function;

public interface TagModifier<T> {

static <T> SimpleTagModifier<T> ofSimple(TagKey<T> tagKey) {
return new SimpleTagModifier<>(tagKey);
}

static <T> AdvancedTagModifier<T> ofAdvanced(TagKey<T> tagKey, AdvancedTagModifier.Priority priority) {
return new AdvancedTagModifier<>(tagKey, priority);
}

TriState status(T value);

boolean result(T value, Function<TagKey<T>, Boolean> backup);

TagKey<T> getTagKey();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.mmodding.mmodding_lib.mixin.injectors;

import com.mmodding.mmodding_lib.interface_injections.TagRuntimeManagement;
import com.mmodding.mmodding_lib.library.tags.modifiers.TagModifier;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.tag.TagKey;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(AbstractBlock.AbstractBlockState.class)
public abstract class AbstractBlockStateMixin implements TagRuntimeManagement.BlockStateTagRuntimeManagement {

@Shadow
public abstract Block getBlock();

@Shadow
public abstract boolean isIn(TagKey<Block> tag);

@Override
public boolean isIn(TagModifier<Block> modifier) {
return modifier.result(this.getBlock(), this::isIn);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.mmodding.mmodding_lib.mixin.injectors;

import com.mmodding.mmodding_lib.interface_injections.FluidGroupComparable;
import com.mmodding.mmodding_lib.interface_injections.TagRuntimeManagement;
import com.mmodding.mmodding_lib.library.fluids.FluidExtensions;
import com.mmodding.mmodding_lib.library.fluids.FluidGroup;
import com.mmodding.mmodding_lib.library.tags.modifiers.TagModifier;
import com.mmodding.mmodding_lib.mixin.accessors.FluidAccessor;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.tag.TagKey;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.BlockView;
Expand All @@ -16,18 +19,26 @@
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(FluidState.class)
public abstract class FluidStateMixin implements FluidGroupComparable {
public abstract class FluidStateMixin implements TagRuntimeManagement.FluidStateTagRuntimeManagement, FluidGroupComparable {

@Shadow
public abstract Fluid getFluid();

@Inject(method = "getVelocity", at = @At("HEAD"), cancellable = true)
@Shadow
public abstract boolean isIn(TagKey<Fluid> tag);

@Inject(method = "getVelocity", at = @At("HEAD"), cancellable = true)
private void getVelocity(BlockView world, BlockPos pos, CallbackInfoReturnable<Vec3d> cir) {
if (this.getFluid() instanceof FluidExtensions extensions) {
cir.setReturnValue(((FluidAccessor) this.getFluid()).invokeGetVelocity(world, pos, (FluidState) (Object) this).multiply(extensions.getVelocityMultiplier()));
}
}

@Override
public boolean isIn(TagModifier<Fluid> modifier) {
return modifier.result(this.getFluid(), this::isIn);
}

@Override
public boolean isOf(FluidGroup group) {
return this.getFluid() == group.getStill() || this.getFluid() == group.getFlowing();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.mmodding.mmodding_lib.mixin.injectors;

import com.mmodding.mmodding_lib.library.tags.modifiers.TagModifier;
import net.minecraft.util.Holder;
import org.spongepowered.asm.mixin.Mixin;

@Mixin(Holder.Direct.class)
public interface HolderDirectMixin<T> extends HolderMixin<T> {

@Override
default boolean isIn(TagModifier<T> modifier) {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.mmodding.mmodding_lib.mixin.injectors;

import com.mmodding.mmodding_lib.interface_injections.TagRuntimeManagement;
import net.minecraft.tag.TagKey;
import net.minecraft.util.Holder;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(Holder.Direct.class)
public interface HolderMixin<T> extends TagRuntimeManagement<T> {

@Shadow
boolean isIn(TagKey<T> tag);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.mmodding.mmodding_lib.mixin.injectors;

import com.mmodding.mmodding_lib.library.tags.modifiers.TagModifier;
import net.minecraft.util.Holder;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(Holder.Reference.class)
public interface HolderReferenceMixin<T> extends HolderMixin<T> {

@Shadow
T value();

@Override
default boolean isIn(TagModifier<T> modifier) {
return modifier.result(this.value(), this::isIn);
}
}
Loading

0 comments on commit f50a6d4

Please sign in to comment.