This commit is contained in:
Sollace 2023-11-28 15:26:55 +00:00
parent 8a85f0709e
commit 16a7b96f81
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
27 changed files with 675 additions and 9 deletions

View file

@ -22,6 +22,8 @@ import com.minelittlepony.unicopia.command.Commands;
import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate; import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate;
import com.minelittlepony.unicopia.container.SpellbookChapterLoader; import com.minelittlepony.unicopia.container.SpellbookChapterLoader;
import com.minelittlepony.unicopia.container.UScreenHandlers; import com.minelittlepony.unicopia.container.UScreenHandlers;
import com.minelittlepony.unicopia.diet.AfflictionType;
import com.minelittlepony.unicopia.diet.DietsLoader;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
import com.minelittlepony.unicopia.entity.effect.UPotions; import com.minelittlepony.unicopia.entity.effect.UPotions;
import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.entity.mob.UEntities;
@ -83,11 +85,7 @@ public class Unicopia implements ModInitializer {
}); });
NocturnalSleepManager.bootstrap(); NocturnalSleepManager.bootstrap();
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(TreeTypeLoader.INSTANCE); registerServerDataReloaders(ResourceManagerHelper.get(ResourceType.SERVER_DATA));
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(UEnchantments.POISONED_JOKE);
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(new TraitLoader());
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(StateMapLoader.INSTANCE);
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(SpellbookChapterLoader.INSTANCE);
UGameEvents.bootstrap(); UGameEvents.bootstrap();
UBlocks.bootstrap(); UBlocks.bootstrap();
@ -98,6 +96,7 @@ public class Unicopia implements ModInitializer {
USounds.bootstrap(); USounds.bootstrap();
Race.bootstrap(); Race.bootstrap();
SpellType.bootstrap(); SpellType.bootstrap();
AfflictionType.bootstrap();
Abilities.bootstrap(); Abilities.bootstrap();
UScreenHandlers.bootstrap(); UScreenHandlers.bootstrap();
UWorldGen.bootstrap(); UWorldGen.bootstrap();
@ -105,6 +104,15 @@ public class Unicopia implements ModInitializer {
UDamageTypes.bootstrap(); UDamageTypes.bootstrap();
} }
private void registerServerDataReloaders(ResourceManagerHelper registry) {
registry.registerReloadListener(TreeTypeLoader.INSTANCE);
registry.registerReloadListener(UEnchantments.POISONED_JOKE);
registry.registerReloadListener(new TraitLoader());
registry.registerReloadListener(StateMapLoader.INSTANCE);
registry.registerReloadListener(SpellbookChapterLoader.INSTANCE);
registry.registerReloadListener(new DietsLoader());
}
public interface SidedAccess { public interface SidedAccess {
Optional<Pony> getPony(); Optional<Pony> getPony();

View file

@ -0,0 +1,70 @@
package com.minelittlepony.unicopia.diet;
import java.util.List;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.Text;
import net.minecraft.util.dynamic.Codecs;
public interface Affliction {
Text NO_EFFECT_TEXT = Text.of("No Effect");
Affliction EMPTY = new Affliction() {
@Override
public void afflict(PlayerEntity player, ItemStack stack) { }
@Override
public Text getName() {
return NO_EFFECT_TEXT;
}
@Override
public AfflictionType<?> getType() {
return AfflictionType.EMPTY;
}
@Override
public void toBuffer(PacketByteBuf buffer) { }
};
Codec<Affliction> CODEC = Codecs.xor(Codec.list(AfflictionType.CODEC)
.mapResult(null)
.xmap(
afflictions -> {
afflictions.removeIf(f -> f.getType() == AfflictionType.EMPTY);
return switch (afflictions.size()) {
case 0 -> EMPTY;
case 1 -> afflictions.get(0);
default -> new CompoundAffliction(afflictions);
};
},
affliction -> ((CompoundAffliction)affliction).afflictions
), AfflictionType.CODEC).xmap(
either -> either.left().or(either::right).get(),
affliction -> affliction instanceof CompoundAffliction ? Either.left(affliction) : Either.right(affliction)
);
void afflict(PlayerEntity player, ItemStack stack);
default void appendTooltip(List<Text> tooltip) {
tooltip.add(getName());
}
Text getName();
AfflictionType<?> getType();
void toBuffer(PacketByteBuf buffer);
static void write(PacketByteBuf buffer, Affliction affliction) {
buffer.writeIdentifier(affliction.getType().id());
affliction.toBuffer(buffer);
}
static Affliction read(PacketByteBuf buffer) {
return AfflictionType.REGISTRY.get(buffer.readIdentifier()).reader().apply(buffer);
}
}

View file

@ -0,0 +1,44 @@
package com.minelittlepony.unicopia.diet;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.util.RegistryUtils;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
import net.minecraft.network.PacketByteBuf.PacketReader;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
import net.minecraft.util.dynamic.Codecs;
public record AfflictionType<T extends Affliction>(Codec<T> codec, Identifier id, PacketReader<T> reader) {
public static final String DEFAULT_ID = "unicopia:apply_status_effect";
public static final Registry<AfflictionType<?>> REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("affliction_type"), DEFAULT_ID);
@SuppressWarnings("unchecked")
public static final Codec<Affliction> CODEC = Codecs.JSON_ELEMENT.<Affliction>flatXmap(json -> {
JsonObject obj = json.getAsJsonObject();
return Identifier.validate(obj.has("type") ? obj.get("type").getAsString() : AfflictionType.DEFAULT_ID).flatMap(type -> {
return AfflictionType.REGISTRY.get(type).codec().parse(JsonOps.INSTANCE, json);
});
}, thing -> {
AfflictionType<?> type = thing.getType();
return ((Codec<Affliction>)type.codec()).encodeStart(JsonOps.INSTANCE, thing).map(json -> {
if (json.isJsonObject()) {
json.getAsJsonObject().addProperty("type", type.id().toString());
}
return json;
});
});
public static final AfflictionType<Affliction> EMPTY = register("empty", Codec.unit(Affliction.EMPTY), buffer -> Affliction.EMPTY);
public static final AfflictionType<Affliction> MANY = register("many", CompoundAffliction.CODEC, CompoundAffliction::new);
public static final AfflictionType<StatusEffectAffliction> APPLY_STATUS_EFFECT = register("apply_status_effect", StatusEffectAffliction.CODEC, StatusEffectAffliction::new);
public static final AfflictionType<MultiplyHungerAffliction> MULTIPLY_HUNGER = register("multiply_hunger", MultiplyHungerAffliction.CODEC, MultiplyHungerAffliction::new);
public static final AfflictionType<ClearLoveSicknessAffliction> CLEAR_LOVE_SICKNESS = register("clear_love_sickness", ClearLoveSicknessAffliction.CODEC, buffer -> ClearLoveSicknessAffliction.INSTANCE);
static <T extends Affliction> AfflictionType<T> register(String name, Codec<T> codec, PacketReader<T> reader) {
return Registry.register(REGISTRY, Unicopia.id(name), new AfflictionType<>(codec, Unicopia.id(name), reader));
}
public static void bootstrap() { }
}

View file

@ -0,0 +1,23 @@
package com.minelittlepony.unicopia.diet;
import com.minelittlepony.unicopia.item.toxin.Toxicity;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.network.PacketByteBuf;
public record Ailment(Toxicity toxicity, Affliction effects) {
public static final Codec<Ailment> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Toxicity.CODEC.fieldOf("toxicity").forGetter(Ailment::toxicity),
Affliction.CODEC.fieldOf("effects").forGetter(Ailment::effects)
).apply(instance, Ailment::new));
public Ailment(PacketByteBuf buffer) {
this(Toxicity.byName(buffer.readString()), Affliction.read(buffer));
}
public void toBuffer(PacketByteBuf buffer) {
buffer.writeString(toxicity.name());
Affliction.write(buffer, effects);
}
}

View file

@ -0,0 +1,35 @@
package com.minelittlepony.unicopia.diet;
import com.minelittlepony.unicopia.entity.effect.UEffects;
import com.mojang.serialization.Codec;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.Text;
public final class ClearLoveSicknessAffliction implements Affliction {
public static final ClearLoveSicknessAffliction INSTANCE = new ClearLoveSicknessAffliction();
public static final Codec<ClearLoveSicknessAffliction> CODEC = Codec.unit(INSTANCE);
@Override
public AfflictionType<?> getType() {
return AfflictionType.CLEAR_LOVE_SICKNESS;
}
@Override
public void afflict(PlayerEntity player, ItemStack stack) {
player.heal(stack.isFood() ? stack.getItem().getFoodComponent().getHunger() : 1);
player.removeStatusEffect(StatusEffects.NAUSEA);
player.removeStatusEffect(UEffects.FOOD_POISONING);
}
@Override
public Text getName() {
return Text.literal("Love");
}
@Override
public void toBuffer(PacketByteBuf buffer) {
}
}

View file

@ -0,0 +1,50 @@
package com.minelittlepony.unicopia.diet;
import java.util.List;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.Text;
class CompoundAffliction implements Affliction {
public final List<Affliction> afflictions;
private final Text name;
public CompoundAffliction(List<Affliction> afflictions) {
this.afflictions = afflictions;
name = afflictions.stream().map(Affliction::getName).reduce(null, (a, b) -> {
return a == null ? b : a.copy().append(" + ").append(b);
});
}
public CompoundAffliction(PacketByteBuf buffer) {
this(buffer.readList(Affliction::read));
}
@Override
public void toBuffer(PacketByteBuf buffer) {
buffer.writeCollection(afflictions, Affliction::write);
}
@Override
public AfflictionType<?> getType() {
return AfflictionType.MANY;
}
@Override
public void appendTooltip(List<Text> tooltip) {
afflictions.forEach(i -> i.appendTooltip(tooltip));
}
@Override
public Text getName() {
return name;
}
@Override
public void afflict(PlayerEntity player, ItemStack stack) {
afflictions.forEach(i -> i.afflict(player, stack));
}
}

