Fix server exception when earth ponies try to kick things. Fixes #63

This commit is contained in:
Sollace 2022-09-23 16:05:04 +02:00
parent a53cb275e9
commit 94d81ff5f5
5 changed files with 55 additions and 30 deletions

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.ability;
import java.util.Optional;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race;
@ -33,10 +35,22 @@ public interface Ability<T extends Hit> {
* <p>
* @return True if the event has been handled.
*/
default boolean onQuickAction(Pony player, ActivationType type, Optional<T> data) {
return onQuickAction(player, type);
}
@Deprecated
default boolean onQuickAction(Pony player, ActivationType type) {
return false;
}
/**
* Called on the client to get any data required for the quick action.
*/
default Optional<T> prepareQuickAction(Pony player, ActivationType type) {
return Optional.empty();
}
/**
* Called to check preconditions for activating the ability.
*
@ -54,14 +68,19 @@ public interface Ability<T extends Hit> {
*/
boolean canUse(Race playerSpecies);
@Deprecated
@Nullable
T tryActivate(Pony player);
/**
* Called on the client to activate the ability.
*
* @param player The player activating the ability
* @return Data to be sent, or null if activation failed
*/
@Nullable
T tryActivate(Pony player);
default Optional<T> prepare(Pony player) {
return Optional.ofNullable(tryActivate(player));
}
Hit.Serializer<T> getSerializer();

View file

@ -44,9 +44,10 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
}
}
private boolean triggerQuickAction(Ability<?> ability, ActivationType pressType) {
if (ability.onQuickAction(player, pressType)) {
Channel.CLIENT_PLAYER_ABILITY.send(new MsgPlayerAbility<>(ability, null, pressType));
private <T extends Hit> boolean triggerQuickAction(Ability<T> ability, ActivationType pressType) {
Optional<T> data = ability.prepareQuickAction(player, pressType);
if (ability.onQuickAction(player, pressType, data)) {
Channel.CLIENT_PLAYER_ABILITY.send(new MsgPlayerAbility<>(ability, data, pressType));
return true;
}
return false;
@ -206,9 +207,9 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
setCooldown(ability.getCooldownTime(player));
if (player.isClientPlayer()) {
T data = ability.tryActivate(player);
Optional<T> data = ability.prepare(player);
if (data != null) {
if (data.isPresent()) {
Channel.CLIENT_PLAYER_ABILITY.send(new MsgPlayerAbility<>(ability, data, ActivationType.NONE));
} else {
player.getEntity().playSound(USounds.GUI_ABILITY_FAIL, 1, 1);

View file

@ -1,6 +1,7 @@
package com.minelittlepony.unicopia.ability;
import java.util.List;
import java.util.Optional;
import org.jetbrains.annotations.Nullable;
@ -65,29 +66,34 @@ public class EarthPonyKickAbility implements Ability<Pos> {
}
@Override
public boolean onQuickAction(Pony player, ActivationType type) {
public Optional<Pos> prepareQuickAction(Pony player, ActivationType type) {
return Optional.of(getDefaultKickLocation(player));
}
@Override
public boolean onQuickAction(Pony player, ActivationType type, Optional<Pos> data) {
if (type == ActivationType.TAP) {
if (!player.isClient()) {
Vec3d origin = player.getOriginVector();
data.ifPresent(kickLocation -> {
Vec3d origin = player.getOriginVector();
World w = player.getReferenceWorld();
Pos kickLocation = getDefaultKickLocation(player);
World w = player.getReferenceWorld();
for (var e : VecHelper.findInRange(player.getEntity(), w, kickLocation.vec(), 2, EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR)) {
if (e instanceof LivingEntity entity) {
float calculatedStrength = 0.5F * (1 + player.getLevel().getScaled(9));
entity.damage(MagicalDamageSource.KICK, player.getReferenceWorld().random.nextBetween(2, 10) + calculatedStrength);
entity.takeKnockback(calculatedStrength, origin.x - entity.getX(), origin.z - entity.getZ());
player.subtractEnergyCost(3);
player.setAnimation(Animation.KICK);
return true;
for (var e : VecHelper.findInRange(player.getEntity(), w, kickLocation.vec(), 2, EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR)) {
if (e instanceof LivingEntity entity) {
float calculatedStrength = 0.5F * (1 + player.getLevel().getScaled(9));
entity.damage(MagicalDamageSource.KICK, player.getReferenceWorld().random.nextBetween(2, 10) + calculatedStrength);
entity.takeKnockback(calculatedStrength, origin.x - entity.getX(), origin.z - entity.getZ());
player.subtractEnergyCost(3);
player.setAnimation(Animation.KICK);
return;
}
}
}
BlockPos pos = kickLocation.pos();
EarthPonyStompAbility.stompBlock(w, pos, 10 * (1 + player.getLevel().getScaled(5)) * w.getBlockState(pos).calcBlockBreakingDelta(player.getMaster(), w, pos));
player.setAnimation(Animation.KICK);
BlockPos pos = kickLocation.pos();
EarthPonyStompAbility.stompBlock(w, pos, 10 * (1 + player.getLevel().getScaled(5)) * w.getBlockState(pos).calcBlockBreakingDelta(player.getMaster(), w, pos));
player.setAnimation(Animation.KICK);
});
}
return true;
@ -112,6 +118,7 @@ public class EarthPonyKickAbility implements Ability<Pos> {
private Pos getDefaultKickLocation(Pony player) {
Vec3d kickVector = player.getMaster().getRotationVector().multiply(1, 0, 1);
player.getMaster();
if (!MineLPDelegate.getInstance().getPlayerPonyRace(player.getMaster()).isDefault()) {
kickVector = kickVector.rotateY((float)Math.PI);
}

View file

@ -23,7 +23,7 @@ import net.minecraft.sound.SoundCategory;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.*;
import net.minecraft.util.math.random.Random;
/**

View file

@ -2,8 +2,6 @@ package com.minelittlepony.unicopia.network;
import java.util.Optional;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.ability.Ability;
import com.minelittlepony.unicopia.ability.ActivationType;
@ -29,9 +27,9 @@ public class MsgPlayerAbility<T extends Hit> implements Packet<ServerPlayerEntit
type = ActivationType.of(buffer.readInt());
}
public MsgPlayerAbility(Ability<T> power, @Nullable T data, ActivationType type) {
public MsgPlayerAbility(Ability<T> power, Optional<T> data, ActivationType type) {
this.power = power;
this.data = Optional.ofNullable(data);
this.data = data;
this.type = type;
}
@ -50,7 +48,7 @@ public class MsgPlayerAbility<T extends Hit> implements Packet<ServerPlayerEntit
}
if (type != ActivationType.NONE) {
power.onQuickAction(player, type);
power.onQuickAction(player, type, data);
} else {
data.filter(data -> power.canApply(player, data)).ifPresentOrElse(
data -> power.apply(player, data),