Send the initial look direction from the client

This commit is contained in:
Sollace 2023-09-05 20:02:26 +01:00
parent 74bdaa7028
commit 54e0922c93
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
10 changed files with 187 additions and 58 deletions

View file

@ -3,14 +3,14 @@ package com.minelittlepony.unicopia.ability;
import java.util.Optional; import java.util.Optional;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.data.Hit.Serializer; import com.minelittlepony.unicopia.ability.data.Hit.Serializer;
import com.minelittlepony.unicopia.ability.data.Rot;
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
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.minelittlepony.unicopia.server.world.UGameRules; import com.minelittlepony.unicopia.server.world.UGameRules;
public class TimeChangeAbility implements Ability<Hit> { public class TimeChangeAbility implements Ability<Rot> {
@Override @Override
public boolean canUse(Race race) { public boolean canUse(Race race) {
@ -38,12 +38,12 @@ public class TimeChangeAbility implements Ability<Hit> {
} }
@Override @Override
public Serializer<Hit> getSerializer() { public Serializer<Rot> getSerializer() {
return Hit.SERIALIZER; return Rot.SERIALIZER;
} }
@Override @Override
public Optional<Hit> prepare(Pony player) { public Optional<Rot> prepare(Pony player) {
if (!player.asWorld().getGameRules().getBoolean(UGameRules.DO_TIME_MAGIC)) { if (!player.asWorld().getGameRules().getBoolean(UGameRules.DO_TIME_MAGIC)) {
return Optional.empty(); return Optional.empty();
@ -53,11 +53,11 @@ public class TimeChangeAbility implements Ability<Hit> {
return Optional.empty(); return Optional.empty();
} }
return Hit.INSTANCE; return Optional.of(Rot.of(player));
} }
@Override @Override
public boolean apply(Pony player, Hit data) { public boolean apply(Pony player, Rot data) {
if (!player.asWorld().getGameRules().getBoolean(UGameRules.DO_TIME_MAGIC)) { if (!player.asWorld().getGameRules().getBoolean(UGameRules.DO_TIME_MAGIC)) {
return false; return false;
} }
@ -65,7 +65,7 @@ public class TimeChangeAbility implements Ability<Hit> {
if (player.getSpellSlot().contains(SpellType.TIME_CONTROL)) { if (player.getSpellSlot().contains(SpellType.TIME_CONTROL)) {
player.getSpellSlot().removeWhere(SpellType.TIME_CONTROL, true); player.getSpellSlot().removeWhere(SpellType.TIME_CONTROL, true);
} else { } else {
SpellType.TIME_CONTROL.withTraits().apply(player, CastingMethod.INNATE); SpellType.TIME_CONTROL.withTraits().apply(player, CastingMethod.INNATE).update(player, data.applyTo(player));
} }
return true; return true;

View file

@ -0,0 +1,24 @@
package com.minelittlepony.unicopia.ability.data;
import com.minelittlepony.unicopia.EntityConvertable;
import net.minecraft.util.math.Vec3d;
public record Rot (float pitch, float yaw) implements Hit {
public static final Serializer<Rot> SERIALIZER = new Serializer<>(
buf -> new Rot(buf.readFloat(), buf.readFloat()),
(buf, t) -> {
buf.writeFloat(t.pitch());
buf.writeFloat(t.yaw());
});
public Rot applyTo(EntityConvertable<?> target) {
Vec3d pos = target.getOriginVector();
target.asEntity().updatePositionAndAngles(pos.x, pos.y, pos.z, yaw, pitch);
return this;
}
public static Rot of(EntityConvertable<?> source) {
return new Rot(source.asEntity().getPitch(1), source.asEntity().getHeadYaw());
}
}

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.ability.magic; package com.minelittlepony.unicopia.ability.magic;
import java.util.UUID;
import java.util.function.Predicate; import java.util.function.Predicate;
import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.ability.magic.spell.*;
@ -15,6 +16,7 @@ public interface SpellPredicate<T extends Spell> extends Predicate<Spell> {
SpellPredicate<MimicSpell> IS_MIMIC = s -> s instanceof MimicSpell; SpellPredicate<MimicSpell> IS_MIMIC = s -> s instanceof MimicSpell;
SpellPredicate<ShieldSpell> IS_SHIELD_LIKE = spell -> spell instanceof ShieldSpell; SpellPredicate<ShieldSpell> IS_SHIELD_LIKE = spell -> spell instanceof ShieldSpell;
SpellPredicate<TimedSpell> IS_TIMED = spell -> spell instanceof TimedSpell; SpellPredicate<TimedSpell> IS_TIMED = spell -> spell instanceof TimedSpell;
SpellPredicate<OrientedSpell> IS_ORIENTED = spell -> spell instanceof OrientedSpell;
SpellPredicate<?> IS_NOT_PLACED = IS_PLACED.negate(); SpellPredicate<?> IS_NOT_PLACED = IS_PLACED.negate();
SpellPredicate<?> IS_VISIBLE = spell -> spell != null && !spell.isHidden(); SpellPredicate<?> IS_VISIBLE = spell -> spell != null && !spell.isHidden();
@ -42,4 +44,8 @@ public interface SpellPredicate<T extends Spell> extends Predicate<Spell> {
default boolean isOn(Entity entity) { default boolean isOn(Entity entity) {
return Caster.of(entity).filter(this::isOn).isPresent(); return Caster.of(entity).filter(this::isOn).isPresent();
} }
default SpellPredicate<T> withId(UUID uuid) {
return and(spell -> spell.getUuid().equals(uuid));
}
} }

View file

@ -1,5 +1,11 @@
package com.minelittlepony.unicopia.ability.magic.spell; package com.minelittlepony.unicopia.ability.magic.spell;
public interface OrientedSpell { import com.minelittlepony.unicopia.ability.data.Rot;
public interface OrientedSpell extends Spell {
void setOrientation(float pitch, float yaw); void setOrientation(float pitch, float yaw);
default void setOrientation(Rot rotation) {
setOrientation(rotation.pitch(), rotation.yaw());
}
} }

View file

@ -10,6 +10,9 @@ import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.entity.EntityReference.EntityValues; import com.minelittlepony.unicopia.entity.EntityReference.EntityValues;
import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; import com.minelittlepony.unicopia.entity.mob.CastSpellEntity;
import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.entity.mob.UEntities;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgCasterLookRequest;
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect; import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleHandle; import com.minelittlepony.unicopia.particle.ParticleHandle;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
@ -19,6 +22,7 @@ import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.minecraft.nbt.*; import net.minecraft.nbt.*;
import net.minecraft.registry.*; import net.minecraft.registry.*;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -84,6 +88,9 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
if (dimension == null) { if (dimension == null) {
dimension = source.asWorld().getRegistryKey(); dimension = source.asWorld().getRegistryKey();
if (source instanceof Pony) {
Channel.SERVER_REQUEST_PLAYER_LOOK.sendToPlayer(new MsgCasterLookRequest(getUuid()), (ServerPlayerEntity)source.asEntity());
}
setDirty(); setDirty();
} }
@ -153,11 +160,10 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
public void setPosition(Caster<?> source, Vec3d position) { public void setPosition(Caster<?> source, Vec3d position) {
this.position = Optional.of(position); this.position = Optional.of(position);
getWorld(source).ifPresent(world -> { this.dimension = source.asWorld().getRegistryKey();
castEntity.ifPresent(world, entity -> { castEntity.ifPresent(source.asWorld(), entity -> {
entity.updatePositionAndAngles(position.x, position.y, position.z, entity.getYaw(), entity.getPitch()); entity.updatePositionAndAngles(position.x, position.y, position.z, entity.getYaw(), entity.getPitch());
}); });
});
getDelegates(spell -> spell instanceof PlaceableSpell o ? o : null) getDelegates(spell -> spell instanceof PlaceableSpell o ? o : null)
.forEach(spell -> spell.setPosition(source, position)); .forEach(spell -> spell.setPosition(source, position));
setDirty(); setDirty();

View file

@ -1,6 +1,7 @@
package com.minelittlepony.unicopia.ability.magic.spell; package com.minelittlepony.unicopia.ability.magic.spell;
import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.ability.data.Rot;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.effect.*; import com.minelittlepony.unicopia.ability.magic.spell.effect.*;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
@ -13,7 +14,7 @@ import net.minecraft.server.world.ServerWorld;
/** /**
* Internal. * Internal.
* <p> * <p>
* Used by the Rainboom ability. * Used by the time change ability
*/ */
public class TimeControlAbilitySpell extends AbstractSpell { public class TimeControlAbilitySpell extends AbstractSpell {
@ -38,11 +39,20 @@ public class TimeControlAbilitySpell extends AbstractSpell {
return false; return false;
} }
if (source.asWorld() instanceof ServerWorld sw) { update(source, Rot.of(source));
return source.subtractEnergyCost(2);
}
float yaw = -(source.asEntity().getHeadYaw() + 90); public void update(Caster<?> source, Rot rotation) {
float pitch = -(source.asEntity().getPitch(1) / 90F); if (!source.asWorld().getGameRules().getBoolean(UGameRules.DO_TIME_MAGIC)) {
return;
}
if (!(source.asWorld() instanceof ServerWorld sw)) {
return;
}
float yaw = -(rotation.yaw() + 90);
float pitch = -(rotation.pitch() / 90F);
long time = (long)(pitch * 6000); long time = (long)(pitch * 6000);
// sunrise(0) - midday(1) - sunset(2) - midnight(3) // sunrise(0) - midday(1) - sunset(2) - midnight(3)
@ -69,9 +79,6 @@ public class TimeControlAbilitySpell extends AbstractSpell {
UnicopiaWorldProperties.forWorld(sw).setTangentalSkyAngle(angleOffset + yaw); UnicopiaWorldProperties.forWorld(sw).setTangentalSkyAngle(angleOffset + yaw);
} }
return source.subtractEnergyCost(2);
}
@Override @Override
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {
super.toNBT(compound); super.toNBT(compound);

View file

@ -11,6 +11,7 @@ import net.minecraft.server.network.ServerPlayerEntity;
public interface Channel { public interface Channel {
C2SPacketType<MsgPlayerAbility<?>> CLIENT_PLAYER_ABILITY = SimpleNetworking.clientToServer(Unicopia.id("player_ability"), MsgPlayerAbility::read); C2SPacketType<MsgPlayerAbility<?>> CLIENT_PLAYER_ABILITY = SimpleNetworking.clientToServer(Unicopia.id("player_ability"), MsgPlayerAbility::read);
C2SPacketType<MsgCasterLookRequest.Reply> CLIENT_CASTER_LOOK = SimpleNetworking.clientToServer(Unicopia.id("caster_look"), MsgCasterLookRequest.Reply::new);
C2SPacketType<MsgRequestSpeciesChange> CLIENT_REQUEST_SPECIES_CHANGE = SimpleNetworking.clientToServer(Unicopia.id("request_capabilities"), MsgRequestSpeciesChange::new); C2SPacketType<MsgRequestSpeciesChange> CLIENT_REQUEST_SPECIES_CHANGE = SimpleNetworking.clientToServer(Unicopia.id("request_capabilities"), MsgRequestSpeciesChange::new);
C2SPacketType<MsgMarkTraitRead> MARK_TRAIT_READ = SimpleNetworking.clientToServer(Unicopia.id("mark_trait_read"), MsgMarkTraitRead::new); C2SPacketType<MsgMarkTraitRead> MARK_TRAIT_READ = SimpleNetworking.clientToServer(Unicopia.id("mark_trait_read"), MsgMarkTraitRead::new);
C2SPacketType<MsgRemoveSpell> REMOVE_SPELL = SimpleNetworking.clientToServer(Unicopia.id("remove_spell"), MsgRemoveSpell::new); C2SPacketType<MsgRemoveSpell> REMOVE_SPELL = SimpleNetworking.clientToServer(Unicopia.id("remove_spell"), MsgRemoveSpell::new);
@ -19,6 +20,7 @@ public interface Channel {
S2CPacketType<MsgSpawnProjectile> SERVER_SPAWN_PROJECTILE = SimpleNetworking.serverToClient(Unicopia.id("projectile_entity"), MsgSpawnProjectile::new); S2CPacketType<MsgSpawnProjectile> SERVER_SPAWN_PROJECTILE = SimpleNetworking.serverToClient(Unicopia.id("projectile_entity"), MsgSpawnProjectile::new);
S2CPacketType<MsgBlockDestruction> SERVER_BLOCK_DESTRUCTION = SimpleNetworking.serverToClient(Unicopia.id("block_destruction"), MsgBlockDestruction::new); S2CPacketType<MsgBlockDestruction> SERVER_BLOCK_DESTRUCTION = SimpleNetworking.serverToClient(Unicopia.id("block_destruction"), MsgBlockDestruction::new);
S2CPacketType<MsgCancelPlayerAbility> CANCEL_PLAYER_ABILITY = SimpleNetworking.serverToClient(Unicopia.id("player_ability_cancel"), MsgCancelPlayerAbility::read); S2CPacketType<MsgCancelPlayerAbility> CANCEL_PLAYER_ABILITY = SimpleNetworking.serverToClient(Unicopia.id("player_ability_cancel"), MsgCancelPlayerAbility::read);
S2CPacketType<MsgCasterLookRequest> SERVER_REQUEST_PLAYER_LOOK = SimpleNetworking.serverToClient(Unicopia.id("request_player_look"), MsgCasterLookRequest::new);
S2CPacketType<MsgUnlockTraits> UNLOCK_TRAITS = SimpleNetworking.serverToClient(Unicopia.id("unlock_traits"), MsgUnlockTraits::new); S2CPacketType<MsgUnlockTraits> UNLOCK_TRAITS = SimpleNetworking.serverToClient(Unicopia.id("unlock_traits"), MsgUnlockTraits::new);
S2CPacketType<MsgTribeSelect> SERVER_SELECT_TRIBE = SimpleNetworking.serverToClient(Unicopia.id("select_tribe"), MsgTribeSelect::new); S2CPacketType<MsgTribeSelect> SERVER_SELECT_TRIBE = SimpleNetworking.serverToClient(Unicopia.id("select_tribe"), MsgTribeSelect::new);

View file

@ -0,0 +1,59 @@
package com.minelittlepony.unicopia.network;
import java.util.UUID;
import com.minelittlepony.unicopia.ability.data.Rot;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.OrientedSpell;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.sollace.fabwork.api.packets.HandledPacket;
import com.sollace.fabwork.api.packets.Packet;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.server.network.ServerPlayerEntity;
/**
* Sent to the client when the server needs to know precisely where the player is looking.
*/
public record MsgCasterLookRequest (UUID spellId) implements Packet<PlayerEntity> {
public MsgCasterLookRequest(PacketByteBuf buffer) {
this(buffer.readUuid());
}
@Override
public void toBuffer(PacketByteBuf buffer) {
buffer.writeUuid(spellId);
}
public record Reply (
UUID spellId,
Rot rotation
) implements HandledPacket<ServerPlayerEntity> {
Reply(PacketByteBuf buffer) {
this(buffer.readUuid(), Rot.SERIALIZER.read().apply(buffer));
}
public Reply(OrientedSpell spell, Caster<?> caster) {
this(spell.getUuid(), Rot.of(caster));
}
@Override
public void toBuffer(PacketByteBuf buffer) {
buffer.writeUuid(spellId);
Rot.SERIALIZER.write().accept(buffer, rotation);
}
@Override
public void handle(ServerPlayerEntity sender) {
Pony.of(sender).getSpellSlot()
.get(SpellPredicate.IS_ORIENTED.withId(spellId), false)
.ifPresent(spell -> {
spell.setOrientation(rotation);
});
}
}
}

View file

@ -5,9 +5,8 @@ import java.util.UUID;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.client.render.PlayerPoser.AnimationInstance; import com.minelittlepony.unicopia.client.render.PlayerPoser.AnimationInstance;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.sollace.fabwork.api.packets.HandledPacket; import com.sollace.fabwork.api.packets.Packet;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
@ -18,10 +17,17 @@ public record MsgPlayerAnimationChange (
UUID playerId, UUID playerId,
AnimationInstance animation, AnimationInstance animation,
int duration int duration
) implements HandledPacket<PlayerEntity> { ) implements Packet<PlayerEntity> {
MsgPlayerAnimationChange(PacketByteBuf buffer) { MsgPlayerAnimationChange(PacketByteBuf buffer) {
this(buffer.readUuid(), new AnimationInstance(buffer.readEnumConstant(Animation.class), buffer.readEnumConstant(Animation.Recipient.class)), buffer.readInt()); this(
buffer.readUuid(),
new AnimationInstance(
buffer.readEnumConstant(Animation.class),
buffer.readEnumConstant(Animation.Recipient.class)
),
buffer.readInt()
);
} }
public MsgPlayerAnimationChange(Pony player, AnimationInstance animation, int duration) { public MsgPlayerAnimationChange(Pony player, AnimationInstance animation, int duration) {
@ -35,14 +41,4 @@ public record MsgPlayerAnimationChange (
buffer.writeEnumConstant(animation.recipient()); buffer.writeEnumConstant(animation.recipient());
buffer.writeInt(duration); buffer.writeInt(duration);
} }
@Override
public void handle(PlayerEntity sender) {
Pony player = Pony.of(MinecraftClient.getInstance().world.getPlayerByUuid(playerId));
if (player == null) {
return;
}
player.setAnimation(animation, duration);
}
} }

View file

@ -5,6 +5,7 @@ import java.util.Map;
import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Owned; import com.minelittlepony.unicopia.Owned;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.Rot;
import com.minelittlepony.unicopia.ability.data.tree.TreeTypes; import com.minelittlepony.unicopia.ability.data.tree.TreeTypes;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
@ -17,6 +18,8 @@ import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Cha
import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.entity.mob.UEntities;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.*; import com.minelittlepony.unicopia.network.*;
import com.minelittlepony.unicopia.network.MsgCasterLookRequest.Reply;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.world.ClientWorld; import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
@ -34,6 +37,8 @@ public class ClientNetworkHandlerImpl {
Channel.UNLOCK_TRAITS.receiver().addPersistentListener(this::handleUnlockTraits); Channel.UNLOCK_TRAITS.receiver().addPersistentListener(this::handleUnlockTraits);
Channel.SERVER_RESOURCES_SEND.receiver().addPersistentListener(this::handleServerResources); Channel.SERVER_RESOURCES_SEND.receiver().addPersistentListener(this::handleServerResources);
Channel.SERVER_SKY_ANGLE.receiver().addPersistentListener(this::handleSkyAngle); Channel.SERVER_SKY_ANGLE.receiver().addPersistentListener(this::handleSkyAngle);
Channel.SERVER_PLAYER_ANIMATION_CHANGE.receiver().addPersistentListener(this::handlePlayerAnimation);
Channel.SERVER_REQUEST_PLAYER_LOOK.receiver().addPersistentListener(this::handleCasterLookRequest);
} }
private void handleTribeScreen(PlayerEntity sender, MsgTribeSelect packet) { private void handleTribeScreen(PlayerEntity sender, MsgTribeSelect packet) {
@ -93,4 +98,22 @@ public class ClientNetworkHandlerImpl {
ClientChapters.load((Map<Identifier, Chapter>)packet.chapters()); ClientChapters.load((Map<Identifier, Chapter>)packet.chapters());
TreeTypes.load(packet.treeTypes()); TreeTypes.load(packet.treeTypes());
} }
private void handlePlayerAnimation(PlayerEntity sender, MsgPlayerAnimationChange packet) {
Pony player = Pony.of(MinecraftClient.getInstance().world.getPlayerByUuid(packet.playerId()));
if (player == null) {
return;
}
player.setAnimation(packet.animation(), packet.duration());
}
private void handleCasterLookRequest(PlayerEntity sender, MsgCasterLookRequest packet) {
Pony player = Pony.of(MinecraftClient.getInstance().player);
if (player == null) {
return;
}
Channel.CLIENT_CASTER_LOOK.sendToServer(new Reply(packet.spellId(), Rot.of(player)));
}
} }