View file

@ -0,0 +1,82 @@
package com.minelittlepony.unicopia.diet;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
public record DietProfile(
float defaultMultiplier,
float foragingMultiplier,
List<Multiplier> multipliers,
List<Effect> effects
) {
public static final Codec<DietProfile> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.FLOAT.fieldOf("default_multiplier").forGetter(DietProfile::defaultMultiplier),
Codec.FLOAT.fieldOf("foraging_multiplier").forGetter(DietProfile::foragingMultiplier),
Codec.list(Multiplier.CODEC).fieldOf("multipliers").forGetter(DietProfile::multipliers),
Codec.list(Effect.CODEC).fieldOf("effects").forGetter(DietProfile::effects)
).apply(instance, DietProfile::new));
public DietProfile(PacketByteBuf buffer) {
this(buffer.readFloat(), buffer.readFloat(), buffer.readList(Multiplier::new), buffer.readList(Effect::new));
}
public void toBuffer(PacketByteBuf buffer) {
buffer.writeFloat(defaultMultiplier);
buffer.writeFloat(foragingMultiplier);
buffer.writeCollection(multipliers, (b, t) -> t.toBuffer(b));
buffer.writeCollection(effects, (b, t) -> t.toBuffer(b));
}
public Optional<Multiplier> findMultiplier(ItemStack stack) {
return multipliers.stream().filter(m -> m.test(stack)).findFirst();
}
public Optional<Effect> findEffect(ItemStack stack) {
return effects.stream().filter(m -> m.test(stack)).findFirst();
}
public record Multiplier(
Set<TagKey<Item>> tags,
float hunger,
float saturation
) implements Predicate<ItemStack> {
public static final Codec<Set<TagKey<Item>>> TAGS_CODEC = Codec.list(TagKey.unprefixedCodec(RegistryKeys.ITEM)).xmap(
l -> l.stream().distinct().collect(Collectors.toSet()),
set -> new ArrayList<>(set)
);
public static final Codec<Multiplier> CODEC = RecordCodecBuilder.create(instance -> instance.group(
TAGS_CODEC.fieldOf("tags").forGetter(Multiplier::tags),
Codec.FLOAT.fieldOf("hunger").forGetter(Multiplier::hunger),
Codec.FLOAT.fieldOf("saturation").forGetter(Multiplier::saturation)
).apply(instance, Multiplier::new));
public Multiplier(PacketByteBuf buffer) {
this(buffer.readCollection(HashSet::new, p -> TagKey.of(RegistryKeys.ITEM, p.readIdentifier())), buffer.readFloat(), buffer.readFloat());
}
@Override
public boolean test(ItemStack stack) {
return tags.stream().anyMatch(tag -> stack.isIn(tag));
}
public void toBuffer(PacketByteBuf buffer) {
buffer.writeCollection(tags, (p, t) -> p.writeIdentifier(t.id()));
buffer.writeFloat(hunger);
buffer.writeFloat(saturation);
}
}
}

View file

@ -0,0 +1,74 @@
package com.minelittlepony.unicopia.diet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import org.slf4j.Logger;
import com.google.gson.JsonElement;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.util.Resources;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.JsonOps;
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.minecraft.resource.JsonDataLoader;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.profiler.Profiler;
public class DietsLoader implements IdentifiableResourceReloadListener {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Identifier ID = Unicopia.id("diets");
@Override
public Identifier getFabricId() {
return ID;
}
@Override
public CompletableFuture<Void> reload(Synchronizer sync, ResourceManager manager,
Profiler prepareProfiler, Profiler applyProfiler,
Executor prepareExecutor, Executor applyExecutor) {
var dietsLoadTask = loadData(manager, prepareExecutor, "diets/races").thenApplyAsync(data -> {
Map<Race, DietProfile> profiles = new HashMap<>();
for (var entry : data.entrySet()) {
Identifier id = entry.getKey();
Race.REGISTRY.getOrEmpty(id).ifPresentOrElse(race -> DietProfile.CODEC.parse(JsonOps.INSTANCE, entry.getValue())
.resultOrPartial(LOGGER::error)
.ifPresent(profile -> profiles.put(race, profile)), () -> LOGGER.warn("Skipped diet for unknown race: " + id));
}
return profiles;
}, applyExecutor);
var effectsLoadTask = loadData(manager, prepareExecutor, "diets/food_effects").thenApplyAsync(data -> data.values().stream()
.map(value -> Effect.CODEC.parse(JsonOps.INSTANCE, value)
.resultOrPartial(LOGGER::error))
.filter(Optional::isPresent)
.map(Optional::get)
.toList());
var future = CompletableFuture.allOf(dietsLoadTask, effectsLoadTask);
sync.getClass();
return future.thenRunAsync(() -> {
PonyDiets.load(new PonyDiets(
dietsLoadTask.getNow(Map.of()),
effectsLoadTask.getNow(List.of())
));
}, applyExecutor);
}
private static CompletableFuture<Map<Identifier, JsonElement>> loadData(ResourceManager manager, Executor prepareExecutor, String path) {
return CompletableFuture.supplyAsync(() -> {
Map<Identifier, JsonElement> results = new HashMap<>();
JsonDataLoader.load(manager, path, Resources.GSON, results);
return results;
});
}
}

View file

@ -0,0 +1,56 @@
package com.minelittlepony.unicopia.diet;
import java.util.Optional;
import java.util.function.Predicate;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
public record Effect(
TagKey<Item> tag,
Optional<FoodComponent> foodComponent,
Ailment ailment
) implements Predicate<ItemStack> {
public static final Codec<Effect> CODEC = RecordCodecBuilder.create(instance -> instance.group(
TagKey.unprefixedCodec(RegistryKeys.ITEM).fieldOf("tag").forGetter(Effect::tag),
FoodComponent.CODEC.optionalFieldOf("food_component").forGetter(Effect::foodComponent),
Ailment.CODEC.fieldOf("ailment").forGetter(Effect::ailment)
).apply(instance, Effect::new));
public Effect(PacketByteBuf buffer) {
this(TagKey.of(RegistryKeys.ITEM, buffer.readIdentifier()), buffer.readOptional(FoodComponent::new), new Ailment(buffer));
}
public void toBuffer(PacketByteBuf buffer) {
buffer.writeIdentifier(tag.id());
buffer.writeOptional(foodComponent, (b, f) -> f.toBuffer(b));
ailment.toBuffer(buffer);
}
@Override
public boolean test(ItemStack stack) {
return stack.isIn(tag);
}
public record FoodComponent (float hunger, float saturation) {
public static final Codec<FoodComponent> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.FLOAT.fieldOf("hunger").forGetter(FoodComponent::hunger),
Codec.FLOAT.fieldOf("saturation").forGetter(FoodComponent::saturation)
).apply(instance, FoodComponent::new));
public FoodComponent(PacketByteBuf buffer) {
this(buffer.readFloat(), buffer.readFloat());
}
public void toBuffer(PacketByteBuf buffer) {
buffer.writeFloat(hunger);
buffer.writeFloat(saturation);
}
}
}

View file

@ -0,0 +1,43 @@
package com.minelittlepony.unicopia.diet;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.FoodComponent;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.Text;
public record MultiplyHungerAffliction(float multiplier) implements Affliction {
public static final Codec<MultiplyHungerAffliction> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.FLOAT.fieldOf("multiplier").forGetter(MultiplyHungerAffliction::multiplier)
).apply(instance, MultiplyHungerAffliction::new));
public MultiplyHungerAffliction(PacketByteBuf buffer) {
this(buffer.readFloat());
}
@Override
public void toBuffer(PacketByteBuf buffer) {
buffer.writeFloat(multiplier);
}
@Override
public AfflictionType<?> getType() {
return AfflictionType.MULTIPLY_HUNGER;
}
@Override
public void afflict(PlayerEntity player, ItemStack stack) {
FoodComponent food = stack.getItem().getFoodComponent();
player.getHungerManager().setFoodLevel((int)(food.getHunger() * multiplier));
player.getHungerManager().setSaturationLevel(food.getSaturationModifier() * multiplier);
}
@Override
public Text getName() {
return Text.translatable("Lose %s%% hunger", multiplier * 100);
}
}

View file

@ -0,0 +1,57 @@
package com.minelittlepony.unicopia.diet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.diet.DietProfile.Multiplier;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
public class PonyDiets {
private final Map<Race, DietProfile> diets;
private final List<Effect> effects;
static PonyDiets INSTANCE = new PonyDiets(Map.of(), List.of());
public static PonyDiets getinstance() {
return INSTANCE;
}
public static void load(PonyDiets diets) {
INSTANCE = diets;
}
PonyDiets(Map<Race, DietProfile> diets, List<Effect> effects) {
this.diets = diets;
this.effects = effects;
}
public PonyDiets(PacketByteBuf buffer) {
this(buffer.readMap(b -> b.readRegistryValue(Race.REGISTRY), DietProfile::new), buffer.readList(Effect::new));
}
public void toBuffer(PacketByteBuf buffer) {
buffer.writeMap(diets, (b, r) -> b.writeRegistryValue(Race.REGISTRY, r), (b, e) -> e.toBuffer(b));
buffer.writeCollection(effects, (b, e) -> e.toBuffer(b));
}
public Optional<DietProfile> getDiet(Race race) {
return Optional.ofNullable(diets.get(race));
}
public Optional<Effect> getEffects(ItemStack stack) {
return effects.stream().filter(effect -> effect.test(stack)).findFirst();
}
public Optional<Effect> getEffects(ItemStack stack, Pony pony) {
return getDiet(pony.getObservedSpecies()).flatMap(diet -> diet.findEffect(stack)).or(() -> getEffects(stack));
}
public Optional<Multiplier> getMultiplier(ItemStack stack, Pony pony) {
return getDiet(pony.getObservedSpecies()).flatMap(diet -> diet.findMultiplier(stack));
}
}

View file

@ -0,0 +1,39 @@
package com.minelittlepony.unicopia.diet;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.dynamic.Codecs;
public record Range(int min, int max) {
public static final Codec<Range> CODEC = Codecs.xor(
Codec.INT.xmap(value -> Range.of(value, -1), range -> range.min()),
RecordCodecBuilder.create(instance -> instance.group(
Codec.INT.fieldOf("min").forGetter(Range::min),
Codec.INT.fieldOf("max").forGetter(Range::max)
).apply(instance, Range::of))
).xmap(either -> either.left().or(either::right).get(), l -> Either.right(l));
public static Range of(int min, int max) {
return new Range(min, max);
}
public static Range of(PacketByteBuf buffer) {
return of(buffer.readInt(), buffer.readInt());
}
public void toBuffer(PacketByteBuf buffer) {
buffer.writeInt(min);
buffer.writeInt(max);
}
public int getTicks(int currentTicks) {
return clamp((min * 20) + currentTicks);
}
public int clamp(int value) {
return max > 0 ? Math.min(value, max * 20) : value;
}
}

