mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Send the initial look direction from the client
This commit is contained in:
parent
74bdaa7028
commit
54e0922c93
10 changed files with 187 additions and 58 deletions
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue