Implement environment attribute easing types
This commit is contained in:
30 files changed
+671
-51
No files matched your search
+1
-1
@@ -28,7 +28,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* @version 1.21.9+
|
||||
* @versions 1.21.9+
|
||||
*/
|
||||
@NullMarked
|
||||
public class ParticleSpellData extends ParticleData {
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.jspecify.annotations.NullMarked;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@NullMarked
|
||||
public interface NbtCodec<T> extends NbtEncoder<T>, NbtDecoder<T> {
|
||||
@@ -43,6 +44,27 @@ public interface NbtCodec<T> extends NbtEncoder<T>, NbtDecoder<T> {
|
||||
};
|
||||
}
|
||||
|
||||
default NbtCodec<T> validate(Predicate<T> predicate) {
|
||||
return new NbtCodec<T>() {
|
||||
@Override
|
||||
public T decode(NBT nbt, PacketWrapper<?> wrapper) throws NbtCodecException {
|
||||
T val = NbtCodec.this.decode(nbt, wrapper);
|
||||
if (!predicate.test(val)) {
|
||||
throw new NbtCodecException("Decode predicate failed " + predicate);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBT encode(PacketWrapper<?> wrapper, T value) throws NbtCodecException {
|
||||
if (!predicate.test(value)) {
|
||||
throw new NbtCodecException("Encode predicate failed " + predicate);
|
||||
}
|
||||
return NbtCodec.this.encode(wrapper, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
default <Z> NbtCodec<Z> apply(Function<T, Z> forward, Function<Z, T> back) {
|
||||
return new NbtCodec<Z>() {
|
||||
@Override
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.Either;
|
||||
import com.github.retrooper.packetevents.util.UniqueIdUtil;
|
||||
import com.github.retrooper.packetevents.util.mappings.IRegistry;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
@@ -336,20 +337,53 @@ public final class NbtCodecs {
|
||||
@Override
|
||||
public T decode(NBT nbt, PacketWrapper<?> wrapper) {
|
||||
IRegistry<T> replacedRegistry = wrapper.replaceRegistry(registry);
|
||||
T entry = null;
|
||||
if (nbt instanceof NBTNumber) {
|
||||
ClientVersion version = wrapper.getServerVersion().toClientVersion();
|
||||
int id = ((NBTNumber) nbt).getAsInt();
|
||||
return replacedRegistry.getByIdOrThrow(version, id);
|
||||
entry = replacedRegistry.getById(version, id);
|
||||
} else if (nbt instanceof NBTString) {
|
||||
return replacedRegistry.getByNameOrThrow(((NBTString) nbt).getValue());
|
||||
entry = replacedRegistry.getByName(((NBTString) nbt).getValue());
|
||||
}
|
||||
throw new IllegalStateException("Can't decode " + nbt + " for " + registry);
|
||||
if (entry == null) {
|
||||
throw new NbtCodecException("Can't decode registry " + registry.getRegistryKey());
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBT encode(PacketWrapper<?> wrapper, T value) {
|
||||
if (!value.isRegistered()) {
|
||||
throw new NbtCodecException("Unregistered entry");
|
||||
}
|
||||
return ResourceLocation.CODEC.encode(wrapper, value.getName());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <L, R> NbtCodec<Either<L, R>> either(NbtCodec<L> left, NbtCodec<R> right) {
|
||||
return new NbtCodec<Either<L, R>>() {
|
||||
@Override
|
||||
public Either<L, R> decode(NBT nbt, PacketWrapper<?> wrapper) throws NbtCodecException {
|
||||
try {
|
||||
return Either.createLeft(left.decode(nbt, wrapper));
|
||||
} catch (NbtCodecException leftException) {
|
||||
try {
|
||||
return Either.createRight(right.decode(nbt, wrapper));
|
||||
} catch (NbtCodecException rightException) {
|
||||
rightException.addSuppressed(leftException);
|
||||
throw rightException;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBT encode(PacketWrapper<?> wrapper, Either<L, R> value) throws NbtCodecException {
|
||||
return value.map(
|
||||
v -> left.encode(wrapper, v),
|
||||
v -> right.encode(wrapper, v)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -25,7 +25,7 @@ import com.github.retrooper.packetevents.protocol.util.NbtCodecs;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* @version 1.21.11+
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public interface AlphaColorModifier<A> extends AttributeModifier<AlphaColor, A> {
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @version 1.21.11+
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public class AmbientSounds {
|
||||
|
||||
+2
-2
@@ -49,8 +49,8 @@ public interface AttributeModifier<T, A> {
|
||||
);
|
||||
|
||||
@SuppressWarnings("unchecked") // types don't matter
|
||||
static <T> AttributeModifier<T, ?> override() {
|
||||
return (AttributeModifier<T, ?>) OverrideModifier.INSTANCE;
|
||||
static <T> AttributeModifier<T, T> override() {
|
||||
return (AttributeModifier<T, T>) OverrideModifier.INSTANCE;
|
||||
}
|
||||
|
||||
T apply(T value, A arg);
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import com.github.retrooper.packetevents.protocol.util.NbtCodec;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* @version 1.21.11+
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public interface AttributeType<T> extends MappedEntity {
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @version 1.21.11+
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public final class AttributeTypes {
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @version 1.21.11+
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public class BackgroundMusic {
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* @version 1.21.11+
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public final class BlendToGrayArgument {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import com.github.retrooper.packetevents.protocol.util.NbtCodecs;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* @version 1.21.11+
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public interface ColorModifier<A> extends AttributeModifier<Color, A> {
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.github.retrooper.packetevents.protocol.world.attributes;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.util.NbtCodec;
|
||||
import com.github.retrooper.packetevents.protocol.util.NbtCodecException;
|
||||
import com.github.retrooper.packetevents.protocol.util.NbtMapCodec;
|
||||
import com.github.retrooper.packetevents.util.MathUtil;
|
||||
import com.github.retrooper.packetevents.util.easing.CubicBezierControls;
|
||||
import com.github.retrooper.packetevents.util.easing.CubicCurve;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public final class CubicBezierEasingType extends AbstractMappedEntity implements EasingType {
|
||||
|
||||
public static final NbtCodec<CubicBezierEasingType> CODEC = new NbtMapCodec<CubicBezierEasingType>() {
|
||||
@Override
|
||||
public CubicBezierEasingType decode(NBTCompound compound, PacketWrapper<?> wrapper) throws NbtCodecException {
|
||||
CubicBezierControls controls = compound.getOrThrow("cubic_bezier", CubicBezierControls.CODEC, wrapper);
|
||||
return new CubicBezierEasingType(controls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(NBTCompound compound, PacketWrapper<?> wrapper, CubicBezierEasingType value) throws NbtCodecException {
|
||||
compound.set("cubic_bezier", value.controls, CubicBezierControls.CODEC, wrapper);
|
||||
}
|
||||
}.codec();
|
||||
|
||||
private static final int NEWTON_RAPHSON_ITERATIONS = 4;
|
||||
|
||||
private final CubicBezierControls controls;
|
||||
private final CubicCurve curveX;
|
||||
private final CubicCurve curveY;
|
||||
|
||||
public CubicBezierEasingType(CubicBezierControls controls) {
|
||||
super(null);
|
||||
this.controls = controls;
|
||||
this.curveX = controls.calcCurveX();
|
||||
this.curveY = controls.calcCurveY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float apply(float x) {
|
||||
// see https://en.wikipedia.org/w/index.php?title=Newton%27s_method&oldid=1321820598
|
||||
// implementation is based on Mojang's code
|
||||
float t = x;
|
||||
for (int i = 0; i < NEWTON_RAPHSON_ITERATIONS; i++) {
|
||||
float gradient = this.curveX.calcSampleGradient(t);
|
||||
if (gradient < MathUtil.EPSILON) {
|
||||
break;
|
||||
}
|
||||
float error = this.curveX.calcSample(t) - x;
|
||||
t -= error / gradient;
|
||||
}
|
||||
return this.curveY.calcSample(t);
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.github.retrooper.packetevents.protocol.world.attributes;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.util.NbtCodec;
|
||||
import com.github.retrooper.packetevents.protocol.util.NbtCodecs;
|
||||
import com.github.retrooper.packetevents.util.Either;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public interface EasingType extends MappedEntity {
|
||||
|
||||
NbtCodec<EasingType> CODEC = NbtCodecs.either(
|
||||
NbtCodecs.forRegistry(EasingTypes.getRegistry()),
|
||||
CubicBezierEasingType.CODEC
|
||||
).apply(Either::unwrap, type -> type instanceof CubicBezierEasingType
|
||||
? Either.createRight((CubicBezierEasingType) type) : Either.createLeft(type));
|
||||
|
||||
float apply(float x);
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package com.github.retrooper.packetevents.protocol.world.attributes;
|
||||
|
||||
import com.github.retrooper.packetevents.util.easing.EasingFunctions;
|
||||
import com.github.retrooper.packetevents.util.FloatUnaryOperator;
|
||||
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* @versions 1.21.1+
|
||||
*/
|
||||
@NullMarked
|
||||
public final class EasingTypes {
|
||||
|
||||
private static final VersionedRegistry<EasingType> REGISTRY = new VersionedRegistry<>("easing_type");
|
||||
|
||||
private EasingTypes() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static EasingType define(String name, FloatUnaryOperator operator) {
|
||||
return REGISTRY.define(name, data -> new StaticEasingType(data, operator));
|
||||
}
|
||||
|
||||
public static VersionedRegistry<EasingType> getRegistry() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
public static final EasingType CONSTANT = define("constant", EasingFunctions::constant);
|
||||
public static final EasingType LINEAR = define("linear", EasingFunctions::linear);
|
||||
public static final EasingType IN_BACK = define("in_back", EasingFunctions::inBack);
|
||||
public static final EasingType IN_BOUNCE = define("in_bounce", EasingFunctions::inBounce);
|
||||
public static final EasingType IN_CIRC = define("in_circ", EasingFunctions::inCirc);
|
||||
public static final EasingType IN_CUBIC = define("in_cubic", EasingFunctions::inCubic);
|
||||
public static final EasingType IN_ELASTIC = define("in_elastic", EasingFunctions::inElastic);
|
||||
public static final EasingType IN_EXPO = define("in_expo", EasingFunctions::inExpo);
|
||||
public static final EasingType IN_QUAD = define("in_quad", EasingFunctions::inQuad);
|
||||
public static final EasingType IN_QUART = define("in_quart", EasingFunctions::inQuart);
|
||||
public static final EasingType IN_QUINT = define("in_quint", EasingFunctions::inQuint);
|
||||
public static final EasingType IN_SINE = define("in_sine", EasingFunctions::inSine);
|
||||
public static final EasingType IN_OUT_BACK = define("in_out_back", EasingFunctions::inOutBack);
|
||||
public static final EasingType IN_OUT_BOUNCE = define("in_out_bounce", EasingFunctions::inOutBounce);
|
||||
public static final EasingType IN_OUT_CIRC = define("in_out_circ", EasingFunctions::inOutCirc);
|
||||
public static final EasingType IN_OUT_CUBIC = define("in_out_cubic", EasingFunctions::inOutCubic);
|
||||
public static final EasingType IN_OUT_ELASTIC = define("in_out_elastic", EasingFunctions::inOutElastic);
|
||||
public static final EasingType IN_OUT_EXPO = define("in_out_expo", EasingFunctions::inOutExpo);
|
||||
public static final EasingType IN_OUT_QUAD = define("in_out_quad", EasingFunctions::inOutQuad);
|
||||
public static final EasingType IN_OUT_QUART = define("in_out_quart", EasingFunctions::inOutQuart);
|
||||
public static final EasingType IN_OUT_QUINT = define("in_out_quint", EasingFunctions::inOutQuint);
|
||||
public static final EasingType IN_OUT_SINE = define("in_out_sine", EasingFunctions::inOutSine);
|
||||
public static final EasingType OUT_BACK = define("out_back", EasingFunctions::outBack);
|
||||
public static final EasingType OUT_BOUNCE = define("out_bounce", EasingFunctions::outBounce);
|
||||
public static final EasingType OUT_CIRC = define("out_circ", EasingFunctions::outCirc);
|
||||
public static final EasingType OUT_CUBIC = define("out_cubic", EasingFunctions::outCubic);
|
||||
public static final EasingType OUT_ELASTIC = define("out_elastic", EasingFunctions::outElastic);
|
||||
public static final EasingType OUT_EXPO = define("out_expo", EasingFunctions::outExpo);
|
||||
public static final EasingType OUT_QUAD = define("out_quad", EasingFunctions::outQuad);
|
||||
public static final EasingType OUT_QUART = define("out_quart", EasingFunctions::outQuart);
|
||||
public static final EasingType OUT_QUINT = define("out_quint", EasingFunctions::outQuint);
|
||||
public static final EasingType OUT_SINE = define("out_sine", EasingFunctions::outSine);
|
||||
|
||||
static {
|
||||
REGISTRY.unloadMappings();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -23,7 +23,7 @@ import com.github.retrooper.packetevents.protocol.util.NbtCodec;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* @version 1.21.11+
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public interface EnvironmentAttribute<T> extends MappedEntity {
|
||||
|
||||
+43
-30
@@ -22,6 +22,9 @@ import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.util.NbtCodec;
|
||||
import com.github.retrooper.packetevents.protocol.util.NbtCodecException;
|
||||
import com.github.retrooper.packetevents.protocol.util.NbtCodecs;
|
||||
import com.github.retrooper.packetevents.protocol.util.NbtMapCodec;
|
||||
import com.github.retrooper.packetevents.util.Either;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@@ -31,9 +34,10 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @version 1.21.11++
|
||||
* @versions 1.21.11++
|
||||
*/
|
||||
@NullMarked
|
||||
public class EnvironmentAttributeMap {
|
||||
@@ -134,41 +138,50 @@ public class EnvironmentAttributeMap {
|
||||
this.modifier = modifier;
|
||||
}
|
||||
|
||||
public static <T> Entry<T, T> createOverride(T value) {
|
||||
return new Entry<>(value, AttributeModifier.override());
|
||||
}
|
||||
|
||||
public static <T> NbtCodec<Entry<T, ?>> codec(EnvironmentAttribute<T> attribute) {
|
||||
NbtCodec<T> valueCodec = attribute.getType().getValueCodec();
|
||||
NbtCodec<AttributeModifier<T, ?>> modifierCodec = attribute.getType().getModifierCodec();
|
||||
return new NbtCodec<Entry<T, ?>>() {
|
||||
@Override
|
||||
public Entry<T, ?> decode(NBT nbt, PacketWrapper<?> wrapper) throws NbtCodecException {
|
||||
try {
|
||||
return new Entry<>(valueCodec.decode(nbt, wrapper), AttributeModifier.override());
|
||||
} catch (NbtCodecException ignored) {
|
||||
}
|
||||
NBTCompound compound = nbt.castOrThrow(NBTCompound.class);
|
||||
AttributeModifier<T, ?> modifier = compound.getOrThrow("modifier", modifierCodec, wrapper);
|
||||
Object arg = compound.getOrThrow("argument", modifier.argumentCodec(attribute), wrapper);
|
||||
@SuppressWarnings("unchecked")
|
||||
Entry<T, Object> entry = new Entry<>(arg, (AttributeModifier<T, ? super Object>) modifier);
|
||||
return entry;
|
||||
}
|
||||
return NbtCodecs.either(
|
||||
valueCodec,
|
||||
new NbtMapCodec<Entry<T, ?>>() {
|
||||
@Override
|
||||
public Entry<T, ?> decode(NBTCompound compound, PacketWrapper<?> wrapper) throws NbtCodecException {
|
||||
AttributeModifier<T, ?> modifier = compound.getOrThrow("modifier", modifierCodec, wrapper);
|
||||
Object arg = compound.getOrThrow("argument", modifier.argumentCodec(attribute), wrapper);
|
||||
@SuppressWarnings("unchecked")
|
||||
Entry<T, Object> entry = new Entry<>(arg, (AttributeModifier<T, ? super Object>) modifier);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBT encode(PacketWrapper<?> wrapper, Entry<T, ?> value) throws NbtCodecException {
|
||||
return this.encode0(wrapper, value);
|
||||
}
|
||||
@Override
|
||||
public void encode(NBTCompound compound, PacketWrapper<?> wrapper, Entry<T, ?> value) throws NbtCodecException {
|
||||
this.encode0(compound, wrapper, value);
|
||||
}
|
||||
|
||||
private <A> NBT encode0(PacketWrapper<?> wrapper, Entry<T, A> value) throws NbtCodecException {
|
||||
if (value.modifier == AttributeModifier.override()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T valueArg = (T) value.argument;
|
||||
return valueCodec.encode(wrapper, valueArg);
|
||||
private <A> void encode0(NBTCompound compound, PacketWrapper<?> wrapper, Entry<T, A> value) throws NbtCodecException {
|
||||
compound.set("modifier", value.modifier, modifierCodec, wrapper);
|
||||
compound.set("argument", value.argument, value.modifier.argumentCodec(attribute), wrapper);
|
||||
}
|
||||
}.codec()
|
||||
).apply(
|
||||
e -> e.map(Entry::createOverride, Function.identity()),
|
||||
e -> {
|
||||
if (e.isOverride()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T arg = (T) e.argument;
|
||||
return Either.createLeft(arg);
|
||||
}
|
||||
return Either.createRight(e);
|
||||
}
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.set("modifier", value.modifier, modifierCodec, wrapper);
|
||||
compound.set("argument", value.argument, value.modifier.argumentCodec(attribute), wrapper);
|
||||
return compound;
|
||||
}
|
||||
};
|
||||
);
|
||||
}
|
||||
|
||||
public boolean isOverride() {
|
||||
return this.modifier == AttributeModifier.override();
|
||||
}
|
||||
|
||||
public T getValue(T base) {
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.21.11+
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public final class EnvironmentAttributes {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import com.github.retrooper.packetevents.util.MathUtil;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* @version 1.21.11+
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public interface FloatModifier<A> extends AttributeModifier<Float, A> {
|
||||
|
||||
+2
-2
@@ -29,14 +29,14 @@ public class KeyframeTrack<T> {
|
||||
@Override
|
||||
public KeyframeTrack<T> decode(NBTCompound compound, PacketWrapper<?> wrapper) throws NbtCodecException {
|
||||
List<Keyframe<T>> keyframes = compound.getOrThrow("keyframes", keyframesCodec, wrapper);
|
||||
EasingType easingType = compound.getOr("ease", EasingType.CODEC, EasingType.LINEAR, wrapper);
|
||||
EasingType easingType = compound.getOr("ease", EasingType.CODEC, EasingTypes.LINEAR, wrapper);
|
||||
return new KeyframeTrack<>(keyframes, easingType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(NBTCompound compound, PacketWrapper<?> wrapper, KeyframeTrack<T> value) throws NbtCodecException {
|
||||
compound.set("keyframes", value.keyframes, keyframesCodec, wrapper);
|
||||
if (value.easingType != EasingType.LINEAR) {
|
||||
if (value.easingType != EasingTypes.LINEAR) {
|
||||
compound.set("ease", value.easingType, EasingType.CODEC, wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import com.github.retrooper.packetevents.protocol.util.NbtCodecs;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* @version 1.21.11+
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public enum MoonPhase implements CodecNameable {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
/**
|
||||
* @version 1.21.11+
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public class StaticAttributeType<T> extends AbstractMappedEntity implements AttributeType<T> {
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.github.retrooper.packetevents.protocol.world.attributes;
|
||||
// Created by booky10 in packetevents (8:41 PM 07.12.2025)
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
|
||||
import com.github.retrooper.packetevents.util.FloatUnaryOperator;
|
||||
import com.github.retrooper.packetevents.util.easing.CubicBezierControls;
|
||||
import com.github.retrooper.packetevents.util.easing.CubicCurve;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @versions 1.21.1+
|
||||
*/
|
||||
@NullMarked
|
||||
public class StaticEasingType extends AbstractMappedEntity implements EasingType {
|
||||
|
||||
private final FloatUnaryOperator operator;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public StaticEasingType(@Nullable TypesBuilderData data, FloatUnaryOperator operator) {
|
||||
super(data);
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float apply(float x) {
|
||||
return this.operator.apply(x);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -25,7 +25,7 @@ import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @version 1.21.11+
|
||||
* @versions 1.21.11+
|
||||
*/
|
||||
@NullMarked
|
||||
public class StaticEnvironmentAttribute<T> extends AbstractMappedEntity implements EnvironmentAttribute<T> {
|
||||
|
||||
@@ -21,6 +21,7 @@ package com.github.retrooper.packetevents.util;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class Either<L, R> {
|
||||
|
||||
@@ -40,10 +41,18 @@ public class Either<L, R> {
|
||||
return new Either<>(null, right);
|
||||
}
|
||||
|
||||
public static <T> T unwrap(Either<T, ? extends T> either) {
|
||||
return either.left != null ? either.left : either.right;
|
||||
}
|
||||
|
||||
public Object get() {
|
||||
return this.left != null ? this.left : this.right;
|
||||
}
|
||||
|
||||
public <T> T map(Function<L, T> leftFn, Function<R, T> rightFn) {
|
||||
return this.left != null ? leftFn.apply(this.left) : rightFn.apply(this.right);
|
||||
}
|
||||
|
||||
public boolean isLeft() {
|
||||
return this.left != null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.github.retrooper.packetevents.util;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@FunctionalInterface
|
||||
@NullMarked
|
||||
public interface FloatUnaryOperator {
|
||||
|
||||
float apply(float v);
|
||||
}
|
||||
@@ -20,9 +20,20 @@ package com.github.retrooper.packetevents.util;
|
||||
|
||||
public final class MathUtil {
|
||||
|
||||
public static final float EPSILON = 1e-5f;
|
||||
public static final float F_PI = (float) Math.PI;
|
||||
|
||||
private MathUtil() {
|
||||
}
|
||||
|
||||
public static float square(float x) {
|
||||
return x * x;
|
||||
}
|
||||
|
||||
public static float cube(float x) {
|
||||
return x * x * x;
|
||||
}
|
||||
|
||||
public static float lerp(float t, float a, float b) {
|
||||
return t * (b - a) + a;
|
||||
}
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package com.github.retrooper.packetevents.util.easing;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.util.NbtCodec;
|
||||
import com.github.retrooper.packetevents.protocol.util.NbtCodecs;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@NullMarked
|
||||
public final class CubicBezierControls {
|
||||
|
||||
public static final NbtCodec<CubicBezierControls> CODEC = NbtCodecs.FLOAT.applyList()
|
||||
.validate(floats -> floats.size() == 4)
|
||||
.apply(l -> new CubicBezierControls(l.get(0), l.get(1), l.get(2), l.get(3)),
|
||||
v -> Arrays.asList(v.x1, v.y1, v.x2, v.y2))
|
||||
.validate(CubicBezierControls::isValid);
|
||||
|
||||
private final float x1;
|
||||
private final float y1;
|
||||
private final float x2;
|
||||
private final float y2;
|
||||
|
||||
public CubicBezierControls(float x1, float y1, float x2, float y2) {
|
||||
this.x1 = x1;
|
||||
this.y1 = y1;
|
||||
this.x2 = x2;
|
||||
this.y2 = y2;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return this.x1 >= 0f && this.x1 <= 1f
|
||||
&& this.x2 >= 0f && this.x2 <= 1f;
|
||||
}
|
||||
|
||||
public CubicCurve calcCurveX() {
|
||||
// based on Mojang's CubicBezier#curveFromControls
|
||||
return new CubicCurve(
|
||||
3f * this.x1 - 3f * this.x2 + 1f,
|
||||
-6f * this.x1 + 3f * this.x2,
|
||||
3f * this.x1
|
||||
);
|
||||
}
|
||||
|
||||
public CubicCurve calcCurveY() {
|
||||
// based on Mojang's CubicBezier#curveFromControls
|
||||
return new CubicCurve(
|
||||
3f * this.y1 - 3f * this.y2 + 1f,
|
||||
-6f * this.y1 + 3f * this.y2,
|
||||
3f * this.y1
|
||||
);
|
||||
}
|
||||
|
||||
public float getX1() {
|
||||
return this.x1;
|
||||
}
|
||||
|
||||
public float getY1() {
|
||||
return this.y1;
|
||||
}
|
||||
|
||||
public float getX2() {
|
||||
return this.x2;
|
||||
}
|
||||
|
||||
public float getY2() {
|
||||
return this.y2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.github.retrooper.packetevents.util.easing;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
// based on Mojang's CubicCurve
|
||||
@NullMarked
|
||||
public final class CubicCurve {
|
||||
|
||||
private final float a;
|
||||
private final float b;
|
||||
private final float c;
|
||||
|
||||
public CubicCurve(float a, float b, float c) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
public float calcSample(float t) {
|
||||
return ((this.a * t + this.b) * t + this.c) * t;
|
||||
}
|
||||
|
||||
public float calcSampleGradient(float t) {
|
||||
return (3f * this.a * t + 2f * this.b) * t + this.c;
|
||||
}
|
||||
|
||||
public float getA() {
|
||||
return this.a;
|
||||
}
|
||||
|
||||
public float getB() {
|
||||
return this.b;
|
||||
}
|
||||
|
||||
public float getC() {
|
||||
return this.c;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
package com.github.retrooper.packetevents.util.easing;
|
||||
|
||||
import com.github.retrooper.packetevents.util.MathUtil;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
// mostly copied from Mojang's Ease class, who took it from https://robertpenner.com/easing/
|
||||
@NullMarked
|
||||
public final class EasingFunctions {
|
||||
|
||||
private EasingFunctions() {
|
||||
}
|
||||
|
||||
public static float constant(float ignoredX) {
|
||||
return 0f;
|
||||
}
|
||||
|
||||
public static float linear(float x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
public static float inBack(float x) {
|
||||
float c1 = 1.70158F;
|
||||
float c3 = c1 + 1f;
|
||||
return (x * x) * (c3 * x - c1);
|
||||
}
|
||||
|
||||
public static float inBounce(float x) {
|
||||
return 1f - outBounce(1f - x);
|
||||
}
|
||||
|
||||
public static float inCubic(float x) {
|
||||
return x * x * x;
|
||||
}
|
||||
|
||||
public static float inElastic(float x) {
|
||||
if (x == 0f) {
|
||||
return 0f;
|
||||
} else if (x == 1f) {
|
||||
return 1f;
|
||||
}
|
||||
float c4 = (float) (Math.PI * 2d / 3d);
|
||||
return (float) (-Math.pow(2d, 10d * (double) x - 10d) * Math.sin(((double) x * 10d - 10.75d) * c4));
|
||||
}
|
||||
|
||||
public static float inExpo(float x) {
|
||||
return x == 0f ? 0f : (float) Math.pow(2d, 10d * (double) x - 10d);
|
||||
}
|
||||
|
||||
public static float inQuart(float x) {
|
||||
return (x * x) * (x * x);
|
||||
}
|
||||
|
||||
public static float inQuint(float x) {
|
||||
return ((x * x) * (x * x)) * x;
|
||||
}
|
||||
|
||||
public static float inSine(float x) {
|
||||
return 1f - (float) Math.cos(x * (float) (Math.PI / 2));
|
||||
}
|
||||
|
||||
public static float inOutBounce(float x) {
|
||||
return x < 0.5f
|
||||
? (1f - outBounce(1f - 2f * x)) / 2f
|
||||
: (1f + outBounce(2f * x - 1f)) / 2f;
|
||||
}
|
||||
|
||||
public static float inOutCirc(float x) {
|
||||
return x < 0.5f
|
||||
? (float) ((1d - Math.sqrt(1d - Math.pow(2d * (double) x, 2d))) / 2d)
|
||||
: (float) ((Math.sqrt(1d - Math.pow(-2d * (double) x + 2d, 2d)) + 1d) / 2d);
|
||||
}
|
||||
|
||||
public static float inOutCubic(float x) {
|
||||
return x < 0.5f
|
||||
? 4f * (x * x * x)
|
||||
: (float) (1d - Math.pow(-2d * (double) x + 2d, 3d) / 2d);
|
||||
}
|
||||
|
||||
public static float inOutQuad(float x) {
|
||||
return x < 0.5f
|
||||
? 2f * (x * x)
|
||||
: (float) (1d - Math.pow(-2d * (double) x + 2d, 2d) / 2d);
|
||||
}
|
||||
|
||||
public static float inOutQuart(float x) {
|
||||
return x < 0.5f
|
||||
? 8f * ((x * x) * (x * x))
|
||||
: (float) (1d - Math.pow(-2d * (double) x + 2d, 4d) / 2d);
|
||||
}
|
||||
|
||||
public static float inOutQuint(float x) {
|
||||
return (double) x < 0.5d
|
||||
? 16f * x * x * x * x * x
|
||||
: (float) (1d - Math.pow(-2d * (double) x + 2d, 5d) / 2d);
|
||||
}
|
||||
|
||||
public static float outBounce(float x) {
|
||||
float n1 = 7.5625f;
|
||||
float d1 = 2.75f;
|
||||
if (x < 1f / d1) {
|
||||
return n1 * (x * x);
|
||||
} else if (x < 2f / d1) {
|
||||
return n1 * MathUtil.square(x - (1.5f / d1)) + (3f / 4f);
|
||||
} else if ((double) x < 2.5f / d1) {
|
||||
return n1 * MathUtil.square(x - (2.25f / d1)) + (15f / 16f);
|
||||
}
|
||||
return n1 * MathUtil.square(x - (2.625f / d1)) + (63f / 64f);
|
||||
}
|
||||
|
||||
public static float outElastic(float x) {
|
||||
float c4 = (float) (Math.PI * 2d / 3d);
|
||||
if (x == 0f) {
|
||||
return 0f;
|
||||
} else if (x == 1f) {
|
||||
return 1f;
|
||||
}
|
||||
return (float) (Math.pow(2d, -10d * (double) x) * Math.sin(((double) x * 10d - 0.75d) * c4) + 1d);
|
||||
}
|
||||
|
||||
public static float outExpo(float x) {
|
||||
return x == 1f ? 1f : 1f - (float) Math.pow(2d, -10d * (double) x);
|
||||
}
|
||||
|
||||
public static float outQuad(float x) {
|
||||
return 1f - MathUtil.square(1f - x);
|
||||
}
|
||||
|
||||
public static float outQuint(float x) {
|
||||
return 1f - (float) Math.pow(1d - (double) x, 5d);
|
||||
}
|
||||
|
||||
public static float outSine(float x) {
|
||||
return (float) Math.sin(x * (float) (Math.PI / 2));
|
||||
}
|
||||
|
||||
public static float inOutSine(float x) {
|
||||
return -((float) Math.cos((float) Math.PI * x) - 1f) / 2f;
|
||||
}
|
||||
|
||||
public static float outBack(float x) {
|
||||
float c1 = 1.70158F;
|
||||
float c3 = 2.70158F;
|
||||
return 1f + c3 * MathUtil.cube(x - 1f) + c1 * MathUtil.square(x - 1f);
|
||||
}
|
||||
|
||||
public static float outQuart(float x) {
|
||||
return 1f - MathUtil.square(MathUtil.square(1f - x));
|
||||
}
|
||||
|
||||
public static float outCubic(float x) {
|
||||
return 1f - MathUtil.cube(1f - x);
|
||||
}
|
||||
|
||||
public static float inOutExpo(float x) {
|
||||
if (x == 0f) {
|
||||
return 0f;
|
||||
} else if (x == 1f) {
|
||||
return 1f;
|
||||
}
|
||||
return x < 0.5f
|
||||
? (float) (Math.pow(2d, 20d * (double) x - 10d) / 2d)
|
||||
: (float) ((2d - Math.pow(2d, -20d * (double) x + 10d)) / 2d);
|
||||
}
|
||||
|
||||
public static float inQuad(float x) {
|
||||
return x * x;
|
||||
}
|
||||
|
||||
public static float outCirc(float x) {
|
||||
return (float) Math.sqrt(1f - MathUtil.square(x - 1f));
|
||||
}
|
||||
|
||||
public static float inOutElastic(float x) {
|
||||
float c5 = (float) Math.PI * 4.0F / 9.0F;
|
||||
if (x == 0f) {
|
||||
return 0f;
|
||||
} else if (x == 1f) {
|
||||
return 1f;
|
||||
}
|
||||
double sin = Math.sin((20d * (double) x - 11.125d) * c5);
|
||||
return x < 0.5f
|
||||
? (float) (-(Math.pow(2d, 20d * (double) x - 10d) * sin) / 2d)
|
||||
: (float) (Math.pow(2d, -20d * (double) x + 10d) * sin / 2d + 1d);
|
||||
}
|
||||
|
||||
public static float inCirc(float x) {
|
||||
return (float) (-Math.sqrt(1f - x * x)) + 1f;
|
||||
}
|
||||
|
||||
public static float inOutBack(float x) {
|
||||
float c1 = 1.70158f;
|
||||
float c2 = c1 * 1.525f;
|
||||
if (x < 0.5F) {
|
||||
return 2f * 2f * x * x * (2f * (c2 + 1f) * x - c2) / 2f;
|
||||
} else {
|
||||
float dt = 2f * x - 2f;
|
||||
return (dt * dt * ((c2 + 1f) * dt + c2) + 2f) / 2f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"V_1_21_11": [
|
||||
"constant",
|
||||
"linear",
|
||||
"in_back",
|
||||
"in_bounce",
|
||||
"in_circ",
|
||||
"in_cubic",
|
||||
"in_elastic",
|
||||
"in_expo",
|
||||
"in_quad",
|
||||
"in_quart",
|
||||
"in_quint",
|
||||
"in_sine",
|
||||
"in_out_back",
|
||||
"in_out_bounce",
|
||||
"in_out_circ",
|
||||
"in_out_cubic",
|
||||
"in_out_elastic",
|
||||
"in_out_expo",
|
||||
"in_out_quad",
|
||||
"in_out_quart",
|
||||
"in_out_quint",
|
||||
"in_out_sine",
|
||||
"out_back",
|
||||
"out_bounce",
|
||||
"out_circ",
|
||||
"out_cubic",
|
||||
"out_elastic",
|
||||
"out_expo",
|
||||
"out_quad",
|
||||
"out_quart",
|
||||
"out_quint",
|
||||
"out_sine"
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user