View file

@ -0,0 +1,78 @@
package com.minelittlepony.unicopia.diet;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.registry.Registries;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.StringHelper;
import net.minecraft.util.math.MathHelper;
public record StatusEffectAffliction(Identifier effect, Range seconds, Range amplifier, int chance) implements Affliction {
public static final Codec<StatusEffectAffliction> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Identifier.CODEC.fieldOf("effect").forGetter(StatusEffectAffliction::effect),
Range.CODEC.fieldOf("seconds").forGetter(StatusEffectAffliction::seconds),
Range.CODEC.optionalFieldOf("amplifier", Range.of(0, -1)).forGetter(StatusEffectAffliction::amplifier),
Codec.INT.optionalFieldOf("chance", 0).forGetter(StatusEffectAffliction::chance)
).apply(instance, StatusEffectAffliction::new));
public StatusEffectAffliction(PacketByteBuf buffer) {
this(buffer.readIdentifier(), Range.of(buffer), Range.of(buffer), buffer.readInt());
}
public void toBuffer(PacketByteBuf buffer) {
buffer.writeIdentifier(effect);
seconds.toBuffer(buffer);
amplifier.toBuffer(buffer);
buffer.writeInt(chance);
}
@Override
public AfflictionType<?> getType() {
return AfflictionType.APPLY_STATUS_EFFECT;
}
@Override
public void afflict(PlayerEntity player, ItemStack stack) {
if (chance > 0 && player.getWorld().random.nextInt(chance) > 0) {
return;
}
Registries.STATUS_EFFECT.getOrEmpty(effect).ifPresent(effect -> {
float health = player.getHealth();
StatusEffectInstance current = player.getStatusEffect(effect);
player.addStatusEffect(new StatusEffectInstance(effect,
seconds.getTicks(current == null ? 0 : current.getDuration()),
amplifier.getTicks(current == null ? 0 : current.getAmplifier())
));
// keep original health
if (effect.getAttributeModifiers().containsKey(EntityAttributes.GENERIC_MAX_HEALTH)) {
player.setHealth(MathHelper.clamp(health, 0, player.getMaxHealth()));
}
});
}
@Override
public Text getName() {
return Registries.STATUS_EFFECT.getOrEmpty(effect).map(effect -> {
MutableText text = effect.getName().copy();
if (amplifier.min() > 0) {
text = Text.translatable("potion.withAmplifier", text, Text.translatable("potion.potency." + (amplifier.min() * 20)));
}
text = Text.translatable("potion.withDuration", text, StringHelper.formatTicks(seconds.min() * 20));
if (chance > 0) {
text = Text.translatable("potion.withChance", chance, text);
}
return (Text)text;
}).orElse(Text.of("No Effect"));
}
}

View file

