Merge branch '1.20.1' into 1.20.2

This commit is contained in:
Sollace 2024-10-08 16:40:25 +01:00
commit e317df4bf9
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
147 changed files with 1814 additions and 518 deletions

38
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
labels: bug
assignees: Sollace
---
**Describe the bug**
A clear and concise description of what the bug is.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Steps to reproduce**
Help us figure out what you did to get this issue
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Version Information:**
- Minecraft Version: [e.g. 1.20.5]
- Mine Little Pony Version:
**Mod Loader:**
- [ ] Fabric
- [ ] Quilt
- [ ] Neoforge (with connector)
**Client/Server Logs**
If applicable, add log files by uploading them as attachments or put them below.
<details>
```
**Paste logs here**
```
</details>

View file

@ -0,0 +1,26 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: Sollace
---
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Additional context**
Add any other context or screenshots about the feature request here.
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Version Information:**
- Minecraft Version: [e.g. 1.20.5]
- Mine Little Pony Version:
**Mod Loader:**
- [ ] Fabric
- [ ] Quilt
- [ ] Neoforge (with connector)

View file

@ -77,9 +77,14 @@ dependencies {
include "com.sollace:Romanizer:Romanizer:1.0.2" include "com.sollace:Romanizer:Romanizer:1.0.2"
modCompileOnly "com.terraformersmc:modmenu:${project.modmenu_version}" modCompileOnly "com.terraformersmc:modmenu:${project.modmenu_version}"
if (project.use_trinkets == '1') {
modCompileOnly "dev.emi:trinkets:${project.trinkets_version}" modCompileOnly "dev.emi:trinkets:${project.trinkets_version}"
modCompileOnly "dev.onyxstudios.cardinal-components-api:cardinal-components-base:5.3.0" modCompileOnly "dev.onyxstudios.cardinal-components-api:cardinal-components-base:5.3.0"
modCompileOnly "dev.onyxstudios.cardinal-components-api:cardinal-components-entity:5.3.0" modCompileOnly "dev.onyxstudios.cardinal-components-api:cardinal-components-entity:5.3.0"
} else {
modCompileOnly "dev.emi:trinkets-dummy:${project.trinkets_version}"
}
modImplementation "com.terraformersmc.terraform-api:terraform-wood-api-v1:${project.terraformer_api_version}" modImplementation "com.terraformersmc.terraform-api:terraform-wood-api-v1:${project.terraformer_api_version}"
include "com.terraformersmc.terraform-api:terraform-wood-api-v1:${project.terraformer_api_version}" include "com.terraformersmc.terraform-api:terraform-wood-api-v1:${project.terraformer_api_version}"
@ -98,7 +103,12 @@ dependencies {
if (project.use_sodium == '1') { if (project.use_sodium == '1') {
modCompileOnly "maven.modrinth:indium:${project.indium_version}", { exclude group: "net.fabricmc.fabric-api" } modCompileOnly "maven.modrinth:indium:${project.indium_version}", { exclude group: "net.fabricmc.fabric-api" }
modCompileOnly "maven.modrinth:sodium:${project.sodium_version}", { exclude group: "net.fabricmc.fabric-api" } modCompileOnly "maven.modrinth:sodium:${project.sodium_version}", { exclude group: "net.fabricmc.fabric-api" }
// modCompileOnly "maven.modrinth:iris:${project.iris_version}", { exclude group: "net.fabricmc.fabric-api" } if (project.use_iris == '1') {
modCompileOnly "maven.modrinth:iris:${project.iris_version}", { exclude group: "net.fabricmc.fabric-api" }
modImplementation "org.anarres:jcpp:1.4.14"
modImplementation "org.antlr:antlr4-runtime:4.13.1"
modImplementation "io.github.douira:glsl-transformer:2.0.1"
}
} }
if (project.tmi_type == 'emi') { if (project.tmi_type == 'emi') {

View file

@ -30,8 +30,10 @@ org.gradle.daemon=false
nodium_version=1.1.0+1.20 nodium_version=1.1.0+1.20
# Testing # Testing
use_trinkets=1
use_pehkui=0 use_pehkui=0
use_sodium=0 use_sodium=0
use_iris=1
farmers_delight_version=1.20.1-2.0.9 farmers_delight_version=1.20.1-2.0.9
pehkui_version=3.7.8+1.14.4-1.20.2 pehkui_version=3.7.8+1.14.4-1.20.2

Binary file not shown.

View file

@ -22,7 +22,7 @@ public interface EquineContext {
} }
default boolean collidesWithClouds() { default boolean collidesWithClouds() {
return getCompositeRace().canInteractWithClouds(); return getCompositeRace().canInteractWithClouds() || getCloudWalkingStrength() >= 1;
} }
default boolean hasFeatherTouch() { default boolean hasFeatherTouch() {

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Stack;
import java.util.UUID; import java.util.UUID;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -37,7 +38,7 @@ public class InteractionManager {
@Nullable @Nullable
private SyncedConfig config; private SyncedConfig config;
private EquineContext equineContext = EquineContext.ABSENT; private final Stack<EquineContext> equineContext = new Stack<>();
public static InteractionManager getInstance() { public static InteractionManager getInstance() {
return INSTANCE; return INSTANCE;
@ -109,11 +110,21 @@ public class InteractionManager {
} }
public void setEquineContext(EquineContext context) { public void setEquineContext(EquineContext context) {
equineContext = context; equineContext.push(context);
}
public void clearEquineContext() {
if (!equineContext.isEmpty()) {
equineContext.pop();
}
} }
public EquineContext getEquineContext() { public EquineContext getEquineContext() {
return getClientPony().map(EquineContext.class::cast).orElse(equineContext); return getClientPony().map(EquineContext.class::cast).orElseGet(this::getPathingEquineContext);
}
public EquineContext getPathingEquineContext() {
return equineContext.isEmpty() ? EquineContext.ABSENT : equineContext.peek();
} }
public Optional<Pony> getClientPony() { public Optional<Pony> getClientPony() {

View file

@ -70,7 +70,7 @@ public record Race (
* This is used if there are no other races. * This is used if there are no other races.
*/ */
public static final Race UNSET = register("unset", new Builder().availability(Availability.COMMANDS)); public static final Race UNSET = register("unset", new Builder().availability(Availability.COMMANDS));
public static final Race HUMAN = register("human", new Builder().availability(Availability.COMMANDS)); public static final Race HUMAN = register("human", new Builder());
public static final Race EARTH = register("earth", new Builder().foraging().earth() public static final Race EARTH = register("earth", new Builder().foraging().earth()
.abilities(Abilities.HUG, Abilities.STOMP, Abilities.KICK, Abilities.GROW) .abilities(Abilities.HUG, Abilities.STOMP, Abilities.KICK, Abilities.GROW)
); );

View file

@ -46,6 +46,7 @@ public interface UConventionalTags {
TagKey<Item> FRUITS = item("fruits"); TagKey<Item> FRUITS = item("fruits");
TagKey<Item> WORMS = item("worms"); TagKey<Item> WORMS = item("worms");
TagKey<Item> ROCKS = item("rocks"); TagKey<Item> ROCKS = item("rocks");
TagKey<Item> GEMS = item("gems");
TagKey<Item> RAW_INSECT = item("raw_insect"); TagKey<Item> RAW_INSECT = item("raw_insect");
TagKey<Item> COOKED_INSECT = item("cooked_insect"); TagKey<Item> COOKED_INSECT = item("cooked_insect");

View file

@ -31,6 +31,7 @@ import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.server.world.BlockDestructionManager; import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
import com.minelittlepony.unicopia.server.world.Ether;
import com.minelittlepony.unicopia.server.world.NocturnalSleepManager; import com.minelittlepony.unicopia.server.world.NocturnalSleepManager;
import com.minelittlepony.unicopia.server.world.UGameRules; import com.minelittlepony.unicopia.server.world.UGameRules;
import com.minelittlepony.unicopia.server.world.UWorldGen; import com.minelittlepony.unicopia.server.world.UWorldGen;
@ -71,6 +72,7 @@ public class Unicopia implements ModInitializer {
((BlockDestructionManager.Source)w).getDestructionManager().tick(); ((BlockDestructionManager.Source)w).getDestructionManager().tick();
ZapAppleStageStore.get(w).tick(); ZapAppleStageStore.get(w).tick();
WeatherConditions.get(w).tick(); WeatherConditions.get(w).tick();
Ether.get(w).tick();
if (Debug.SPELLBOOK_CHAPTERS) { if (Debug.SPELLBOOK_CHAPTERS) {
SpellbookChapterLoader.INSTANCE.sendUpdate(w.getServer()); SpellbookChapterLoader.INSTANCE.sendUpdate(w.getServer());
} }

View file

@ -37,7 +37,7 @@ public class BatPonyHangAbility implements Ability<Multi> {
} }
return TraceHelper.findBlock(player.asEntity(), 5, 1) return TraceHelper.findBlock(player.asEntity(), 5, 1)
.map(BlockPos::down) .map(pos -> pos.down(player.getPhysics().getGravitySignum()))
.filter(player.getAcrobatics()::canHangAt) .filter(player.getAcrobatics()::canHangAt)
.map(pos -> new Multi(pos, 1)); .map(pos -> new Multi(pos, 1));
} }

View file

@ -14,6 +14,7 @@ import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.recipe.TransformCropsRecipe; import com.minelittlepony.unicopia.recipe.TransformCropsRecipe;
import com.minelittlepony.unicopia.recipe.URecipes; import com.minelittlepony.unicopia.recipe.URecipes;
import com.minelittlepony.unicopia.server.world.BlockDestructionManager; import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
import com.minelittlepony.unicopia.server.world.ModificationType;
import com.minelittlepony.unicopia.util.TraceHelper; import com.minelittlepony.unicopia.util.TraceHelper;
import com.minelittlepony.unicopia.util.VecHelper; import com.minelittlepony.unicopia.util.VecHelper;
@ -70,8 +71,10 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
for (BlockPos pos : BlockPos.iterate( for (BlockPos pos : BlockPos.iterate(
data.pos().add(-2, -2, -2), data.pos().add(-2, -2, -2),
data.pos().add( 2, 2, 2))) { data.pos().add( 2, 2, 2))) {
if (player.canModifyAt(pos, ModificationType.PHYSICAL)) {
count += applySingle(player, player.asWorld(), player.asWorld().getBlockState(pos), pos); count += applySingle(player, player.asWorld(), player.asWorld().getBlockState(pos), pos);
} }
}
} else { } else {
count = 1; count = 1;
} }

View file

@ -17,6 +17,7 @@ import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.server.world.BlockDestructionManager; import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
import com.minelittlepony.unicopia.server.world.ModificationType;
import com.minelittlepony.unicopia.util.*; import com.minelittlepony.unicopia.util.*;
import net.minecraft.block.BeehiveBlock; import net.minecraft.block.BeehiveBlock;
@ -98,7 +99,7 @@ public class EarthPonyKickAbility implements Ability<Pos> {
} }
BlockPos pos = kickLocation.pos(); BlockPos pos = kickLocation.pos();
EarthPonyStompAbility.stompBlock(w, pos, 10 * (1 + player.getLevel().getScaled(5)) * w.getBlockState(pos).calcBlockBreakingDelta(player.asEntity(), w, pos)); EarthPonyStompAbility.stompBlock(player, w, pos, 10 * (1 + player.getLevel().getScaled(5)) * w.getBlockState(pos).calcBlockBreakingDelta(player.asEntity(), w, pos));
player.setAnimation(Animation.KICK, Animation.Recipient.ANYONE); player.setAnimation(Animation.KICK, Animation.Recipient.ANYONE);
}); });
} }
@ -165,10 +166,16 @@ public class EarthPonyKickAbility implements Ability<Pos> {
if (BlockDestructionManager.of(player.getWorld()).getBlockDestruction(pos) + 4 >= BlockDestructionManager.MAX_DAMAGE) { if (BlockDestructionManager.of(player.getWorld()).getBlockDestruction(pos) + 4 >= BlockDestructionManager.MAX_DAMAGE) {
if (player.getWorld().random.nextInt(30) == 0) { if (player.getWorld().random.nextInt(30) == 0) {
tree.logs().forEach(player.getWorld(), (w, state, p) -> w.breakBlock(p, true)); tree.logs().forEach(player.getWorld(), (w, state, p) -> {
if (iplayer.canModifyAt(p, ModificationType.PHYSICAL)) {
w.breakBlock(p, true);
}
});
tree.leaves().forEach(player.getWorld(), (w, state, p) -> { tree.leaves().forEach(player.getWorld(), (w, state, p) -> {
if (iplayer.canModifyAt(p, ModificationType.PHYSICAL)) {
Block.dropStacks(w.getBlockState(p), w, p); Block.dropStacks(w.getBlockState(p), w, p);
w.setBlockState(p, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL); w.setBlockState(p, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL);
}
}); });
} }

View file

@ -19,6 +19,7 @@ import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.server.world.BlockDestructionManager; import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
import com.minelittlepony.unicopia.server.world.ModificationType;
import com.minelittlepony.unicopia.util.PosHelper; import com.minelittlepony.unicopia.util.PosHelper;
import com.minelittlepony.unicopia.util.VecHelper; import com.minelittlepony.unicopia.util.VecHelper;
@ -166,7 +167,7 @@ public class EarthPonyStompAbility implements Ability<Hit> {
double radius = rad + heavyness * 0.3; double radius = rad + heavyness * 0.3;
spawnEffectAround(player, center, radius, rad); spawnEffectAround(iplayer, player, center, radius, rad);
ParticleUtils.spawnParticle(player.getWorld(), UParticles.GROUND_POUND, player.getX(), player.getY() - 1, player.getZ(), 0, 0, 0); ParticleUtils.spawnParticle(player.getWorld(), UParticles.GROUND_POUND, player.getX(), player.getY() - 1, player.getZ(), 0, 0, 0);
BlockState steppingState = player.getSteppingBlockState(); BlockState steppingState = player.getSteppingBlockState();
@ -198,17 +199,17 @@ public class EarthPonyStompAbility implements Ability<Hit> {
return true; return true;
} }
public static void spawnEffectAround(Entity source, BlockPos center, double radius, double range) { public static void spawnEffectAround(Pony pony, Entity source, BlockPos center, double radius, double range) {
BlockPos.stream(new BlockBox(center).expand(MathHelper.ceil(radius))).forEach(i -> { BlockPos.stream(new BlockBox(center).expand(MathHelper.ceil(radius))).forEach(i -> {
double dist = Math.sqrt(i.getSquaredDistance(source.getX(), source.getY(), source.getZ())); double dist = Math.sqrt(i.getSquaredDistance(source.getX(), source.getY(), source.getZ()));
if (dist <= radius) { if (dist <= radius) {
spawnEffect(source.getWorld(), i, dist, range); spawnEffect(pony, source.getWorld(), i, dist, range);
} }
}); });
} }
public static void spawnEffect(World w, BlockPos pos, double dist, double rad) { public static void spawnEffect(Pony pony, World w, BlockPos pos, double dist, double rad) {
if (w.getBlockState(pos.up()).isAir()) { if (w.getBlockState(pos.up()).isAir()) {
BlockState state = w.getBlockState(pos); BlockState state = w.getBlockState(pos);
@ -216,18 +217,18 @@ public class EarthPonyStompAbility implements Ability<Hit> {
float scaledHardness = (1 - hardness / 70); float scaledHardness = (1 - hardness / 70);
float damage = hardness < 0 ? 0 : MathHelper.clamp((int)((1 - dist / rad) * 9 * scaledHardness), 0, BlockDestructionManager.MAX_DAMAGE - 1); float damage = hardness < 0 ? 0 : MathHelper.clamp((int)((1 - dist / rad) * 9 * scaledHardness), 0, BlockDestructionManager.MAX_DAMAGE - 1);
stompBlock(w, pos, damage); stompBlock(pony, w, pos, damage);
} }
} }
public static void stompBlock(World w, BlockPos pos, float damage) { public static void stompBlock(Pony pony, World w, BlockPos pos, float damage) {
BlockState state = w.getBlockState(pos); BlockState state = w.getBlockState(pos);
if (state.isAir() || damage <= 0) { if (state.isAir() || damage <= 0) {
return; return;
} }
if (BlockDestructionManager.of(w).damageBlock(pos, damage) >= BlockDestructionManager.MAX_DAMAGE) { if (BlockDestructionManager.of(w).damageBlock(pos, damage) >= BlockDestructionManager.MAX_DAMAGE && pony.canModifyAt(pos, ModificationType.PHYSICAL)) {
w.breakBlock(pos, true); w.breakBlock(pos, true);
if (w instanceof ServerWorld) { if (w instanceof ServerWorld) {

View file

@ -8,6 +8,7 @@ import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.ability.data.Numeric; import com.minelittlepony.unicopia.ability.data.Numeric;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.advancement.UCriteria; import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
@ -126,8 +127,10 @@ public class ScreechAbility implements Ability<Numeric> {
@Override @Override
public void coolDown(Pony player, AbilitySlot slot) { public void coolDown(Pony player, AbilitySlot slot) {
Vec3d eyePos = player.asEntity().getPos().add(0, MineLPDelegate.getInstance().getPonyHeight(player.asEntity()) * 0.8, 0);
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
player.addParticle(ParticleTypes.BUBBLE_POP, player.asEntity().getEyePos(), player.addParticle(ParticleTypes.BUBBLE_POP, eyePos,
VecHelper.supply(() -> (player.asWorld().getRandom().nextGaussian() - 0.5) * 0.3) VecHelper.supply(() -> (player.asWorld().getRandom().nextGaussian() - 0.5) * 0.3)
); );
} }

View file

@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d;
public class ToggleFlightAbility implements Ability<Hit> { public class ToggleFlightAbility implements Ability<Hit> {
@ -27,7 +28,7 @@ public class ToggleFlightAbility implements Ability<Hit> {
@Nullable @Nullable
@Override @Override
public Optional<Hit> prepare(Pony player) { public Optional<Hit> prepare(Pony player) {
return Hit.of(!player.asEntity().hasVehicle() && !player.asEntity().isCreative() && !player.getPhysics().getFlightType().isGrounded()); return Hit.of(!player.asEntity().isCreative() && !player.getPhysics().getFlightType().isGrounded());
} }
@Override @Override
@ -59,6 +60,11 @@ public class ToggleFlightAbility implements Ability<Hit> {
player.subtractEnergyCost(1); player.subtractEnergyCost(1);
if (!player.getPhysics().isFlying()) { if (!player.getPhysics().isFlying()) {
if (player.asEntity().hasVehicle()) {
Vec3d pos = player.asEntity().getPos();
player.asEntity().stopRiding();
player.asEntity().setPosition(pos.getX(), pos.getY() + 0.25, pos.getZ());
}
player.asEntity().addVelocity(0, player.getPhysics().getGravitySignum() * 0.7F, 0); player.asEntity().addVelocity(0, player.getPhysics().getGravitySignum() * 0.7F, 0);
Living.updateVelocity(player.asEntity()); Living.updateVelocity(player.asEntity());
player.getPhysics().startFlying(true); player.getPhysics().startFlying(true);

View file

@ -116,6 +116,9 @@ class MultiSpellSlot implements SpellSlots, NbtSerialisable {
if (s != null) { if (s != null) {
s.setDead(); s.setDead();
s.tickDying(owner); s.tickDying(owner);
if (s.isDead()) {
s.destroy(owner);
}
} }
} }
} }
@ -128,7 +131,7 @@ class MultiSpellSlot implements SpellSlots, NbtSerialisable {
return hasValue ? Status.NEW : Status.REMOVED; return hasValue ? Status.NEW : Status.REMOVED;
} }
return spell.hasDirtySpell() ? Status.UPDATED : Status.DEFAULT; return Status.DEFAULT;
} }
@Override @Override

View file

@ -8,8 +8,10 @@ import com.minelittlepony.unicopia.ability.magic.spell.attribute.TooltipFactory;
import com.minelittlepony.unicopia.ability.magic.spell.effect.*; import com.minelittlepony.unicopia.ability.magic.spell.effect.*;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import net.minecraft.util.math.MathHelper;
public abstract class AbstractAreaEffectSpell extends AbstractSpell { public abstract class AbstractAreaEffectSpell extends AbstractSpell {
protected static final SpellAttribute<Float> RANGE = SpellAttribute.create(SpellAttributeType.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> Math.max(0, 4 + power)); protected static final SpellAttribute<Float> RANGE = SpellAttribute.create(SpellAttributeType.RANGE, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.POWER, power -> MathHelper.clamp(4 + power, 0, 32));
public static final TooltipFactory TOOLTIP = RANGE; public static final TooltipFactory TOOLTIP = RANGE;
protected AbstractAreaEffectSpell(CustomisedSpellType<?> type) { protected AbstractAreaEffectSpell(CustomisedSpellType<?> type) {

View file

@ -80,18 +80,6 @@ public abstract class AbstractDelegatingSpell implements Spell {
return getOrEmpty().isDying(); return getOrEmpty().isDying();
} }
@Deprecated
@Override
public boolean isDirty() {
return delegate.hasDirtySpell();
}
@Deprecated
@Override
public void setDirty() {
getOrEmpty().setDirty();
}
@Override @Override
public boolean isHidden() { public boolean isHidden() {
return getOrEmpty().isHidden(); return getOrEmpty().isHidden();

View file

@ -20,7 +20,7 @@ import net.minecraft.nbt.NbtCompound;
*/ */
public abstract class AbstractDisguiseSpell extends AbstractSpell implements Disguise, ProjectileImpactListener { public abstract class AbstractDisguiseSpell extends AbstractSpell implements Disguise, ProjectileImpactListener {
private final EntityAppearance disguise = new EntityAppearance(); private final EntityAppearance disguise = dataTracker.startTracking(new EntityAppearance());
public AbstractDisguiseSpell(CustomisedSpellType<?> type) { public AbstractDisguiseSpell(CustomisedSpellType<?> type) {
super(type); super(type);

View file

@ -26,11 +26,18 @@ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements I
private final DataTracker.Entry<Boolean> suppressed = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); private final DataTracker.Entry<Boolean> suppressed = dataTracker.startTracking(TrackableDataType.BOOLEAN, false);
private int suppressionCounter; private int suppressionCounter;
private boolean forced;
public DispersableDisguiseSpell(CustomisedSpellType<?> type) { public DispersableDisguiseSpell(CustomisedSpellType<?> type) {
super(type); super(type);
setHidden(true); setHidden(true);
} }
public void setForced() {
forced = true;
setHidden(false);
}
@Override @Override
public boolean isVulnerable(Caster<?> otherSource, Spell other) { public boolean isVulnerable(Caster<?> otherSource, Spell other) {
return suppressionCounter <= otherSource.getLevel().get(); return suppressionCounter <= otherSource.getLevel().get();
@ -59,7 +66,7 @@ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements I
} }
} }
if (!source.canUse(Abilities.DISGUISE)) { if (!forced && !source.canUse(Abilities.DISGUISE)) {
setDead(); setDead();
} }
@ -91,12 +98,14 @@ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements I
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {
super.toNBT(compound); super.toNBT(compound);
compound.putInt("suppressionCounter", suppressionCounter); compound.putInt("suppressionCounter", suppressionCounter);
compound.putBoolean("forced", forced);
} }
@Override @Override
public void fromNBT(NbtCompound compound) { public void fromNBT(NbtCompound compound) {
super.fromNBT(compound); super.fromNBT(compound);
suppressionCounter = compound.getInt("suppressionCounter"); suppressionCounter = compound.getInt("suppressionCounter");
forced = compound.getBoolean("forced");
if (suppressionCounter > 0) { if (suppressionCounter > 0) {
suppressed.set(true); suppressed.set(true);
} }

View file

@ -44,11 +44,6 @@ public final class EmptySpell implements Spell {
return false; return false;
} }
@Override
public boolean isDirty() {
return false;
}
@Override @Override
public boolean tick(Caster<?> caster, Situation situation) { public boolean tick(Caster<?> caster, Situation situation) {
return false; return false;
@ -57,9 +52,6 @@ public final class EmptySpell implements Spell {
@Override @Override
public void tickDying(Caster<?> caster) { } public void tickDying(Caster<?> caster) { }
@Override
public void setDirty() { }
@Override @Override
public boolean isHidden() { public boolean isHidden() {
return true; return true;

View file

@ -9,6 +9,8 @@ import com.minelittlepony.unicopia.ability.magic.spell.effect.AbstractSpell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; import com.minelittlepony.unicopia.entity.mob.CastSpellEntity;
import com.minelittlepony.unicopia.network.track.DataTracker;
import com.minelittlepony.unicopia.network.track.TrackableDataType;
import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.server.world.Ether;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
@ -21,12 +23,10 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
public class PlacementControlSpell extends AbstractSpell implements OrientedSpell { public class PlacementControlSpell extends AbstractSpell implements OrientedSpell {
@Nullable private final DataTracker.Entry<UUID> placedEntityId = dataTracker.startTracking(TrackableDataType.UUID, null);
private UUID placedEntityId; private final DataTracker.Entry<Optional<RegistryKey<World>>> dimension = dataTracker.startTracking(TrackableDataType.ofRegistryKey(), Optional.empty());
private final DataTracker.Entry<Optional<Vec3d>> position = dataTracker.startTracking(TrackableDataType.OPTIONAL_VECTOR, Optional.empty());
private Optional<RegistryKey<World>> dimension = Optional.empty(); private final DataTracker.Entry<Optional<Vec3d>> orientation = dataTracker.startTracking(TrackableDataType.OPTIONAL_VECTOR, Optional.empty());
private Optional<Vec3d> position = Optional.empty();
private Optional<Vec3d> orientation = Optional.empty();
@Nullable @Nullable
private Spell delegate; private Spell delegate;
@ -46,26 +46,23 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel
} }
public Optional<Vec3d> getPosition() { public Optional<Vec3d> getPosition() {
return position; return position.get();
} }
public void setDimension(RegistryKey<World> dimension) { public void setDimension(RegistryKey<World> dimension) {
this.dimension = Optional.of(dimension); this.dimension.set(Optional.of(dimension));
setDirty();
} }
public void setPosition(Vec3d position) { public void setPosition(Vec3d position) {
this.position = Optional.of(position); this.position.set(Optional.of(position));
setDirty();
} }
@Override @Override
public void setOrientation(Caster<?> caster, float pitch, float yaw) { public void setOrientation(Caster<?> caster, float pitch, float yaw) {
this.orientation = Optional.of(new Vec3d(pitch, yaw, 0)); this.orientation.set(Optional.of(new Vec3d(pitch, yaw, 0)));
if (delegate instanceof OrientedSpell o) { if (delegate instanceof OrientedSpell o) {
o.setOrientation(caster, pitch, yaw); o.setOrientation(caster, pitch, yaw);
} }
setDirty();
if (!caster.isClient()) { if (!caster.isClient()) {
var entry = getConnection(caster); var entry = getConnection(caster);
if (entry != null) { if (entry != null) {
@ -77,62 +74,60 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel
@Override @Override
public boolean apply(Caster<?> caster) { public boolean apply(Caster<?> caster) {
if (delegate == null) { return delegate != null && super.apply(caster);
return false;
}
boolean result = super.apply(caster);
if (result) {
if (dimension.isEmpty()) {
setDimension(caster.asWorld().getRegistryKey());
}
if (position.isEmpty()) {
setPosition(caster.asEntity().getPos());
}
if (delegate instanceof PlacementDelegate) {
((PlacementDelegate)delegate).onPlaced(caster, this);
}
CastSpellEntity entity = new CastSpellEntity(caster.asWorld(), caster, this);
Vec3d pos = position.get();
Vec3d rot = orientation.orElse(Vec3d.ZERO);
entity.updatePositionAndAngles(pos.x, pos.y, pos.z, (float)rot.y, (float)rot.x);
entity.getWorld().spawnEntity(entity);
placedEntityId = entity.getUuid();
}
return result;
} }
@Override @Override
public boolean tick(Caster<?> source, Situation situation) { public boolean tick(Caster<?> source, Situation situation) {
if (!source.isClient() && getConnection(source) == null) { if (!source.isClient()) {
if (placedEntityId.get() == null) {
if (dimension.get().isEmpty()) {
setDimension(source.asWorld().getRegistryKey());
}
if (getPosition().isEmpty()) {
setPosition(source.asEntity().getPos());
}
CastSpellEntity entity = new CastSpellEntity(source.asWorld(), source, this);
Vec3d pos = getPosition().get();
Vec3d rot = orientation.get().orElse(Vec3d.ZERO);
entity.updatePositionAndAngles(pos.x, pos.y, pos.z, (float)rot.y, (float)rot.x);
entity.getWorld().spawnEntity(entity);
placedEntityId.set(entity.getUuid());
} else {
if (getConnection(source) == null) {
setDead(); setDead();
} }
}
}
return !isDead(); return !isDead();
} }
@Nullable @Nullable
private Ether.Entry<?> getConnection(Caster<?> source) { private Ether.Entry<?> getConnection(Caster<?> source) {
return delegate == null || placedEntityId == null ? null : getWorld(source) return delegate == null || placedEntityId.get() == null ? null : getWorld(source)
.map(world -> Ether.get(world).get(getDelegate().getTypeAndTraits().type(), placedEntityId, delegate.getUuid())) .map(world -> Ether.get(world).get(getDelegate().getTypeAndTraits().type(), placedEntityId.get(), delegate.getUuid()))
.orElse(null); .orElse(null);
} }
private Optional<World> getWorld(Caster<?> source) { private Optional<World> getWorld(Caster<?> source) {
return dimension.map(source.asWorld().getServer()::getWorld); return dimension.get().map(source.asWorld().getServer()::getWorld);
} }
@Override @Override
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {
super.toNBT(compound); super.toNBT(compound);
compound.put("spell", Spell.writeNbt(delegate)); compound.put("spell", Spell.writeNbt(delegate));
position.ifPresent(pos -> compound.put("position", NbtSerialisable.writeVector(pos))); position.get().ifPresent(pos -> compound.put("position", NbtSerialisable.writeVector(pos)));
orientation.ifPresent(o -> compound.put("orientation", NbtSerialisable.writeVector(o))); orientation.get().ifPresent(o -> compound.put("orientation", NbtSerialisable.writeVector(o)));
dimension.ifPresent(d -> compound.putString("dimension", d.getValue().toString())); dimension.get().ifPresent(d -> compound.putString("dimension", d.getValue().toString()));
if (placedEntityId != null) { if (placedEntityId.get() != null) {
compound.putUuid("placedEntityId", placedEntityId); compound.putUuid("placedEntityId", placedEntityId.get());
} }
} }
@ -140,12 +135,10 @@ public class PlacementControlSpell extends AbstractSpell implements OrientedSpel
public void fromNBT(NbtCompound compound) { public void fromNBT(NbtCompound compound) {
super.fromNBT(compound); super.fromNBT(compound);
delegate = Spell.readNbt(compound.getCompound("spell")); delegate = Spell.readNbt(compound.getCompound("spell"));
placedEntityId = compound.containsUuid("placedEntityId") ? compound.getUuid("placedEntityId") : null; placedEntityId.set(compound.containsUuid("placedEntityId") ? compound.getUuid("placedEntityId") : null);
position = compound.contains("position") ? Optional.of(NbtSerialisable.readVector(compound.getList("position", NbtElement.DOUBLE_TYPE))) : Optional.empty(); position.set(compound.contains("position") ? Optional.of(NbtSerialisable.readVector(compound.getList("position", NbtElement.DOUBLE_TYPE))) : Optional.empty());
orientation = compound.contains("orientation") ? Optional.of(NbtSerialisable.readVector(compound.getList("orientation", NbtElement.DOUBLE_TYPE))) : Optional.empty(); orientation.set(compound.contains("orientation") ? Optional.of(NbtSerialisable.readVector(compound.getList("orientation", NbtElement.DOUBLE_TYPE))) : Optional.empty());
if (compound.contains("dimension", NbtElement.STRING_TYPE)) { dimension.set(compound.contains("dimension", NbtElement.STRING_TYPE) ? Optional.ofNullable(Identifier.tryParse(compound.getString("dimension"))).map(id -> RegistryKey.of(RegistryKeys.WORLD, id)) : Optional.empty());
dimension = Optional.ofNullable(Identifier.tryParse(compound.getString("dimension"))).map(id -> RegistryKey.of(RegistryKeys.WORLD, id));
}
} }
public interface PlacementDelegate { public interface PlacementDelegate {

View file

@ -74,18 +74,6 @@ public interface Spell extends NbtSerialisable, Affine {
boolean isDying(); boolean isDying();
/**
* Returns true if this effect has changes that need to be sent to the client.
*/
@Deprecated
boolean isDirty();
/**
* Marks this effect as dirty.
*/
@Deprecated
void setDirty();
/** /**
* Applies this spell to the supplied caster. * Applies this spell to the supplied caster.
* @param caster The caster to apply the spell to * @param caster The caster to apply the spell to

View file

@ -25,11 +25,6 @@ public final class SpellReference<T extends Spell> implements NbtSerialisable {
set(spell, null); set(spell, null);
} }
@Deprecated
public boolean hasDirtySpell() {
return spell != null && spell.isDirty();
}
public boolean set(T spell, @Nullable Caster<?> owner) { public boolean set(T spell, @Nullable Caster<?> owner) {
spell = spell == null || spell.isDead() ? null : spell; spell = spell == null || spell.isDead() ? null : spell;
if (spell == this.spell) { if (spell == this.spell) {

View file

@ -20,7 +20,6 @@ public abstract class AbstractSpell implements Spell {
private final DataTracker.Entry<Boolean> dead = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); private final DataTracker.Entry<Boolean> dead = dataTracker.startTracking(TrackableDataType.BOOLEAN, false);
private final DataTracker.Entry<Boolean> dying = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); private final DataTracker.Entry<Boolean> dying = dataTracker.startTracking(TrackableDataType.BOOLEAN, false);
private boolean dirty;
private final DataTracker.Entry<Boolean> hidden = dataTracker.startTracking(TrackableDataType.BOOLEAN, false); private final DataTracker.Entry<Boolean> hidden = dataTracker.startTracking(TrackableDataType.BOOLEAN, false);
private boolean destroyed; private boolean destroyed;
@ -66,18 +65,6 @@ public abstract class AbstractSpell implements Spell {
return dying.get(); return dying.get();
} }
@Deprecated
@Override
public final boolean isDirty() {
return dirty;
}
@Deprecated
@Override
public final void setDirty() {
dirty = true;
}
@Override @Override
public final boolean isHidden() { public final boolean isHidden() {
return hidden.get(); return hidden.get();
@ -120,7 +107,6 @@ public abstract class AbstractSpell implements Spell {
@Override @Override
public void fromNBT(NbtCompound compound) { public void fromNBT(NbtCompound compound) {
dirty = false;
if (compound.containsUuid("uuid")) { if (compound.containsUuid("uuid")) {
uuid = compound.getUuid("uuid"); uuid = compound.getUuid("uuid");
} }

View file

@ -28,14 +28,12 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp
static final TooltipFactory TARGET = (type, tooltip) -> (TARGET_FOCUSED_ENTITY.get(type.traits()) ? TARGET_FOCUSED_ENTITY : ShieldSpell.TARGET).appendTooltip(type, tooltip); static final TooltipFactory TARGET = (type, tooltip) -> (TARGET_FOCUSED_ENTITY.get(type.traits()) ? TARGET_FOCUSED_ENTITY : ShieldSpell.TARGET).appendTooltip(type, tooltip);
static final TooltipFactory TOOLTIP = TooltipFactory.of(TIME, RANGE, TARGET, STICK_TO_TARGET, CAST_ON); static final TooltipFactory TOOLTIP = TooltipFactory.of(TIME, RANGE, TARGET, STICK_TO_TARGET, CAST_ON);
private final EntityReference<Entity> target = new EntityReference<>(); private final EntityReference<Entity> target = dataTracker.startTracking(new EntityReference<>());
private final Timer timer; private final Timer timer = new Timer(TIME.get(getTraits()));
protected AttractiveSpell(CustomisedSpellType<?> type) { protected AttractiveSpell(CustomisedSpellType<?> type) {
super(type); super(type);
timer = new Timer(TIME.get(getTraits()));
dataTracker.startTracking(target);
} }
@Override @Override

View file

@ -19,11 +19,10 @@ import net.minecraft.registry.Registries;
public class AwkwardSpell extends AbstractSpell implements TimedSpell { public class AwkwardSpell extends AbstractSpell implements TimedSpell {
private final Timer timer; private final Timer timer = new Timer(20);
protected AwkwardSpell(CustomisedSpellType<?> type) { protected AwkwardSpell(CustomisedSpellType<?> type) {
super(type); super(type);
timer = new Timer(20);
} }
@Override @Override

View file

@ -56,17 +56,14 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell,
static final TooltipFactory TOOLTIP = TooltipFactory.of(TimedSpell.TIME, SOAPINESS); static final TooltipFactory TOOLTIP = TooltipFactory.of(TimedSpell.TIME, SOAPINESS);
private final Timer timer; private final Timer timer = new Timer(TIME.get(getTraits()));
private float prevRadius; private float prevRadius;
private DataTracker.Entry<Float> radius; private DataTracker.Entry<Float> radius = dataTracker.startTracking(TrackableDataType.FLOAT, 0F);
private DataTracker.Entry<Integer> struggles; private DataTracker.Entry<Integer> struggles = dataTracker.startTracking(TrackableDataType.INT, SOAPINESS.get(getTraits()));
protected BubbleSpell(CustomisedSpellType<?> type) { protected BubbleSpell(CustomisedSpellType<?> type) {
super(type); super(type);
timer = new Timer(TIME.get(getTraits()));
radius = dataTracker.startTracking(TrackableDataType.FLOAT, 0F);
struggles = dataTracker.startTracking(TrackableDataType.INT, SOAPINESS.get(getTraits()));
} }
@Override @Override

View file

@ -18,13 +18,13 @@ import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
public class DisplacementSpell extends AbstractSpell implements HomingSpell, ProjectileDelegate.EntityHitListener { public class DisplacementSpell extends AbstractSpell implements HomingSpell, ProjectileDelegate.HitListener {
private static final SpellAttribute<Float> DAMAGE_TO_TARGET = SpellAttribute.create(SpellAttributeType.DAMAGE_TO_TARGET, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.BLOOD, blood -> blood); private static final SpellAttribute<Float> DAMAGE_TO_TARGET = SpellAttribute.create(SpellAttributeType.DAMAGE_TO_TARGET, AttributeFormat.REGULAR, AttributeFormat.PERCENTAGE, Trait.BLOOD, blood -> blood);
static final TooltipFactory TOOLTIP = DAMAGE_TO_TARGET; static final TooltipFactory TOOLTIP = DAMAGE_TO_TARGET;
private final EntityReference<Entity> target = new EntityReference<>(); private final EntityReference<Entity> target = dataTracker.startTracking(new EntityReference<>());
private int ticks = 10; private int ticks = 10;
@ -34,7 +34,7 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pro
@Override @Override
public Spell prepareForCast(Caster<?> caster, CastingMethod method) { public Spell prepareForCast(Caster<?> caster, CastingMethod method) {
return toPlaceable(); return method.isIndirectCause() ? this : toPlaceable();
} }
@Override @Override
@ -43,14 +43,23 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pro
originator.asEntity().setGlowing(true); originator.asEntity().setGlowing(true);
if (situation == Situation.PROJECTILE) {
return !isDead();
}
ticks--; ticks--;
if (originator.isClient()) { if (originator.isClient()) {
return !isDead() || ticks >= -10; return !isDead() || ticks >= -10;
} }
if (!originator.isClient()) {
target.ifPresent(originator.asWorld(), target -> {
target.setGlowing(true);
if (ticks == 0) { if (ticks == 0) {
target.ifPresent(originator.asWorld(), target -> apply(originator, target)); apply(originator, target);
}
});
} }
return ticks >= -10; return ticks >= -10;
@ -58,7 +67,18 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pro
@Override @Override
public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) { public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) {
Caster.of(projectile.getMaster()).ifPresent(originator -> apply(originator, hit.getEntity())); HitListener.super.onImpact(projectile, hit);
Caster.of(projectile.getMaster()).ifPresent(originator -> {
apply(originator, hit.getEntity());
});
}
@Override
public void onImpact(MagicProjectileEntity projectile) {
if (projectile.getMaster() != null) {
projectile.getMaster().setGlowing(false);
}
target.ifPresent(projectile.asWorld(), e -> e.setGlowing(false));
} }
private void apply(Caster<?> originator, Entity target) { private void apply(Caster<?> originator, Entity target) {
@ -107,11 +127,13 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pro
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {
super.toNBT(compound); super.toNBT(compound);
compound.putInt("ticks", ticks); compound.putInt("ticks", ticks);
compound.put("target", target.toNBT());
} }
@Override @Override
public void fromNBT(NbtCompound compound) { public void fromNBT(NbtCompound compound) {
super.fromNBT(compound); super.fromNBT(compound);
ticks = compound.getInt("ticks"); ticks = compound.getInt("ticks");
target.fromNBT(compound.getCompound("target"));
} }
} }

View file

@ -59,11 +59,10 @@ public class FeatherFallSpell extends AbstractSpell implements TimedSpell {
.with(Trait.ORDER, 15) .with(Trait.ORDER, 15)
.build(); .build();
private final Timer timer; private final Timer timer = new Timer(DURATION.get(getTraits()));
protected FeatherFallSpell(CustomisedSpellType<?> type) { protected FeatherFallSpell(CustomisedSpellType<?> type) {
super(type); super(type);
timer = new Timer(DURATION.get(getTraits()));
} }
@Override @Override

View file

@ -47,7 +47,7 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell,
static final TooltipFactory TOOLTIP = TooltipFactory.of(EXPLOSION_STRENGTH, VELOCITY, PROJECTILE_COUNT, FOLLOWS_TARGET, FOLLOW_RANGE.conditionally(FOLLOWS_TARGET::get)); static final TooltipFactory TOOLTIP = TooltipFactory.of(EXPLOSION_STRENGTH, VELOCITY, PROJECTILE_COUNT, FOLLOWS_TARGET, FOLLOW_RANGE.conditionally(FOLLOWS_TARGET::get));
private final EntityReference<Entity> target = new EntityReference<>(); private final EntityReference<Entity> target = dataTracker.startTracking(new EntityReference<>());
protected FireBoltSpell(CustomisedSpellType<?> type) { protected FireBoltSpell(CustomisedSpellType<?> type) {
super(type); super(type);

View file

@ -38,13 +38,12 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD
static final TooltipFactory TOOLTIP = TooltipFactory.of(TIME, ORB_COUNT); static final TooltipFactory TOOLTIP = TooltipFactory.of(TIME, ORB_COUNT);
private final Timer timer; private final Timer timer = new Timer(TIME.get(getTraits()));
private final List<EntityReference<FairyEntity>> lights = new ArrayList<>(); private final List<EntityReference<FairyEntity>> lights = new ArrayList<>();
protected LightSpell(CustomisedSpellType<?> type) { protected LightSpell(CustomisedSpellType<?> type) {
super(type); super(type);
timer = new Timer(TIME.get(getTraits()));
} }
@Override @Override

View file

@ -11,11 +11,10 @@ public class MimicSpell extends AbstractDisguiseSpell implements HomingSpell, Ti
static final TooltipFactory TOOLTIP = TimedSpell.TIME; static final TooltipFactory TOOLTIP = TimedSpell.TIME;
private final Timer timer; private final Timer timer = new Timer(TIME.get(getTraits()));
protected MimicSpell(CustomisedSpellType<?> type) { protected MimicSpell(CustomisedSpellType<?> type) {
super(type); super(type);
timer = new Timer(TIME.get(getTraits()));
} }
@Override @Override

View file

@ -46,7 +46,7 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell.
private final DataTracker.Entry<UUID> targetPortalId = dataTracker.startTracking(TrackableDataType.UUID, Util.NIL_UUID); private final DataTracker.Entry<UUID> targetPortalId = dataTracker.startTracking(TrackableDataType.UUID, Util.NIL_UUID);
private final DataTracker.Entry<Float> targetPortalPitch = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); private final DataTracker.Entry<Float> targetPortalPitch = dataTracker.startTracking(TrackableDataType.FLOAT, 0F);
private final DataTracker.Entry<Float> targetPortalYaw = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); private final DataTracker.Entry<Float> targetPortalYaw = dataTracker.startTracking(TrackableDataType.FLOAT, 0F);
private final EntityReference<Entity> teleportationTarget = new EntityReference<>(); private final EntityReference<Entity> teleportationTarget = dataTracker.startTracking(new EntityReference<>());
private final DataTracker.Entry<Float> pitch = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); private final DataTracker.Entry<Float> pitch = dataTracker.startTracking(TrackableDataType.FLOAT, 0F);
private final DataTracker.Entry<Float> yaw = dataTracker.startTracking(TrackableDataType.FLOAT, 0F); private final DataTracker.Entry<Float> yaw = dataTracker.startTracking(TrackableDataType.FLOAT, 0F);

View file

@ -205,7 +205,7 @@ public class EdibleBlock extends HayBlock {
if (world.random.nextInt(10) == 0) { if (world.random.nextInt(10) == 0) {
player.playSound(USounds.Vanilla.ENTITY_PLAYER_BURP, 1, player.getSoundPitch()); player.playSound(USounds.Vanilla.ENTITY_PLAYER_BURP, 1, player.getSoundPitch());
} }
player.getHungerManager().add(4, 2.3F); player.getHungerManager().add(2, 1.3F);
} }
return ActionResult.SUCCESS; return ActionResult.SUCCESS;
} }

View file

@ -24,7 +24,7 @@ public class CloudBedBlock extends FancyBedBlock implements CloudLike {
private final CloudBlock baseBlock; private final CloudBlock baseBlock;
public CloudBedBlock(String base, BlockState baseState, Settings settings) { public CloudBedBlock(String base, BlockState baseState, Settings settings) {
super(base, settings.dynamicBounds()); super(base, CloudLike.applyCloudProperties(settings));
this.baseState = baseState; this.baseState = baseState;
this.baseBlock = (CloudBlock)baseState.getBlock(); this.baseBlock = (CloudBlock)baseState.getBlock();
} }
@ -75,6 +75,6 @@ public class CloudBedBlock extends FancyBedBlock implements CloudLike {
@Override @Override
@Deprecated @Deprecated
public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) { public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) {
return true; return baseState.canPathfindThrough(world, pos, type);
} }
} }

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.block.cloud;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.EquineContext; import com.minelittlepony.unicopia.EquineContext;
import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.block.Block; import net.minecraft.block.Block;
@ -30,10 +31,21 @@ public class CloudBlock extends Block implements CloudLike {
protected final boolean meltable; protected final boolean meltable;
public CloudBlock(Settings settings, boolean meltable) { public CloudBlock(Settings settings, boolean meltable) {
super((meltable ? settings.ticksRandomly() : settings).nonOpaque().dynamicBounds()); super(CloudLike.applyCloudProperties(meltable ? settings.ticksRandomly() : settings));
this.meltable = meltable; this.meltable = meltable;
} }
@Override
@Deprecated
public float getAmbientOcclusionLightLevel(BlockState state, BlockView world, BlockPos pos) {
return 0.9F;
}
@Override
public boolean isTransparent(BlockState state, BlockView world, BlockPos pos) {
return true;
}
@Override @Override
public void onEntityLand(BlockView world, Entity entity) { public void onEntityLand(BlockView world, Entity entity) {
boolean bounce = Math.abs(entity.getVelocity().y) > 0.3; boolean bounce = Math.abs(entity.getVelocity().y) > 0.3;
@ -105,10 +117,9 @@ public class CloudBlock extends Block implements CloudLike {
entity.addVelocity(0, 0.07, 0); entity.addVelocity(0, 0.07, 0);
entity.setOnGround(true); entity.setOnGround(true);
} }
entity.setVelocity(entity.getVelocity().multiply(0.9F, 1, 0.9F));
} else {
entity.setVelocity(entity.getVelocity().multiply(0.9F));
} }
entity.setVelocity(entity.getVelocity().multiply(0.9F, 1, 0.9F));
} }
@Override @Override
@ -163,7 +174,8 @@ public class CloudBlock extends Block implements CloudLike {
@Override @Override
@Deprecated @Deprecated
public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) { public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) {
return true; System.out.println(InteractionManager.getInstance().getPathingEquineContext().collidesWithClouds());
return type != NavigationType.LAND || !InteractionManager.getInstance().getPathingEquineContext().collidesWithClouds();
} }
protected VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context, EquineContext equineContext) { protected VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context, EquineContext equineContext) {

View file

@ -5,6 +5,7 @@ import java.util.Optional;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.EquineContext; import com.minelittlepony.unicopia.EquineContext;
import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.block.UBlockEntities; import com.minelittlepony.unicopia.block.UBlockEntities;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.ChestBlock; import net.minecraft.block.ChestBlock;
@ -77,7 +78,7 @@ public class CloudChestBlock extends ChestBlock implements CloudLike {
}; };
public CloudChestBlock(Settings settings, BlockState baseState) { public CloudChestBlock(Settings settings, BlockState baseState) {
super(settings.dynamicBounds(), () -> UBlockEntities.CLOUD_CHEST); super(CloudLike.applyCloudProperties(settings), () -> UBlockEntities.CLOUD_CHEST);
this.baseState = baseState; this.baseState = baseState;
this.baseBlock = (CloudBlock)baseState.getBlock(); this.baseBlock = (CloudBlock)baseState.getBlock();
} }
@ -139,7 +140,7 @@ public class CloudChestBlock extends ChestBlock implements CloudLike {
@Override @Override
@Deprecated @Deprecated
public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) { public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) {
return true; return type != NavigationType.LAND || !InteractionManager.getInstance().getPathingEquineContext().collidesWithClouds();
} }
public static class TileData extends ChestBlockEntity { public static class TileData extends ChestBlockEntity {

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.block.cloud;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.EquineContext; import com.minelittlepony.unicopia.EquineContext;
import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import net.minecraft.block.BlockSetType; import net.minecraft.block.BlockSetType;
@ -10,6 +11,7 @@ import net.minecraft.block.BlockState;
import net.minecraft.block.DoorBlock; import net.minecraft.block.DoorBlock;
import net.minecraft.block.ShapeContext; import net.minecraft.block.ShapeContext;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.ai.pathing.NavigationType;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemPlacementContext;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
@ -26,7 +28,7 @@ public class CloudDoorBlock extends DoorBlock implements CloudLike {
private final CloudBlock baseBlock; private final CloudBlock baseBlock;
public CloudDoorBlock(Settings settings, BlockState baseState, BlockSetType blockSet) { public CloudDoorBlock(Settings settings, BlockState baseState, BlockSetType blockSet) {
super(settings.dynamicBounds(), blockSet); super(CloudLike.applyCloudProperties(settings), blockSet);
this.baseState = baseState; this.baseState = baseState;
this.baseBlock = (CloudBlock)baseState.getBlock(); this.baseBlock = (CloudBlock)baseState.getBlock();
} }
@ -84,4 +86,10 @@ public class CloudDoorBlock extends DoorBlock implements CloudLike {
entity.setVelocity(entity.getVelocity().multiply(0.5F, 1, 0.5F)); entity.setVelocity(entity.getVelocity().multiply(0.5F, 1, 0.5F));
} }
} }
@Override
@Deprecated
public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) {
return !InteractionManager.getInstance().getPathingEquineContext().collidesWithClouds() || super.canPathfindThrough(state, world, pos, type);
}
} }

View file

@ -1,5 +1,13 @@
package com.minelittlepony.unicopia.block.cloud; package com.minelittlepony.unicopia.block.cloud;
public interface CloudLike { import net.minecraft.block.Block;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnGroup;
public interface CloudLike {
static Block.Settings applyCloudProperties(Block.Settings settings) {
return settings.nonOpaque().dynamicBounds().allowsSpawning((state, world, pos, type) -> {
return type == EntityType.PHANTOM || type == EntityType.PARROT || type.getSpawnGroup() == SpawnGroup.AMBIENT;
});
}
} }

View file

@ -21,10 +21,21 @@ public class CloudStairsBlock extends StairsBlock implements CloudLike {
private final CloudBlock baseBlock; private final CloudBlock baseBlock;
public CloudStairsBlock(BlockState baseState, Settings settings) { public CloudStairsBlock(BlockState baseState, Settings settings) {
super(baseState, settings.dynamicBounds()); super(baseState, CloudLike.applyCloudProperties(settings));
this.baseBlock = (CloudBlock)baseState.getBlock(); this.baseBlock = (CloudBlock)baseState.getBlock();
} }
@Override
@Deprecated
public float getAmbientOcclusionLightLevel(BlockState state, BlockView world, BlockPos pos) {
return baseBlock.getAmbientOcclusionLightLevel(state, world, pos);
}
@Override
public boolean isTransparent(BlockState state, BlockView world, BlockPos pos) {
return baseBlock.isTransparent(state, world, pos);
}
@Override @Override
public void onEntityLand(BlockView world, Entity entity) { public void onEntityLand(BlockView world, Entity entity) {
baseBlock.onEntityLand(world, entity); baseBlock.onEntityLand(world, entity);
@ -86,6 +97,6 @@ public class CloudStairsBlock extends StairsBlock implements CloudLike {
@Override @Override
@Deprecated @Deprecated
public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) { public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) {
return true; return baseBlock.canPathfindThrough(state, world, pos, type);
} }
} }

View file

@ -25,10 +25,11 @@ public class NaturalCloudBlock extends PoreousCloudBlock {
public NaturalCloudBlock(Settings settings, boolean meltable, public NaturalCloudBlock(Settings settings, boolean meltable,
@Nullable Supplier<Soakable> soggyBlock, @Nullable Supplier<Soakable> soggyBlock,
Supplier<Block> compactedBlock) { Supplier<Block> compactedBlock) {
super(settings.nonOpaque(), meltable, soggyBlock); super(settings, meltable, soggyBlock);
this.compactedBlock = compactedBlock; this.compactedBlock = compactedBlock;
} }
@Deprecated
@Override @Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
ItemStack stack = player.getStackInHand(hand); ItemStack stack = player.getStackInHand(hand);
@ -41,6 +42,6 @@ public class NaturalCloudBlock extends PoreousCloudBlock {
return ActionResult.SUCCESS; return ActionResult.SUCCESS;
} }
return ActionResult.PASS; return super.onUse(state, world, pos, player, hand, hit);
} }
} }

View file

@ -7,9 +7,14 @@ import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.block.state.StateUtil; import com.minelittlepony.unicopia.block.state.StateUtil;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random; import net.minecraft.util.math.random.Random;
import net.minecraft.world.World;
public class PoreousCloudBlock extends CloudBlock implements Soakable { public class PoreousCloudBlock extends CloudBlock implements Soakable {
@Nullable @Nullable
@ -20,6 +25,12 @@ public class PoreousCloudBlock extends CloudBlock implements Soakable {
this.soggyBlock = soggyBlock; this.soggyBlock = soggyBlock;
} }
@Deprecated
@Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
return Soakable.tryDepositMoisture(state, world, pos, player, hand, hit);
}
@Nullable @Nullable
@Override @Override
public BlockState getStateWithMoisture(BlockState state, int moisture) { public BlockState getStateWithMoisture(BlockState state, int moisture) {

View file

@ -7,6 +7,12 @@ import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.block.state.StateUtil; import com.minelittlepony.unicopia.block.state.StateUtil;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class PoreousCloudStairsBlock extends CloudStairsBlock implements Soakable { public class PoreousCloudStairsBlock extends CloudStairsBlock implements Soakable {
@ -17,6 +23,12 @@ public class PoreousCloudStairsBlock extends CloudStairsBlock implements Soakabl
this.soggyBlock = soggyBlock; this.soggyBlock = soggyBlock;
} }
@Deprecated
@Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
return Soakable.tryDepositMoisture(state, world, pos, player, hand, hit);
}
@Nullable @Nullable
@Override @Override
public BlockState getStateWithMoisture(BlockState state, int moisture) { public BlockState getStateWithMoisture(BlockState state, int moisture) {

View file

@ -9,8 +9,11 @@ import com.minelittlepony.unicopia.USounds;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUsage;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.potion.PotionUtil;
import net.minecraft.potion.Potions;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents; import net.minecraft.sound.SoundEvents;
@ -50,15 +53,8 @@ public interface Soakable {
static ActionResult tryCollectMoisture(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { static ActionResult tryCollectMoisture(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
if (state.getBlock() instanceof Soakable soakable) { if (state.getBlock() instanceof Soakable soakable) {
ItemStack stack = player.getStackInHand(hand); ItemStack stack = player.getStackInHand(hand);
if (stack.getItem() == Items.GLASS_BOTTLE) { if (stack.isOf(Items.GLASS_BOTTLE)) {
if (!player.isCreative()) { player.setStackInHand(hand, ItemUsage.exchangeStack(stack, player, Items.POTION.getDefaultStack(), false));
stack.split(1);
}
if (stack.isEmpty()) {
player.setStackInHand(hand, Items.POTION.getDefaultStack());
} else {
player.giveItemStack(Items.POTION.getDefaultStack());
}
world.playSound(player, player.getX(), player.getY(), player.getZ(), USounds.Vanilla.ITEM_BOTTLE_FILL, SoundCategory.NEUTRAL, 1, 1); world.playSound(player, player.getX(), player.getY(), player.getZ(), USounds.Vanilla.ITEM_BOTTLE_FILL, SoundCategory.NEUTRAL, 1, 1);
world.emitGameEvent(player, GameEvent.FLUID_PICKUP, pos); world.emitGameEvent(player, GameEvent.FLUID_PICKUP, pos);
updateMoisture(soakable, state, world, pos, soakable.getMoisture(state) - 1); updateMoisture(soakable, state, world, pos, soakable.getMoisture(state) - 1);
@ -67,6 +63,24 @@ public interface Soakable {
} }
} }
return tryDepositMoisture(state, world, pos, player, hand, hit);
}
static ActionResult tryDepositMoisture(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
if (state.getBlock() instanceof Soakable soakable) {
ItemStack stack = player.getStackInHand(hand);
if (soakable.getMoisture(state) < 7
&& stack.isOf(Items.POTION)
&& PotionUtil.getPotion(stack) == Potions.WATER) {
player.setStackInHand(hand, ItemUsage.exchangeStack(stack, player, Items.GLASS_BOTTLE.getDefaultStack(), false));
world.playSound(player, player.getX(), player.getY(), player.getZ(), USounds.Vanilla.ITEM_BUCKET_EMPTY, SoundCategory.NEUTRAL, 1, 1);
world.emitGameEvent(player, GameEvent.FLUID_PLACE, pos);
updateMoisture(soakable, state, world, pos, soakable.getMoisture(state) + 1);
return ActionResult.SUCCESS;
}
}
return ActionResult.PASS; return ActionResult.PASS;
} }
@ -78,7 +92,7 @@ public interface Soakable {
if (moisture < 7) { if (moisture < 7) {
world.setBlockState(pos, soakable.getStateWithMoisture(state, moisture + 1)); world.setBlockState(pos, soakable.getStateWithMoisture(state, moisture + 1));
} }
} else { } else if (!world.isAir(pos.up())) {
if (moisture > 1) { if (moisture > 1) {
BlockPos neighborPos = pos.offset(Util.getRandom(Soakable.DIRECTIONS, random)); BlockPos neighborPos = pos.offset(Util.getRandom(Soakable.DIRECTIONS, random));
BlockState neighborState = world.getBlockState(neighborPos); BlockState neighborState = world.getBlockState(neighborPos);

View file

@ -8,10 +8,15 @@ import com.minelittlepony.unicopia.block.state.StateUtil;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.state.StateManager; import net.minecraft.state.StateManager;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView; import net.minecraft.world.BlockView;
import net.minecraft.world.World;
public class SoggyCloudStairsBlock extends CloudStairsBlock implements Soakable { public class SoggyCloudStairsBlock extends CloudStairsBlock implements Soakable {
@ -34,6 +39,12 @@ public class SoggyCloudStairsBlock extends CloudStairsBlock implements Soakable
return dryBlock.get().getPickStack(world, pos, state); return dryBlock.get().getPickStack(world, pos, state);
} }
@Deprecated
@Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
return Soakable.tryCollectMoisture(state, world, pos, player, hand, hit);
}
@Nullable @Nullable
@Override @Override
public BlockState getStateWithMoisture(BlockState state, int moisture) { public BlockState getStateWithMoisture(BlockState state, int moisture) {

View file

@ -5,11 +5,11 @@ import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents;
import com.minelittlepony.unicopia.block.ItemJarBlock.TileData; import com.minelittlepony.unicopia.block.ItemJarBlock.TileData;
import com.minelittlepony.unicopia.util.FluidHelper; import com.minelittlepony.unicopia.util.FluidHelper;
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult; import net.minecraft.util.TypedActionResult;
@ -27,7 +27,7 @@ public record FluidOnlyJarContents (
@Override @Override
public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) { public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
ItemStack stack = player.getStackInHand(hand); ItemStack stack = player.getStackInHand(hand);
if (stack.isOf(Items.BUCKET)) { if (stack.isIn(ConventionalItemTags.EMPTY_BUCKETS)) {
long remainder = FluidHelper.deposit(stack, player, hand, fluid, amount); long remainder = FluidHelper.deposit(stack, player, hand, fluid, amount);
tile.markDirty(); tile.markDirty();
fluid.getFluid().getBucketFillSound().ifPresent(sound -> player.playSound(sound, 1, 1)); fluid.getFluid().getBucketFillSound().ifPresent(sound -> player.playSound(sound, 1, 1));

View file

@ -30,15 +30,16 @@ public record ItemsJarContents (
TileData tile, TileData tile,
List<ItemStack> stacks List<ItemStack> stacks
) implements JarContents, SidedInventory { ) implements JarContents, SidedInventory {
private static final int[] SLOTS = IntStream.range(0, 16).toArray(); private static final int MAX_SIZE = 16;
private static final int[] SLOTS = IntStream.range(0, MAX_SIZE).toArray();
public ItemsJarContents(TileData tile) { public ItemsJarContents(TileData tile) {
this(tile, new ArrayList<>()); this(tile, new ArrayList<>(MAX_SIZE));
} }
public ItemsJarContents(TileData tile, NbtCompound compound) { public ItemsJarContents(TileData tile, NbtCompound compound) {
this(tile, NbtSerialisable.ITEM_STACK.readAll(compound.getList("items", NbtElement.COMPOUND_TYPE)) this(tile, NbtSerialisable.ITEM_STACK.readAll(compound.getList("items", NbtElement.COMPOUND_TYPE))
.limit(15) .limit(MAX_SIZE)
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }
@ -115,7 +116,7 @@ public record ItemsJarContents (
@Override @Override
public int size() { public int size() {
return 15; return MAX_SIZE;
} }
@Override @Override

View file

@ -3,9 +3,9 @@ package com.minelittlepony.unicopia.client;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects; import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.player.PlayerEntity;
public class BatEyesApplicator { public class BatEyesApplicator {
@ -15,11 +15,17 @@ public class BatEyesApplicator {
private final MinecraftClient client = MinecraftClient.getInstance(); private final MinecraftClient client = MinecraftClient.getInstance();
public float getWorldBrightness(float initial, LivingEntity entity, float tickDelta) {
if (!EquinePredicates.PLAYER_BAT.test(entity)) {
return initial;
}
return 0.6F;
}
public void enable() { public void enable() {
if (client.world != null) { if (client.world != null && client.player != null) {
PlayerEntity player = client.player; if (!client.player.hasStatusEffect(StatusEffects.NIGHT_VISION) && EquinePredicates.PLAYER_BAT.test(client.player)) {
if (!player.hasStatusEffect(StatusEffects.NIGHT_VISION) && EquinePredicates.PLAYER_BAT.test(player)) { client.player.addStatusEffect(new StatusEffectInstance(StatusEffects.NIGHT_VISION, -1, 1, false, false));
player.addStatusEffect(new StatusEffectInstance(StatusEffects.NIGHT_VISION, 1, 1, false, false));
batEyesApplied = true; batEyesApplied = true;
} }
} }

View file

@ -21,7 +21,6 @@ import com.minelittlepony.unicopia.container.*;
import com.minelittlepony.unicopia.entity.player.PlayerCamera; import com.minelittlepony.unicopia.entity.player.PlayerCamera;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.handler.ClientNetworkHandlerImpl; import com.minelittlepony.unicopia.network.handler.ClientNetworkHandlerImpl;
import com.minelittlepony.unicopia.server.world.WeatherConditions;
import com.minelittlepony.unicopia.server.world.ZapAppleStageStore; import com.minelittlepony.unicopia.server.world.ZapAppleStageStore;
import com.minelittlepony.unicopia.util.Lerp; import com.minelittlepony.unicopia.util.Lerp;
@ -38,7 +37,6 @@ import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.resource.ResourceType; import net.minecraft.resource.ResourceType;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -55,10 +53,6 @@ public class UnicopiaClient implements ClientModInitializer {
return Pony.of(MinecraftClient.getInstance().player); return Pony.of(MinecraftClient.getInstance().player);
} }
@Nullable
private Float originalRainGradient;
private final Lerp rainGradient = new Lerp(0);
public final Lerp tangentalSkyAngle = new Lerp(0, true); public final Lerp tangentalSkyAngle = new Lerp(0, true);
public final Lerp skyAngle = new Lerp(0, true); public final Lerp skyAngle = new Lerp(0, true);
@ -106,10 +100,6 @@ public class UnicopiaClient implements ClientModInitializer {
return Unicopia.getConfig().preferredRace.get(); return Unicopia.getConfig().preferredRace.get();
} }
public static float getWorldBrightness(float initial) {
return 0.6F;
}
public UnicopiaClient() { public UnicopiaClient() {
instance = this; instance = this;
} }
@ -157,38 +147,22 @@ public class UnicopiaClient implements ClientModInitializer {
} }
private void onWorldTick(ClientWorld world) { private void onWorldTick(ClientWorld world) {
BlockPos pos = MinecraftClient.getInstance().getCameraEntity().getBlockPos(); /*BlockPos pos = MinecraftClient.getInstance().getCameraEntity().getBlockPos();
float tickDelta = MinecraftClient.getInstance().getTickDelta(); float tickDelta = MinecraftClient.getInstance().getTickDelta();
Float targetRainGradient = getTargetRainGradient(world, pos, tickDelta); Float targetRainGradient = ((WeatherAccess)world).isInRangeOfStorm(pos) ? (Float)1F : ((WeatherAccess)world).isBelowCloudLayer(pos) ? null : (Float)0F;
Float targetThunderGradient = ((WeatherAccess)world).isInRangeOfStorm(pos) ? (Float)1F : null;
if (targetRainGradient != null) { ((WeatherAccess)world).setWeatherOverride(null, null);
rainGradient.update(targetRainGradient, 2000); rainGradient.update(targetRainGradient == null ? world.getRainGradient(tickDelta) : targetRainGradient, 2000);
}
float gradient = rainGradient.getValue(); ((WeatherAccess)world).setWeatherOverride(1F, null);
if (!rainGradient.isFinished()) { thunderGradient.update(targetThunderGradient == null ? world.getThunderGradient(tickDelta) : targetThunderGradient, 2000);
world.setRainGradient(gradient);
world.setThunderGradient(gradient);
}
}
private Float getTargetRainGradient(ClientWorld world, BlockPos pos, float tickDelta) { ((WeatherAccess)world).setWeatherOverride(
if (WeatherConditions.get(world).isInRangeOfStorm(pos)) { rainGradient.isFinished() ? targetRainGradient : (Float)rainGradient.getValue(),
if (originalRainGradient == null) { thunderGradient.isFinished() ? targetThunderGradient : (Float)thunderGradient.getValue()
originalRainGradient = world.getRainGradient(tickDelta); );*/
}
return 1F;
}
if (originalRainGradient != null) {
Float f = originalRainGradient;
originalRainGradient = null;
return f;
}
return null;
} }
private void onScreenInit(Screen screen, ButtonList buttons) { private void onScreenInit(Screen screen, ButtonList buttons) {

View file

@ -14,6 +14,7 @@ import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.MutableText; import net.minecraft.text.MutableText;
import net.minecraft.util.Colors;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
@ -145,10 +146,7 @@ class Slot {
return; return;
} }
MutableText label = KeyBindingsHandler.INSTANCE.getBinding(aSlot).getLabel().copy().formatted(Formatting.BOLD); MutableText label = KeyBindingsHandler.INSTANCE.getBinding(aSlot).getLabel().copy();
MatrixStack matrices = context.getMatrices();
matrices.push();
int x = getX(); int x = getX();
if (uHud.xDirection > 0) { if (uHud.xDirection > 0) {
@ -158,9 +156,6 @@ class Slot {
x -= uHud.client.textRenderer.getWidth(label)/2; x -= uHud.client.textRenderer.getWidth(label)/2;
} }
matrices.translate(x, getY() + labelY, 0);
matrices.scale(0.5F, 0.5F, 0.5F);
ActivationType activation = KeyBindingsHandler.INSTANCE.getForcedActivationType(); ActivationType activation = KeyBindingsHandler.INSTANCE.getForcedActivationType();
if (activation.isResult()) { if (activation.isResult()) {
label = label.append("+T" + activation.getTapCount()); label = label.append("+T" + activation.getTapCount());
@ -169,8 +164,6 @@ class Slot {
} }
} }
context.drawText(uHud.font, label, 0, 0, 0xFFFFFF, true); DrawableUtil.drawScaledText(context, label, x, getY() + labelY, 0.5F, Colors.WHITE);
matrices.pop();
} }
} }

View file

@ -104,10 +104,12 @@ public class TribeConfirmationScreen extends GameGui implements HidesHud {
@Override @Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) { public void render(DrawContext context, int mouseX, int mouseY, float delta) {
context.getMatrices().push();
context.getMatrices().translate(0, 0, -2);
if (parent != null) { if (parent != null) {
context.getMatrices().push(); context.getMatrices().push();
context.getMatrices().translate(0, 0, -100); context.getMatrices().translate(0, 0, -100);
parent.render(context, 0, 0, delta); parent.render(context, -1, -1, delta);
context.getMatrices().pop(); context.getMatrices().pop();
} }
@ -119,30 +121,20 @@ public class TribeConfirmationScreen extends GameGui implements HidesHud {
int left = (width - columnWidth) / 2; int left = (width - columnWidth) / 2;
top += 40; top += 40;
final int zOffset = 0; final int zOffset = 0;
context.drawTexture(TribeSelectionScreen.TEXTURE, left + zOffset, top, 0, 70, 123, columnHeight); context.drawTexture(TribeSelectionScreen.TEXTURE, left + zOffset, top, 0, 70, 123, columnHeight);
context.drawTexture(TribeSelectionScreen.TEXTURE, left + segmentWidth + zOffset, top, 20, 70, 123, columnHeight); context.drawTexture(TribeSelectionScreen.TEXTURE, left + segmentWidth + zOffset, top, 20, 70, 123, columnHeight);
context.drawTexture(TribeSelectionScreen.TEXTURE, width - left - segmentWidth + zOffset + 1, top, 10, 70, 123, columnHeight);
context.drawTexture(TribeSelectionScreen.TEXTURE, width - left - segmentWidth + zOffset, top, 10, 70, 123, columnHeight);
top -= 31; top -= 31;
left = width / 2; left = width / 2;
context.drawTexture(TribeSelectionScreen.TEXTURE, left - 55, top, 140, 70, 21, 50); context.drawTexture(TribeSelectionScreen.TEXTURE, left - 55, top, 140, 70, 21, 50);
context.drawTexture(TribeSelectionScreen.TEXTURE, left + 35, top, 148, 70, 21, 50); context.drawTexture(TribeSelectionScreen.TEXTURE, left + 35, top, 148, 70, 21, 50);
textBody.render(context, mouseX, mouseY, delta); textBody.render(context, mouseX, mouseY, delta);
context.getMatrices().pop();
context.getMatrices().push();
context.getMatrices().translate(0, 0, 2);
context.drawTexture(TribeSelectionScreen.TEXTURE, left - 35, top - 5, 10, 70, 69, 50); context.drawTexture(TribeSelectionScreen.TEXTURE, left - 35, top - 5, 10, 70, 69, 50);
context.drawTexture(TribeSelectionScreen.TEXTURE, left - 35, top - 15, 10, 70, 69, 50); context.drawTexture(TribeSelectionScreen.TEXTURE, left - 35, top - 15, 10, 70, 69, 50);
super.render(context, mouseX, mouseY, delta); super.render(context, mouseX, mouseY, delta);
context.getMatrices().pop();
} }
@Override @Override

View file

@ -51,8 +51,8 @@ public class UHud {
private final List<Slot> slots = List.of( private final List<Slot> slots = List.of(
new ManaRingSlot(this, AbilitySlot.PRIMARY, AbilitySlot.PASSIVE, 0, 0), new ManaRingSlot(this, AbilitySlot.PRIMARY, AbilitySlot.PASSIVE, 0, 0),
new Slot(this, AbilitySlot.SECONDARY, AbilitySlot.SECONDARY, 30, -8), new Slot(this, AbilitySlot.SECONDARY, AbilitySlot.SECONDARY, 30, -10),
new Slot(this, AbilitySlot.TERTIARY, AbilitySlot.TERTIARY, 40, 18) new Slot(this, AbilitySlot.TERTIARY, AbilitySlot.TERTIARY, 43, 10)
); );
@Nullable @Nullable
@ -84,7 +84,7 @@ public class UHud {
Pony pony = Pony.of(client.player); Pony pony = Pony.of(client.player);
matrices.push(); matrices.push();
matrices.translate(0, 0, hotbarZ); matrices.translate(0, 0, hotbarZ - 9800);
renderViewEffects(pony, context, scaledWidth, scaledHeight, tickDelta); renderViewEffects(pony, context, scaledWidth, scaledHeight, tickDelta);
matrices.pop(); matrices.pop();
@ -137,9 +137,11 @@ public class UHud {
slots.forEach(slot -> slot.renderBackground(context, abilities, swap, tickDelta)); slots.forEach(slot -> slot.renderBackground(context, abilities, swap, tickDelta));
int currentPage = Unicopia.getConfig().hudPage.get();
int maxPages = pony.getAbilities().getMaxPage();
Ability<?> ability = pony.getAbilities().getStat(AbilitySlot.PRIMARY) Ability<?> ability = pony.getAbilities().getStat(AbilitySlot.PRIMARY)
.getAbility(Unicopia.getConfig().hudPage.get()) .getAbility(currentPage)
.orElse(null); .orElse(null);
boolean canCast = ability == Abilities.CAST || ability == Abilities.KIRIN_CAST || ability == Abilities.SHOOT; boolean canCast = ability == Abilities.CAST || ability == Abilities.KIRIN_CAST || ability == Abilities.SHOOT;
@ -168,6 +170,14 @@ public class UHud {
slots.forEach(slot -> slot.renderLabel(context, abilities, tickDelta)); slots.forEach(slot -> slot.renderLabel(context, abilities, tickDelta));
//if (maxPages > 0) {
DrawableUtil.drawScaledText(context, Text.literal((currentPage + 1) + "/" + (maxPages + 1)), 44, 38, 0.5F, Colors.WHITE);
//down
context.drawTexture(HUD_TEXTURE, 42, 43, 52, currentPage == 0 ? 6 : 0, 6, 6, 128, 128);
//up
context.drawTexture(HUD_TEXTURE, 48, 43, 57, currentPage < maxPages ? 0 : 6, 8, 6, 128, 128);
//}
matrices.pop(); matrices.pop();
if (canCast) { if (canCast) {
@ -188,7 +198,7 @@ public class UHud {
int progress = Math.min(255, (int)(time * 255F / 20F)); int progress = Math.min(255, (int)(time * 255F / 20F));
if (progress > 8) { if (progress > 8) {
int color = 0xFFFFFF; int color = Colors.WHITE;
int alpha = progress << 24 & -16777216; int alpha = progress << 24 & -16777216;
color |= alpha; color |= alpha;

View file

@ -116,7 +116,9 @@ public class Main extends MineLPDelegate implements ClientModInitializer {
@Override @Override
public float getPonyHeight(Entity entity) { public float getPonyHeight(Entity entity) {
return super.getPonyHeight(entity) * com.minelittlepony.api.pony.Pony.getManager().getPony(entity).map(pony -> pony.metadata().size().scaleFactor() + 0.1F).orElse(1F); return super.getPonyHeight(entity) * com.minelittlepony.api.pony.Pony.getManager().getPony(entity)
.map(pony -> pony.race().isHuman() ? 1 : pony.metadata().size().scaleFactor() + 0.1F)
.orElse(1F);
} }
private static Race toUnicopiaRace(com.minelittlepony.api.pony.meta.Race race) { private static Race toUnicopiaRace(com.minelittlepony.api.pony.meta.Race race) {

View file

@ -49,7 +49,9 @@ public class AmuletFeatureRenderer<E extends LivingEntity> implements AccessoryF
VertexConsumer consumer = ItemRenderer.getArmorGlintConsumer(renderContext, RenderLayer.getArmorCutoutNoCull(texture), false, false); VertexConsumer consumer = ItemRenderer.getArmorGlintConsumer(renderContext, RenderLayer.getArmorCutoutNoCull(texture), false, false);
if (context.getModel() instanceof BipedEntityModel) {
model.setAngles(entity, context.getModel()); model.setAngles(entity, context.getModel());
}
model.render(matrices, consumer, lightUv, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1); model.render(matrices, consumer, lightUv, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1);
} }
} }

View file

@ -67,10 +67,6 @@ class EntityReplacementManager implements Disguise {
return disguise; return disguise;
} }
@Override
public void setDirty() {
}
@Override @Override
public boolean isDead() { public boolean isDead() {
return false; return false;

View file

@ -9,7 +9,6 @@ import com.google.common.collect.*;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.logging.LogUtils; import com.mojang.logging.LogUtils;
import it.unimi.dsi.fastutil.objects.Object2FloatMap; import it.unimi.dsi.fastutil.objects.Object2FloatMap;
@ -52,11 +51,7 @@ public class ViewportShader implements SynchronousResourceReloader, Identifiable
} }
} }
if (shaderId == null) { if (shaderId == null || Unicopia.getConfig().disableShaders.get()) {
return;
}
if (Unicopia.getConfig().disableShaders.get()) {
return; return;
} }
@ -81,13 +76,10 @@ public class ViewportShader implements SynchronousResourceReloader, Identifiable
} }
if (shader != null && client.player != null) { if (shader != null && client.player != null) {
RenderSystem.disableBlend();
RenderSystem.disableDepthTest();
RenderSystem.resetTextureMatrix();
Pony pony = Pony.of(client.player); Pony pony = Pony.of(client.player);
float corruption = pony.getCorruption().getScaled(0.9F); float corruption = pony.getCorruption().getScaled(0.9F);
if (!MathHelper.approximatelyEquals(corruption, 0)) {
corruption = pony.getInterpolator().interpolate("corruption", corruption, 10); corruption = pony.getInterpolator().interpolate("corruption", corruption, 10);
corruption = 1 - corruption + 0.05F; corruption = 1 - corruption + 0.05F;
@ -96,14 +88,11 @@ public class ViewportShader implements SynchronousResourceReloader, Identifiable
shader.render(tickDelta); shader.render(tickDelta);
} }
} }
}
@Override @Override
public void reload(ResourceManager var1) { public void reload(ResourceManager var1) {
if (shader != null) { loadShader(shader != null ? shader.id : DESATURATION_SHADER);
loadShader(shader.id);
} else {
loadShader(DESATURATION_SHADER);
}
} }
static class LoadedShader extends PostEffectProcessor { static class LoadedShader extends PostEffectProcessor {

View file

@ -19,19 +19,22 @@ public class BubbleSpellRenderer extends SpellRenderer<BubbleSpell> {
super.render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch); super.render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch);
matrices.push(); matrices.push();
double height = caster.asEntity().getEyeY() - caster.getOriginVector().y; double height = caster.asEntity().getEyeY() - caster.getOriginVector().getY();
matrices.translate(0, height * 0.5F, 0);
float radius = spell.getRadius(tickDelta) * 0.7F;
VertexConsumer buffer = vertices.getBuffer(RenderLayers.getMagicNoColor()); float radius = spell.getRadius(tickDelta) * 1.5F;
matrices.translate(0, radius * 0.5F + height, 0);
VertexConsumer buffer = vertices.getBuffer(RenderLayers.getMagicShield());
Entity cameraEntity = MinecraftClient.getInstance().getCameraEntity(); Entity cameraEntity = MinecraftClient.getInstance().getCameraEntity();
matrices.push(); matrices.push();
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-45)); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
matrices.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(45 + cameraEntity.getYaw(tickDelta))); matrices.multiply(RotationAxis.NEGATIVE_Z.rotationDegrees(cameraEntity.getYaw(tickDelta) - 25));
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-cameraEntity.getPitch(tickDelta))); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-cameraEntity.getPitch(tickDelta)));
new SphereModel(40, 40, DrawableUtil.PI * 0.25F).render(matrices, buffer, light, 0, radius - 0.1F, 0.9F, 0.9F, 1, 0.3F); new SphereModel(40, 40, DrawableUtil.PI * 0.25F).render(matrices, buffer, light, 0, radius - 0.1F, 0.9F, 0.9F, 1, 0.3F);
matrices.pop(); matrices.pop();

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.client.render.spell; package com.minelittlepony.unicopia.client.render.spell;
import org.joml.Quaternionf;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.Spell;
@ -13,6 +15,8 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.model.json.ModelTransformationMode; import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis; import net.minecraft.util.math.RotationAxis;
@ -37,6 +41,8 @@ public class SpellRenderer<T extends Spell> {
private void renderGemstone(MatrixStack matrices, VertexConsumerProvider vertices, T spell, Caster<?> caster, int light, float tickDelta, float animationProgress) { private void renderGemstone(MatrixStack matrices, VertexConsumerProvider vertices, T spell, Caster<?> caster, int light, float tickDelta, float animationProgress) {
matrices.push(); matrices.push();
float scale = 1/8F;
matrices.scale(scale, scale, scale);
transformGemstone(matrices, vertices, spell, caster, animationProgress); transformGemstone(matrices, vertices, spell, caster, animationProgress);
matrices.push(); matrices.push();
@ -46,6 +52,22 @@ public class SpellRenderer<T extends Spell> {
matrices.pop(); matrices.pop();
if (spell instanceof TimedSpell timed) { if (spell instanceof TimedSpell timed) {
if (caster.asEntity() instanceof LivingEntity l && !l.isInPose(EntityPose.SLEEPING)) {
float bodyYaw = MathHelper.lerpAngleDegrees(tickDelta, l.prevBodyYaw, l.bodyYaw);
float headYaw = MathHelper.lerpAngleDegrees(tickDelta, l.prevHeadYaw, l.headYaw);
float yawDifference = headYaw - bodyYaw;
if (l.hasVehicle() && l.getVehicle() instanceof LivingEntity vehicle) {
bodyYaw = MathHelper.lerpAngleDegrees(tickDelta, vehicle.prevBodyYaw, vehicle.bodyYaw);
yawDifference = headYaw - bodyYaw;
float clampedYawDifference = MathHelper.clamp(MathHelper.wrapDegrees(yawDifference), -85, 85);
bodyYaw = headYaw - clampedYawDifference;
if (clampedYawDifference * clampedYawDifference > 2500) {
bodyYaw += clampedYawDifference * 0.2F;
}
yawDifference = headYaw - bodyYaw;
}
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - bodyYaw));
}
renderCountdown(matrices, timed, tickDelta); renderCountdown(matrices, timed, tickDelta);
} }
@ -53,7 +75,7 @@ public class SpellRenderer<T extends Spell> {
} }
protected void renderCountdown(MatrixStack matrices, TimedSpell spell, float tickDelta) { protected void renderCountdown(MatrixStack matrices, TimedSpell spell, float tickDelta) {
matrices.multiply(client.getEntityRenderDispatcher().getRotation().invert()); matrices.multiply(client.getEntityRenderDispatcher().getRotation().invert(new Quaternionf()));
float radius = 0.6F; float radius = 0.6F;
float timeRemaining = spell.getTimer().getPercentTimeRemaining(tickDelta); float timeRemaining = spell.getTimer().getPercentTimeRemaining(tickDelta);
@ -67,6 +89,6 @@ public class SpellRenderer<T extends Spell> {
if (caster.asEntity() instanceof CastSpellEntity) { if (caster.asEntity() instanceof CastSpellEntity) {
y = 1F; y = 1F;
} }
matrices.translate(0, y + MathHelper.sin(animationProgress / 3F) * 0.2F, 0); matrices.translate(0, y * 8 + MathHelper.sin(animationProgress / 3F) * 0.2F, 0);
} }
} }

View file

@ -23,7 +23,6 @@ import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.RegistryWrapper; import net.minecraft.registry.RegistryWrapper;
import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@ -63,10 +62,8 @@ public class ConfigCommand {
}))) })))
) )
.then(CommandManager.literal("list").executes(source -> ConfigCommand.<Set<String>>getProperty(configName, values -> { .then(CommandManager.literal("list").executes(source -> ConfigCommand.<Set<String>>getProperty(configName, values -> {
ServerPlayerEntity player = source.getSource().getPlayerOrThrow(); source.getSource().sendFeedback(() -> Text.translatable("command.unicopia.config.list", configName, values.size()), false);
values.forEach(line -> source.getSource().sendFeedback(() -> Text.literal(line), false));
player.sendMessage(Text.translatable("command.unicopia.config.list", configName, values.size()), false);
values.forEach(line -> player.sendMessage(Text.literal(line)));
})) }))
); );
} }

View file

@ -4,8 +4,10 @@ import java.util.function.Function;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
import com.minelittlepony.unicopia.ability.magic.spell.DispersableDisguiseSpell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
@ -81,7 +83,13 @@ public class DisguiseCommand {
Pony iplayer = Pony.of(player); Pony iplayer = Pony.of(player);
iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE) iplayer.getSpellSlot().get(SpellType.CHANGELING_DISGUISE)
.orElseGet(() -> SpellType.CHANGELING_DISGUISE.withTraits().apply(iplayer, CastingMethod.INNATE)) .orElseGet(() -> {
DispersableDisguiseSpell spell = SpellType.CHANGELING_DISGUISE.withTraits().apply(iplayer, CastingMethod.INNATE);
if (!iplayer.canUse(Abilities.DISGUISE)) {
spell.setForced();
}
return spell;
})
.setDisguise(entity); .setDisguise(entity);
if (source.getEntity() == player) { if (source.getEntity() == player) {

View file

@ -50,17 +50,19 @@ class GravityCommand {
l.getPhysics().setBaseGravityModifier(gravity); l.getPhysics().setBaseGravityModifier(gravity);
if (l.asEntity() instanceof PlayerEntity player) { if (l.asEntity() instanceof PlayerEntity player) {
if (source.getEntity() == player) { if (source.getEntity() == player) {
player.sendMessage(Text.translatable("commands.gravity.set.self", gravity)); source.sendFeedback(() -> Text.translatable("commands.gravity.set.self", gravity), true);
} else if (source.getWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) { } else {
player.sendMessage(Text.translatable("commands.gravity.set.other", l.asEntity().getDisplayName(), gravity)); if (source.getWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) {
player.sendMessage(Text.translatable("commands.gravity.set", gravity));
}
source.sendFeedback(() -> Text.translatable("commands.gravity.set.other", l.asEntity().getDisplayName(), gravity), true);
} }
} }
return (Entity)l.asEntity(); return (Entity)l.asEntity();
}).toList(); }).toList();
if (affected.size() == 1) { if (affected.size() > 1) {
source.sendFeedback(() -> Text.translatable("commands.gravity.set.other", affected.get(0).getDisplayName()), true);
} else {
source.sendFeedback(() -> Text.translatable("commands.gravity.set.multiple", affected.size()), true); source.sendFeedback(() -> Text.translatable("commands.gravity.set.multiple", affected.size()), true);
} }
return 0; return 0;

View file

@ -24,7 +24,7 @@ public class ManaCommand {
var pony = Pony.of(source.getSource().getPlayer()); var pony = Pony.of(source.getSource().getPlayer());
var bar = type.getBar(pony.getMagicalReserves()); var bar = type.getBar(pony.getMagicalReserves());
source.getSource().getPlayer().sendMessage(Text.literal(type.name() + " is " + bar.get() + "/" + bar.getMax())); source.getSource().sendFeedback(() -> Text.literal(type.name() + " is " + bar.get() + "/" + bar.getMax()), true);
return 0; return 0;
}) })
.then(CommandManager.argument("value", FloatArgumentType.floatArg()).executes(source -> { .then(CommandManager.argument("value", FloatArgumentType.floatArg()).executes(source -> {
@ -48,7 +48,8 @@ public class ManaCommand {
pony.asWorld().playSound(null, pony.getOrigin(), USounds.Vanilla.ENTITY_PLAYER_LEVELUP, SoundCategory.PLAYERS, 1, 2); pony.asWorld().playSound(null, pony.getOrigin(), USounds.Vanilla.ENTITY_PLAYER_LEVELUP, SoundCategory.PLAYERS, 1, 2);
} }
bar.set(value); bar.set(value);
source.getSource().getPlayer().sendMessage(Text.literal("Set " + type.name() + " to " + bar.get() + "/" + bar.getMax())); var t = type;
source.getSource().sendFeedback(() -> Text.literal("Set " + t.name() + " to " + bar.get() + "/" + bar.getMax()), true);
return 0; return 0;
}))); })));
} }

