Added a gamerule to force players to select a new tribe after death

This commit is contained in:
Sollace 2023-01-27 18:06:06 +00:00
parent e052eb534f
commit 2b227eee1a
13 changed files with 91 additions and 49 deletions

View file

@ -0,0 +1,10 @@
package com.minelittlepony.unicopia;
import net.minecraft.world.GameRules;
import net.minecraft.world.GameRules.BooleanRule;
public interface UGameRules {
GameRules.Key<BooleanRule> SWAP_TRIBE_ON_DEATH = GameRules.register("swapTribeOnDeath", GameRules.Category.SPAWNING, BooleanRule.create(false));
static void bootstrap() { }
}

View file

@ -84,6 +84,7 @@ public class Unicopia implements ModInitializer {
Abilities.bootstrap();
UScreenHandlers.bootstrap();
UTreeGen.bootstrap();
UGameRules.bootstrap();
}
public interface SidedAccess {

View file

@ -14,6 +14,7 @@ import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgMarkTraitRead;
import com.minelittlepony.unicopia.network.MsgUnlockTraits;
import com.minelittlepony.unicopia.util.Copyable;
import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.fabricmc.api.EnvType;
@ -31,7 +32,7 @@ import net.minecraft.util.Identifier;
import net.minecraft.registry.Registries;
import net.minecraft.world.World;
public class TraitDiscovery implements NbtSerialisable {
public class TraitDiscovery implements NbtSerialisable, Copyable<TraitDiscovery> {
private final Set<Trait> unreadTraits = new HashSet<>();
private final Set<Trait> traits = new HashSet<>();
@ -152,7 +153,8 @@ public class TraitDiscovery implements NbtSerialisable {
return SpellTraits.fromNbt(nbt);
}
public void copyFrom(TraitDiscovery old) {
@Override
public void copyFrom(TraitDiscovery old, boolean alive) {
clear();
unreadTraits.addAll(old.unreadTraits);
traits.addAll(old.traits);

View file

@ -151,8 +151,10 @@ public class EntityPhysics<T extends Entity> implements Physics, Copyable<Entity
}
@Override
public void copyFrom(EntityPhysics<T> other) {
setBaseGravityModifier(other.getBaseGravityModifier());
public void copyFrom(EntityPhysics<T> other, boolean alive) {
if (alive) {
setBaseGravityModifier(other.getBaseGravityModifier());
}
}
@Override

View file

@ -123,9 +123,11 @@ public class ItemTracker implements NbtSerialisable, Copyable<ItemTracker>, Tick
}
@Override
public void copyFrom(ItemTracker other) {
public void copyFrom(ItemTracker other, boolean alive) {
items.clear();
items.putAll(other.items);
if (alive) {
items.putAll(other.items);
}
}
public interface Trackable extends ItemConvertible {

View file

@ -70,6 +70,10 @@ public class RaceChangeStatusEffect extends StatusEffect {
return;
}
if (eq instanceof Pony pony) {
pony.setRespawnRace(race);
}
int ticks = Math.max(0, MAX_DURATION - state.getDuration());
Stage stage = Stage.forDuration(ticks / STAGE_DURATION);
@ -80,23 +84,20 @@ public class RaceChangeStatusEffect extends StatusEffect {
int progression = ticks % (stage.ordinal() * STAGE_DURATION);
if ((eq instanceof Pony pony ? pony.getActualSpecies() : eq.getSpecies()) == race || !race.isPermitted(entity instanceof PlayerEntity ? (PlayerEntity)entity : null)) {
if (progression == 0 && entity instanceof PlayerEntity && stage == Stage.CRAWLING) {
((PlayerEntity)entity).sendMessage(Stage.INITIAL.getMessage(race), true);
if ((eq instanceof Pony pony ? pony.getActualSpecies() : eq.getSpecies()) == race || !race.isPermitted(entity instanceof PlayerEntity player ? player : null)) {
if (progression == 0 && entity instanceof PlayerEntity player && stage == Stage.CRAWLING) {
player.sendMessage(Stage.INITIAL.getMessage(race), true);
}
return;
}
if (progression == 0) {
if (stage != Stage.DEATH && entity instanceof PlayerEntity) {
((PlayerEntity)entity).sendMessage(stage.getMessage(race), true);
}
if (progression == 0 && stage != Stage.DEATH && entity instanceof PlayerEntity player) {
player.sendMessage(stage.getMessage(race), true);
}
entity.setHealth(1);
if (entity instanceof PlayerEntity) {
Pony pony = (Pony)eq;
if (eq instanceof Pony pony) {
MagicReserves magic = pony.getMagicalReserves();
magic.getExertion().add(50);
magic.getEnergy().add(3);
@ -108,8 +109,6 @@ public class RaceChangeStatusEffect extends StatusEffect {
}
if (stage == Stage.DEATH) {
eq.setSpecies(race);
if (eq instanceof Caster) {
((Caster<?>)eq).getSpellSlot().clear();
}
@ -119,11 +118,10 @@ public class RaceChangeStatusEffect extends StatusEffect {
magic.getEnergy().set(0.6F);
magic.getExhaustion().set(0);
magic.getExertion().set(0);
pony.setDirty();
entity.damage(MagicalDamageSource.TRIBE_SWAP, Float.MAX_VALUE);
} else {
eq.setSpecies(race);
}
entity.damage(MagicalDamageSource.TRIBE_SWAP, Float.MAX_VALUE);
entity.setHealth(0);
}
}

View file

@ -21,10 +21,8 @@ import com.minelittlepony.unicopia.entity.effect.SunBlindnessStatusEffect;
import com.minelittlepony.unicopia.entity.effect.UEffects;
import com.minelittlepony.unicopia.item.FriendshipBraceletItem;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgOtherPlayerCapabilities;
import com.minelittlepony.unicopia.network.MsgPlayerAnimationChange;
import com.minelittlepony.unicopia.util.*;
import com.minelittlepony.unicopia.network.*;
import com.minelittlepony.unicopia.network.datasync.EffectSync.UpdateCallback;
import com.minelittlepony.unicopia.trinkets.TrinketsDelegate;
import com.minelittlepony.common.util.animation.LinearInterpolator;
@ -82,6 +80,8 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
private final Interpolator interpolator = new LinearInterpolator();
private Race respawnRace = Race.UNSET;
private boolean dirty;
private int ticksHanging;
@ -151,6 +151,10 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
return advancementProgress;
}
public void setRespawnRace(Race race) {
respawnRace = race;
}
@Override
public Race getSpecies() {
if (AmuletSelectors.ALICORN_AMULET.test(entity)) {
@ -621,21 +625,41 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
}
@Override
public void copyFrom(Pony oldPlayer) {
if (!oldPlayer.asEntity().isRemoved()) {
public void copyFrom(Pony oldPlayer, boolean alive) {
boolean forcedSwap = !alive
&& entity instanceof ServerPlayerEntity
&& entity.world.getGameRules().getBoolean(UGameRules.SWAP_TRIBE_ON_DEATH)
&& oldPlayer.asEntity().getDamageTracker().getMostRecentDamage().getDamageSource() != MagicalDamageSource.TRIBE_SWAP;
if (alive) {
oldPlayer.getSpellSlot().stream(true).forEach(getSpellSlot()::put);
} else {
oldPlayer.getSpellSlot().stream(true).filter(SpellPredicate.IS_PLACED).forEach(getSpellSlot()::put);
if (forcedSwap) {
Channel.SERVER_SELECT_TRIBE.sendToPlayer(new MsgTribeSelect(Race.allPermitted(entity), Text.translatable("gui.unicopia.tribe_selection.respawn")), (ServerPlayerEntity)entity);
} else {
oldPlayer.getSpellSlot().stream(true).filter(SpellPredicate.IS_PLACED).forEach(getSpellSlot()::put);
}
}
oldPlayer.getSpellSlot().put(null);
getArmour().copyFrom(oldPlayer.getArmour());
setSpecies(oldPlayer.getActualSpecies());
getDiscoveries().copyFrom(oldPlayer.getDiscoveries());
getCharms().equipSpell(Hand.MAIN_HAND, oldPlayer.getCharms().getEquippedSpell(Hand.MAIN_HAND));
getCharms().equipSpell(Hand.OFF_HAND, oldPlayer.getCharms().getEquippedSpell(Hand.OFF_HAND));
corruption.set(oldPlayer.getCorruption().get());
levels.set(oldPlayer.getLevel().get());
mana.getXp().set(oldPlayer.getMagicalReserves().getXp().get());
setSpecies(oldPlayer.respawnRace != Race.UNSET && !alive ? oldPlayer.respawnRace : oldPlayer.getActualSpecies());
getDiscoveries().copyFrom(oldPlayer.getDiscoveries(), alive);
getPhysics().copyFrom(oldPlayer.getPhysics(), alive);
if (!forcedSwap) {
getArmour().copyFrom(oldPlayer.getArmour(), alive);
getCharms().equipSpell(Hand.MAIN_HAND, oldPlayer.getCharms().getEquippedSpell(Hand.MAIN_HAND));
getCharms().equipSpell(Hand.OFF_HAND, oldPlayer.getCharms().getEquippedSpell(Hand.OFF_HAND));
corruption.set(oldPlayer.getCorruption().get());
levels.set(oldPlayer.getLevel().get());
mana.getXp().set(oldPlayer.getMagicalReserves().getXp().get());
} else {
mana.getEnergy().set(0.6F);
mana.getExhaustion().set(0);
mana.getExertion().set(0);
}
advancementProgress.putAll(oldPlayer.getAdvancementProgress());
setDirty();
onSpawn();

View file

@ -24,7 +24,7 @@ abstract class MixinServerPlayerEntity extends PlayerEntity implements ScreenHan
@SuppressWarnings("unchecked")
@Inject(method = "copyFrom(Lnet/minecraft/server/network/ServerPlayerEntity;Z)V", at = @At("HEAD"))
private void onCopyFrom(ServerPlayerEntity oldPlayer, boolean alive, CallbackInfo info) {
get().copyFrom(((Equine.Container<Pony>)oldPlayer).get());
get().copyFrom(((Equine.Container<Pony>)oldPlayer).get(), alive);
}
}

View file

@ -7,6 +7,7 @@ import com.sollace.fabwork.api.packets.*;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
public interface Channel {
C2SPacketType<MsgPlayerAbility<?>> CLIENT_PLAYER_ABILITY = SimpleNetworking.clientToServer(Unicopia.id("player_ability"), MsgPlayerAbility::read);
@ -39,7 +40,7 @@ public interface Channel {
race = Race.UNSET;
}
if (race.isUnset()) {
sender.sendPacket(SERVER_SELECT_TRIBE.id(), new MsgTribeSelect(Race.allPermitted(handler.player)).toBuffer());
sender.sendPacket(SERVER_SELECT_TRIBE.id(), new MsgTribeSelect(Race.allPermitted(handler.player), Text.translatable("gui.unicopia.tribe_selection.journey")).toBuffer());
} else {
pony.setSpecies(race);
Unicopia.LOGGER.info("Setting {}'s race to {} due to host setting", handler.player.getDisplayName().getString(), Race.REGISTRY.getId(race).toString());

View file

@ -8,19 +8,19 @@ import com.sollace.fabwork.api.packets.Packet;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.Text;
public record MsgTribeSelect (Set<Race> availableRaces) implements Packet<PlayerEntity> {
public record MsgTribeSelect (Set<Race> availableRaces, Text serverMessage) implements Packet<PlayerEntity> {
public MsgTribeSelect(PacketByteBuf buffer) {
this(new HashSet<>());
int len = buffer.readInt();
while (len-- > 0) {
availableRaces.add(buffer.readRegistryValue(Race.REGISTRY));
}
this(
buffer.readCollection(HashSet::new, buf -> buf.readRegistryValue(Race.REGISTRY)),
buffer.readText()
);
}
@Override
public void toBuffer(PacketByteBuf buffer) {
buffer.writeInt(availableRaces.size());
availableRaces.forEach(race -> buffer.writeRegistryValue(Race.REGISTRY, race));
buffer.writeCollection(availableRaces, (buf, race) -> buf.writeRegistryValue(Race.REGISTRY, race));
buffer.writeText(serverMessage);
}
}

View file

@ -1,5 +1,5 @@
package com.minelittlepony.unicopia.util;
public interface Copyable<T extends Copyable<T>> {
void copyFrom(T other);
void copyFrom(T other, boolean alive);
}

View file

@ -18,7 +18,7 @@ public class MagicalDamageSource extends EntityDamageSource {
public static final DamageSource EXHAUSTION = new MagicalDamageSource("magical_exhaustion", null, true, true);
public static final DamageSource ALICORN_AMULET = new MagicalDamageSource("alicorn_amulet", null, true, true);
public static final DamageSource FOOD_POISONING = new DamageSource("food_poisoning");
public static final DamageSource TRIBE_SWAP = new DamageSource("tribe_swap");
public static final DamageSource TRIBE_SWAP = new DamageSource("tribe_swap").setOutOfWorld().setUnblockable();
public static final DamageSource ZAP_APPLE = create("zap");
public static final DamageSource KICK = create("kick");
public static final DamageSource SUN = new DamageSource("sun").setBypassesArmor().setFire();

View file

@ -1,4 +1,6 @@
accessWidener v1 named
accessible class net/minecraft/client/render/RenderLayer$MultiPhaseParameters
accessible method net/minecraft/client/render/RenderLayer of (Ljava/lang/String;Lnet/minecraft/client/render/VertexFormat;Lnet/minecraft/client/render/VertexFormat$DrawMode;IZZLnet/minecraft/client/render/RenderLayer$MultiPhaseParameters;)Lnet/minecraft/client/render/RenderLayer$MultiPhase;
accessible class net/minecraft/client/render/item/HeldItemRenderer$HandRenderType
accessible method net/minecraft/client/render/RenderLayer of (Ljava/lang/String;Lnet/minecraft/client/render/VertexFormat;Lnet/minecraft/client/render/VertexFormat$DrawMode;IZZLnet/minecraft/client/render/RenderLayer$MultiPhaseParameters;)Lnet/minecraft/client/render/RenderLayer$MultiPhase;
accessible class net/minecraft/client/render/item/HeldItemRenderer$HandRenderType
accessible method net/minecraft/world/GameRules register (Ljava/lang/String;Lnet/minecraft/world/GameRules$Category;Lnet/minecraft/world/GameRules$Type;)Lnet/minecraft/world/GameRules$Key;
accessible method net/minecraft/world/GameRules$BooleanRule create (Z)Lnet/minecraft/world/GameRules$Type;