@ -94,7 +94,6 @@ public interface Toxin extends Affliction {
}; };
} }
@Deprecated
static Toxin of(Text name, Affliction affliction) { static Toxin of(Text name, Affliction affliction) {
return new Toxin() { return new Toxin() {
@Override @Override

View file

@ -6,6 +6,7 @@ import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.ability.data.tree.TreeTypeLoader; import com.minelittlepony.unicopia.ability.data.tree.TreeTypeLoader;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.container.SpellbookChapterLoader; import com.minelittlepony.unicopia.container.SpellbookChapterLoader;
import com.minelittlepony.unicopia.diet.PonyDiets;
import com.sollace.fabwork.api.packets.Packet; import com.sollace.fabwork.api.packets.Packet;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@ -15,13 +16,15 @@ import net.minecraft.util.Identifier;
public record MsgServerResources ( public record MsgServerResources (
Map<Identifier, SpellTraits> traits, Map<Identifier, SpellTraits> traits,
Map<Identifier, ?> chapters, Map<Identifier, ?> chapters,
Map<Identifier, TreeTypeLoader.TreeTypeDef> treeTypes Map<Identifier, TreeTypeLoader.TreeTypeDef> treeTypes,
PonyDiets diets
) implements Packet<PlayerEntity> { ) implements Packet<PlayerEntity> {
public MsgServerResources() { public MsgServerResources() {
this( this(
SpellTraits.all(), SpellTraits.all(),
SpellbookChapterLoader.INSTANCE.getChapters(), SpellbookChapterLoader.INSTANCE.getChapters(),
TreeTypeLoader.INSTANCE.getEntries() TreeTypeLoader.INSTANCE.getEntries(),
PonyDiets.getinstance()
); );
} }
@ -29,7 +32,8 @@ public record MsgServerResources (
this( this(
buffer.readMap(PacketByteBuf::readIdentifier, SpellTraits::fromPacket), buffer.readMap(PacketByteBuf::readIdentifier, SpellTraits::fromPacket),
InteractionManager.instance().readChapters(buffer), InteractionManager.instance().readChapters(buffer),
buffer.readMap(PacketByteBuf::readIdentifier, TreeTypeLoader.TreeTypeDef::new) buffer.readMap(PacketByteBuf::readIdentifier, TreeTypeLoader.TreeTypeDef::new),
new PonyDiets(buffer)
); );
} }
@ -38,5 +42,6 @@ public record MsgServerResources (
buffer.writeMap(traits, PacketByteBuf::writeIdentifier, (r, v) -> v.write(r)); buffer.writeMap(traits, PacketByteBuf::writeIdentifier, (r, v) -> v.write(r));
buffer.writeMap(chapters, PacketByteBuf::writeIdentifier, (r, v) -> ((SpellbookChapterLoader.Chapter)v).write(r)); buffer.writeMap(chapters, PacketByteBuf::writeIdentifier, (r, v) -> ((SpellbookChapterLoader.Chapter)v).write(r));
buffer.writeMap(treeTypes, PacketByteBuf::writeIdentifier, (r, v) -> v.write(r)); buffer.writeMap(treeTypes, PacketByteBuf::writeIdentifier, (r, v) -> v.write(r));
diets.toBuffer(buffer);
} }
} }

View file

@ -15,6 +15,7 @@ import com.minelittlepony.unicopia.client.UnicopiaClient;
import com.minelittlepony.unicopia.client.gui.TribeSelectionScreen; import com.minelittlepony.unicopia.client.gui.TribeSelectionScreen;
import com.minelittlepony.unicopia.client.gui.spellbook.ClientChapters; import com.minelittlepony.unicopia.client.gui.spellbook.ClientChapters;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Chapter; import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Chapter;
import com.minelittlepony.unicopia.diet.PonyDiets;
import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.entity.mob.UEntities;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.*; import com.minelittlepony.unicopia.network.*;
@ -97,6 +98,7 @@ public class ClientNetworkHandlerImpl {
SpellTraits.load(packet.traits()); SpellTraits.load(packet.traits());
ClientChapters.load((Map<Identifier, Chapter>)packet.chapters()); ClientChapters.load((Map<Identifier, Chapter>)packet.chapters());
TreeTypes.load(packet.treeTypes()); TreeTypes.load(packet.treeTypes());
PonyDiets.load(packet.diets());
} }
private void handlePlayerAnimation(PlayerEntity sender, MsgPlayerAnimationChange packet) { private void handlePlayerAnimation(PlayerEntity sender, MsgPlayerAnimationChange packet) {

View file

@ -374,6 +374,7 @@
"item.minecraft.lingering_potion.effect.unicopia.tribe_swap_hippogriff": "Lingering Potion of Hippogriff Metamorphosis", "item.minecraft.lingering_potion.effect.unicopia.tribe_swap_hippogriff": "Lingering Potion of Hippogriff Metamorphosis",
"item.minecraft.tipped_arrow.effect.unicopia.tribe_swap_hippogriff": "Arrow of Hippogriff Metamorphosis", "item.minecraft.tipped_arrow.effect.unicopia.tribe_swap_hippogriff": "Arrow of Hippogriff Metamorphosis",
"potion.withChance": "1 in %s chance of %s",
"potion.potency.6": "VII", "potion.potency.6": "VII",
"spell.unicopia.frost": "Frost", "spell.unicopia.frost": "Frost",