View file

@ -44,10 +44,10 @@ class SpeciesCommand {
)) ))
.then(CommandManager.literal("describe") .then(CommandManager.literal("describe")
.then(CommandManager.argument("race", Race.argument()).suggests(UCommandSuggestion.ALL_RACE_SUGGESTIONS) .then(CommandManager.argument("race", Race.argument()).suggests(UCommandSuggestion.ALL_RACE_SUGGESTIONS)
.executes(context -> describe(context.getSource().getPlayer(), Race.fromArgument(context, "race"))) .executes(context -> describe(context.getSource(), Race.fromArgument(context, "race")))
)) ))
.then(CommandManager.literal("list") .then(CommandManager.literal("list")
.executes(context -> list(context.getSource().getPlayer()) .executes(context -> list(context.getSource())
)); ));
} }
@ -70,57 +70,59 @@ class SpeciesCommand {
} }
source.sendFeedback(() -> Text.translatable("commands.race.success.other", player.getName(), race.getDisplayName()), true); source.sendFeedback(() -> Text.translatable("commands.race.success.other", player.getName(), race.getDisplayName()), true);
} }
} else if (player.getEntityWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) { } else {
player.sendMessage(Text.translatable("commands.race.permission"), false); source.sendFeedback(() -> Text.translatable("commands.race.permission"), false);
} }
return 0; return 0;
} }
static int get(ServerCommandSource source, PlayerEntity player, boolean isSelf) { static int get(ServerCommandSource source, PlayerEntity player, boolean isSelf) {
source.sendFeedback(() -> {
Race spec = Pony.of(player).getSpecies(); Race spec = Pony.of(player).getSpecies();
String name = "commands.race.tell."; String name = "commands.race.tell.";
name += isSelf ? "self" : "other"; name += isSelf ? "self" : "other";
player.sendMessage(Text.translatable(name, player.getName()) return Text.translatable(name, player.getName())
.append(Text.translatable(spec.getTranslationKey()) .append(Text.translatable(spec.getTranslationKey())
.styled(s -> s.withColor(Formatting.GOLD))), false); .styled(s -> s.withColor(Formatting.GOLD)));
}, false);
return 0; return 0;
} }
static int list(PlayerEntity player) { static int list(ServerCommandSource source) {
player.sendMessage(Text.translatable("commands.race.list"), false); source.sendFeedback(() -> Text.translatable("commands.race.list"), false);
source.sendFeedback(() -> {
MutableText message = Text.literal(""); MutableText message = Text.literal("");
boolean first = true; boolean first = true;
for (Race i : Race.REGISTRY) { for (Race i : Race.REGISTRY) {
if (i.availability().isGrantable() && !i.isUnset() && i.isPermitted(player)) { if (i.availability().isGrantable() && !i.isUnset() && i.isPermitted(source.getPlayer())) {
message.append(Text.literal((!first ? "\n" : "") + " - ")); message.append(Text.literal((!first ? "\n" : "") + " - "));
message.append(i.getDisplayName()); message.append(i.getDisplayName());
first = false; first = false;
} }
} }
player.sendMessage(message.styled(s -> s.withColor(Formatting.GOLD)), false); return message.styled(s -> s.withColor(Formatting.GOLD));
}, false);
return 0; return 0;
} }
static int describe(PlayerEntity player, Race species) { static int describe(ServerCommandSource source, Race species) {
Identifier id = Race.REGISTRY.getId(species); Identifier id = Race.REGISTRY.getId(species);
for (String category : new String[] { "goods", "bads" }) { for (String category : new String[] { "goods", "bads" }) {
player.sendMessage(Text.translatable( source.sendFeedback(() -> Text.translatable(
String.format("gui.unicopia.tribe_selection.confirm.%s.%d.%s.%s", category), String.format("gui.unicopia.tribe_selection.confirm.%s.%d.%s.%s", category),
species.getAltDisplayName() species.getAltDisplayName()
), false); ), false);
for (int i = 1; i < 5; i++) { for (int i = 1; i < 5; i++) {
String line = String.format("gui.unicopia.tribe_selection.confirm.%s.%d.%s.%s", category, i, id.getNamespace(), id.getPath()); String line = String.format("gui.unicopia.tribe_selection.confirm.%s.%d.%s.%s", category, i, id.getNamespace(), id.getPath());
player.sendMessage(Text.translatable(line).styled(s -> s.withColor(category.equals("goods") ? Formatting.YELLOW : Formatting.RED)), false); source.sendFeedback(() -> Text.translatable(line).styled(s -> s.withColor(category.equals("goods") ? Formatting.YELLOW : Formatting.RED)), false);
} }
} }

View file

@ -13,6 +13,7 @@ import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.*; import net.minecraft.text.*;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.world.GameRules;
class TraitCommand { class TraitCommand {
static LiteralArgumentBuilder<ServerCommandSource> create() { static LiteralArgumentBuilder<ServerCommandSource> create() {
@ -78,7 +79,9 @@ class TraitCommand {
float gravity = iplayer.getPhysics().getGravityModifier(); float gravity = iplayer.getPhysics().getGravityModifier();
if (source.getPlayer() == player) { if (source.getPlayer() == player) {
if (player.getEntityWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) {
player.sendMessage(Text.translatable(translationKey, gravity), false); player.sendMessage(Text.translatable(translationKey, gravity), false);
}
} else { } else {
source.sendFeedback(() -> Text.translatable(translationKey + ".other", player.getName(), gravity), true); source.sendFeedback(() -> Text.translatable(translationKey + ".other", player.getName(), gravity), true);
} }

View file

@ -127,7 +127,7 @@ public interface TrinketsDelegate {
} }
record EquippedStack(ItemStack stack, Runnable sendUpdate, Consumer<LivingEntity> breakStatusSender) { record EquippedStack(ItemStack stack, Runnable sendUpdate, Consumer<LivingEntity> breakStatusSender) {
public static EquippedStack EMPTY = new EquippedStack(ItemStack.EMPTY, () -> {}, l -> {}); public static final EquippedStack EMPTY = new EquippedStack(ItemStack.EMPTY, () -> {}, l -> {});
EquippedStack(LivingEntity entity, EquipmentSlot slot) { EquippedStack(LivingEntity entity, EquipmentSlot slot) {
this(entity.getEquippedStack(slot), () -> {}, l -> l.sendEquipmentBreakStatus(slot)); this(entity.getEquippedStack(slot), () -> {}, l -> l.sendEquipmentBreakStatus(slot));

View file

@ -148,12 +148,14 @@ public class DietProfileGenerator {
bakedGoodExtremePreference, pineconeMultiplier, properMeatStandards, seaFoodExclusions, bakedGoodExtremePreference, pineconeMultiplier, properMeatStandards, seaFoodExclusions,
// They have a sweet tooth // They have a sweet tooth
new Multiplier.Builder().tag(Unicopia.id("candy")).tag(Unicopia.id("desserts")).tag(Unicopia.id("rocks")).hunger(2.5F).saturation(1.7F).build(), new Multiplier.Builder().tag(Unicopia.id("candy")).tag(Unicopia.id("desserts")).tag(Unicopia.id("rocks")).hunger(2.5F).saturation(1.7F).build(),
new Multiplier.Builder().tag(Unicopia.id("gems")).hunger(0.5F).saturation(0.7F).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(0.2F).saturation(0.3F).build(), new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(0.2F).saturation(0.3F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(0.1F).saturation(0.1F).build(), new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(0.1F).saturation(0.1F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(0.1F).saturation(0.1F).build() new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(0.1F).saturation(0.1F).build()
), List.of( ), List.of(
// Candy and rocks gives them a massive saturation boost. Maybe too much? // Candy and rocks gives them a massive saturation boost. Maybe too much?
new FoodGroupEffects.Builder().tag(Unicopia.id("candy")).tag(Unicopia.id("rocks")).food(UFoodComponents.builder(5, 12).alwaysEdible()).build(), new FoodGroupEffects.Builder().tag(Unicopia.id("candy")).tag(Unicopia.id("rocks")).food(UFoodComponents.builder(5, 12).alwaysEdible()).build(),
new FoodGroupEffects.Builder().tag(Unicopia.id("gems")).food(UFoodComponents.builder(2, 1.5F).snack().alwaysEdible()).build(),
new FoodGroupEffects.Builder().tag(Unicopia.id("desserts")).food(UFoodComponents.builder(12, 32).snack().alwaysEdible()).build() new FoodGroupEffects.Builder().tag(Unicopia.id("desserts")).food(UFoodComponents.builder(12, 32).snack().alwaysEdible()).build()
), Optional.empty())); ), Optional.empty()));
// Pegasi prefer fish over other food sources // Pegasi prefer fish over other food sources

View file

@ -31,6 +31,7 @@ public class FoodGroupsGenerator {
exporter.accept(Unicopia.id("desserts"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.DESSERTS).food(FoodComponents.COOKIE)); exporter.accept(Unicopia.id("desserts"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.DESSERTS).food(FoodComponents.COOKIE));
exporter.accept(Unicopia.id("fruit"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.FRUITS).food(UFoodComponents.BANANA)); exporter.accept(Unicopia.id("fruit"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.FRUITS).food(UFoodComponents.BANANA));
exporter.accept(Unicopia.id("rocks"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.ROCKS).tag(UTags.Items.ROCK_STEWS).food(FoodComponents.MUSHROOM_STEW)); exporter.accept(Unicopia.id("rocks"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.ROCKS).tag(UTags.Items.ROCK_STEWS).food(FoodComponents.MUSHROOM_STEW));
exporter.accept(Unicopia.id("gems"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.GEMS));
exporter.accept(Unicopia.id("shells"), new FoodGroupEffects.Builder().tag(UTags.Items.SHELLS).food(UFoodComponents.SHELL)); exporter.accept(Unicopia.id("shells"), new FoodGroupEffects.Builder().tag(UTags.Items.SHELLS).food(UFoodComponents.SHELL));
exporter.accept(Unicopia.id("special_shells"), new FoodGroupEffects.Builder().tag(UTags.Items.SPECIAL_SHELLS).food(UFoodComponents.SHELLY)); exporter.accept(Unicopia.id("special_shells"), new FoodGroupEffects.Builder().tag(UTags.Items.SPECIAL_SHELLS).food(UFoodComponents.SHELLY));
exporter.accept(Unicopia.id("love"), new FoodGroupEffects.Builder().tag(UTags.Items.CONTAINER_WITH_LOVE).food(UFoodComponents.LOVE_MUG).ailment(new CompoundAffliction(List.<Affliction>of( exporter.accept(Unicopia.id("love"), new FoodGroupEffects.Builder().tag(UTags.Items.CONTAINER_WITH_LOVE).food(UFoodComponents.LOVE_MUG).ailment(new CompoundAffliction(List.<Affliction>of(

View file

@ -0,0 +1,32 @@
package com.minelittlepony.unicopia.datagen.providers.tag;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
public interface SereneSeasonsTags {
interface Items {
TagKey<Item> AUTUMN_CROPS = item("autumn_crops");
TagKey<Item> WINTER_CROPS = item("winter_crops");
TagKey<Item> SPRING_CROPS = item("spring_crops");
TagKey<Item> SUMMER_CROPS = item("summer_crops");
private static TagKey<Item> item(String name) {
return TagKey.of(RegistryKeys.ITEM, new Identifier("sereneseasons", name));
}
}
interface Blocks {
TagKey<Block> AUTUMN_CROPS = block("autumn_crops");
TagKey<Block> WINTER_CROPS = block("winter_crops");
TagKey<Block> SPRING_CROPS = block("spring_crops");
TagKey<Block> SUMMER_CROPS = block("summer_crops");
private static TagKey<Block> block(String name) {
return TagKey.of(RegistryKeys.BLOCK, new Identifier("sereneseasons", name));
}
}
}

View file

@ -8,6 +8,7 @@ import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.block.UBlocks; import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.server.world.Tree; import com.minelittlepony.unicopia.server.world.Tree;
import com.minelittlepony.unicopia.server.world.UTreeGen;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
@ -103,6 +104,30 @@ public class UBlockTagProvider extends FabricTagProvider.BlockTagProvider {
).forceAddTag(TagKey.of(RegistryKeys.BLOCK, new Identifier("c", "concrete_powders"))); ).forceAddTag(TagKey.of(RegistryKeys.BLOCK, new Identifier("c", "concrete_powders")));
getOrCreateTagBuilder(UTags.Blocks.UNAFFECTED_BY_GROW_ABILITY).add(Blocks.GRASS_BLOCK); getOrCreateTagBuilder(UTags.Blocks.UNAFFECTED_BY_GROW_ABILITY).add(Blocks.GRASS_BLOCK);
addSeasonalCrops();
}
private void addSeasonalCrops() {
getOrCreateTagBuilder(SereneSeasonsTags.Blocks.AUTUMN_CROPS).add(
UBlocks.GREEN_APPLE_LEAVES, UBlocks.GREEN_APPLE_SPROUT, UTreeGen.GREEN_APPLE_TREE.sapling().get(),
UBlocks.SOUR_APPLE_LEAVES, UBlocks.SOUR_APPLE_SPROUT, UTreeGen.SOUR_APPLE_TREE.sapling().get(),
UBlocks.OATS_CROWN, UBlocks.OATS_STEM, UBlocks.OATS,
UBlocks.ROCKS
);
getOrCreateTagBuilder(SereneSeasonsTags.Blocks.WINTER_CROPS).add(UBlocks.ROCKS);
getOrCreateTagBuilder(SereneSeasonsTags.Blocks.SPRING_CROPS).add(
UBlocks.SWEET_APPLE_LEAVES, UBlocks.SWEET_APPLE_SPROUT, UTreeGen.SWEET_APPLE_TREE.sapling().get(),
UBlocks.GOLDEN_OAK_LEAVES, UBlocks.GOLDEN_OAK_SPROUT, UTreeGen.GOLDEN_APPLE_TREE.sapling().get(),
UBlocks.PALM_LEAVES, UBlocks.BANANAS, UTreeGen.BANANA_TREE.sapling().get(),
UBlocks.PINEAPPLE,
UBlocks.ROCKS
);
getOrCreateTagBuilder(SereneSeasonsTags.Blocks.SUMMER_CROPS).add(
UBlocks.SWEET_APPLE_LEAVES, UBlocks.SWEET_APPLE_SPROUT, UTreeGen.SWEET_APPLE_TREE.sapling().get(),
UBlocks.MANGO_LEAVES, UTreeGen.MANGO_TREE.sapling().get(),
UBlocks.OATS_CROWN, UBlocks.OATS_STEM, UBlocks.OATS,
UBlocks.ROCKS
);
} }
private void addFruitTrees() { private void addFruitTrees() {

View file

@ -8,6 +8,7 @@ import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
import net.minecraft.entity.damage.DamageType; import net.minecraft.entity.damage.DamageType;
import net.minecraft.entity.damage.DamageTypes;
import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.RegistryWrapper.WrapperLookup; import net.minecraft.registry.RegistryWrapper.WrapperLookup;
import net.minecraft.registry.tag.DamageTypeTags; import net.minecraft.registry.tag.DamageTypeTags;
@ -25,7 +26,11 @@ public class UDamageTypeProvider extends FabricTagProvider<DamageType> {
).forceAddTag(DamageTypeTags.IS_FALL).forceAddTag(DamageTypeTags.IS_FREEZING).forceAddTag(DamageTypeTags.IS_LIGHTNING).forceAddTag(DamageTypeTags.IS_PROJECTILE); ).forceAddTag(DamageTypeTags.IS_FALL).forceAddTag(DamageTypeTags.IS_FREEZING).forceAddTag(DamageTypeTags.IS_LIGHTNING).forceAddTag(DamageTypeTags.IS_PROJECTILE);
getOrCreateTagBuilder(UTags.DamageTypes.FROM_ROCKS).add(UDamageTypes.ROCK); getOrCreateTagBuilder(UTags.DamageTypes.FROM_ROCKS).add(UDamageTypes.ROCK);
getOrCreateTagBuilder(UTags.DamageTypes.FROM_HORSESHOES).add(UDamageTypes.HORSESHOE); getOrCreateTagBuilder(UTags.DamageTypes.FROM_HORSESHOES).add(UDamageTypes.HORSESHOE);
getOrCreateTagBuilder(UTags.DamageTypes.BREAKS_SUNGLASSES).add(UDamageTypes.BAT_SCREECH, UDamageTypes.RAINBOOM); getOrCreateTagBuilder(UTags.DamageTypes.BREAKS_SUNGLASSES).add(
UDamageTypes.BAT_SCREECH, UDamageTypes.RAINBOOM,
DamageTypes.FLY_INTO_WALL, DamageTypes.FALLING_ANVIL, DamageTypes.FALLING_BLOCK,
DamageTypes.SONIC_BOOM
).forceAddTag(DamageTypeTags.IS_EXPLOSION);
getOrCreateTagBuilder(DamageTypeTags.AVOIDS_GUARDIAN_THORNS).add( getOrCreateTagBuilder(DamageTypeTags.AVOIDS_GUARDIAN_THORNS).add(
UDamageTypes.EXHAUSTION, UDamageTypes.ALICORN_AMULET, UDamageTypes.ZAP_APPLE, UDamageTypes.KICK, UDamageTypes.SMASH, UDamageTypes.EXHAUSTION, UDamageTypes.ALICORN_AMULET, UDamageTypes.ZAP_APPLE, UDamageTypes.KICK, UDamageTypes.SMASH,
@ -35,9 +40,13 @@ public class UDamageTypeProvider extends FabricTagProvider<DamageType> {
UDamageTypes.EXHAUSTION, UDamageTypes.GAVITY_WELL_RECOIL, UDamageTypes.ALICORN_AMULET, UDamageTypes.EXHAUSTION, UDamageTypes.GAVITY_WELL_RECOIL, UDamageTypes.ALICORN_AMULET,
UDamageTypes.ZAP_APPLE, UDamageTypes.KICK, UDamageTypes.SMASH, UDamageTypes.BAT_SCREECH, UDamageTypes.ZAP_APPLE, UDamageTypes.KICK, UDamageTypes.SMASH, UDamageTypes.BAT_SCREECH,
UDamageTypes.LOVE_DRAINING, UDamageTypes.LIFE_DRAINING, UDamageTypes.STEAMROLLER, UDamageTypes.RAINBOOM, UDamageTypes.LOVE_DRAINING, UDamageTypes.LIFE_DRAINING, UDamageTypes.STEAMROLLER, UDamageTypes.RAINBOOM,
UDamageTypes.SUN, UDamageTypes.SUNLIGHT, UDamageTypes.PETRIFIED UDamageTypes.SUN, UDamageTypes.SUNLIGHT, UDamageTypes.PETRIFIED, UDamageTypes.TRIBE_SWAP
); );
getOrCreateTagBuilder(DamageTypeTags.BYPASSES_INVULNERABILITY).add(UDamageTypes.TRIBE_SWAP); getOrCreateTagBuilder(DamageTypeTags.BYPASSES_INVULNERABILITY).add(UDamageTypes.TRIBE_SWAP);
getOrCreateTagBuilder(DamageTypeTags.BYPASSES_COOLDOWN).add(UDamageTypes.TRIBE_SWAP);
getOrCreateTagBuilder(DamageTypeTags.BYPASSES_EFFECTS).add(UDamageTypes.TRIBE_SWAP);
getOrCreateTagBuilder(DamageTypeTags.BYPASSES_RESISTANCE).add(UDamageTypes.TRIBE_SWAP);
getOrCreateTagBuilder(DamageTypeTags.BYPASSES_ENCHANTMENTS).add(UDamageTypes.TRIBE_SWAP);
getOrCreateTagBuilder(DamageTypeTags.BYPASSES_SHIELD).add( getOrCreateTagBuilder(DamageTypeTags.BYPASSES_SHIELD).add(
UDamageTypes.EXHAUSTION, UDamageTypes.BAT_SCREECH, UDamageTypes.ALICORN_AMULET, UDamageTypes.EXHAUSTION, UDamageTypes.BAT_SCREECH, UDamageTypes.ALICORN_AMULET,
UDamageTypes.LOVE_DRAINING, UDamageTypes.LIFE_DRAINING, UDamageTypes.LOVE_DRAINING, UDamageTypes.LIFE_DRAINING,

View file

@ -175,6 +175,11 @@ public class UItemTagProvider extends FabricTagProvider.ItemTagProvider {
copy(UTags.Blocks.CLOUD_STAIRS, UTags.Items.CLOUD_STAIRS); copy(UTags.Blocks.CLOUD_STAIRS, UTags.Items.CLOUD_STAIRS);
copy(UTags.Blocks.CLOUD_BLOCKS, UTags.Items.CLOUD_BLOCKS); copy(UTags.Blocks.CLOUD_BLOCKS, UTags.Items.CLOUD_BLOCKS);
copy(UTags.Blocks.CHITIN_BLOCKS, UTags.Items.CHITIN_BLOCKS); copy(UTags.Blocks.CHITIN_BLOCKS, UTags.Items.CHITIN_BLOCKS);
copy(SereneSeasonsTags.Blocks.AUTUMN_CROPS, SereneSeasonsTags.Items.AUTUMN_CROPS);
copy(SereneSeasonsTags.Blocks.WINTER_CROPS, SereneSeasonsTags.Items.WINTER_CROPS);
copy(SereneSeasonsTags.Blocks.SPRING_CROPS, SereneSeasonsTags.Items.SPRING_CROPS);
copy(SereneSeasonsTags.Blocks.SUMMER_CROPS, SereneSeasonsTags.Items.SUMMER_CROPS);
} }
private void exportForagingTags() { private void exportForagingTags() {
@ -348,6 +353,7 @@ public class UItemTagProvider extends FabricTagProvider.ItemTagProvider {
getOrCreateTagBuilder(UConventionalTags.Items.WORMS).add(UItems.WHEAT_WORMS); getOrCreateTagBuilder(UConventionalTags.Items.WORMS).add(UItems.WHEAT_WORMS);
getOrCreateTagBuilder(UConventionalTags.Items.STICKS).add(Items.STICK); getOrCreateTagBuilder(UConventionalTags.Items.STICKS).add(Items.STICK);
getOrCreateTagBuilder(UConventionalTags.Items.ROCKS).add(UItems.ROCK); getOrCreateTagBuilder(UConventionalTags.Items.ROCKS).add(UItems.ROCK);
getOrCreateTagBuilder(UConventionalTags.Items.GEMS).add(UItems.GEMSTONE, UItems.BOTCHED_GEM);
getOrCreateTagBuilder(UConventionalTags.Items.PINECONES).add(UItems.PINECONE); getOrCreateTagBuilder(UConventionalTags.Items.PINECONES).add(UItems.PINECONE);
getOrCreateTagBuilder(UConventionalTags.Items.PINEAPPLES).add(UItems.PINEAPPLE); getOrCreateTagBuilder(UConventionalTags.Items.PINEAPPLES).add(UItems.PINEAPPLE);
getOrCreateTagBuilder(UConventionalTags.Items.MANGOES).add(UItems.MANGO); getOrCreateTagBuilder(UConventionalTags.Items.MANGOES).add(UItems.MANGO);

View file

@ -26,7 +26,7 @@ public interface AttributeContainer {
EntityAttributeModifier modifier = instance.getModifier(id); EntityAttributeModifier modifier = instance.getModifier(id);
if (!MathHelper.approximatelyEquals(desiredValue, modifier == null ? 0 : modifier.getValue())) { if (!MathHelper.approximatelyEquals(desiredValue, modifier == null ? 0 : modifier.getValue())) {
instance.tryRemoveModifier(id); instance.removeModifier(id);
if (desiredValue != 0) { if (desiredValue != 0) {
if (permanent) { if (permanent) {

View file

@ -11,7 +11,6 @@ import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.WeaklyOwned; import com.minelittlepony.unicopia.WeaklyOwned;
import com.minelittlepony.unicopia.ability.magic.*; import com.minelittlepony.unicopia.ability.magic.*;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.TargetSelecter; import com.minelittlepony.unicopia.ability.magic.spell.effect.TargetSelecter;
import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal; import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal;
import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal; import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal;
@ -302,9 +301,6 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
@Override @Override
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {
super.toNBT(compound); super.toNBT(compound);
getSpellSlot().get().ifPresent(effect -> {
compound.put("effect", Spell.writeNbt(effect));
});
compound.put("master", getMasterReference().toNBT()); compound.put("master", getMasterReference().toNBT());
physics.toNBT(compound); physics.toNBT(compound);
compound.putBoolean("discorded", isDiscorded()); compound.putBoolean("discorded", isDiscorded());
@ -313,9 +309,6 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
@Override @Override
public void fromNBT(NbtCompound compound) { public void fromNBT(NbtCompound compound) {
super.fromNBT(compound); super.fromNBT(compound);
if (compound.contains("effect")) {
getSpellSlot().put(Spell.readNbt(compound.getCompound("effect")));
}
if (compound.contains("master", NbtElement.COMPOUND_TYPE)) { if (compound.contains("master", NbtElement.COMPOUND_TYPE)) {
owner.fromNBT(compound.getCompound("master")); owner.fromNBT(compound.getCompound("master"));
if (owner.isSet()) { if (owner.isSet()) {

View file

@ -10,12 +10,12 @@ import com.minelittlepony.unicopia.util.Tickable;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.FenceGateBlock; import net.minecraft.block.FenceGateBlock;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.MobEntity;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.tag.BlockTags; import net.minecraft.registry.tag.BlockTags;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
public class EntityPhysics<T extends Entity> implements Physics, Copyable<EntityPhysics<T>>, Tickable { public class EntityPhysics<T extends Entity> implements Physics, Copyable<EntityPhysics<T>>, Tickable {
@ -75,18 +75,17 @@ public class EntityPhysics<T extends Entity> implements Physics, Copyable<Entity
@Override @Override
public BlockPos getHeadPosition() { public BlockPos getHeadPosition() {
BlockPos pos = BlockPos.ofFloored(
BlockPos pos = new BlockPos( entity.getX(),
MathHelper.floor(entity.getX()), entity.getY() + entity.getEyeHeight(EntityPose.STANDING),
MathHelper.floor(entity.getY() + entity.getHeight() + 0.20000000298023224D), entity.getZ()
MathHelper.floor(entity.getZ())
); );
if (entity.getWorld().getBlockState(pos).isAir()) { if (entity.getWorld().getBlockState(pos).isAir()) {
BlockPos below = pos.down(); BlockPos below = pos.down();
BlockState block = entity.getWorld().getBlockState(below); BlockState block = entity.getWorld().getBlockState(below);
if (block.isIn(BlockTags.FENCES) || block.isIn(BlockTags.WALLS) || block.getBlock() instanceof FenceGateBlock) { if (block.isIn(BlockTags.FENCES) || block.isIn(BlockTags.WALLS) || block.getBlock() instanceof FenceGateBlock) {
return below; // return below;
} }
} }

View file

@ -381,7 +381,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
} }
} }
if (entity instanceof HostileEntity mob && mob.hasStatusEffect(UEffects.CORRUPT_INFLUENCE) && mob.getRandom().nextInt(4) == 0) { if (entity instanceof HostileEntity mob && mob.hasStatusEffect(UEffects.CORRUPT_INFLUENCE) && mob.getRandom().nextInt(4000) == 0) {
CorruptInfluenceStatusEffect.reproduce(mob); CorruptInfluenceStatusEffect.reproduce(mob);
} }

View file

@ -49,6 +49,7 @@ public class BreakHeartGoal extends Goal {
public void stop() { public void stop() {
targetter.stop(); targetter.stop();
mob.getNavigation().stop(); mob.getNavigation().stop();
mob.setTarget(null);
} }
@Override @Override

View file

@ -24,8 +24,6 @@ public interface Disguise extends FlightType.Provider, PlayerDimensions.Provider
EntityAppearance getDisguise(); EntityAppearance getDisguise();
void setDirty();
boolean isDead(); boolean isDead();
default Optional<EntityAppearance> getAppearance() { default Optional<EntityAppearance> getAppearance() {
@ -57,7 +55,6 @@ public interface Disguise extends FlightType.Provider, PlayerDimensions.Provider
} }
getDisguise().setAppearance(entity); getDisguise().setAppearance(entity);
setDirty();
return this; return this;
} }

View file

@ -21,6 +21,7 @@ import com.minelittlepony.unicopia.entity.mob.SombraEntity;
import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes;
import com.minelittlepony.unicopia.entity.player.PlayerDimensions; import com.minelittlepony.unicopia.entity.player.PlayerDimensions;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.track.TrackableObject;
import com.minelittlepony.unicopia.projectile.ProjectileUtil; import com.minelittlepony.unicopia.projectile.ProjectileUtil;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
@ -51,7 +52,7 @@ import net.minecraft.nbt.NbtElement;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShape;
public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provider, FlightType.Provider, EntityCollisions.ComplexCollidable { public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provider, FlightType.Provider, EntityCollisions.ComplexCollidable, TrackableObject<EntityAppearance> {
private static final Optional<Float> BLOCK_HEIGHT = Optional.of(0.5F); private static final Optional<Float> BLOCK_HEIGHT = Optional.of(0.5F);
@NotNull @NotNull
@ -77,6 +78,8 @@ public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provi
@Nullable @Nullable
private NbtCompound entityNbt; private NbtCompound entityNbt;
private boolean dirty;
@Nullable @Nullable
public Entity getAppearance() { public Entity getAppearance() {
return entity; return entity;
@ -109,6 +112,7 @@ public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provi
entityNbt = entity == null ? null : encodeEntityToNBT(entity); entityNbt = entity == null ? null : encodeEntityToNBT(entity);
entityId = entityNbt == null ? "" : entityNbt.getString("id"); entityId = entityNbt == null ? "" : entityNbt.getString("id");
markDirty();
} }
public boolean isPresent() { public boolean isPresent() {
@ -392,4 +396,44 @@ public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provi
getAttachments().forEach(e -> EntityCollisions.getCollissionShapes(e.entity(), context, output)); getAttachments().forEach(e -> EntityCollisions.getCollissionShapes(e.entity(), context, output));
} }
public void markDirty() {
dirty = true;
}
@Override
public Status getStatus() {
if (dirty) {
dirty = false;
return Status.UPDATED;
}
return Status.DEFAULT;
}
@Override
public void readTrackedNbt(NbtCompound nbt) {
fromNBT(nbt);
}
@Override
public NbtCompound writeTrackedNbt() {
return toNBT();
}
@Override
public void discard(boolean immediate) {
setAppearance(null);
dirty = false;
}
@Override
public void copyTo(EntityAppearance destination) {
destination.entityId = entityId;
destination.entity = entity;
destination.blockEntity = blockEntity;
destination.attachments.addAll(attachments);
destination.dimensions = dimensions;
destination.tag = tag == null ? null : tag.copy();
destination.entityNbt = entityNbt == null ? null : entityNbt.copy();
}
} }

View file

@ -65,7 +65,7 @@ public class SheepBehaviour extends EntityBehaviour<SheepEntity> {
} }
} while (dropAmount-- > 0); } while (dropAmount-- > 0);
} }
spell.setDirty(); spell.getAppearance().ifPresent(EntityAppearance::markDirty);
} }
} }
} }

View file

@ -89,6 +89,9 @@ public class CorruptInfluenceStatusEffect extends StatusEffect {
} }
} }
if (mob.getRandom().nextInt(4) != 0) {
clone.clearStatusEffects();
}
mob.getWorld().spawnEntity(clone); mob.getWorld().spawnEntity(clone);
if (!mob.isSilent()) { if (!mob.isSilent()) {

View file

@ -20,11 +20,11 @@ import net.minecraft.util.Identifier;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
public interface UPotions { public interface UPotions {
MorphingPotion MORPH_EARTH_PONY = new MorphingPotion(Race.EARTH).registerBaseRecipes(Potions.STRENGTH, UItems.CURING_JOKE); MorphingPotion MORPH_EARTH_PONY = new MorphingPotion(Race.EARTH).registerBaseRecipes(Potions.STRENGTH, UItems.CURING_JOKE, UItems.PEBBLES);
MorphingPotion MORPH_UNICORN = new MorphingPotion(Race.UNICORN).registerBaseRecipes(Potions.REGENERATION, UItems.BOTCHED_GEM); MorphingPotion MORPH_UNICORN = new MorphingPotion(Race.UNICORN).registerBaseRecipes(Potions.REGENERATION, UItems.BOTCHED_GEM, UItems.GEMSTONE);
MorphingPotion MORPH_PEGASUS = new MorphingPotion(Race.PEGASUS).registerBaseRecipes(Potions.SWIFTNESS, UItems.PEGASUS_FEATHER, UItems.HIPPOGRIFF_BADGE, Items.FEATHER); MorphingPotion MORPH_PEGASUS = new MorphingPotion(Race.PEGASUS).registerBaseRecipes(Potions.SWIFTNESS, UItems.PEGASUS_FEATHER, UItems.GRYPHON_FEATHER, Items.FEATHER);
MorphingPotion MORPH_BAT = new MorphingPotion(Race.BAT).registerBaseRecipes(Potions.NIGHT_VISION, UItems.BUTTERFLY); MorphingPotion MORPH_BAT = new MorphingPotion(Race.BAT).registerBaseRecipes(Potions.NIGHT_VISION, UItems.BUTTERFLY);
MorphingPotion MORPH_CHANGELING = new MorphingPotion(Race.CHANGELING).registerBaseRecipes(Potions.HARMING, UItems.CARAPACE); MorphingPotion MORPH_CHANGELING = new MorphingPotion(Race.CHANGELING).registerBaseRecipes(Potions.HARMING, UItems.CARAPACE, UItems.ROTTEN_APPLE);
MorphingPotion MORPH_KIRIN = new MorphingPotion(Race.KIRIN).registerBaseRecipes(Potions.FIRE_RESISTANCE, Items.MAGMA_CREAM); MorphingPotion MORPH_KIRIN = new MorphingPotion(Race.KIRIN).registerBaseRecipes(Potions.FIRE_RESISTANCE, Items.MAGMA_CREAM);
MorphingPotion MORPH_HIPPOGRIFF = new MorphingPotion(Race.HIPPOGRIFF).registerBaseRecipes(Potions.WATER_BREATHING, UItems.CLAM_SHELL, UItems.TURRET_SHELL, UItems.SCALLOP_SHELL); MorphingPotion MORPH_HIPPOGRIFF = new MorphingPotion(Race.HIPPOGRIFF).registerBaseRecipes(Potions.WATER_BREATHING, UItems.CLAM_SHELL, UItems.TURRET_SHELL, UItems.SCALLOP_SHELL);

View file

@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.ability.magic.SpellSlots;
import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell; import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell.PlacementDelegate;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.entity.EntityPhysics; import com.minelittlepony.unicopia.entity.EntityPhysics;
import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.EntityReference;
@ -70,8 +71,12 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster<CastS
this.controllingEntityUuid = caster.asEntity().getUuid(); this.controllingEntityUuid = caster.asEntity().getUuid();
this.controllingSpellUuid = control.getUuid(); this.controllingSpellUuid = control.getUuid();
setCaster(caster); setCaster(caster);
Spell spell = Spell.copy(control.getDelegate());
spells.getSlots().put(spell); if (control.getDelegate() instanceof PlacementDelegate delegate) {
delegate.onPlaced(caster, control);
}
spells.getSlots().put(Spell.copy(control.getDelegate()));
} }
public CastSpellEntity(EntityType<?> type, World world) { public CastSpellEntity(EntityType<?> type, World world) {

View file

@ -58,6 +58,8 @@ public class Acrobatics implements Tickable, NbtSerialisable {
public void tick() { public void tick() {
BlockPos climbingPos = entity.getClimbingPos().orElse(null); BlockPos climbingPos = entity.getClimbingPos().orElse(null);
BlockPos hangingPos = pony.getPhysics().getHeadPosition();
if (!pony.getPhysics().isFlying() && !entity.getAbilities().flying if (!pony.getPhysics().isFlying() && !entity.getAbilities().flying
&& climbingPos != null && climbingPos != null
&& pony.getObservedSpecies() == Race.CHANGELING && pony.getObservedSpecies() == Race.CHANGELING
@ -68,7 +70,8 @@ public class Acrobatics implements Tickable, NbtSerialisable {
} }
distanceClimbed += Math.abs(pony.getMotion().getClientVelocity().y); distanceClimbed += Math.abs(pony.getMotion().getClientVelocity().y);
BlockPos hangingPos = entity.getBlockPos().up();
boolean canhangHere = canHangAt(hangingPos); boolean canhangHere = canHangAt(hangingPos);
if (distanceClimbed > 1.5) { if (distanceClimbed > 1.5) {
@ -156,8 +159,9 @@ public class Acrobatics implements Tickable, NbtSerialisable {
} }
public void startHanging(BlockPos pos) { public void startHanging(BlockPos pos) {
boolean inverted = pony.getPhysics().isGravityNegative();
hangingPos.set(Optional.of(pos)); hangingPos.set(Optional.of(pos));
entity.teleport(pos.getX() + 0.5, pos.getY() - 1, pos.getZ() + 0.5); entity.teleport(pos.getX() + 0.5, pos.getY() - (inverted ? 0 : 1), pos.getZ() + 0.5);
entity.setVelocity(Vec3d.ZERO); entity.setVelocity(Vec3d.ZERO);
entity.setSneaking(false); entity.setSneaking(false);
entity.stopFallFlying(); entity.stopFallFlying();
@ -165,14 +169,17 @@ public class Acrobatics implements Tickable, NbtSerialisable {
} }
public boolean canHangAt(BlockPos pos) { public boolean canHangAt(BlockPos pos) {
if (!pony.asWorld().isAir(pos) || !pony.asWorld().isAir(pos.down())) { int gravity = pony.getPhysics().getGravitySignum() * (isHanging() && pony.getObservedSpecies() == Race.BAT ? -1 : 1);
BlockState state = pony.asWorld().getBlockState(pos);
if (!pony.asWorld().isAir(pos) || !pony.asWorld().isAir(pos.down(gravity))) {
return false; return false;
} }
pos = pos.up(); pos = pos.up(gravity);
BlockState state = pony.asWorld().getBlockState(pos); state = pony.asWorld().getBlockState(pos);
return state.isSolidSurface(pony.asWorld(), pos, entity, Direction.DOWN) && entity.getWorld().isAir(entity.getBlockPos().down()); return state.isSolidSurface(pony.asWorld(), pos, entity, gravity > 0 ? Direction.UP : Direction.DOWN);
} }
private boolean canKeepHanging() { private boolean canKeepHanging() {
@ -184,7 +191,7 @@ public class Acrobatics implements Tickable, NbtSerialisable {
return true; return true;
} }
return getHangingPosition().filter(hangingPos -> { return getHangingPosition().filter(hangingPos -> {
return (race != Race.BAT || hangingPos.equals(pony.getOrigin().down())) && canHangAt(hangingPos); return (race != Race.BAT || hangingPos.equals(pony.asEntity().getBlockPos().up(pony.getPhysics().isGravityNegative() ? 1 : 0))) && canHangAt(hangingPos);
}).isPresent(); }).isPresent();
} }

View file

@ -242,7 +242,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
public void tick() { public void tick() {
super.tick(); super.tick();
if (pony.isClientPlayer() && isFlying() && (pony.getJumpingHeuristic().hasChanged(Heuristic.ONCE) || pony.sneakingChanged())) { if (pony.isClientPlayer() && (pony.getJumpingHeuristic().hasChanged(Heuristic.ONCE) || pony.sneakingChanged())) {
Channel.FLIGHT_CONTROLS_INPUT.sendToServer(new MsgPlayerFlightControlsInput(pony)); Channel.FLIGHT_CONTROLS_INPUT.sendToServer(new MsgPlayerFlightControlsInput(pony));
} }
@ -369,7 +369,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
pony.getMagicalReserves().getCharge().set(0); pony.getMagicalReserves().getCharge().set(0);
} }
if (!creative) { if (!creative && !pony.isClient()) {
checkAvianTakeoffConditions(velocity); checkAvianTakeoffConditions(velocity);
} }
} }
@ -377,16 +377,17 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
tickGrounded(); tickGrounded();
} }
if (!entity.isOnGround()) {
float heavyness = 1 - EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, entity) * 0.015F;
velocity.x /= heavyness;
velocity.z /= heavyness;
}
float maximum = 1.5F; float maximum = 1.5F;
velocity.x = MathHelper.clamp(velocity.x, -maximum, maximum); velocity.x = MathHelper.clamp(velocity.x, -maximum, maximum);
velocity.y = MathHelper.clamp(velocity.y, -maximum, maximum); velocity.y = MathHelper.clamp(velocity.y, -maximum, maximum);
velocity.z = MathHelper.clamp(velocity.z, -maximum, maximum); velocity.z = MathHelper.clamp(velocity.z, -maximum, maximum);
if (!entity.isOnGround()) {
float heavyness = 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, entity) * 0.009F;
velocity.x /= heavyness;
velocity.z /= heavyness;
}
entity.setVelocity(velocity.toImmutable()); entity.setVelocity(velocity.toImmutable());
if (isFlying() && !entity.isFallFlying() && !pony.getAcrobatics().isHanging() && pony.isClient()) { if (isFlying() && !entity.isFallFlying() && !pony.getAcrobatics().isHanging() && pony.isClient()) {
@ -463,7 +464,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
entity.damage(entity.getDamageSources().generic(), 0.5F); entity.damage(entity.getDamageSources().generic(), 0.5F);
} }
if (type.isAvian()) { if (type.isAvian() && !entity.getWorld().isClient) {
if (pony.getObservedSpecies() != Race.BAT && entity.getWorld().random.nextInt(9000) == 0) { if (pony.getObservedSpecies() != Race.BAT && entity.getWorld().random.nextInt(9000) == 0) {
entity.dropItem(pony.getObservedSpecies() == Race.HIPPOGRIFF ? UItems.GRYPHON_FEATHER : UItems.PEGASUS_FEATHER); entity.dropItem(pony.getObservedSpecies() == Race.HIPPOGRIFF ? UItems.GRYPHON_FEATHER : UItems.PEGASUS_FEATHER);
playSound(USounds.ENTITY_PLAYER_PEGASUS_MOLT, 0.3F, 1); playSound(USounds.ENTITY_PLAYER_PEGASUS_MOLT, 0.3F, 1);
@ -530,7 +531,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
} }
private void playSound(SoundEvent sound, float volume, float pitch) { private void playSound(SoundEvent sound, float volume, float pitch) {
entity.getWorld().playSoundFromEntity(entity, entity, sound, SoundCategory.PLAYERS, volume, pitch); entity.getWorld().playSoundFromEntity(entity.getWorld().isClient ? entity : null, entity, sound, SoundCategory.PLAYERS, volume, pitch);
} }
private void tickNaturalFlight(MutableVector velocity) { private void tickNaturalFlight(MutableVector velocity) {
@ -689,7 +690,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
if (entity.getWorld().hasRain(entity.getBlockPos())) { if (entity.getWorld().hasRain(entity.getBlockPos())) {
applyTurbulance(velocity); applyTurbulance(velocity);
} else { } else {
float targetUpdraft = (float)WeatherConditions.getUpdraft(new BlockPos.Mutable().set(entity.getBlockPos()), entity.getWorld()) / 3F; float targetUpdraft = WeatherConditions.THERMAL_FIELD.getValue(entity.getWorld(), new BlockPos.Mutable().set(entity.getBlockPos())) / 3F;
targetUpdraft *= 1 + motion; targetUpdraft *= 1 + motion;
if (isGravityNegative()) { if (isGravityNegative()) {
targetUpdraft *= -1; targetUpdraft *= -1;
@ -829,8 +830,8 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
.reduce(0, (u, pos) -> { .reduce(0, (u, pos) -> {
if (pony.canModifyAt(pos, ModificationType.PHYSICAL)) { if (pony.canModifyAt(pos, ModificationType.PHYSICAL)) {
if (isEarthPonySmash) { if (isEarthPonySmash) {
BlockDestructionManager.of(entity.getWorld()).damageBlock(pos, (int)entity.getWorld().getRandom().nextTriangular(5, 3)); float destruction = BlockDestructionManager.of(entity.getWorld()).damageBlock(pos, (int)entity.getWorld().getRandom().nextTriangular(5, 3));
if (BlockDestructionManager.of(entity.getWorld()).getBlockDestruction(pos) >= 9) { if (destruction >= BlockDestructionManager.MAX_DAMAGE - 1 && pony.canModifyAt(pos, ModificationType.PHYSICAL)) {
entity.getWorld().breakBlock(pos, true); entity.getWorld().breakBlock(pos, true);
} }
} else { } else {
@ -862,7 +863,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
if (isFlying()) { if (isFlying()) {
playSound(USounds.ENTITY_PLAYER_PEGASUS_DASH, 1, 1); playSound(USounds.ENTITY_PLAYER_PEGASUS_DASH, 1, 1);
} else { } else {
playSound(USounds.ENTITY_PLAYER_EARTHPONY_DASH, 2, 0.3F); playSound(USounds.ENTITY_PLAYER_EARTHPONY_DASH, 2, 1.3F);
} }
} }

View file

@ -224,6 +224,11 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
return compositeRace; return compositeRace;
} }
@Override
public boolean collidesWithClouds() {
return getCompositeRace().canInteractWithClouds() || entity.isCreative();
}
@Override @Override
public void setSpecies(Race race) { public void setSpecies(Race race) {
race = race.validate(entity); race = race.validate(entity);
@ -597,7 +602,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
float lightScale = light / 15F; float lightScale = light / 15F;
float approachFactor = ((velocityScale + lightScale) / 2F); float approachFactor = ((velocityScale + lightScale) / 2F);
if (approachFactor < (entity.isSneaking() ? 0.8F : 0.6F)) { if (approachFactor < (entity.isSneaking() ? 0.8F : 0.3F)) {
return false; return false;
} }
} }
@ -703,7 +708,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
if (EffectUtils.hasExtraDefenses(entity)) { if (EffectUtils.hasExtraDefenses(entity)) {
double radius = distance / 10; double radius = distance / 10;
if (radius > 0) { if (radius > 0) {
EarthPonyStompAbility.spawnEffectAround(entity, entity.getSteppingPos(), radius, radius); EarthPonyStompAbility.spawnEffectAround(this, entity, entity.getSteppingPos(), radius, radius);
} }
} }
@ -807,7 +812,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
public ActionResult canSleepNow() { public ActionResult canSleepNow() {
if (asWorld().getGameRules().getBoolean(UGameRules.DO_NOCTURNAL_BAT_PONIES) && getSpecies().isNocturnal()) { if (asWorld().getGameRules().getBoolean(UGameRules.DO_NOCTURNAL_BAT_PONIES) && getSpecies().isNocturnal()) {
return asWorld().isDay() ? ActionResult.SUCCESS : ActionResult.FAIL; return asWorld().isDay() || asWorld().getAmbientDarkness() >= 4 ? ActionResult.SUCCESS : ActionResult.FAIL;
} }
return ActionResult.PASS; return ActionResult.PASS;

View file

@ -101,7 +101,7 @@ public class AmuletItem extends WearableItem implements ChargeableItem {
} }
public static TrinketsDelegate.EquippedStack get(LivingEntity entity) { public static TrinketsDelegate.EquippedStack get(LivingEntity entity) {
return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE) return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE, stack -> stack.getItem() instanceof AmuletItem)
.findFirst() .findFirst()
.orElse(TrinketsDelegate.EquippedStack.EMPTY); .orElse(TrinketsDelegate.EquippedStack.EMPTY);
} }

View file

@ -18,12 +18,13 @@ public class HeavyProjectileItem extends ProjectileItem {
@Override @Override
public PhysicsBodyProjectileEntity createProjectile(ItemStack stack, World world, @Nullable PlayerEntity player) { public PhysicsBodyProjectileEntity createProjectile(ItemStack stack, World world, @Nullable PlayerEntity player) {
PhysicsBodyProjectileEntity projectile = player == null ? new PhysicsBodyProjectileEntity(world) : new PhysicsBodyProjectileEntity(world, player); PhysicsBodyProjectileEntity projectile = player == null
? new PhysicsBodyProjectileEntity(world, stack.copyWithCount(1))
: new PhysicsBodyProjectileEntity(world, player, stack.copyWithCount(1));
if (player != null) { if (player != null) {
projectile.setVelocity(player, player.getPitch(), player.getYaw(), 0, 1.5F, 1); projectile.setVelocity(player, player.getPitch(), player.getYaw(), 0, 1.5F, 1);
} }
projectile.pickupType = PersistentProjectileEntity.PickupPermission.ALLOWED; projectile.pickupType = PersistentProjectileEntity.PickupPermission.ALLOWED;
projectile.setStack(stack.copy().split(1));
return projectile; return projectile;
} }

View file

@ -7,14 +7,17 @@ import com.google.common.collect.Multimap;
import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes;
import com.minelittlepony.unicopia.item.enchantment.CustomEnchantableItem;
import net.minecraft.block.*; import net.minecraft.block.*;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.attribute.*; import net.minecraft.entity.attribute.*;
import net.minecraft.item.*; import net.minecraft.item.*;
public class PolearmItem extends SwordItem { public class PolearmItem extends SwordItem implements CustomEnchantableItem {
static final UUID ATTACK_RANGE_MODIFIER_ID = UUID.fromString("A7B3659C-AA74-469C-963A-09A391DCAA0F"); static final UUID ATTACK_RANGE_MODIFIER_ID = UUID.fromString("A7B3659C-AA74-469C-963A-09A391DCAA0F");
private final Multimap<EntityAttribute, EntityAttributeModifier> attributeModifiers; private final Multimap<EntityAttribute, EntityAttributeModifier> attributeModifiers;
@ -65,4 +68,9 @@ public class PolearmItem extends SwordItem {
return true; return true;
} }
@Override
public boolean isAcceptableEnchant(ItemStack stack, Enchantment enchantment) {
return enchantment != Enchantments.SWEEPING;
}
} }

View file

@ -20,6 +20,8 @@ import net.minecraft.util.TypedActionResult;
import net.minecraft.util.math.BlockPointer; import net.minecraft.util.math.BlockPointer;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Position;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
public class SpellbookItem extends BookItem implements Dispensable { public class SpellbookItem extends BookItem implements Dispensable {
@ -29,17 +31,20 @@ public class SpellbookItem extends BookItem implements Dispensable {
} }
@Override @Override
public TypedActionResult<ItemStack> dispenseStack(BlockPointer source, ItemStack stack) { public TypedActionResult<ItemStack> dispenseStack(BlockPointer pointer, ItemStack stack) {
Direction facing = source.state().get(DispenserBlock.FACING); Direction facing = pointer.state().get(DispenserBlock.FACING);
BlockPos pos = source.pos().offset(facing); Position pos = DispenserBlock.getOutputLocation(pointer);
float yaw = facing.getOpposite().asRotation(); float yaw = facing.getOpposite().asRotation();
placeBook(stack, source.world(), pos.getX(), pos.getY(), pos.getZ(), yaw, null); if (placeBook(stack, pointer.world(), pos, yaw, null)) {
stack.decrement(1); stack.decrement(1);
return new TypedActionResult<>(ActionResult.SUCCESS, stack); return new TypedActionResult<>(ActionResult.SUCCESS, stack);
} }
return new TypedActionResult<>(ActionResult.FAIL, stack);
}
@Override @Override
public ActionResult useOnBlock(ItemUsageContext context) { public ActionResult useOnBlock(ItemUsageContext context) {
@ -49,24 +54,28 @@ public class SpellbookItem extends BookItem implements Dispensable {
if (!context.getWorld().isClient) { if (!context.getWorld().isClient) {
BlockPos pos = context.getBlockPos().offset(context.getSide()); BlockPos pos = context.getBlockPos().offset(context.getSide());
placeBook(context.getStack(), context.getWorld(), pos.getX(), pos.getY(), pos.getZ(), context.getPlayerYaw() + 180, player); if (placeBook(context.getStack(), context.getWorld(), Vec3d.ofBottomCenter(pos), context.getPlayerYaw() + 180, player)) {
if (!player.getAbilities().creativeMode) { if (!player.getAbilities().creativeMode) {
player.getStackInHand(context.getHand()).decrement(1); player.getStackInHand(context.getHand()).decrement(1);
} }
return ActionResult.SUCCESS; return ActionResult.SUCCESS;
} }
}
return ActionResult.PASS; return ActionResult.PASS;
} }
private static void placeBook(ItemStack stack, World world, int x, int y, int z, float yaw, @Nullable Entity placer) { private static boolean placeBook(ItemStack stack, World world, Position pos, float yaw, @Nullable Entity placer) {
SpellbookEntity book = UEntities.SPELLBOOK.create(world); SpellbookEntity book = UEntities.SPELLBOOK.create(world);
book.refreshPositionAndAngles(x + 0.5, y, z + 0.5, 0, 0); book.refreshPositionAndAngles(pos.getX(), pos.getY(), pos.getZ(), 0, 0);
book.setHeadYaw(yaw); book.setHeadYaw(yaw);
book.setYaw(yaw); book.setYaw(yaw);
if (!book.canSpawn(world)) {
return false;
}
@Nullable @Nullable
NbtCompound tag = stack.getSubNbt("spellbookState"); NbtCompound tag = stack.getSubNbt("spellbookState");
if (tag != null) { if (tag != null) {
@ -80,6 +89,8 @@ public class SpellbookItem extends BookItem implements Dispensable {
altar.generateDecorations(world); altar.generateDecorations(world);
UCriteria.LIGHT_ALTAR.trigger(placer); UCriteria.LIGHT_ALTAR.trigger(placer);
}); });
return true;
} }
} }

View file

@ -146,12 +146,12 @@ public interface UItems {
Item COPPER_HORSE_SHOE = register("copper_horse_shoe", new HorseShoeItem(new Item.Settings().maxDamage(250), 6, 0.5F, 0.8F), ItemGroups.COMBAT); Item COPPER_HORSE_SHOE = register("copper_horse_shoe", new HorseShoeItem(new Item.Settings().maxDamage(250), 6, 0.5F, 0.8F), ItemGroups.COMBAT);
Item NETHERITE_HORSE_SHOE = register("netherite_horse_shoe", new HorseShoeItem(new Item.Settings().maxDamage(800), 3, 0.7F, 1.2F), ItemGroups.COMBAT); Item NETHERITE_HORSE_SHOE = register("netherite_horse_shoe", new HorseShoeItem(new Item.Settings().maxDamage(800), 3, 0.7F, 1.2F), ItemGroups.COMBAT);
Item WOODEN_POLEARM = register("wooden_polearm", new PolearmItem(ToolMaterials.WOOD, 2, -3.6F, 2, new Item.Settings()), ItemGroups.COMBAT); Item WOODEN_POLEARM = register("wooden_polearm", new PolearmItem(ToolMaterials.WOOD, 2, -3.2F, 2, new Item.Settings()), ItemGroups.COMBAT);
Item STONE_POLEARM = register("stone_polearm", new PolearmItem(ToolMaterials.STONE, 2, -3.6F, 2, new Item.Settings()), ItemGroups.COMBAT); Item STONE_POLEARM = register("stone_polearm", new PolearmItem(ToolMaterials.STONE, 2, -3.2F, 2, new Item.Settings()), ItemGroups.COMBAT);
Item IRON_POLEARM = register("iron_polearm", new PolearmItem(ToolMaterials.IRON, 2, -3.6F, 3, new Item.Settings()), ItemGroups.COMBAT); Item IRON_POLEARM = register("iron_polearm", new PolearmItem(ToolMaterials.IRON, 2, -3.1F, 3, new Item.Settings()), ItemGroups.COMBAT);
Item GOLDEN_POLEARM = register("golden_polearm", new PolearmItem(ToolMaterials.GOLD, 2, -3.6F, 4, new Item.Settings()), ItemGroups.COMBAT); Item GOLDEN_POLEARM = register("golden_polearm", new PolearmItem(ToolMaterials.GOLD, 3, -3F, 4, new Item.Settings()), ItemGroups.COMBAT);
Item DIAMOND_POLEARM = register("diamond_polearm", new PolearmItem(ToolMaterials.DIAMOND, 2, -3.6F, 5, new Item.Settings()), ItemGroups.COMBAT); Item DIAMOND_POLEARM = register("diamond_polearm", new PolearmItem(ToolMaterials.DIAMOND, 3, -3F, 5, new Item.Settings()), ItemGroups.COMBAT);
Item NETHERITE_POLEARM = register("netherite_polearm", new PolearmItem(ToolMaterials.NETHERITE, 2, -3.6F, 5, new Item.Settings().fireproof()), ItemGroups.COMBAT); Item NETHERITE_POLEARM = register("netherite_polearm", new PolearmItem(ToolMaterials.NETHERITE, 3, -3F, 6, new Item.Settings().fireproof()), ItemGroups.COMBAT);
Item LOOT_BUG_SPAWN_EGG = register("loot_bug_spawn_egg", new SpawnEggItem(UEntities.LOOT_BUG, 0x3C9D14, 0xE66F16, new Item.Settings()), ItemGroups.SPAWN_EGGS); Item LOOT_BUG_SPAWN_EGG = register("loot_bug_spawn_egg", new SpawnEggItem(UEntities.LOOT_BUG, 0x3C9D14, 0xE66F16, new Item.Settings()), ItemGroups.SPAWN_EGGS);
Item BUTTERFLY_SPAWN_EGG = register("butterfly_spawn_egg", new SpawnEggItem(UEntities.BUTTERFLY, 0x222200, 0xAAEEFF, new Item.Settings()), ItemGroups.SPAWN_EGGS); Item BUTTERFLY_SPAWN_EGG = register("butterfly_spawn_egg", new SpawnEggItem(UEntities.BUTTERFLY, 0x222200, 0xAAEEFF, new Item.Settings()), ItemGroups.SPAWN_EGGS);

View file

@ -0,0 +1,8 @@
package com.minelittlepony.unicopia.item.enchantment;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.item.ItemStack;
public interface CustomEnchantableItem {
boolean isAcceptableEnchant(ItemStack stack, Enchantment enchantment);
}

View file

@ -0,0 +1,21 @@
package com.minelittlepony.unicopia.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.item.enchantment.CustomEnchantableItem;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.item.ItemStack;
@Mixin(Enchantment.class)
abstract class MixinEnchantment {
@Inject(method = "isAcceptableItem", at = @At("HEAD"), cancellable = true)
private void onIsAcceptableItem(ItemStack stack, CallbackInfoReturnable<Boolean> info) {
if (stack.getItem() instanceof CustomEnchantableItem item && !item.isAcceptableEnchant(stack, (Enchantment)(Object)this)) {
info.setReturnValue(false);
}
}
}

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.mixin; package com.minelittlepony.unicopia.mixin;
import java.util.List;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
@ -9,7 +11,9 @@ import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.EnchantmentLevelEntry;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
@Mixin(EnchantmentHelper.class) @Mixin(EnchantmentHelper.class)
abstract class MixinEnchantmentHelper { abstract class MixinEnchantmentHelper {
@ -23,4 +27,9 @@ abstract class MixinEnchantmentHelper {
} }
}); });
} }
@Inject(method = "getPossibleEntries", at = @At("RETURN"))
private static void onGetPossibleEntries(int power, ItemStack stack, boolean treasureAllowed, CallbackInfoReturnable<List<EnchantmentLevelEntry>> info) {
info.getReturnValue().removeIf(entry -> !entry.enchantment.isAcceptableItem(stack));
}
} }

View file

@ -0,0 +1,21 @@
package com.minelittlepony.unicopia.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.block.cloud.CloudLike;
import net.minecraft.block.BlockState;
import net.minecraft.world.Heightmap;
@Mixin(Heightmap.class)
abstract class MixinHeightmap {
@Inject(method = "method_16682", at = @At("HEAD"), cancellable = true)
private static void excludeCloudsFromWorldSurfaceHeightMap(BlockState state, CallbackInfoReturnable<Boolean> info) {
if (state.getBlock() instanceof CloudLike) {
info.setReturnValue(false);
}
}
}

View file

@ -1,21 +1,32 @@
package com.minelittlepony.unicopia.mixin; package com.minelittlepony.unicopia.mixin;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.entity.duck.RotatedView; import com.minelittlepony.unicopia.entity.duck.RotatedView;
import com.minelittlepony.unicopia.server.world.BlockDestructionManager; import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
import com.minelittlepony.unicopia.server.world.WeatherAccess;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.WorldAccess; import net.minecraft.world.WorldAccess;
@Mixin(World.class) @Mixin(World.class)
abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source, RotatedView { abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source, RotatedView, WeatherAccess {
private final Supplier<BlockDestructionManager> destructions = BlockDestructionManager.create((World)(Object)this); private final Supplier<BlockDestructionManager> destructions = BlockDestructionManager.create((World)(Object)this);
@Nullable
private Float rainGradientOverride;
@Nullable
private Float thunderGradientOverride;
private boolean mirrorEntityStatuses; private boolean mirrorEntityStatuses;
@Override @Override
@ -28,11 +39,36 @@ abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source
return destructions.get(); return destructions.get();
} }
@Override
public void setWeatherOverride(Float rain, Float thunder) {
rainGradientOverride = rain;
thunderGradientOverride = thunder;
}
@Inject(method = "sendEntityStatus(Lnet/minecraft/entity/Entity;B)V", at = @At("HEAD")) @Inject(method = "sendEntityStatus(Lnet/minecraft/entity/Entity;B)V", at = @At("HEAD"))
private void onSendEntityStatus(Entity entity, byte status, CallbackInfo info) { private void onSendEntityStatus(Entity entity, byte status, CallbackInfo info) {
if (mirrorEntityStatuses) { if (mirrorEntityStatuses) {
entity.handleStatus(status); entity.handleStatus(status);
} }
} }
@Inject(method = "getThunderGradient", at = @At("HEAD"), cancellable = true)
private void onGetThunderGradient(float delta, CallbackInfoReturnable<Float> info) {
if (thunderGradientOverride != null) {
info.setReturnValue(thunderGradientOverride * ((World)(Object)this).getRainGradient(delta));
}
}
@Inject(method = "getRainGradient", at = @At("HEAD"), cancellable = true)
private void onGetRainGradient(float delta, CallbackInfoReturnable<Float> info) {
if (rainGradientOverride != null) {
info.setReturnValue(rainGradientOverride);
}
}
@Inject(method = "hasRain", at = @At("RETURN"), cancellable = true)
private void onHasRain(BlockPos pos, CallbackInfoReturnable<Boolean> info) {
info.setReturnValue((info.getReturnValue() && isBelowCloudLayer(pos)) || isInRangeOfStorm(pos));
}
} }

View file

@ -6,7 +6,6 @@ import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.client.BatEyesApplicator; import com.minelittlepony.unicopia.client.BatEyesApplicator;
import com.minelittlepony.unicopia.client.UnicopiaClient; import com.minelittlepony.unicopia.client.UnicopiaClient;
import com.minelittlepony.unicopia.client.render.shader.ViewportShader; import com.minelittlepony.unicopia.client.render.shader.ViewportShader;
@ -17,7 +16,6 @@ import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.RotationAxis; import net.minecraft.util.math.RotationAxis;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.resource.SynchronousResourceReloader; import net.minecraft.resource.SynchronousResourceReloader;
@Mixin(value = GameRenderer.class, priority = Integer.MAX_VALUE) @Mixin(value = GameRenderer.class, priority = Integer.MAX_VALUE)
@ -46,21 +44,11 @@ abstract class MixinGameRenderer implements AutoCloseable, SynchronousResourceRe
BatEyesApplicator.INSTANCE.disable(); BatEyesApplicator.INSTANCE.disable();
} }
@Inject(method = "getNightVisionStrength(Lnet/minecraft/entity/LivingEntity;F)F",
at = @At("HEAD"),
cancellable = true)
private static void onGetNightVisionStrengthHead(LivingEntity entity, float tickDelta, CallbackInfoReturnable<Float> info) {
if (!entity.hasStatusEffect(StatusEffects.NIGHT_VISION)) {
info.setReturnValue(UnicopiaClient.getWorldBrightness(0));
}
}
@Inject(method = "getNightVisionStrength(Lnet/minecraft/entity/LivingEntity;F)F", @Inject(method = "getNightVisionStrength(Lnet/minecraft/entity/LivingEntity;F)F",
at = @At("RETURN"), at = @At("RETURN"),
cancellable = true) cancellable = true)
private static void onGetNightVisionStrengthReturn(LivingEntity entity, float tickDelta, CallbackInfoReturnable<Float> info) { private static void onGetNightVisionStrengthReturn(LivingEntity entity, float tickDelta, CallbackInfoReturnable<Float> info) {
if (entity.hasStatusEffect(StatusEffects.NIGHT_VISION) && EquinePredicates.PLAYER_BAT.test(entity)) { info.setReturnValue(BatEyesApplicator.INSTANCE.getWorldBrightness(info.getReturnValueF(), entity, tickDelta));
info.setReturnValue(UnicopiaClient.getWorldBrightness(info.getReturnValueF()));
}
} }
@Inject(method = "render", @Inject(method = "render",

View file

@ -15,6 +15,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.minelittlepony.unicopia.client.ClientBlockDestructionManager; import com.minelittlepony.unicopia.client.ClientBlockDestructionManager;
import com.minelittlepony.unicopia.client.UnicopiaClient; import com.minelittlepony.unicopia.client.UnicopiaClient;
import com.minelittlepony.unicopia.server.world.WeatherAccess;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import net.minecraft.client.render.BlockBreakingInfo; import net.minecraft.client.render.BlockBreakingInfo;
import net.minecraft.client.render.Camera; import net.minecraft.client.render.Camera;
@ -22,7 +24,10 @@ import net.minecraft.client.render.WorldRenderer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld; import net.minecraft.client.world.ClientWorld;
import net.minecraft.resource.SynchronousResourceReloader; import net.minecraft.resource.SynchronousResourceReloader;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RotationAxis; import net.minecraft.util.math.RotationAxis;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biome.Precipitation;
@Mixin(value = WorldRenderer.class, priority = 1001) @Mixin(value = WorldRenderer.class, priority = 1001)
abstract class MixinWorldRenderer implements SynchronousResourceReloader, AutoCloseable, ClientBlockDestructionManager.Source { abstract class MixinWorldRenderer implements SynchronousResourceReloader, AutoCloseable, ClientBlockDestructionManager.Source {
@ -80,4 +85,13 @@ abstract class MixinWorldRenderer implements SynchronousResourceReloader, AutoCl
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(UnicopiaClient.getInstance().getSkyAngleDelta(tickDelta))); matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(UnicopiaClient.getInstance().getSkyAngleDelta(tickDelta)));
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(UnicopiaClient.getInstance().tangentalSkyAngle.getValue())); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(UnicopiaClient.getInstance().tangentalSkyAngle.getValue()));
} }
@Redirect(method = "renderWeather", at = @At(value = "INVOKE", target = "net/minecraft/world/biome/Biome.getPrecipitation(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/world/biome/Biome$Precipitation;"))
private Biome.Precipitation modifyPrecipitation(Biome biome, BlockPos pos) {
Biome.Precipitation precipitation = biome.getPrecipitation(pos);
if (!((WeatherAccess)world).isBelowClientCloudLayer(pos)) {
return Precipitation.NONE;
}
return precipitation;
}
} }

View file

@ -0,0 +1,26 @@
package com.minelittlepony.unicopia.mixin.server;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.minelittlepony.unicopia.EquineContext;
import com.minelittlepony.unicopia.InteractionManager;
import net.minecraft.entity.ai.pathing.PathNodeMaker;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.world.chunk.ChunkCache;
@Mixin(PathNodeMaker.class)
abstract class MixinPathNodeMaker {
@Inject(method = "init", at = @At("HEAD"))
private void onInit(ChunkCache cachedWorld, MobEntity entity, CallbackInfo info) {
InteractionManager.getInstance().setEquineContext(EquineContext.of(entity));
}
@Inject(method = "clear", at = @At("HEAD"))
private void onClear(CallbackInfo info) {
InteractionManager.getInstance().clearEquineContext();
}
}

Some files were not shown because too many files have changed in this diff Show more