Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package at.petrak.hexcasting.api.casting.iota;

import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.samsthenerd.inline.api.InlineAPI;
Expand All @@ -21,23 +22,24 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.ref.WeakReference;
import java.util.Optional;
import java.util.UUID;

public class EntityIota extends Iota {
private final UUID entityId;
@Nullable
private final Component entityName;
private boolean isPlayer;

public EntityIota(@NotNull Entity e) {
this(e.getUUID(), getEntityNameWithInline(e));
this(e.getUUID(), getEntityNameWithInline(e), e instanceof Player);
}

public EntityIota(UUID entityId, @Nullable Component entityName) {
public EntityIota(UUID entityId, @Nullable Component entityName, boolean isPlayer) {
super(() -> HexIotaTypes.ENTITY);
this.entityId = entityId;
this.entityName = entityName;
this.isPlayer = isPlayer;
}

public UUID getEntityId() {
Expand All @@ -52,6 +54,10 @@ public Entity getEntity(ServerLevel level) {
return entityName;
}

public boolean isPlayer() {
return isPlayer;
}

@Override
public boolean toleratesOther(Iota that) {
return typesMatch(this, that)
Expand Down Expand Up @@ -93,18 +99,22 @@ private static Component getEntityNameWithInline(Entity entity) {
public static final MapCodec<EntityIota> CODEC = RecordCodecBuilder.mapCodec(inst ->
inst.group(
UUIDUtil.CODEC.fieldOf("entityId").forGetter(EntityIota::getEntityId),
ComponentSerialization.CODEC.optionalFieldOf("entityName").forGetter(iota -> Optional.ofNullable(iota.getEntityName()))
).apply(inst, (a, b) -> new EntityIota(a, b.orElse(null))));
ComponentSerialization.CODEC.optionalFieldOf("entityName").forGetter(iota -> Optional.ofNullable(iota.getEntityName())),
Codec.BOOL.fieldOf("isPlayer").orElse(true).forGetter(EntityIota::isPlayer)
).apply(inst, (a, b, c) -> new EntityIota(a, b.orElse(null), c)));
public static final StreamCodec<RegistryFriendlyByteBuf, EntityIota> STREAM_CODEC =
StreamCodec.composite(
UUIDUtil.STREAM_CODEC, EntityIota::getEntityId,
ByteBufCodecs.optional(ComponentSerialization.STREAM_CODEC), iota -> Optional.ofNullable(iota.getEntityName()),
(a, b) -> new EntityIota(a, b.orElse(null))
ByteBufCodecs.BOOL, EntityIota::isPlayer,
(a, b, c) -> new EntityIota(a, b.orElse(null), c)
);

@Override
public boolean validate(EntityIota iota, ServerLevel level) {
var entity = iota.getEntity(level);
// update isPlayer so older non-player entity iotas are not protected
iota.isPlayer = (entity instanceof Player);
return entity != null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,34 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.DyeColor

/**
* Also throwable for your *own* name, for cases like Chronicler's Gambit
* Also throwable for your *own* name, for cases like Chronicler's Gambit.
* confidant == null means the player is offline.
*/
class MishapOthersName(val confidant: Player) : Mishap() {
class MishapOthersName(val confidant: Player?) : Mishap() {
override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenPigment =
dyeColor(DyeColor.BLACK)

override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: TreeList<Iota>): TreeList<Iota> {
val seconds = if (this.confidant == ctx.castingEntity) 5 else 60
val seconds = if (this.confidant != null && this.confidant == ctx.castingEntity) 5 else 60
ctx.mishapEnvironment.blind(seconds * 20)
return stack
}

override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =
if (this.confidant == ctx.castingEntity)
error("others_name.self")
else
error("others_name", confidant.name)
when (this.confidant) {
null -> error("others_name.offline")
ctx.castingEntity -> error("others_name.self")
else -> error("others_name", confidant.name)
}

companion object {
/**
* Return any true names found in this iota.
* Returns a mishap if any true names are found in this iota.
*
* If `caster` is non-null, it will ignore that when checking.
*/
@JvmStatic
fun getTrueNameFromDatum(level: ServerLevel, datum: Iota, caster: Player?): Player? {
fun getTrueNameMishapFromDatum(level: ServerLevel, datum: Iota, caster: Player?): MishapOthersName? {
val poolToSearch = ArrayDeque<Iota>()
poolToSearch.addLast(datum)

Expand All @@ -44,8 +46,10 @@ class MishapOthersName(val confidant: Player) : Mishap() {

if(datumToCheck is EntityIota) {
val ent = datumToCheck.getEntity(level)
if (ent == null && datumToCheck.isPlayer)
return MishapOthersName(null)
if(ent is Player && ent != caster)
return ent
return MishapOthersName(ent)
}

val datumSubIotas = datumToCheck.subIotas()
Expand All @@ -57,8 +61,8 @@ class MishapOthersName(val confidant: Player) : Mishap() {
}

@JvmStatic
fun getTrueNameFromArgs(level: ServerLevel, datums: List<Iota>, caster: Player?): Player? {
return datums.firstNotNullOfOrNull { getTrueNameFromDatum(level, it, caster) }
fun getTrueNameMishapFromArgs(level: ServerLevel, datums: List<Iota>, caster: Player?): MishapOthersName? {
return datums.firstNotNullOfOrNull { getTrueNameMishapFromDatum(level, it, caster) }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ object OpAkashicWrite : SpellAction {
throw MishapNoAkashicRecord(pos)
}

val trueName = MishapOthersName.getTrueNameFromDatum(env.world, datum, env.castingEntity as? ServerPlayer)
if (trueName != null)
throw MishapOthersName(trueName)
val trueNameMishap = MishapOthersName.getTrueNameMishapFromDatum(env.world, datum, env.castingEntity as? ServerPlayer)
if (trueNameMishap != null)
throw trueNameMishap

return SpellAction.Result(
Spell(record, pos, key, datum),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ object OpTheCoolerWrite : SpellAction {

// We pass null here so that even the own caster won't be allowed into a focus.
// Otherwise, you could sentinel scout to people and remotely write their names into things using a cleric circle.
val trueName = MishapOthersName.getTrueNameFromDatum(env.world, datum, null)
if (trueName != null)
throw MishapOthersName(trueName)
val trueNameMishap = MishapOthersName.getTrueNameMishapFromDatum(env.world, datum, null)
if (trueNameMishap != null)
throw trueNameMishap

val burstPos = if (target is ItemEntity) {
// Special case these because the render is way above the entity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ object OpWrite : SpellAction {
if (!datumHolder.writeIota(datum, true))
throw MishapBadOffhandItem.of(handStack, "iota.readonly", datum.display())

val trueName = MishapOthersName.getTrueNameFromDatum(env.world, datum, env.castingEntity as? ServerPlayer)
if (trueName != null)
throw MishapOthersName(trueName)
val trueNameMishap = MishapOthersName.getTrueNameMishapFromDatum(env.world, datum, env.castingEntity as? ServerPlayer)
if (trueNameMishap != null)
throw trueNameMishap

return SpellAction.Result(
Spell(datum, datumHolder),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ class OpMakePackagedSpell(val isValid: Predicate<ItemStack>, val expectedTypeDes
)
}

val trueName = MishapOthersName.getTrueNameFromArgs(env.world, patterns, env.castingEntity as? ServerPlayer)
if (trueName != null)
throw MishapOthersName(trueName)
val trueNameMishap = MishapOthersName.getTrueNameMishapFromArgs(env.world, patterns, env.castingEntity as? ServerPlayer)
if (trueNameMishap != null)
throw trueNameMishap

return SpellAction.Result(
Spell(entity, patterns, handStack),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,7 @@
no_spell_circle: "requires a spell circle",
others_name: "Tried to invade the privacy of %s's soul",
"others_name.self": "Tried to divulge my Name too recklessly",
"others_name.offline": "Tried to invade the privacy of an absent player's soul",

divide_by_zero: {
divide: "Attempted to divide %s by %s",
Expand Down
Loading