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 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.Rot;
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.server.world.UGameRules;
public class TimeChangeAbility implements Ability<Hit> {
public class TimeChangeAbility implements Ability<Rot> {
@Override
public boolean canUse(Race race) {
@ -38,12 +38,12 @@ public class TimeChangeAbility implements Ability<Hit> {
}
@Override
public Serializer<Hit> getSerializer() {
return Hit.SERIALIZER;
public Serializer<Rot> getSerializer() {
return Rot.SERIALIZER;
}
@Override
public Optional<Hit> prepare(Pony player) {
public Optional<Rot> prepare(Pony player) {
if (!player.asWorld().getGameRules().getBoolean(UGameRules.DO_TIME_MAGIC)) {
return Optional.empty();
@ -53,11 +53,11 @@ public class TimeChangeAbility implements Ability<Hit> {
return Optional.empty();
}
return Hit.INSTANCE;
return Optional.of(Rot.of(player));
}
@Override
public boolean apply(Pony player, Hit data) {
public boolean apply(Pony player, Rot data) {
if (!player.asWorld().getGameRules().getBoolean(UGameRules.DO_TIME_MAGIC)) {
return false;
}
@ -65,7 +65,7 @@ public class TimeChangeAbility implements Ability<Hit> {
if (player.getSpellSlot().contains(SpellType.TIME_CONTROL)) {
player.getSpellSlot().removeWhere(SpellType.TIME_CONTROL, true);
} else {
SpellType.TIME_CONTROL.withTraits().apply(player, CastingMethod.INNATE);
SpellType.TIME_CONTROL.withTraits().apply(player, CastingMethod.INNATE).update(player, data.applyTo(player));
}
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;
import java.util.UUID;
import java.util.function.Predicate;
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<ShieldSpell> IS_SHIELD_LIKE = spell -> spell instanceof ShieldSpell;
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_VISIBLE = spell -> spell != null && !spell.isHidden();
@ -42,4 +44,8 @@ public interface SpellPredicate<T extends Spell> extends Predicate<Spell> {
default boolean isOn(Entity entity) {
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;
public interface OrientedSpell {
import com.minelittlepony.unicopia.ability.data.Rot;
public interface OrientedSpell extends Spell {
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.mob.CastSpellEntity;
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.ParticleHandle;
import com.minelittlepony.unicopia.particle.UParticles;
@ -19,6 +22,7 @@ import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.minecraft.nbt.*;
import net.minecraft.registry.*;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
@ -84,6 +88,9 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
if (dimension == null) {
dimension = source.asWorld().getRegistryKey();
if (source instanceof Pony) {
Channel.SERVER_REQUEST_PLAYER_LOOK.sendToPlayer(new MsgCasterLookRequest(getUuid()), (ServerPlayerEntity)source.asEntity());
}
setDirty();
}
@ -153,13 +160,12 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
public void setPosition(Caster<?> source, Vec3d position) {
this.position = Optional.of(position);
getWorld(source).ifPresent(world -> {
castEntity.ifPresent(world, entity -> {
entity.updatePositionAndAngles(position.x, position.y, position.z, entity.getYaw(), entity.getPitch());
});
this.dimension = source.asWorld().getRegistryKey();
castEntity.ifPresent(source.asWorld(), entity -> {
entity.updatePositionAndAngles(position.x, position.y, position.z, entity.getYaw(), entity.getPitch());
});
getDelegates(spell -> spell instanceof PlaceableSpell o ? o : null)
.forEach(spell -> spell.setPosition(source ,position));
.forEach(spell -> spell.setPosition(source, position));
setDirty();
}

View file

@ -1,6 +1,7 @@
package com.minelittlepony.unicopia.ability.magic.spell;
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.spell.effect.*;
import com.minelittlepony.unicopia.entity.player.Pony;
@ -13,7 +14,7 @@ import net.minecraft.server.world.ServerWorld;
/**
* Internal.
* <p>
* Used by the Rainboom ability.
* Used by the time change ability
*/
public class TimeControlAbilitySpell extends AbstractSpell {
@ -38,38 +39,44 @@ public class TimeControlAbilitySpell extends AbstractSpell {
return false;
}
if (source.asWorld() instanceof ServerWorld sw) {
update(source, Rot.of(source));
return source.subtractEnergyCost(2);
}
float yaw = -(source.asEntity().getHeadYaw() + 90);
float pitch = -(source.asEntity().getPitch(1) / 90F);
long time = (long)(pitch * 6000);
// sunrise(0) - midday(1) - sunset(2) - midnight(3)
if (!initilized) {
initilized = true;
timeOffset = sw.getTimeOfDay() - time;
angleOffset = UnicopiaWorldProperties.forWorld(sw).getTangentalSkyAngle() - yaw;
}
if (angleOffset > 90 && angleOffset < 270) {
time *= -1;
}
time += timeOffset;
if (time < 0) {
time += 24000;
}
time %= 24000;
sw.setTimeOfDay(time);
sw.getServer().sendTimeUpdatePackets();
UnicopiaWorldProperties.forWorld(sw).setTangentalSkyAngle(angleOffset + yaw);
public void update(Caster<?> source, Rot rotation) {
if (!source.asWorld().getGameRules().getBoolean(UGameRules.DO_TIME_MAGIC)) {
return;
}
if (!(source.asWorld() instanceof ServerWorld sw)) {
return;
}
return source.subtractEnergyCost(2);
float yaw = -(rotation.yaw() + 90);
float pitch = -(rotation.pitch() / 90F);
long time = (long)(pitch * 6000);
// sunrise(0) - midday(1) - sunset(2) - midnight(3)
if (!initilized) {
initilized = true;
timeOffset = sw.getTimeOfDay() - time;
angleOffset = UnicopiaWorldProperties.forWorld(sw).getTangentalSkyAngle() - yaw;
}
if (angleOffset > 90 && angleOffset < 270) {
time *= -1;
}
time += timeOffset;
if (time < 0) {
time += 24000;
}
time %= 24000;
sw.setTimeOfDay(time);
sw.getServer().sendTimeUpdatePackets();
UnicopiaWorldProperties.forWorld(sw).setTangentalSkyAngle(angleOffset + yaw);
}
@Override

View file

@ -11,6 +11,7 @@ import net.minecraft.server.network.ServerPlayerEntity;
public interface Channel {
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<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);
@ -19,6 +20,7 @@ public interface Channel {
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<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<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.AnimationInstance;
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.network.PacketByteBuf;
@ -18,10 +17,17 @@ public record MsgPlayerAnimationChange (
UUID playerId,
AnimationInstance animation,
int duration
) implements HandledPacket<PlayerEntity> {
) implements Packet<PlayerEntity> {
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) {
@ -35,14 +41,4 @@ public record MsgPlayerAnimationChange (
buffer.writeEnumConstant(animation.recipient());
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.Owned;
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.magic.spell.trait.SpellTraits;
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.player.Pony;
import com.minelittlepony.unicopia.network.*;
import com.minelittlepony.unicopia.network.MsgCasterLookRequest.Reply;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
@ -34,6 +37,8 @@ public class ClientNetworkHandlerImpl {
Channel.UNLOCK_TRAITS.receiver().addPersistentListener(this::handleUnlockTraits);
Channel.SERVER_RESOURCES_SEND.receiver().addPersistentListener(this::handleServerResources);
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) {
@ -93,4 +98,22 @@ public class ClientNetworkHandlerImpl {
ClientChapters.load((Map<Identifier, Chapter>)packet.chapters());
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)));
}
}