Store the default race with the world and properly sync with the client upon joining

This commit is contained in:
Sollace 2020-09-23 21:56:57 +02:00
parent 77f0915d82
commit 2fd270131f
13 changed files with 170 additions and 69 deletions

View file

@ -18,18 +18,21 @@ public class InteractionManager {
return INSTANCE; return INSTANCE;
} }
/**
* Returns true on the client if the passed in player entity is the client's player.
* Always returns false on the server.
*/
public boolean isClientPlayer(@Nullable PlayerEntity player) { public boolean isClientPlayer(@Nullable PlayerEntity player) {
return false; return false;
} }
/**
* The player's camera mode. Always 0 on the server.
*/
public int getViewMode() { public int getViewMode() {
return 0; return 0;
} }
public Race getPreferredRace() {
return Unicopia.getConfig().getPrefferedRace();
}
/** /**
* Side-independent method to create a new player. * Side-independent method to create a new player.
* *

View file

@ -7,9 +7,12 @@ import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.minelittlepony.common.client.gui.sprite.TextureSprite;
import com.minelittlepony.common.client.gui.style.Style;
import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.Affine;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Identifier;
public enum Race implements Affine { public enum Race implements Affine {
/** /**
@ -101,6 +104,16 @@ public enum Race implements Affine {
return this; return this;
} }
public Style getStyle() {
return new Style()
.setIcon(new TextureSprite()
.setPosition(2, 2)
.setSize(16, 16)
.setTexture(new Identifier("unicopia", "textures/gui/icons.png"))
.setTextureOffset((16 * ordinal()) % 256, (ordinal() / 256) * 16)
)
.setTooltip(getTranslationKey(), 0, 10);
}
public boolean equals(String s) { public boolean equals(String s) {
return name().equalsIgnoreCase(s) return name().equalsIgnoreCase(s)

View file

@ -0,0 +1,38 @@
package com.minelittlepony.unicopia;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.PersistentState;
import net.minecraft.world.dimension.DimensionType;
public class WorldTribeManager extends PersistentState {
private Race defaultRace = Unicopia.getConfig().getPrefferedRace();
public WorldTribeManager(ServerWorld world) {
super("unicopia:tribes" + world.getDimension().getSuffix());
}
public Race getDefaultRace() {
return defaultRace;
}
@Override
public void fromTag(CompoundTag tag) {
defaultRace = Race.fromName(tag.getString("defaultRace"));
}
@Override
public CompoundTag toTag(CompoundTag tag) {
tag.putString("defaultRace", defaultRace.name());
return tag;
}
public static String nameFor(DimensionType dimension) {
return "unicopia:tribes" + dimension.getSuffix();
}
public static WorldTribeManager forWorld(ServerWorld world) {
return world.getPersistentStateManager().getOrCreate(() -> new WorldTribeManager(world), nameFor(world.getDimension()));
}
}

View file

@ -164,7 +164,7 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
T data = ability.tryActivate(player); T data = ability.tryActivate(player);
if (data != null) { if (data != null) {
Channel.PLAYER_ABILITY.send(new MsgPlayerAbility<>(ability, data)); Channel.CLIENT_PLAYER_ABILITY.send(new MsgPlayerAbility<>(ability, data));
} else { } else {
setCooldown(0); setCooldown(0);
} }

View file

@ -4,8 +4,6 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.entity.player.dummy.DummyClientPlayerEntity; import com.minelittlepony.unicopia.entity.player.dummy.DummyClientPlayerEntity;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
@ -16,7 +14,6 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
public class ClientInteractionManager extends InteractionManager { public class ClientInteractionManager extends InteractionManager {
@Override @Override
@Nonnull @Nonnull
public PlayerEntity createPlayer(Entity observer, GameProfile profile) { public PlayerEntity createPlayer(Entity observer, GameProfile profile) {
@ -28,29 +25,9 @@ public class ClientInteractionManager extends InteractionManager {
@Override @Override
public boolean isClientPlayer(@Nullable PlayerEntity player) { public boolean isClientPlayer(@Nullable PlayerEntity player) {
if (MinecraftClient.getInstance().player == player) { return (MinecraftClient.getInstance().player != null && player != null)
return true; && (MinecraftClient.getInstance().player == player
} || Pony.equal(MinecraftClient.getInstance().player, player));
if (MinecraftClient.getInstance().player == null || player == null) {
return false;
}
return Pony.equal(MinecraftClient.getInstance().player, player);
}
@Override
public Race getPreferredRace() {
if (!Unicopia.getConfig().ignoresMineLittlePony()
&& MinecraftClient.getInstance().player != null) {
Race race = MineLPConnector.getPlayerPonyRace();
if (!race.isDefault()) {
return race;
}
}
return Unicopia.getConfig().getPrefferedRace();
} }
@Override @Override

View file

@ -24,13 +24,14 @@ public final class MineLPConnector {
case GRYPHON: case GRYPHON:
case HIPPOGRIFF: case HIPPOGRIFF:
case PEGASUS: case PEGASUS:
case BATPONY:
return Race.PEGASUS; return Race.PEGASUS;
case BATPONY:
return Race.BAT;
case SEAPONY: case SEAPONY:
case UNICORN: case UNICORN:
return Race.UNICORN; return Race.UNICORN;
default: default:
return Race.EARTH; return Race.HUMAN;
} }
} }
} }

View file

@ -1,38 +1,70 @@
package com.minelittlepony.unicopia.client; package com.minelittlepony.unicopia.client;
import com.minelittlepony.common.client.gui.element.Cycler;
import com.minelittlepony.common.event.ScreenInitCallback;
import com.minelittlepony.common.event.ScreenInitCallback.ButtonList;
import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.network.MsgRequestCapabilities;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.world.CreateWorldScreen;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.MathHelper;
public class UnicopiaClient implements ClientModInitializer { public class UnicopiaClient implements ClientModInitializer {
private Race lastPreferredRace = InteractionManager.instance().getPreferredRace(); public static Race getPreferredRace() {
if (!Unicopia.getConfig().ignoresMineLittlePony()
&& MinecraftClient.getInstance().player != null) {
Race race = MineLPConnector.getPlayerPonyRace();
if (!race.isDefault()) {
return race;
}
}
return Unicopia.getConfig().getPrefferedRace();
}
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
lastPreferredRace = InteractionManager.instance().getPreferredRace();
InteractionManager.INSTANCE = new ClientInteractionManager(); InteractionManager.INSTANCE = new ClientInteractionManager();
URenderers.bootstrap(); URenderers.bootstrap();
ClientTickEvents.END_CLIENT_TICK.register(client -> { ClientTickEvents.END_CLIENT_TICK.register(this::onTick);
PlayerEntity player = client.player; ScreenInitCallback.EVENT.register(this::onScreenInit);
}
if (player != null && !player.removed) { private void onTick(MinecraftClient client) {
Race newRace = InteractionManager.instance().getPreferredRace(); KeyBindingsHandler.INSTANCE.tick(client);
}
if (newRace != lastPreferredRace) { private void onScreenInit(Screen screen, ButtonList buttons) {
lastPreferredRace = newRace; if (screen instanceof CreateWorldScreen) {
buttons.add(new Cycler(screen.width / 2 + 110, 60, 20, 20) {
Channel.REQUEST_CAPABILITIES.send(new MsgRequestCapabilities(lastPreferredRace)); @Override
protected void renderForground(MatrixStack matrices, MinecraftClient mc, int mouseX, int mouseY, int foreColor) {
super.renderForground(matrices, mc, mouseX, mouseY, foreColor);
if (isMouseOver(mouseX, mouseY)) {
renderToolTip(matrices, screen, mouseX, mouseY);
}
} }
} }).setStyles(
Race.EARTH.getStyle(),
Race.UNICORN.getStyle(),
Race.PEGASUS.getStyle(),
Race.BAT.getStyle(),
Race.ALICORN.getStyle(),
Race.CHANGELING.getStyle()
).onChange(i -> {
Unicopia.getConfig().setPreferredRace(Race.fromId(i + 1));
KeyBindingsHandler.INSTANCE.tick(client); return i;
}); }).setValue(MathHelper.clamp(Unicopia.getConfig().getPrefferedRace().ordinal() - 1, 0, 5));
}
} }
} }

View file

@ -5,8 +5,10 @@ import java.util.Optional;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.client.UnicopiaClient;
import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.WorldTribeManager;
import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.AbilityDispatcher;
import com.minelittlepony.unicopia.ability.magic.AttachableSpell; import com.minelittlepony.unicopia.ability.magic.AttachableSpell;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
@ -21,11 +23,13 @@ import com.minelittlepony.unicopia.item.toxin.Toxin;
import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.EffectSync; import com.minelittlepony.unicopia.network.EffectSync;
import com.minelittlepony.unicopia.network.MsgPlayerCapabilities; import com.minelittlepony.unicopia.network.MsgPlayerCapabilities;
import com.minelittlepony.unicopia.network.MsgRequestCapabilities;
import com.minelittlepony.unicopia.network.Transmittable; import com.minelittlepony.unicopia.network.Transmittable;
import com.minelittlepony.unicopia.util.Copieable; import com.minelittlepony.unicopia.util.Copieable;
import com.minelittlepony.common.util.animation.LinearInterpolator; import com.minelittlepony.common.util.animation.LinearInterpolator;
import com.minelittlepony.common.util.animation.Interpolator; import com.minelittlepony.common.util.animation.Interpolator;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageSource;
@ -38,6 +42,7 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.packet.s2c.play.EntityPassengersSetS2CPacket; import net.minecraft.network.packet.s2c.play.EntityPassengersSetS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText; import net.minecraft.text.TranslatableText;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@ -65,7 +70,12 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
private final PlayerEntity entity; private final PlayerEntity entity;
private boolean dirty = false; private boolean dirty;
private boolean speciesSet;
private boolean speciesPersisted;
@Nullable
private Race clientPreferredRace;
private boolean invisible = false; private boolean invisible = false;
@ -73,7 +83,7 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
this.entity = player; this.entity = player;
this.mana = new ManaContainer(this); this.mana = new ManaContainer(this);
player.getDataTracker().startTracking(RACE, Race.EARTH.ordinal()); player.getDataTracker().startTracking(RACE, Race.HUMAN.ordinal());
player.getDataTracker().startTracking(EFFECT, new CompoundTag()); player.getDataTracker().startTracking(EFFECT, new CompoundTag());
player.getDataTracker().startTracking(HELD_EFFECT, new CompoundTag()); player.getDataTracker().startTracking(HELD_EFFECT, new CompoundTag());
} }
@ -94,6 +104,7 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
@Override @Override
public void setSpecies(Race race) { public void setSpecies(Race race) {
race = race.validate(entity); race = race.validate(entity);
speciesSet = true;
entity.getDataTracker().set(RACE, race.ordinal()); entity.getDataTracker().set(RACE, race.ordinal());
@ -110,6 +121,10 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
return invisible && hasSpell(); return invisible && hasSpell();
} }
public boolean isSpeciesPersisted() {
return speciesPersisted;
}
@Override @Override
public void setInvisible(boolean invisible) { public void setInvisible(boolean invisible) {
this.invisible = invisible; this.invisible = invisible;
@ -129,7 +144,6 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
dirty = false; dirty = false;
if (entity instanceof ServerPlayerEntity) { if (entity instanceof ServerPlayerEntity) {
System.out.println("Sending capabilities for player");
Channel.BROADCAST_CAPABILITIES.send(new MsgPlayerCapabilities(full, this)); Channel.BROADCAST_CAPABILITIES.send(new MsgPlayerCapabilities(full, this));
} }
} }
@ -161,7 +175,25 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
@Override @Override
public boolean beforeUpdate() { public boolean beforeUpdate() {
if (entity.world.isClient()) {
if (!speciesSet && getWorld() instanceof ServerWorld) {
setSpecies(WorldTribeManager.forWorld((ServerWorld)getWorld()).getDefaultRace());
setDirty();
}
if (isClientPlayer() && !speciesSet) {
Race race = UnicopiaClient.getPreferredRace();
if (race != clientPreferredRace) {
clientPreferredRace = race;
if (race != getSpecies()) {
Channel.CLIENT_REQUEST_CAPABILITIES.send(new MsgRequestCapabilities(race));
}
}
}
if (isClient()) {
if (entity.hasVehicle() && entity.isSneaking()) { if (entity.hasVehicle() && entity.isSneaking()) {
Entity ridee = entity.getVehicle(); Entity ridee = entity.getVehicle();
@ -300,6 +332,7 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
@Override @Override
public void fromNBT(CompoundTag compound) { public void fromNBT(CompoundTag compound) {
speciesPersisted = true;
setSpecies(Race.fromName(compound.getString("playerSpecies"))); setSpecies(Race.fromName(compound.getString("playerSpecies")));
powers.fromNBT(compound.getCompound("powers")); powers.fromNBT(compound.getCompound("powers"));
@ -312,6 +345,7 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
@Override @Override
public void copyFrom(Pony oldPlayer) { public void copyFrom(Pony oldPlayer) {
speciesPersisted = oldPlayer.speciesPersisted;
setSpell(oldPlayer.getSpell()); setSpell(oldPlayer.getSpell());
setSpecies(oldPlayer.getSpecies()); setSpecies(oldPlayer.getSpecies());
setDirty(); setDirty();

View file

@ -12,14 +12,15 @@ import net.minecraft.network.PacketByteBuf;
public interface Channel { public interface Channel {
SPacketType<MsgPlayerAbility<?>> PLAYER_ABILITY = clientToServer(new Identifier("unicopia", "player_ability"), MsgPlayerAbility::new); SPacketType<MsgPlayerAbility<?>> CLIENT_PLAYER_ABILITY = clientToServer(new Identifier("unicopia", "player_ability"), MsgPlayerAbility::new);
SPacketType<MsgRequestCapabilities> REQUEST_CAPABILITIES = clientToServer(new Identifier("unicopia", "request_capabilities"), MsgRequestCapabilities::new); SPacketType<MsgRequestCapabilities> CLIENT_REQUEST_CAPABILITIES = clientToServer(new Identifier("unicopia", "request_capabilities"), MsgRequestCapabilities::new);
CPacketType<MsgPlayerCapabilities> PLAYER_CAPABILITIES = serverToClient(new Identifier("unicopia", "player_capabilities"), MsgPlayerCapabilities::new);
SPacketType<MsgPlayerCapabilities> BROADCAST_CAPABILITIES = broadcast(PLAYER_CAPABILITIES, MsgPlayerCapabilities::new); CPacketType<MsgPlayerCapabilities> SERVER_PLAYER_CAPABILITIES = serverToClient(new Identifier("unicopia", "player_capabilities"), MsgPlayerCapabilities::new);
CPacketType<MsgSpawnProjectile> SPAWN_PROJECTILE = serverToClient(new Identifier("unicopia", "projectile_entity"), MsgSpawnProjectile::new); SPacketType<MsgPlayerCapabilities> BROADCAST_CAPABILITIES = broadcast(SERVER_PLAYER_CAPABILITIES, MsgPlayerCapabilities::new);
CPacketType<MsgSpawnProjectile> SERVER_SPAWN_PROJECTILE = serverToClient(new Identifier("unicopia", "projectile_entity"), MsgSpawnProjectile::new);
static void bootstrap() { } static void bootstrap() { }

View file

@ -50,7 +50,6 @@ public class MsgPlayerCapabilities implements Channel.Packet {
@Override @Override
public void handle(PacketContext context) { public void handle(PacketContext context) {
System.out.println("Got capabilities for player " + newRace + " " + context.getPacketEnvironment());
Pony player = Pony.of(context.getPlayer()); Pony player = Pony.of(context.getPlayer());
if (compoundTag.isEmpty()) { if (compoundTag.isEmpty()) {
player.setSpecies(newRace); player.setSpecies(newRace);

View file

@ -1,37 +1,40 @@
package com.minelittlepony.unicopia.network; package com.minelittlepony.unicopia.network;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.WorldTribeManager;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.fabricmc.fabric.api.network.PacketContext; import net.fabricmc.fabric.api.network.PacketContext;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
import net.minecraft.server.world.ServerWorld;
public class MsgRequestCapabilities implements Channel.Packet { public class MsgRequestCapabilities implements Channel.Packet {
private final Race race; private final Race clientPreferredRace;
MsgRequestCapabilities(PacketByteBuf buffer) { MsgRequestCapabilities(PacketByteBuf buffer) {
race = Race.values()[buffer.readInt()]; clientPreferredRace = Race.values()[buffer.readInt()];
} }
public MsgRequestCapabilities(Race preferredRace) { public MsgRequestCapabilities(Race preferredRace) {
race = preferredRace; clientPreferredRace = preferredRace;
} }
@Override @Override
public void toBuffer(PacketByteBuf buffer) { public void toBuffer(PacketByteBuf buffer) {
buffer.writeInt(race.ordinal()); buffer.writeInt(clientPreferredRace.ordinal());
} }
@Override @Override
public void handle(PacketContext context) { public void handle(PacketContext context) {
System.out.println("Requesting player capabilities " + context.getPacketEnvironment());
Pony player = Pony.of(context.getPlayer()); Pony player = Pony.of(context.getPlayer());
if (player.getSpecies().isDefault()) { Race worldDefaultRace = WorldTribeManager.forWorld((ServerWorld)player.getWorld()).getDefaultRace();
player.setSpecies(race);
if (player.getSpecies().isDefault() || (player.getSpecies() == worldDefaultRace && !player.isSpeciesPersisted())) {
player.setSpecies(clientPreferredRace.isPermitted(context.getPlayer()) ? clientPreferredRace : worldDefaultRace);
} }
Channel.PLAYER_CAPABILITIES.send(context.getPlayer(), new MsgPlayerCapabilities(true, player)); Channel.SERVER_PLAYER_CAPABILITIES.send(context.getPlayer(), new MsgPlayerCapabilities(true, player));
} }
} }

View file

@ -293,6 +293,6 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
@Override @Override
public Packet<?> createSpawnPacket() { public Packet<?> createSpawnPacket() {
return Channel.SPAWN_PROJECTILE.toPacket(new MsgSpawnProjectile(this)); return Channel.SERVER_SPAWN_PROJECTILE.toPacket(new MsgSpawnProjectile(this));
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB