Skip to content

Commit

Permalink
Multiplier based attribute functions
Browse files Browse the repository at this point in the history
+Added multiplier based attribute functions. Why: among other things such as being a requested enhancement, flat Attack Speed buffs are too OP and really need a multiplier type mechanic. How: when defining attribute functions in JSON, instead of the value being a number/double, it is an object containing aforementioned number as well as a FunctionBehaviour reference. This lets the game know how the value should be used.

This is a breaking change, hence the buff in middle version number. All mods/datapacks will need to adjust their data JSON accordingly.
  • Loading branch information
CleverNucleus committed Jan 1, 2023
1 parent aba3910 commit c04e106
Show file tree
Hide file tree
Showing 13 changed files with 175 additions and 39 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ minecraft_version=1.18.2
yarn_mappings=1.18.2+build.4
loader_version=0.14.10

mod_version = 1.1.13
mod_version = 1.3.0
maven_group = com.github.clevernucleus
archives_base_name = dataattributes

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.github.clevernucleus.dataattributes.api.attribute;

/**
* @since 1.3.0
* @author CleverNucleus
*/
public enum FunctionBehaviour {
/** Addition of values as defined by the parent attribute. Equivalent of EntityAttributeModifier.Operation.ADDITION. */
ADDITION((byte)0),
/** Multiplication of parent attribute. Equivalent of EntityAttributeModifier.Operation.MULTIPLY_TOTAL. */
MULTIPLY((byte)1);

private final byte id;

private FunctionBehaviour(final byte id) {
this.id = id;
}

public static FunctionBehaviour of(final byte id) {
return switch(id) {
case 0 -> ADDITION;
case 1 -> MULTIPLY;
default -> ADDITION;
};
}

public byte id() {
return this.id;
}

@Override
public String toString() {
return String.valueOf(this.id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.github.clevernucleus.dataattributes.api.attribute;

/**
* @since 1.3.0
* @author CleverNucleus
*/
public interface IAttributeFunction {

/**
* @return The FunctionBehaviour associated with this attribute function.
*/
FunctionBehaviour behaviour();

/**
* @return The value associated with this attribute function.
*/
double value();
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ public interface IEntityAttribute {

/**
* @return An immutable map of the function-parents attached to this attribute.
* @since 1.3.0
*/
Map<IEntityAttribute, Double> parents();
Map<IEntityAttribute, IAttributeFunction> parents();

/**
* @return An immutable map of the function-children attached to this attribute.
* @since 1.3.0
*/
Map<IEntityAttribute, Double> children();
Map<IEntityAttribute, IAttributeFunction> children();

/**
* @return An immutable collection of the properties' keys attached to this attribute.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,5 @@ default void onStackCreated(final ItemStack itemStack, final int count) {}
* @param itemStack
* @return
*/
SoundEvent getEquipSound(final ItemStack itemStack);
default SoundEvent getEquipSound(final ItemStack itemStack) { return null; }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.clevernucleus.dataattributes.api.util;

import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
Expand Down Expand Up @@ -57,10 +58,31 @@ public static double stairs(final double x, final double stretch, final double s
* @param min
* @param max
* @return Returns true if the value is less than max and greater than or equal to min.
* @since 1.3.0
*/
public static boolean isWithinLimits(final double value, final double min, final double max) {
if(value < min) return false;
if(value >= max) return false;
if(value < min || value >= max) return false;
return true;
}

/**
* @param value
* @param arraySize This MUST be 8 or greater! No Checks are implemented for the sake of performance.
* @return Returns a byte array with the first 8 bytes storing the input double.
* @since 1.3.0
*/
public static byte[] doubleToByteArray(final double value, final int arraySize) {
byte[] array = new byte[arraySize];
ByteBuffer.wrap(array).putDouble(value);
return array;
}

/**
* @param array This MUST be an array of size 8 or greater! No Checks are implemented for the sake of performance.
* @return Returns the double stored in the first 8 bytes of the array.
* @since 1.3.0
*/
public static double byteArrayToDouble(final byte[] array) {
return ByteBuffer.wrap(array).getDouble();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.github.clevernucleus.dataattributes.api.event.AttributesReloadedEvent;
import com.github.clevernucleus.dataattributes.json.AttributeOverrideJson;
import com.github.clevernucleus.dataattributes.json.EntityTypesJson;
import com.github.clevernucleus.dataattributes.json.AttributeFunctionJson;
import com.github.clevernucleus.dataattributes.json.FunctionsJson;
import com.github.clevernucleus.dataattributes.json.PropertiesJson;
import com.github.clevernucleus.dataattributes.mutable.MutableEntityAttribute;
Expand Down Expand Up @@ -64,11 +65,11 @@ public Wrapper(Map<Identifier, EntityAttributeData> entityAttributeData, Map<Ide

public AttributeManager() {}

private static Map<Identifier, Double> formatFunctions(Map<String, Double> functionsIn) {
Map<Identifier, Double> functions = new HashMap<Identifier, Double>();
private static Map<Identifier, AttributeFunctionJson> formatFunctions(Map<String, AttributeFunctionJson> functionsIn) {
Map<Identifier, AttributeFunctionJson> functions = new HashMap<Identifier, AttributeFunctionJson>();

for(String key : functionsIn.keySet()) {
double value = functionsIn.get(key);
AttributeFunctionJson value = functionsIn.get(key);

functions.put(new Identifier(key), value);
}
Expand Down Expand Up @@ -146,7 +147,7 @@ private static void loadFunctions(ResourceManager manager, Map<Identifier, Entit
}
}

Map<String, Map<String, Double>> functions = new HashMap<String, Map<String, Double>>();
Map<String, Map<String, AttributeFunctionJson>> functions = new HashMap<String, Map<String, AttributeFunctionJson>>();
cache.values().forEach(json -> json.merge(functions));

for(String key : functions.keySet()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.function.BiFunction;

import com.github.clevernucleus.dataattributes.json.AttributeOverrideJson;
import com.github.clevernucleus.dataattributes.json.AttributeFunctionJson;
import com.github.clevernucleus.dataattributes.mutable.MutableEntityAttribute;

import net.minecraft.entity.attribute.EntityAttribute;
Expand All @@ -14,11 +15,11 @@

public final class EntityAttributeData {
private AttributeOverrideJson attribute;
private final Map<Identifier, Double> functions;
private final Map<Identifier, AttributeFunctionJson> functions;
private final Map<String, String> properties;

public EntityAttributeData() {
this.functions = new HashMap<Identifier, Double>();
this.functions = new HashMap<Identifier, AttributeFunctionJson>();
this.properties = new HashMap<String, String>();
}

Expand All @@ -42,12 +43,12 @@ public void copy(EntityAttribute entityAttributeIn) {

if(entityAttribute == null) continue;

double multiplier = this.functions.get(identifier);
mutableEntityAttribute.addChild((MutableEntityAttribute)entityAttribute, multiplier);
AttributeFunctionJson function = this.functions.get(identifier);
mutableEntityAttribute.addChild((MutableEntityAttribute)entityAttribute, function);
}
}

public void putFunctions(Map<Identifier, Double> functions) {
public void putFunctions(Map<Identifier, AttributeFunctionJson> functions) {
this.functions.putAll(functions);
}

Expand All @@ -62,7 +63,7 @@ public void readFromNbt(NbtCompound tag) {
}

NbtCompound functions = tag.getCompound("Functions");
functions.getKeys().forEach(key -> this.functions.put(new Identifier(key), functions.getDouble(key)));
functions.getKeys().forEach(key -> this.functions.put(new Identifier(key), AttributeFunctionJson.read(functions.getByteArray(key))));

NbtCompound properties = tag.getCompound("Properties");
properties.getKeys().forEach(key -> this.properties.put(key, properties.getString(key)));
Expand All @@ -77,7 +78,7 @@ public void writeToNbt(NbtCompound tag) {
}

NbtCompound functions = new NbtCompound();
this.functions.forEach((key, value) -> functions.putDouble(key.toString(), value));
this.functions.forEach((key, value) -> functions.putByteArray(key.toString(), value.write()));
tag.put("Functions", functions);

NbtCompound properties = new NbtCompound();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.github.clevernucleus.dataattributes.json;

import com.github.clevernucleus.dataattributes.api.attribute.FunctionBehaviour;
import com.github.clevernucleus.dataattributes.api.attribute.IAttributeFunction;
import com.github.clevernucleus.dataattributes.api.util.Maths;
import com.google.gson.annotations.Expose;

public final class AttributeFunctionJson implements IAttributeFunction {
@Expose private FunctionBehaviour behaviour;
@Expose private double value;

private AttributeFunctionJson() {}

public static AttributeFunctionJson read(byte[] byteArray) {
AttributeFunctionJson functionTypeJson = new AttributeFunctionJson();
functionTypeJson.behaviour = FunctionBehaviour.of(byteArray[8]);
functionTypeJson.value = Maths.byteArrayToDouble(byteArray);
return functionTypeJson;
}

public byte[] write() {
byte[] byteArray = Maths.doubleToByteArray(this.value, 9);
byteArray[8] = this.behaviour.id();
return byteArray;
}

@Override
public FunctionBehaviour behaviour() {
return this.behaviour;
}

@Override
public double value() {
return this.value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
import com.google.gson.annotations.Expose;

public final class FunctionsJson {
@Expose private HashMap<String, HashMap<String, Double>> values;
@Expose private HashMap<String, HashMap<String, AttributeFunctionJson>> values;

private FunctionsJson() {}

public void merge(Map<String, Map<String, Double>> functionsIn) {
public void merge(Map<String, Map<String, AttributeFunctionJson>> functionsIn) {
for(String key : this.values.keySet()) {
Map<String, Double> functions = functionsIn.getOrDefault(key, new HashMap<String, Double>());
Map<String, AttributeFunctionJson> functions = functionsIn.getOrDefault(key, new HashMap<String, AttributeFunctionJson>());
this.values.get(key).forEach(functions::put);
functionsIn.put(key, functions);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import com.github.clevernucleus.dataattributes.api.attribute.FunctionBehaviour;
import com.github.clevernucleus.dataattributes.api.attribute.IEntityAttribute;
import com.github.clevernucleus.dataattributes.api.attribute.IEntityAttributeInstance;
import com.github.clevernucleus.dataattributes.api.attribute.StackingBehaviour;
import com.github.clevernucleus.dataattributes.api.event.EntityAttributeModifiedEvents;
import com.github.clevernucleus.dataattributes.api.util.VoidConsumer;
import com.github.clevernucleus.dataattributes.json.AttributeFunctionJson;
import com.github.clevernucleus.dataattributes.mutable.MutableAttributeContainer;
import com.github.clevernucleus.dataattributes.mutable.MutableAttributeInstance;
import com.github.clevernucleus.dataattributes.mutable.MutableAttributeModifier;
Expand Down Expand Up @@ -110,14 +112,16 @@ private void data_computeValue(CallbackInfoReturnable<Double> info) {
}

if(this.data_containerCallback != null) {
Map<IEntityAttribute, Double> parents = ((MutableEntityAttribute)attribute).parentsMutable();
Map<IEntityAttribute, AttributeFunctionJson> parents = ((MutableEntityAttribute)attribute).parentsMutable();

for(IEntityAttribute parent : parents.keySet()) {
EntityAttributeInstance instance = this.data_containerCallback.getCustomInstance((EntityAttribute)parent);

if(instance == null) continue;
AttributeFunctionJson function = parents.get(parent);

double multiplier = parents.get(parent);
if(function.behaviour() != FunctionBehaviour.ADDITION) continue;
double multiplier = function.value();
double value = multiplier * instance.getValue();

if(value > 0.0D) {
Expand All @@ -143,6 +147,20 @@ private void data_computeValue(CallbackInfoReturnable<Double> info) {
e *= 1.0D + modifier.getValue();
}

if(this.data_containerCallback != null) {
Map<IEntityAttribute, AttributeFunctionJson> parents = ((MutableEntityAttribute)attribute).parentsMutable();

for(IEntityAttribute parent : parents.keySet()) {
EntityAttributeInstance instance = this.data_containerCallback.getCustomInstance((EntityAttribute)parent);

if(instance == null) continue;
AttributeFunctionJson function = parents.get(parent);

if(function.behaviour() != FunctionBehaviour.MULTIPLY) continue;
e *= 1.0D + (instance.getValue() * function.value());
}
}

double value = ((EntityAttribute)attribute).clamp(e);
info.setReturnValue(value);
}
Expand Down
Loading

0 comments on commit c04e106

Please sign in to comment.