Merge branch 'main' into fancy-lightning

This commit is contained in:
Alwinfy 2022-05-25 18:46:00 -04:00
commit 0a85f08877
No known key found for this signature in database
GPG key ID: 2CCB99445F0C949E
90 changed files with 2003 additions and 852 deletions

29
.github/workflows/build_docs.yml vendored Normal file
View file

@ -0,0 +1,29 @@
name: Build the Python doc-gen
on:
push:
branches: [main]
jobs:
build_docs:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v3
- name: Generate file
run: doc/collate_data.py Common/src/main/resources hexcasting thehexbook doc/template.html index.html.uncommitted
- name: Check out gh-pages
uses: actions/checkout@v3
with:
clean: false
ref: gh-pages
- name: Overwrite file and commmit
run: |
mv index.html.uncommitted index.html
git config user.name "Documentation Generation Bot"
git config user.email "noreply@github.com"
git add index.html
git diff-index --quiet HEAD || git commit -m "Update docs at index.html from $GITHUB_REF"
- name: Upload changes
run: git push

View file

@ -86,14 +86,14 @@ object PatternRegistry {
// when we try to look // when we try to look
for (handler in specialHandlers) { for (handler in specialHandlers) {
val op = handler.handler.handlePattern(pat) val op = handler.handler.handlePattern(pat)
if (op != null) return Pair(op, handler.id) if (op != null) return op to handler.id
} }
// Is it global? // Is it global?
val sig = pat.anglesSignature() val sig = pat.anglesSignature()
this.regularPatternLookup[sig]?.let { this.regularPatternLookup[sig]?.let {
val op = this.operatorLookup[it.opId] ?: throw MishapInvalidPattern() val op = this.operatorLookup[it.opId] ?: throw MishapInvalidPattern()
return Pair(op, it.opId) return op to it.opId
} }
// Look it up in the world? // Look it up in the world?
@ -102,7 +102,7 @@ object PatternRegistry {
ds.computeIfAbsent(Save.Companion::load, { Save.create(overworld.seed) }, TAG_SAVED_DATA) ds.computeIfAbsent(Save.Companion::load, { Save.create(overworld.seed) }, TAG_SAVED_DATA)
perWorldPatterns.lookup[sig]?.let { perWorldPatterns.lookup[sig]?.let {
val op = this.operatorLookup[it.first]!! val op = this.operatorLookup[it.first]!!
return Pair(op, it.first) return op to it.first
} }
throw MishapInvalidPattern() throw MishapInvalidPattern()
@ -129,7 +129,7 @@ object PatternRegistry {
} }
for ((sig, entry) in this.regularPatternLookup) { for ((sig, entry) in this.regularPatternLookup) {
if (entry.opId == opId) { if (entry.opId == opId) {
val pattern = HexPattern.FromAnglesSig(sig, entry.preferredStart) val pattern = HexPattern.fromAngles(sig, entry.preferredStart)
return PatternEntry(pattern, this.operatorLookup[entry.opId]!!, false) return PatternEntry(pattern, this.operatorLookup[entry.opId]!!, false)
} }
} }
@ -188,7 +188,7 @@ object PatternRegistry {
val entry = tag.getCompound(sig) val entry = tag.getCompound(sig)
val opId = ResourceLocation.tryParse(entry.getString(TAG_OP_ID))!! val opId = ResourceLocation.tryParse(entry.getString(TAG_OP_ID))!!
val startDir = HexDir.values()[entry.getInt(TAG_START_DIR)] val startDir = HexDir.values()[entry.getInt(TAG_START_DIR)]
map[sig] = Pair(opId, startDir) map[sig] = opId to startDir
} }
return Save(map) return Save(map)
} }
@ -199,7 +199,7 @@ object PatternRegistry {
for ((opId, entry) in PatternRegistry.perWorldPatternLookup) { for ((opId, entry) in PatternRegistry.perWorldPatternLookup) {
// waugh why doesn't kotlin recursively destructure things // waugh why doesn't kotlin recursively destructure things
val scrungled = EulerPathFinder.findAltDrawing(entry.prototype, seed) val scrungled = EulerPathFinder.findAltDrawing(entry.prototype, seed)
map[scrungled.anglesSignature()] = Pair(opId, scrungled.startDir) map[scrungled.anglesSignature()] = opId to scrungled.startDir
} }
val save = Save(map) val save = Save(map)
save.setDirty() save.setDirty()

View file

@ -13,7 +13,7 @@ public interface DataHolder {
default SpellDatum<?> readDatum(ServerLevel world) { default SpellDatum<?> readDatum(ServerLevel world) {
var tag = readRawDatum(); var tag = readRawDatum();
if (tag != null) { if (tag != null) {
return SpellDatum.DeserializeFromNBT(tag, world); return SpellDatum.fromNBT(tag, world);
} else { } else {
return null; return null;
} }

View file

@ -132,7 +132,7 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen
if (this.activator != null && this.colorizer != null && this.nextBlock != null && this.trackedBlocks != null) { if (this.activator != null && this.colorizer != null && this.nextBlock != null && this.trackedBlocks != null) {
tag.putUUID(TAG_ACTIVATOR, this.activator); tag.putUUID(TAG_ACTIVATOR, this.activator);
tag.put(TAG_NEXT_BLOCK, NbtUtils.writeBlockPos(this.nextBlock)); tag.put(TAG_NEXT_BLOCK, NbtUtils.writeBlockPos(this.nextBlock));
tag.put(TAG_COLORIZER, this.colorizer.serialize()); tag.put(TAG_COLORIZER, this.colorizer.serializeToNBT());
tag.putBoolean(TAG_FOUND_ALL, this.foundAll); tag.putBoolean(TAG_FOUND_ALL, this.foundAll);
var trackeds = new ListTag(); var trackeds = new ListTag();
@ -155,7 +155,7 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen
tag.contains(TAG_NEXT_BLOCK, Tag.TAG_COMPOUND) && tag.contains(TAG_NEXT_BLOCK, Tag.TAG_COMPOUND) &&
tag.contains(TAG_TRACKED_BLOCKS, Tag.TAG_LIST)) { tag.contains(TAG_TRACKED_BLOCKS, Tag.TAG_LIST)) {
this.activator = tag.getUUID(TAG_ACTIVATOR); this.activator = tag.getUUID(TAG_ACTIVATOR);
this.colorizer = FrozenColorizer.deserialize(tag.getCompound(TAG_COLORIZER)); this.colorizer = FrozenColorizer.fromNBT(tag.getCompound(TAG_COLORIZER));
this.nextBlock = NbtUtils.readBlockPos(tag.getCompound(TAG_NEXT_BLOCK)); this.nextBlock = NbtUtils.readBlockPos(tag.getCompound(TAG_NEXT_BLOCK));
this.foundAll = tag.getBoolean(TAG_FOUND_ALL); this.foundAll = tag.getBoolean(TAG_FOUND_ALL);
var trackeds = tag.getList(TAG_TRACKED_BLOCKS, Tag.TAG_COMPOUND); var trackeds = tag.getList(TAG_TRACKED_BLOCKS, Tag.TAG_COMPOUND);
@ -526,11 +526,6 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen
} }
} }
@Override
public void setChanged() {
this.sync();
}
@Override @Override
public boolean stillValid(Player player) { public boolean stillValid(Player player) {
return false; return false;

View file

@ -28,7 +28,7 @@ public interface DataHolderItem {
var tag = dh.readDatumTag(stack); var tag = dh.readDatumTag(stack);
if (tag != null) { if (tag != null) {
return SpellDatum.DeserializeFromNBT(tag, world); return SpellDatum.fromNBT(tag, world);
} else { } else {
return null; return null;
} }
@ -47,7 +47,7 @@ public interface DataHolderItem {
TooltipFlag pIsAdvanced) { TooltipFlag pIsAdvanced) {
var datumTag = self.readDatumTag(pStack); var datumTag = self.readDatumTag(pStack);
if (datumTag != null) { if (datumTag != null) {
var component = SpellDatum.DisplayFromTag(datumTag); var component = SpellDatum.displayFromNBT(datumTag);
pTooltipComponents.add(new TranslatableComponent("hexcasting.spelldata.onitem", component)); pTooltipComponents.add(new TranslatableComponent("hexcasting.spelldata.onitem", component));
if (pIsAdvanced.isAdvanced()) { if (pIsAdvanced.isAdvanced()) {

View file

@ -29,14 +29,14 @@ public record FrozenColorizer(ItemStack item, UUID owner) {
public static final Supplier<FrozenColorizer> DEFAULT = public static final Supplier<FrozenColorizer> DEFAULT =
() -> new FrozenColorizer(new ItemStack(HexItems.DYE_COLORIZERS.get(DyeColor.WHITE)), Util.NIL_UUID); () -> new FrozenColorizer(new ItemStack(HexItems.DYE_COLORIZERS.get(DyeColor.WHITE)), Util.NIL_UUID);
public CompoundTag serialize() { public CompoundTag serializeToNBT() {
var out = new CompoundTag(); var out = new CompoundTag();
out.put(TAG_STACK, HexUtils.serialize(this.item)); out.put(TAG_STACK, HexUtils.serializeToNBT(this.item));
out.putUUID(TAG_OWNER, this.owner); out.putUUID(TAG_OWNER, this.owner);
return out; return out;
} }
public static FrozenColorizer deserialize(CompoundTag tag) { public static FrozenColorizer fromNBT(CompoundTag tag) {
if (tag.isEmpty()) { if (tag.isEmpty()) {
return FrozenColorizer.DEFAULT.get(); return FrozenColorizer.DEFAULT.get();
} }

View file

@ -12,7 +12,7 @@ import net.minecraft.world.entity.Entity
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
import kotlin.math.abs import kotlin.math.abs
fun GetNumOrVec(datum: SpellDatum<*>, reverseIdx: Int): Either<Double, Vec3> = fun numOrVec(datum: SpellDatum<*>, reverseIdx: Int): Either<Double, Vec3> =
when (datum.payload) { when (datum.payload) {
is Double -> Either.left(datum.payload) is Double -> Either.left(datum.payload)
is Vec3 -> Either.right(datum.payload) is Vec3 -> Either.right(datum.payload)
@ -23,7 +23,7 @@ fun GetNumOrVec(datum: SpellDatum<*>, reverseIdx: Int): Either<Double, Vec3> =
) )
} }
fun GetNumOrList(datum: SpellDatum<*>, reverseIdx: Int): Either<Double, SpellList> = fun numOrList(datum: SpellDatum<*>, reverseIdx: Int): Either<Double, SpellList> =
when (datum.payload) { when (datum.payload) {
is Double -> Either.left(datum.payload) is Double -> Either.left(datum.payload)
is SpellList -> Either.right(datum.payload) is SpellList -> Either.right(datum.payload)

View file

@ -9,12 +9,12 @@ import net.minecraft.world.phys.Vec3
data class ParticleSpray(val pos: Vec3, val vel: Vec3, val fuzziness: Double, val spread: Double, val count: Int = 20) { data class ParticleSpray(val pos: Vec3, val vel: Vec3, val fuzziness: Double, val spread: Double, val count: Int = 20) {
companion object { companion object {
@JvmStatic @JvmStatic
fun Burst(pos: Vec3, size: Double, count: Int = 20): ParticleSpray { fun burst(pos: Vec3, size: Double, count: Int = 20): ParticleSpray {
return ParticleSpray(pos, Vec3(size, 0.0, 0.0), 0.0, 3.14, count) return ParticleSpray(pos, Vec3(size, 0.0, 0.0), 0.0, 3.14, count)
} }
@JvmStatic @JvmStatic
fun Cloud(pos: Vec3, size: Double, count: Int = 20): ParticleSpray { fun cloud(pos: Vec3, size: Double, count: Int = 20): ParticleSpray {
return ParticleSpray(pos, Vec3(0.0, 0.001, 0.0), size, 0.0, count) return ParticleSpray(pos, Vec3(0.0, 0.001, 0.0), size, 0.0, count)
} }
} }

View file

@ -3,11 +3,11 @@ package at.petrak.hexcasting.api.spell
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.math.HexPattern import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidSpellDatumType import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidSpellDatumType
import at.petrak.hexcasting.api.utils.HexUtils import at.petrak.hexcasting.api.utils.*
import at.petrak.hexcasting.api.utils.HexUtils.serializeToNBT
import at.petrak.hexcasting.api.utils.getList
import net.minecraft.ChatFormatting import net.minecraft.ChatFormatting
import net.minecraft.nbt.* import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.NbtUtils
import net.minecraft.nbt.Tag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TextComponent import net.minecraft.network.chat.TextComponent
import net.minecraft.network.chat.TranslatableComponent import net.minecraft.network.chat.TranslatableComponent
@ -22,7 +22,7 @@ import java.util.*
* We use the following types: * We use the following types:
* * [Entity] * * [Entity]
* * [Double] * * [Double]
* * [Vec3][net.minecraft.world.phys.Vec3] as both position and (when normalized) direction * * [Vec3] as both position and (when normalized) direction
* * [Widget]; [Widget.NULL] is used as our null value * * [Widget]; [Widget.NULL] is used as our null value
* * [SpellList] * * [SpellList]
* * [HexPattern]! Yes, we have meta-evaluation everyone. * * [HexPattern]! Yes, we have meta-evaluation everyone.
@ -33,39 +33,19 @@ import java.util.*
class SpellDatum<T : Any> private constructor(val payload: T) { class SpellDatum<T : Any> private constructor(val payload: T) {
val clazz: Class<T> = payload.javaClass val clazz: Class<T> = payload.javaClass
fun serializeToNBT(): CompoundTag { fun serializeToNBT() = NBTBuilder {
val out = CompoundTag() when (val pl = payload) {
when (val pl = this.payload) { is Entity -> TAG_ENTITY %= compound {
is Entity -> { TAG_ENTITY_UUID %= NbtUtils.createUUID(pl.uuid)
val subtag = CompoundTag() TAG_ENTITY_NAME_CHEATY %= Component.Serializer.toJson(pl.displayName)
subtag.put(TAG_ENTITY_UUID, NbtUtils.createUUID(pl.uuid))
// waayyghg
val json = Component.Serializer.toJson(pl.displayName)
subtag.putString(TAG_ENTITY_NAME_CHEATY, json)
out.put(TAG_ENTITY, subtag)
}
is Double -> out.put(
TAG_DOUBLE, DoubleTag.valueOf(pl)
)
is Vec3 -> out.put(
TAG_VEC3, pl.serializeToNBT()
)
is SpellList -> {
val subtag = ListTag()
for (elt in pl)
subtag.add(elt.serializeToNBT())
out.put(TAG_LIST, subtag)
}
is Widget -> {
out.putString(TAG_WIDGET, pl.name)
}
is HexPattern -> {
out.put(TAG_PATTERN, pl.serializeToNBT())
} }
is Double -> TAG_DOUBLE %= pl
is Vec3 -> TAG_VEC3 %= pl.serializeToNBT()
is SpellList -> TAG_LIST %= pl.serializeToNBT()
is Widget -> TAG_WIDGET %= pl.name
is HexPattern -> TAG_PATTERN %= pl.serializeToNBT()
else -> throw RuntimeException("cannot serialize $pl because it is of type ${pl.javaClass.canonicalName} which is not serializable") else -> throw RuntimeException("cannot serialize $pl because it is of type ${pl.javaClass.canonicalName} which is not serializable")
} }
return out
} }
override fun toString(): String = override fun toString(): String =
@ -85,7 +65,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
fun display(): Component { fun display(): Component {
val nbt = this.serializeToNBT() val nbt = this.serializeToNBT()
return DisplayFromTag(nbt) return displayFromNBT(nbt)
} }
fun getType(): DatumType = fun getType(): DatumType =
@ -101,6 +81,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
companion object { companion object {
@JvmStatic @JvmStatic
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
fun make(payload: Any): SpellDatum<*> = fun make(payload: Any): SpellDatum<*> =
if (payload is SpellDatum<*>) { if (payload is SpellDatum<*>) {
payload payload
@ -114,23 +95,23 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
} else if (payload is Vec3) { } else if (payload is Vec3) {
SpellDatum( SpellDatum(
Vec3( Vec3(
HexUtils.FixNANs(payload.x), fixNAN(payload.x),
HexUtils.FixNANs(payload.y), fixNAN(payload.y),
HexUtils.FixNANs(payload.z), fixNAN(payload.z),
) )
) )
} else if (IsValidType(payload)) { } else if (isValidType(payload)) {
SpellDatum(payload) SpellDatum(payload)
} else if (payload is java.lang.Double) { } else if (payload is java.lang.Double) {
// Check to see if it's a java *boxed* double, for when we call this from Java // Check to see if it's a java *boxed* double, for when we call this from Java
val num = payload.toDouble() val num = payload.toDouble()
SpellDatum(HexUtils.FixNANs(num)) SpellDatum(fixNAN(num))
} else { } else {
throw MishapInvalidSpellDatumType(payload) throw MishapInvalidSpellDatumType(payload)
} }
@JvmStatic @JvmStatic
fun DeserializeFromNBT(nbt: CompoundTag, world: ServerLevel): SpellDatum<*> { fun fromNBT(nbt: CompoundTag, world: ServerLevel): SpellDatum<*> {
val keys = nbt.allKeys val keys = nbt.allKeys
if (keys.size != 1) if (keys.size != 1)
throw IllegalArgumentException("Expected exactly one kv pair: $nbt") throw IllegalArgumentException("Expected exactly one kv pair: $nbt")
@ -144,21 +125,15 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
SpellDatum(if (entity == null || !entity.isAlive) Widget.NULL else entity) SpellDatum(if (entity == null || !entity.isAlive) Widget.NULL else entity)
} }
TAG_DOUBLE -> SpellDatum(nbt.getDouble(key)) TAG_DOUBLE -> SpellDatum(nbt.getDouble(key))
TAG_VEC3 -> SpellDatum(HexUtils.DeserializeVec3FromNBT(nbt.getLongArray(key))) TAG_VEC3 -> SpellDatum(vecFromNBT(nbt.getLongArray(key)))
TAG_LIST -> { TAG_LIST -> {
val arr = nbt.getList(key, Tag.TAG_COMPOUND) SpellDatum(SpellList.fromNBT(nbt.getList(key, Tag.TAG_COMPOUND), world))
val out = ArrayList<SpellDatum<*>>(arr.size)
for (subtag in arr) {
// this is safe because otherwise we wouldn't have been able to get the list before
out.add(DeserializeFromNBT(subtag as CompoundTag, world))
}
SpellDatum(SpellList.LList(0, out))
} }
TAG_WIDGET -> { TAG_WIDGET -> {
SpellDatum(Widget.valueOf(nbt.getString(key))) SpellDatum(Widget.valueOf(nbt.getString(key)))
} }
TAG_PATTERN -> { TAG_PATTERN -> {
SpellDatum(HexPattern.DeserializeFromNBT(nbt.getCompound(TAG_PATTERN))) SpellDatum(HexPattern.fromNBT(nbt.getCompound(TAG_PATTERN)))
} }
else -> throw IllegalArgumentException("Unknown key $key: $nbt") else -> throw IllegalArgumentException("Unknown key $key: $nbt")
} }
@ -171,11 +146,11 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
) )
) )
@JvmStatic @JvmStatic
fun DeserializeFromNBT(nbt: CompoundTag, ctx: CastingContext): SpellDatum<*> = fun fromNBT(nbt: CompoundTag, ctx: CastingContext): SpellDatum<*> =
DeserializeFromNBT(nbt, ctx.world) fromNBT(nbt, ctx.world)
@JvmStatic @JvmStatic
fun DisplayFromTag(nbt: CompoundTag): Component { fun displayFromNBT(nbt: CompoundTag): Component {
val keys = nbt.allKeys val keys = nbt.allKeys
if (keys.size != 1) if (keys.size != 1)
throw IllegalArgumentException("Expected exactly one kv pair: $nbt") throw IllegalArgumentException("Expected exactly one kv pair: $nbt")
@ -188,7 +163,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
) )
).withStyle(ChatFormatting.GREEN) ).withStyle(ChatFormatting.GREEN)
TAG_VEC3 -> { TAG_VEC3 -> {
val vec = HexUtils.DeserializeVec3FromNBT(nbt.getLongArray(key)) val vec = vecFromNBT(nbt.getLongArray(key))
// the focus color is really more red, but we don't want to show an error-y color // the focus color is really more red, but we don't want to show an error-y color
TextComponent( TextComponent(
String.format( String.format(
@ -205,7 +180,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
val arr = nbt.getList(key, Tag.TAG_COMPOUND) val arr = nbt.getList(key, Tag.TAG_COMPOUND)
for ((i, subtag) in arr.withIndex()) { for ((i, subtag) in arr.withIndex()) {
// this is safe because otherwise we wouldn't have been able to get the list before // this is safe because otherwise we wouldn't have been able to get the list before
out.append(DisplayFromTag(subtag as CompoundTag)) out.append(displayFromNBT(subtag as CompoundTag))
if (i != arr.lastIndex) { if (i != arr.lastIndex) {
out.append(", ") out.append(", ")
} }
@ -223,7 +198,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
else TextComponent(widget.toString()).withStyle(ChatFormatting.DARK_PURPLE) else TextComponent(widget.toString()).withStyle(ChatFormatting.DARK_PURPLE)
} }
TAG_PATTERN -> { TAG_PATTERN -> {
val pat = HexPattern.DeserializeFromNBT(nbt.getCompound(TAG_PATTERN)) val pat = HexPattern.fromNBT(nbt.getCompound(TAG_PATTERN))
var angleDesc = pat.anglesSignature() var angleDesc = pat.anglesSignature()
if (angleDesc.isNotBlank()) angleDesc = " $angleDesc"; if (angleDesc.isNotBlank()) angleDesc = " $angleDesc";
val out = TextComponent("HexPattern(").withStyle(ChatFormatting.GOLD) val out = TextComponent("HexPattern(").withStyle(ChatFormatting.GOLD)
@ -267,11 +242,11 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
// Also encode the entity's name as a component for the benefit of the client // Also encode the entity's name as a component for the benefit of the client
const val TAG_ENTITY_NAME_CHEATY = "name" const val TAG_ENTITY_NAME_CHEATY = "name"
fun <T : Any> IsValidType(checkee: T): Boolean = fun <T : Any> isValidType(checkee: T): Boolean =
ValidTypes.any { clazz -> clazz.isAssignableFrom(checkee.javaClass) } ValidTypes.any { clazz -> clazz.isAssignableFrom(checkee.javaClass) }
@JvmStatic @JvmStatic
fun GetTagName(datumType: DatumType): String { fun tagForType(datumType: DatumType): String {
return when (datumType) { return when (datumType) {
DatumType.ENTITY -> TAG_ENTITY DatumType.ENTITY -> TAG_ENTITY
DatumType.WIDGET -> TAG_WIDGET DatumType.WIDGET -> TAG_WIDGET

View file

@ -1,5 +1,9 @@
package at.petrak.hexcasting.api.spell package at.petrak.hexcasting.api.spell
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.server.level.ServerLevel
/** /**
* Restricted interface for functional lists. * Restricted interface for functional lists.
* *
@ -73,4 +77,16 @@ sealed class SpellList: Iterable<SpellDatum<*>> {
return car return car
} }
} }
companion object {
@JvmStatic
fun fromNBT(nbt: ListTag, world: ServerLevel): LList {
val out = ArrayList<SpellDatum<*>>(nbt.size)
for (subtag in nbt) {
// this is safe because otherwise we wouldn't have been able to get the list before
out.add(SpellDatum.fromNBT(subtag as CompoundTag, world))
}
return LList(0, out)
}
}
} }

View file

@ -6,7 +6,7 @@ import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.api.spell.mishaps.MishapEntityTooFarAway import at.petrak.hexcasting.api.spell.mishaps.MishapEntityTooFarAway
import at.petrak.hexcasting.api.spell.mishaps.MishapEvalTooDeep import at.petrak.hexcasting.api.spell.mishaps.MishapEvalTooDeep
import at.petrak.hexcasting.api.spell.mishaps.MishapLocationTooFarAway import at.petrak.hexcasting.api.spell.mishaps.MishapLocationTooFarAway
import at.petrak.hexcasting.api.utils.HexUtils import at.petrak.hexcasting.api.utils.otherHand
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerLevel
@ -33,7 +33,7 @@ data class CastingContext(
private var depth: Int = 0 private var depth: Int = 0
val world: ServerLevel get() = caster.getLevel() val world: ServerLevel get() = caster.getLevel()
val otherHand: InteractionHand get() = HexUtils.OtherHand(this.castingHand) val otherHand: InteractionHand get() = otherHand(this.castingHand)
val position: Vec3 get() = caster.position() val position: Vec3 get() = caster.position()
private val entitiesGivenMotion = mutableSetOf<Entity>() private val entitiesGivenMotion = mutableSetOf<Entity>()

View file

@ -12,12 +12,9 @@ import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.math.HexDir import at.petrak.hexcasting.api.spell.math.HexDir
import at.petrak.hexcasting.api.spell.math.HexPattern import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.spell.mishaps.* import at.petrak.hexcasting.api.spell.mishaps.*
import at.petrak.hexcasting.api.utils.ManaHelper import at.petrak.hexcasting.api.utils.*
import at.petrak.hexcasting.api.utils.asCompound
import at.petrak.hexcasting.api.utils.getList
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
@ -57,7 +54,7 @@ class CastingHarness private constructor(
// Initialize the continuation stack to a single top-level eval for all iotas. // Initialize the continuation stack to a single top-level eval for all iotas.
var continuation = SpellContinuation.Done.pushFrame(ContinuationFrame.Evaluate(SpellList.LList(0, iotas))) var continuation = SpellContinuation.Done.pushFrame(ContinuationFrame.Evaluate(SpellList.LList(0, iotas)))
// Begin aggregating info // Begin aggregating info
val info = TempControllerInfo(false, false) val info = TempControllerInfo(playSound = false, earlyExit = false)
var lastResolutionType = ResolvedPatternType.UNRESOLVED var lastResolutionType = ResolvedPatternType.UNRESOLVED
while (continuation is SpellContinuation.NotDone && !info.earlyExit) { while (continuation is SpellContinuation.NotDone && !info.earlyExit) {
// Take the top of the continuation stack... // Take the top of the continuation stack...
@ -388,10 +385,10 @@ class CastingHarness private constructor(
} }
if (casterStack.`is`(HexItemTags.WANDS) || ipsCanDrawFromInv) { if (casterStack.`is`(HexItemTags.WANDS) || ipsCanDrawFromInv) {
val manableItems = this.ctx.caster.inventory.items val manableItems = this.ctx.caster.inventory.items
.filter(ManaHelper::isManaItem) .filter(::isManaItem)
.sortedWith(Comparator(ManaHelper::compare).reversed()) .sortedWith(Comparator(::compareManaItem).reversed())
for (stack in manableItems) { for (stack in manableItems) {
costLeft -= ManaHelper.extractMana(stack, costLeft) costLeft -= extractMana(stack, costLeft)
if (costLeft <= 0) if (costLeft <= 0)
break break
} }
@ -431,29 +428,17 @@ class CastingHarness private constructor(
} }
fun serializeToNBT(): CompoundTag { fun serializeToNBT() = NBTBuilder {
val out = CompoundTag() TAG_STACK %= stack.serializeToNBT()
val stackTag = ListTag() TAG_LOCAL %= localIota.serializeToNBT()
for (datum in this.stack) TAG_PAREN_COUNT %= parenCount
stackTag.add(datum.serializeToNBT()) TAG_ESCAPE_NEXT %= escapeNext
out.put(TAG_STACK, stackTag)
out.put(TAG_LOCAL, localIota.serializeToNBT()) TAG_PARENTHESIZED %= parenthesized.serializeToNBT()
out.putInt(TAG_PAREN_COUNT, this.parenCount) if (prepackagedColorizer != null)
out.putBoolean(TAG_ESCAPE_NEXT, this.escapeNext) TAG_PREPACKAGED_COLORIZER %= prepackagedColorizer.serializeToNBT()
val parensTag = ListTag()
for (pat in this.parenthesized)
parensTag.add(pat.serializeToNBT())
out.put(TAG_PARENTHESIZED, parensTag)
if (this.prepackagedColorizer != null) {
out.put(TAG_PREPACKAGED_COLORIZER, this.prepackagedColorizer.serialize())
}
return out
} }
@ -466,18 +451,18 @@ class CastingHarness private constructor(
const val TAG_PREPACKAGED_COLORIZER = "prepackaged_colorizer" const val TAG_PREPACKAGED_COLORIZER = "prepackaged_colorizer"
@JvmStatic @JvmStatic
fun DeserializeFromNBT(nbt: CompoundTag, ctx: CastingContext): CastingHarness { fun fromNBT(nbt: CompoundTag, ctx: CastingContext): CastingHarness {
return try { return try {
val stack = mutableListOf<SpellDatum<*>>() val stack = mutableListOf<SpellDatum<*>>()
val stackTag = nbt.getList(TAG_STACK, Tag.TAG_COMPOUND) val stackTag = nbt.getList(TAG_STACK, Tag.TAG_COMPOUND)
for (subtag in stackTag) { for (subtag in stackTag) {
val datum = SpellDatum.DeserializeFromNBT(subtag.asCompound, ctx.world) val datum = SpellDatum.fromNBT(subtag.asCompound, ctx.world)
stack.add(datum) stack.add(datum)
} }
val localTag = nbt.getCompound(TAG_LOCAL) val localTag = nbt.getCompound(TAG_LOCAL)
val localIota = val localIota =
if (localTag.size() == 1) SpellDatum.DeserializeFromNBT(localTag, ctx.world) else SpellDatum.make( if (localTag.size() == 1) SpellDatum.fromNBT(localTag, ctx.world) else SpellDatum.make(
Widget.NULL Widget.NULL
) )
@ -485,16 +470,16 @@ class CastingHarness private constructor(
val parenTag = nbt.getList(TAG_PARENTHESIZED, Tag.TAG_COMPOUND) val parenTag = nbt.getList(TAG_PARENTHESIZED, Tag.TAG_COMPOUND)
for (subtag in parenTag) { for (subtag in parenTag) {
if (subtag.asCompound.size() != 1) if (subtag.asCompound.size() != 1)
parenthesized.add(SpellDatum.make(HexPattern.DeserializeFromNBT(subtag.asCompound))) parenthesized.add(SpellDatum.make(HexPattern.fromNBT(subtag.asCompound)))
else else
parenthesized.add(SpellDatum.DeserializeFromNBT(subtag.asCompound, ctx.world)) parenthesized.add(SpellDatum.fromNBT(subtag.asCompound, ctx.world))
} }
val parenCount = nbt.getInt(TAG_PAREN_COUNT) val parenCount = nbt.getInt(TAG_PAREN_COUNT)
val escapeNext = nbt.getBoolean(TAG_ESCAPE_NEXT) val escapeNext = nbt.getBoolean(TAG_ESCAPE_NEXT)
val colorizer = if (nbt.contains(TAG_PREPACKAGED_COLORIZER)) { val colorizer = if (nbt.contains(TAG_PREPACKAGED_COLORIZER)) {
FrozenColorizer.deserialize(nbt.getCompound(TAG_PREPACKAGED_COLORIZER)) FrozenColorizer.fromNBT(nbt.getCompound(TAG_PREPACKAGED_COLORIZER))
} else { } else {
null null
} }

View file

@ -3,6 +3,12 @@ package at.petrak.hexcasting.api.spell.casting
import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingHarness.CastResult import at.petrak.hexcasting.api.spell.casting.CastingHarness.CastResult
import at.petrak.hexcasting.api.utils.NBTBuilder
import at.petrak.hexcasting.api.utils.getList
import at.petrak.hexcasting.api.utils.hasList
import at.petrak.hexcasting.api.utils.serializeToNBT
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerLevel
/** /**
@ -32,13 +38,18 @@ sealed interface ContinuationFrame {
*/ */
fun breakDownwards(stack: List<SpellDatum<*>>): Pair<Boolean, List<SpellDatum<*>>> fun breakDownwards(stack: List<SpellDatum<*>>): Pair<Boolean, List<SpellDatum<*>>>
/**
* Serializes this frame. Used for things like delays, where we pause execution.
*/
fun serializeToNBT(): CompoundTag
/** /**
* A list of patterns to be evaluated in sequence. * A list of patterns to be evaluated in sequence.
* @property list the *remaining* list of patterns to be evaluated * @property list the *remaining* list of patterns to be evaluated
*/ */
data class Evaluate(val list: SpellList) : ContinuationFrame { data class Evaluate(val list: SpellList) : ContinuationFrame {
// Discard this frame and keep discarding frames. // Discard this frame and keep discarding frames.
override fun breakDownwards(stack: List<SpellDatum<*>>) = Pair(false, stack) override fun breakDownwards(stack: List<SpellDatum<*>>) = false to stack
// Step the list of patterns, evaluating a single one. // Step the list of patterns, evaluating a single one.
override fun evaluate( override fun evaluate(
@ -60,15 +71,19 @@ sealed interface ContinuationFrame {
} }
} }
override fun serializeToNBT() = NBTBuilder {
"type" %= "evaluate"
"patterns" %= list.serializeToNBT()
}
} }
/** /**
* A stack marker representing the end of a Hermes evaluation, * A stack marker representing the end of a Hermes evaluation,
* so that we know when to stop removing frames during a Halt. * so that we know when to stop removing frames during a Halt.
*/ */
class FinishEval() : ContinuationFrame { object FinishEval : ContinuationFrame {
// Don't do anything else to the stack, just finish the halt statement. // Don't do anything else to the stack, just finish the halt statement.
override fun breakDownwards(stack: List<SpellDatum<*>>) = Pair(true, stack) override fun breakDownwards(stack: List<SpellDatum<*>>) = true to stack
// Evaluating it does nothing; it's only a boundary condition. // Evaluating it does nothing; it's only a boundary condition.
override fun evaluate( override fun evaluate(
@ -83,6 +98,10 @@ sealed interface ContinuationFrame {
listOf() listOf()
) )
} }
override fun serializeToNBT() = NBTBuilder {
"type" %= "end"
}
} }
/** /**
@ -103,10 +122,10 @@ sealed interface ContinuationFrame {
/** When halting, we add the stack state at halt to the stack accumulator, then return the original pre-Thoth stack, plus the accumulator. */ /** When halting, we add the stack state at halt to the stack accumulator, then return the original pre-Thoth stack, plus the accumulator. */
override fun breakDownwards(stack: List<SpellDatum<*>>): Pair<Boolean, List<SpellDatum<*>>> { override fun breakDownwards(stack: List<SpellDatum<*>>): Pair<Boolean, List<SpellDatum<*>>> {
val newStack = baseStack!!.toMutableList() val newStack = baseStack?.toMutableList() ?: mutableListOf()
acc.addAll(stack) acc.addAll(stack)
newStack.add(SpellDatum.make(acc)) newStack.add(SpellDatum.make(acc))
return Pair(true, newStack) return true to newStack
} }
/** Step the Thoth computation, enqueueing one code evaluation. */ /** Step the Thoth computation, enqueueing one code evaluation. */
@ -127,17 +146,15 @@ sealed interface ContinuationFrame {
// If we still have data to process... // If we still have data to process...
val (stackTop, newCont) = if (data.nonEmpty) { val (stackTop, newCont) = if (data.nonEmpty) {
Pair( // Push the next datum to the top of the stack,
data.car, // Push the next datum to the top of the stack, data.car to continuation
continuation // put the next Thoth object back on the stack for the next Thoth cycle,
// put the next Thoth object back on the stack for the next Thoth cycle, .pushFrame(ForEach(data.cdr, code, stack, acc))
.pushFrame(ForEach(data.cdr, code, stack, acc)) // and prep the Thoth'd code block for evaluation.
// and prep the Thoth'd code block for evaluation. .pushFrame(Evaluate(code))
.pushFrame(Evaluate(code))
)
} else { } else {
// Else, dump our final list onto the stack. // Else, dump our final list onto the stack.
Pair(SpellDatum.make(acc), continuation) SpellDatum.make(acc) to continuation
} }
val tStack = stack.toMutableList() val tStack = stack.toMutableList()
tStack.add(stackTop) tStack.add(stackTop)
@ -148,5 +165,31 @@ sealed interface ContinuationFrame {
listOf() listOf()
) )
} }
override fun serializeToNBT() = NBTBuilder {
"type" %= "foreach"
"data" %= data.serializeToNBT()
"code" %= code.serializeToNBT()
if (baseStack != null)
"base" %= baseStack.serializeToNBT()
"accumulator" %= acc.serializeToNBT()
}
}
companion object {
@JvmStatic
fun fromNBT(tag: CompoundTag, world: ServerLevel): ContinuationFrame {
return when (tag.getString("type")) {
"eval" -> Evaluate(SpellList.fromNBT(tag.getList("patterns", Tag.TAG_COMPOUND), world))
"end" -> FinishEval
"foreach" -> ForEach(
SpellList.fromNBT(tag.getList("data", Tag.TAG_COMPOUND), world),
SpellList.fromNBT(tag.getList("code", Tag.TAG_COMPOUND), world),
if (tag.hasList("base", Tag.TAG_COMPOUND)) SpellList.fromNBT(tag.getList("base", Tag.TAG_COMPOUND), world).toList() else null,
SpellList.fromNBT(tag.getList("accumulator", Tag.TAG_COMPOUND), world).toMutableList()
)
else -> Evaluate(SpellList.LList(0, listOf()));
}
}
} }
} }

View file

@ -4,8 +4,6 @@ import at.petrak.hexcasting.api.spell.SpellDatum
/** /**
* A change to the data in a CastHarness after a pattern is drawn. * A change to the data in a CastHarness after a pattern is drawn.
*
* [wasThisPatternInvalid] is for the benefit of the controller.
*/ */
data class FunctionalData( data class FunctionalData(
val stack: List<SpellDatum<*>>, val stack: List<SpellDatum<*>>,

View file

@ -2,24 +2,23 @@ package at.petrak.hexcasting.api.spell.casting
import at.petrak.hexcasting.api.spell.math.HexCoord import at.petrak.hexcasting.api.spell.math.HexCoord
import at.petrak.hexcasting.api.spell.math.HexPattern import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.utils.NBTBuilder
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import java.util.* import java.util.*
data class ResolvedPattern(val pattern: HexPattern, val origin: HexCoord, var type: ResolvedPatternType) { data class ResolvedPattern(val pattern: HexPattern, val origin: HexCoord, var type: ResolvedPatternType) {
fun serializeToNBT(): CompoundTag { fun serializeToNBT() = NBTBuilder {
val tag = CompoundTag() "Pattern" %= pattern.serializeToNBT()
tag.put("Pattern", pattern.serializeToNBT()) "OriginQ" %= origin.q
tag.putInt("OriginQ", origin.q) "OriginR" %= origin.r
tag.putInt("OriginR", origin.r) "Valid" %= type.name.lowercase(Locale.ROOT)
tag.putString("Valid", type.name.lowercase(Locale.ROOT))
return tag
} }
companion object { companion object {
@JvmStatic @JvmStatic
fun DeserializeFromNBT(tag: CompoundTag): ResolvedPattern { fun fromNBT(tag: CompoundTag): ResolvedPattern {
val pattern = HexPattern.DeserializeFromNBT(tag.getCompound("Pattern")) val pattern = HexPattern.fromNBT(tag.getCompound("Pattern"))
val origin = HexCoord(tag.getInt("OriginQ"), tag.getInt("OriginR")) val origin = HexCoord(tag.getInt("OriginQ"), tag.getInt("OriginR"))
val valid = try { val valid = try {
ResolvedPatternType.valueOf(tag.getString("Valid").uppercase(Locale.ROOT)) ResolvedPatternType.valueOf(tag.getString("Valid").uppercase(Locale.ROOT))

View file

@ -1,5 +1,6 @@
package at.petrak.hexcasting.api.spell.casting package at.petrak.hexcasting.api.spell.casting
import at.petrak.hexcasting.api.utils.NBTBuilder
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.world.phys.AABB import net.minecraft.world.phys.AABB
@ -8,23 +9,19 @@ import net.minecraft.world.phys.AABB
* Optional field on a [CastingContext] for the spell circle * Optional field on a [CastingContext] for the spell circle
*/ */
data class SpellCircleContext(val impetusPos: BlockPos, val aabb: AABB, val activatorAlwaysInRange: Boolean) { data class SpellCircleContext(val impetusPos: BlockPos, val aabb: AABB, val activatorAlwaysInRange: Boolean) {
fun serializeToNBT(): CompoundTag { fun serializeToNBT() = NBTBuilder {
val out = CompoundTag() TAG_IMPETUS_X %= impetusPos.x
TAG_IMPETUS_Y %= impetusPos.y
TAG_IMPETUS_Z %= impetusPos.z
out.putInt(TAG_IMPETUS_X, impetusPos.x) TAG_MIN_X %= aabb.minX
out.putInt(TAG_IMPETUS_Y, impetusPos.y) TAG_MIN_Y %= aabb.minY
out.putInt(TAG_IMPETUS_Z, impetusPos.z) TAG_MIN_Z %= aabb.minZ
TAG_MAX_X %= aabb.maxX
TAG_MAX_Y %= aabb.maxY
TAG_MAX_Z %= aabb.maxZ
out.putDouble(TAG_MIN_X, aabb.minX) TAG_PLAYER_ALWAYS_IN_RANGE %= activatorAlwaysInRange
out.putDouble(TAG_MIN_Y, aabb.minY)
out.putDouble(TAG_MIN_Z, aabb.minZ)
out.putDouble(TAG_MAX_X, aabb.maxX)
out.putDouble(TAG_MAX_Y, aabb.maxY)
out.putDouble(TAG_MAX_Z, aabb.maxZ)
out.putBoolean(TAG_PLAYER_ALWAYS_IN_RANGE, activatorAlwaysInRange)
return out
} }
companion object { companion object {
@ -39,7 +36,7 @@ data class SpellCircleContext(val impetusPos: BlockPos, val aabb: AABB, val acti
const val TAG_MAX_Z = "max_z" const val TAG_MAX_Z = "max_z"
const val TAG_PLAYER_ALWAYS_IN_RANGE = "player_always_in_range" const val TAG_PLAYER_ALWAYS_IN_RANGE = "player_always_in_range"
fun DeserializeFromNBT(tag: CompoundTag): SpellCircleContext { fun fromNBT(tag: CompoundTag): SpellCircleContext {
val impX = tag.getInt(TAG_IMPETUS_X) val impX = tag.getInt(TAG_IMPETUS_X)
val impY = tag.getInt(TAG_IMPETUS_Y) val impY = tag.getInt(TAG_IMPETUS_Y)
val impZ = tag.getInt(TAG_IMPETUS_Z) val impZ = tag.getInt(TAG_IMPETUS_Z)

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.api.spell.math package at.petrak.hexcasting.api.spell.math
import at.petrak.hexcasting.api.utils.HexUtils import at.petrak.hexcasting.api.utils.NBTBuilder
import net.minecraft.nbt.ByteArrayTag import at.petrak.hexcasting.api.utils.coordToPx
import net.minecraft.nbt.ByteTag import at.petrak.hexcasting.api.utils.findCenter
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
import net.minecraft.world.phys.Vec2 import net.minecraft.world.phys.Vec2
@ -23,15 +23,15 @@ data class HexPattern(public val startDir: HexDir, public val angles: MutableLis
var compass = this.startDir var compass = this.startDir
var cursor = HexCoord.Origin var cursor = HexCoord.Origin
for (a in this.angles) { for (a in this.angles) {
linesSeen.add(Pair(cursor, compass)) linesSeen.add(cursor to compass)
// Line from here to there also blocks there to here // Line from here to there also blocks there to here
linesSeen.add(Pair(cursor + compass, compass.rotatedBy(HexAngle.BACK))) linesSeen.add(cursor + compass to compass.rotatedBy(HexAngle.BACK))
cursor += compass cursor += compass
compass *= a compass *= a
} }
cursor += compass cursor += compass
val potentialNewLine = Pair(cursor, newDir) val potentialNewLine = cursor to newDir
if (potentialNewLine in linesSeen) return false if (potentialNewLine in linesSeen) return false
val nextAngle = newDir - compass val nextAngle = newDir - compass
if (nextAngle == HexAngle.BACK) return false if (nextAngle == HexAngle.BACK) return false
@ -71,12 +71,9 @@ data class HexPattern(public val startDir: HexDir, public val angles: MutableLis
this.angles.fold(this.startDir) { acc, angle -> acc * angle } this.angles.fold(this.startDir) { acc, angle -> acc * angle }
fun serializeToNBT(): CompoundTag { fun serializeToNBT() = NBTBuilder {
val out = CompoundTag() TAG_START_DIR %= byte(startDir.ordinal)
out.put(TAG_START_DIR, ByteTag.valueOf(this.startDir.ordinal.toByte())) TAG_ANGLES %= byteArray(angles.map(HexAngle::ordinal))
val anglesTag = ByteArrayTag(this.angles.map { it.ordinal.toByte() })
out.put(TAG_ANGLES, anglesTag)
return out
} }
// Terrible shorthand method for easy matching // Terrible shorthand method for easy matching
@ -103,9 +100,9 @@ data class HexPattern(public val startDir: HexDir, public val angles: MutableLis
*/ */
@JvmOverloads @JvmOverloads
fun getCenter(hexRadius: Float, origin: HexCoord = HexCoord.Origin): Vec2 { fun getCenter(hexRadius: Float, origin: HexCoord = HexCoord.Origin): Vec2 {
val originPx = HexUtils.coordToPx(origin, hexRadius, Vec2.ZERO) val originPx = coordToPx(origin, hexRadius, Vec2.ZERO)
val points = this.toLines(hexRadius, originPx) val points = this.toLines(hexRadius, originPx)
return HexUtils.FindCenter(points) return findCenter(points)
} }
@ -113,7 +110,7 @@ data class HexPattern(public val startDir: HexDir, public val angles: MutableLis
* Convert a hex pattern into a sequence of straight linePoints spanning its points. * Convert a hex pattern into a sequence of straight linePoints spanning its points.
*/ */
fun toLines(hexSize: Float, origin: Vec2): List<Vec2> = fun toLines(hexSize: Float, origin: Vec2): List<Vec2> =
this.positions().map { HexUtils.coordToPx(it, hexSize, origin) } this.positions().map { coordToPx(it, hexSize, origin) }
override fun toString(): String = buildString { override fun toString(): String = buildString {
append("HexPattern[") append("HexPattern[")
@ -128,7 +125,7 @@ data class HexPattern(public val startDir: HexDir, public val angles: MutableLis
const val TAG_ANGLES = "angles" const val TAG_ANGLES = "angles"
@JvmStatic @JvmStatic
fun IsHexPattern(tag: CompoundTag): Boolean { fun isPattern(tag: CompoundTag): Boolean {
return tag.contains(TAG_START_DIR, Tag.TAG_ANY_NUMERIC.toInt()) && tag.contains( return tag.contains(TAG_START_DIR, Tag.TAG_ANY_NUMERIC.toInt()) && tag.contains(
TAG_ANGLES, TAG_ANGLES,
Tag.TAG_BYTE_ARRAY.toInt() Tag.TAG_BYTE_ARRAY.toInt()
@ -136,14 +133,14 @@ data class HexPattern(public val startDir: HexDir, public val angles: MutableLis
} }
@JvmStatic @JvmStatic
fun DeserializeFromNBT(tag: CompoundTag): HexPattern { fun fromNBT(tag: CompoundTag): HexPattern {
val startDir = HexDir.values()[tag.getByte(TAG_START_DIR).toInt()] val startDir = HexDir.values()[tag.getByte(TAG_START_DIR).toInt()]
val angles = tag.getByteArray(TAG_ANGLES).map { HexAngle.values()[it.toInt()] } val angles = tag.getByteArray(TAG_ANGLES).map { HexAngle.values()[it.toInt()] }
return HexPattern(startDir, angles.toMutableList()) return HexPattern(startDir, angles.toMutableList())
} }
@JvmStatic @JvmStatic
fun FromAnglesSig(signature: String, startDir: HexDir): HexPattern { fun fromAngles(signature: String, startDir: HexDir): HexPattern {
val out = HexPattern(startDir) val out = HexPattern(startDir)
var compass = startDir var compass = startDir

View file

@ -18,7 +18,7 @@ class MishapAlreadyBrainswept(val villager: Villager) : Mishap() {
} }
override fun particleSpray(ctx: CastingContext): ParticleSpray { override fun particleSpray(ctx: CastingContext): ParticleSpray {
return ParticleSpray.Burst(villager.eyePosition, 1.0) return ParticleSpray.burst(villager.eyePosition, 1.0)
} }
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component = override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component =

View file

@ -20,7 +20,7 @@ class MishapBadBlock(val pos: BlockPos, val expected: Component) : Mishap() {
} }
override fun particleSpray(ctx: CastingContext): ParticleSpray { override fun particleSpray(ctx: CastingContext): ParticleSpray {
return ParticleSpray.Burst(Vec3.atCenterOf(pos), 1.0) return ParticleSpray.burst(Vec3.atCenterOf(pos), 1.0)
} }
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component { override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component {

View file

@ -20,7 +20,7 @@ class MishapBadBrainsweep(val villager: Villager, val pos: BlockPos) : Mishap()
} }
override fun particleSpray(ctx: CastingContext): ParticleSpray { override fun particleSpray(ctx: CastingContext): ParticleSpray {
return ParticleSpray.Burst(Vec3.atCenterOf(pos), 1.0) return ParticleSpray.burst(Vec3.atCenterOf(pos), 1.0)
} }
override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component { override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component {

View file

@ -1,7 +1,10 @@
@file:JvmName("HexUtils")
package at.petrak.hexcasting.api.utils package at.petrak.hexcasting.api.utils
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.math.HexCoord import at.petrak.hexcasting.api.spell.math.HexCoord
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.LongArrayTag import net.minecraft.nbt.LongArrayTag
import net.minecraft.world.InteractionHand import net.minecraft.world.InteractionHand
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
@ -12,88 +15,82 @@ import kotlin.math.max
import kotlin.math.min import kotlin.math.min
import kotlin.math.roundToInt import kotlin.math.roundToInt
object HexUtils { const val TAU = Math.PI * 2.0
const val SQRT_3 = 1.7320508f const val SQRT_3 = 1.7320508f
@JvmStatic fun Vec3.serializeToNBT(): LongArrayTag =
fun Vec3.serializeToNBT(): LongArrayTag = LongArrayTag(longArrayOf(this.x.toRawBits(), this.y.toRawBits(), this.z.toRawBits()))
LongArrayTag(longArrayOf(this.x.toRawBits(), this.y.toRawBits(), this.z.toRawBits()))
@JvmStatic fun vecFromNBT(tag: LongArray): Vec3 = if (tag.size != 3) Vec3.ZERO else
fun DeserializeVec3FromNBT(tag: LongArray): Vec3 = if (tag.size != 3) Vec3.ZERO else Vec3(
Vec3( Double.fromBits(tag[0]),
Double.fromBits(tag[0]), Double.fromBits(tag[1]),
Double.fromBits(tag[1]), Double.fromBits(tag[2])
Double.fromBits(tag[2]) )
)
@JvmStatic fun Vec2.serializeToNBT(): LongArrayTag =
fun Vec2.serializeToNBT(): LongArrayTag = LongArrayTag(longArrayOf(this.x.toDouble().toRawBits(), this.y.toDouble().toRawBits()))
LongArrayTag(longArrayOf(this.x.toDouble().toRawBits(), this.y.toDouble().toRawBits()))
@JvmStatic fun vec2FromNBT(tag: LongArray): Vec2 = if (tag.size != 2) Vec2.ZERO else
fun DeserializeVec2FromNBT(tag: LongArray): Vec2 = if (tag.size != 2) Vec2.ZERO else Vec2(
Vec2( Double.fromBits(tag[0]).toFloat(),
Double.fromBits(tag[0]).toFloat(), Double.fromBits(tag[1]).toFloat(),
Double.fromBits(tag[1]).toFloat(), )
)
@JvmStatic fun otherHand(hand: InteractionHand) =
fun OtherHand(hand: InteractionHand) = if (hand == InteractionHand.MAIN_HAND) InteractionHand.OFF_HAND else InteractionHand.MAIN_HAND
if (hand == InteractionHand.MAIN_HAND) InteractionHand.OFF_HAND else InteractionHand.MAIN_HAND
@JvmStatic fun fixNAN(x: Double): Double = if (x.isFinite()) x else 0.0
fun FixNANs(x: Double): Double = if (x.isFinite()) x else 0.0
@JvmStatic fun findCenter(points: List<Vec2>): Vec2 {
fun FindCenter(points: List<Vec2>): Vec2 { var minX = Float.POSITIVE_INFINITY
var minX = Float.POSITIVE_INFINITY var minY = Float.POSITIVE_INFINITY
var minY = Float.POSITIVE_INFINITY var maxX = Float.NEGATIVE_INFINITY
var maxX = Float.NEGATIVE_INFINITY var maxY = Float.NEGATIVE_INFINITY
var maxY = Float.NEGATIVE_INFINITY
for (pos in points) { for (pos in points) {
minX = min(minX, pos.x) minX = min(minX, pos.x)
minY = min(minY, pos.y) minY = min(minY, pos.y)
maxX = max(maxX, pos.x) maxX = max(maxX, pos.x)
maxY = max(maxY, pos.y) maxY = max(maxY, pos.y)
}
return Vec2(
(minX + maxX) / 2f,
(minY + maxY) / 2f
)
}
@JvmStatic
fun coordToPx(coord: HexCoord, size: Float, offset: Vec2) =
Vec2(
SQRT_3 * coord.q.toFloat() + SQRT_3 / 2.0f * coord.r.toFloat(),
1.5f * coord.r.toFloat()
).scale(size).add(offset)
@JvmStatic
fun pxToCoord(px: Vec2, size: Float, offset: Vec2): HexCoord {
val offsetted = px.add(offset.negated())
var qf = (SQRT_3 / 3.0f * offsetted.x - 0.33333f * offsetted.y) / size
var rf = (0.66666f * offsetted.y) / size
val q = qf.roundToInt()
val r = rf.roundToInt()
qf -= q
rf -= r
return if (q.absoluteValue >= r.absoluteValue)
HexCoord(q + (qf + 0.5f * rf).roundToInt(), r)
else
HexCoord(q, r + (rf + 0.5 * qf).roundToInt())
}
const val TAU = Math.PI * 2.0
// Copy the impl from forge
@JvmStatic
fun ItemStack.serialize(): CompoundTag {
val out = CompoundTag()
this.save(out)
return out
} }
return Vec2(
(minX + maxX) / 2f,
(minY + maxY) / 2f
)
}
fun coordToPx(coord: HexCoord, size: Float, offset: Vec2): Vec2 =
Vec2(
SQRT_3 * coord.q.toFloat() + SQRT_3 / 2.0f * coord.r.toFloat(),
1.5f * coord.r.toFloat()
).scale(size).add(offset)
fun pxToCoord(px: Vec2, size: Float, offset: Vec2): HexCoord {
val offsetted = px.add(offset.negated())
var qf = (SQRT_3 / 3.0f * offsetted.x - 0.33333f * offsetted.y) / size
var rf = (0.66666f * offsetted.y) / size
val q = qf.roundToInt()
val r = rf.roundToInt()
qf -= q
rf -= r
return if (q.absoluteValue >= r.absoluteValue)
HexCoord(q + (qf + 0.5f * rf).roundToInt(), r)
else
HexCoord(q, r + (rf + 0.5 * qf).roundToInt())
}
fun Iterable<SpellDatum<*>>.serializeToNBT(): ListTag {
val tag = ListTag()
for (elt in this)
tag.add(elt.serializeToNBT())
return tag
}
// Copy the impl from forge
fun ItemStack.serializeToNBT(): CompoundTag {
val out = CompoundTag()
this.save(out)
return out
} }

View file

@ -1,3 +1,4 @@
@file:JvmName("ManaHelper")
package at.petrak.hexcasting.api.utils package at.petrak.hexcasting.api.utils
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
@ -5,76 +6,70 @@ import net.minecraft.util.Mth
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import kotlin.math.roundToInt import kotlin.math.roundToInt
object ManaHelper { fun isManaItem(stack: ItemStack): Boolean {
@JvmStatic val manaHolder = IXplatAbstractions.INSTANCE.findManaHolder(stack) ?: return false
fun isManaItem(stack: ItemStack): Boolean { if (!manaHolder.canProvide())
val manaHolder = IXplatAbstractions.INSTANCE.findManaHolder(stack) ?: return false return false
if (!manaHolder.canProvide()) return manaHolder.withdrawMana(-1, true) > 0
return false }
return manaHolder.withdrawMana(-1, true) > 0
}
/** /**
* Extract [cost] mana from [stack]. If [cost] is less than zero, extract all mana instead. * Extract [cost] mana from [stack]. If [cost] is less than zero, extract all mana instead.
* This may mutate [stack] (and may consume it) unless [simulate] is set. * This may mutate [stack] (and may consume it) unless [simulate] is set.
* *
* If [drainForBatteries] is false, this will only consider forms of mana that can be used to make new batteries. * If [drainForBatteries] is false, this will only consider forms of mana that can be used to make new batteries.
* *
* Return the amount of mana extracted. This may be over [cost] if mana is wasted. * Return the amount of mana extracted. This may be over [cost] if mana is wasted.
*/ */
@JvmStatic @JvmOverloads
@JvmOverloads fun extractMana(
fun extractMana( stack: ItemStack,
stack: ItemStack, cost: Int = -1,
cost: Int = -1, drainForBatteries: Boolean = false,
drainForBatteries: Boolean = false, simulate: Boolean = false
simulate: Boolean = false ): Int {
): Int { val manaHolder = IXplatAbstractions.INSTANCE.findManaHolder(stack) ?: return 0
val manaHolder = IXplatAbstractions.INSTANCE.findManaHolder(stack) ?: return 0
if (drainForBatteries && !manaHolder.canConstructBattery()) if (drainForBatteries && !manaHolder.canConstructBattery())
return 0 return 0
return manaHolder.withdrawMana(cost, simulate) return manaHolder.withdrawMana(cost, simulate)
} }
/** /**
* Sorted from least important to most important * Sorted from least important to most important
*/ */
fun compare(astack: ItemStack, bstack: ItemStack): Int { fun compareManaItem(astack: ItemStack, bstack: ItemStack): Int {
val aMana = IXplatAbstractions.INSTANCE.findManaHolder(astack) val aMana = IXplatAbstractions.INSTANCE.findManaHolder(astack)
val bMana = IXplatAbstractions.INSTANCE.findManaHolder(bstack) val bMana = IXplatAbstractions.INSTANCE.findManaHolder(bstack)
return if (astack.item != bstack.item) { return if (astack.item != bstack.item) {
(aMana?.consumptionPriority ?: 0) - (bMana?.consumptionPriority ?: 0) (aMana?.consumptionPriority ?: 0) - (bMana?.consumptionPriority ?: 0)
} else if (aMana != null && bMana != null) { } else if (aMana != null && bMana != null) {
aMana.mana - bMana.mana aMana.mana - bMana.mana
} else { } else {
astack.count - bstack.count astack.count - bstack.count
}
}
@JvmStatic
fun barColor(mana: Int, maxMana: Int): Int {
val amt = if (maxMana == 0) {
0f
} else {
mana.toFloat() / maxMana.toFloat()
}
val r = Mth.lerp(amt, 84f, 254f)
val g = Mth.lerp(amt, 57f, 203f)
val b = Mth.lerp(amt, 138f, 230f)
return Mth.color(r / 255f, g / 255f, b / 255f)
}
@JvmStatic
fun barWidth(mana: Int, maxMana: Int): Int {
val amt = if (maxMana == 0) {
0f
} else {
mana.toFloat() / maxMana.toFloat()
}
return (13f * amt).roundToInt()
} }
} }
fun manaBarColor(mana: Int, maxMana: Int): Int {
val amt = if (maxMana == 0) {
0f
} else {
mana.toFloat() / maxMana.toFloat()
}
val r = Mth.lerp(amt, 84f, 254f)
val g = Mth.lerp(amt, 57f, 203f)
val b = Mth.lerp(amt, 138f, 230f)
return Mth.color(r / 255f, g / 255f, b / 255f)
}
fun manaBarWidth(mana: Int, maxMana: Int): Int {
val amt = if (maxMana == 0) {
0f
} else {
mana.toFloat() / maxMana.toFloat()
}
return (13f * amt).roundToInt()
}

View file

@ -0,0 +1,210 @@
@file:Suppress("NOTHING_TO_INLINE")
package at.petrak.hexcasting.api.utils
import net.minecraft.nbt.*
// https://github.com/TeamWizardry/LibrarianLib/blob/9cfb2cf3e35685568942ad41395265a2edc27d30/modules/core/src/main/kotlin/com/teamwizardry/librarianlib/core/util/kotlin/NbtBuilder.kt
@DslMarker
internal annotation class NBTDslMarker
@NBTDslMarker
object NBTBuilder {
inline operator fun invoke(block: NbtCompoundBuilder.() -> Unit) = compound(block)
inline operator fun invoke(tag: CompoundTag, block: NbtCompoundBuilder.() -> Unit) = use(tag, block)
inline fun use(tag: CompoundTag, block: NbtCompoundBuilder.() -> Unit): CompoundTag =
NbtCompoundBuilder(tag).also(block).tag
inline fun compound(block: NbtCompoundBuilder.() -> Unit): CompoundTag =
NbtCompoundBuilder(CompoundTag()).also(block).tag
inline fun list(block: NbtListBuilder.() -> Unit): ListTag =
NbtListBuilder(ListTag()).also(block).tag
inline fun list(vararg elements: Tag, block: NbtListBuilder.() -> Unit): ListTag =
NbtListBuilder(ListTag()).also {
it.addAll(elements.toList())
it.block()
}.tag
inline fun list(vararg elements: Tag): ListTag = ListTag().also { it.addAll(elements) }
inline fun list(elements: Collection<Tag>): ListTag = ListTag().also { it.addAll(elements) }
inline fun <T> list(elements: Collection<T>, mapper: (T) -> Tag): ListTag = ListTag().also { it.addAll(elements.map(mapper)) }
inline fun double(value: Number): DoubleTag = DoubleTag.valueOf(value.toDouble())
inline fun float(value: Number): FloatTag = FloatTag.valueOf(value.toFloat())
inline fun long(value: Number): LongTag = LongTag.valueOf(value.toLong())
inline fun int(value: Number): IntTag = IntTag.valueOf(value.toInt())
inline fun short(value: Number): ShortTag = ShortTag.valueOf(value.toShort())
inline fun byte(value: Number): ByteTag = ByteTag.valueOf(value.toByte())
inline fun string(value: String): StringTag = StringTag.valueOf(value)
inline fun byteArray(value: Collection<Number>): ByteArrayTag = ByteArrayTag(value.map { it.toByte() })
inline fun byteArray(vararg value: Int): ByteArrayTag = ByteArrayTag(ByteArray(value.size) { value[it].toByte() })
inline fun byteArray(vararg value: Byte): ByteArrayTag = ByteArrayTag(value)
inline fun byteArray(): ByteArrayTag = ByteArrayTag(byteArrayOf()) // avoiding overload ambiguity
inline fun longArray(value: Collection<Number>): LongArrayTag = LongArrayTag(value.map { it.toLong() })
inline fun longArray(vararg value: Int): LongArrayTag = LongArrayTag(LongArray(value.size) { value[it].toLong() })
inline fun longArray(vararg value: Long): LongArrayTag = LongArrayTag(value)
inline fun longArray(): LongArrayTag = LongArrayTag(longArrayOf()) // avoiding overload ambiguity
inline fun intArray(value: Collection<Number>): IntArrayTag = IntArrayTag(value.map { it.toInt() })
inline fun intArray(vararg value: Int): IntArrayTag = IntArrayTag(value)
}
@JvmInline
@NBTDslMarker
value class NbtCompoundBuilder(val tag: CompoundTag) {
// configuring this tag
inline operator fun String.remAssign(nbt: Tag) {
tag.put(this, nbt)
}
inline operator fun String.remAssign(str: String) {
tag.put(this, string(str))
}
inline operator fun String.remAssign(num: Int) {
tag.put(this, int(num))
}
inline operator fun String.remAssign(num: Double) {
tag.put(this, double(num))
}
inline operator fun String.remAssign(num: Float) {
tag.put(this, float(num))
}
inline operator fun String.remAssign(bool: Boolean) {
tag.put(this, byte(if (bool) 1 else 0))
}
// creating new tags
inline fun compound(block: NbtCompoundBuilder.() -> Unit): CompoundTag =
NbtCompoundBuilder(CompoundTag()).also { it.block() }.tag
inline fun list(block: NbtListBuilder.() -> Unit): ListTag =
NbtListBuilder(ListTag()).also { it.block() }.tag
inline fun list(vararg elements: Tag, block: NbtListBuilder.() -> Unit): ListTag =
NbtListBuilder(ListTag()).also {
it.addAll(elements.toList())
it.block()
}.tag
inline fun list(vararg elements: Tag): ListTag = ListTag().also { it.addAll(elements) }
inline fun list(elements: Collection<Tag>): ListTag = ListTag().also { it.addAll(elements) }
inline fun <T> list(elements: Collection<T>, mapper: (T) -> Tag): ListTag = ListTag().also { it.addAll(elements.map(mapper)) }
inline fun double(value: Number): DoubleTag = DoubleTag.valueOf(value.toDouble())
inline fun float(value: Number): FloatTag = FloatTag.valueOf(value.toFloat())
inline fun long(value: Number): LongTag = LongTag.valueOf(value.toLong())
inline fun int(value: Number): IntTag = IntTag.valueOf(value.toInt())
inline fun short(value: Number): ShortTag = ShortTag.valueOf(value.toShort())
inline fun byte(value: Number): ByteTag = ByteTag.valueOf(value.toByte())
inline fun string(value: String): StringTag = StringTag.valueOf(value)
inline fun byteArray(value: Collection<Number>): ByteArrayTag = ByteArrayTag(value.map { it.toByte() })
inline fun byteArray(vararg value: Int): ByteArrayTag = ByteArrayTag(ByteArray(value.size) { value[it].toByte() })
inline fun byteArray(vararg value: Byte): ByteArrayTag = ByteArrayTag(value)
inline fun byteArray(): ByteArrayTag = ByteArrayTag(byteArrayOf()) // avoiding overload ambiguity
inline fun longArray(value: Collection<Number>): LongArrayTag = LongArrayTag(value.map { it.toLong() })
inline fun longArray(vararg value: Int): LongArrayTag = LongArrayTag(LongArray(value.size) { value[it].toLong() })
inline fun longArray(vararg value: Long): LongArrayTag = LongArrayTag(value)
inline fun longArray(): LongArrayTag = LongArrayTag(longArrayOf()) // avoiding overload ambiguity
inline fun intArray(value: Collection<Number>): IntArrayTag = IntArrayTag(value.map { it.toInt() })
inline fun intArray(vararg value: Int): IntArrayTag = IntArrayTag(value)
}
@JvmInline
@NBTDslMarker
value class NbtListBuilder(val tag: ListTag) {
// configuring this tag
/**
* Add the given tag to this list
*/
inline operator fun Tag.unaryPlus() {
tag.add(this)
}
/**
* Add the given tags to this list
*/
inline operator fun Collection<Tag>.unaryPlus() {
tag.addAll(this)
}
/**
* Add the given tag to this list. This is explicitly defined for [ListTag] because otherwise there is overload
* ambiguity between the [Tag] and [Collection]<Tag> methods.
*/
inline operator fun ListTag.unaryPlus() {
tag.add(this)
}
inline fun addAll(nbt: Collection<Tag>) {
this.tag.addAll(nbt)
}
inline fun add(nbt: Tag) {
this.tag.add(nbt)
}
// creating new tags
inline fun compound(block: NbtCompoundBuilder.() -> Unit): CompoundTag =
NbtCompoundBuilder(CompoundTag()).also { it.block() }.tag
inline fun list(block: NbtListBuilder.() -> Unit): ListTag =
NbtListBuilder(ListTag()).also { it.block() }.tag
inline fun list(vararg elements: Tag, block: NbtListBuilder.() -> Unit): ListTag =
NbtListBuilder(ListTag()).also {
it.addAll(elements.toList())
it.block()
}.tag
inline fun list(vararg elements: Tag): ListTag = ListTag().also { it.addAll(elements) }
inline fun list(elements: Collection<Tag>): ListTag = ListTag().also { it.addAll(elements) }
inline fun <T> list(elements: Collection<T>, mapper: (T) -> Tag): ListTag = ListTag().also { it.addAll(elements.map(mapper)) }
inline fun double(value: Number): DoubleTag = DoubleTag.valueOf(value.toDouble())
inline fun float(value: Number): FloatTag = FloatTag.valueOf(value.toFloat())
inline fun long(value: Number): LongTag = LongTag.valueOf(value.toLong())
inline fun int(value: Number): IntTag = IntTag.valueOf(value.toInt())
inline fun short(value: Number): ShortTag = ShortTag.valueOf(value.toShort())
inline fun byte(value: Number): ByteTag = ByteTag.valueOf(value.toByte())
inline fun string(value: String): StringTag = StringTag.valueOf(value)
inline fun byteArray(value: Collection<Number>): ByteArrayTag = ByteArrayTag(value.map { it.toByte() })
inline fun byteArray(vararg value: Int): ByteArrayTag = ByteArrayTag(ByteArray(value.size) { value[it].toByte() })
inline fun byteArray(vararg value: Byte): ByteArrayTag = ByteArrayTag(value)
inline fun byteArray(): ByteArrayTag = ByteArrayTag(byteArrayOf()) // avoiding overload ambiguity
inline fun longArray(value: Collection<Number>): LongArrayTag = LongArrayTag(value.map { it.toLong() })
inline fun longArray(vararg value: Int): LongArrayTag = LongArrayTag(LongArray(value.size) { value[it].toLong() })
inline fun longArray(vararg value: Long): LongArrayTag = LongArrayTag(value)
inline fun longArray(): LongArrayTag = LongArrayTag(longArrayOf()) // avoiding overload ambiguity
inline fun intArray(value: Collection<Number>): IntArrayTag = IntArrayTag(value.map { it.toInt() })
inline fun intArray(vararg value: Int): IntArrayTag = IntArrayTag(value)
inline fun doubles(vararg value: Int): List<DoubleTag> = value.map { DoubleTag.valueOf(it.toDouble()) }
inline fun doubles(vararg value: Double): List<DoubleTag> = value.map { DoubleTag.valueOf(it) }
inline fun floats(vararg value: Int): List<FloatTag> = value.map { FloatTag.valueOf(it.toFloat()) }
inline fun floats(vararg value: Float): List<FloatTag> = value.map { FloatTag.valueOf(it) }
inline fun longs(vararg value: Int): List<LongTag> = value.map { LongTag.valueOf(it.toLong()) }
inline fun longs(vararg value: Long): List<LongTag> = value.map { LongTag.valueOf(it) }
inline fun ints(vararg value: Int): List<IntTag> = value.map { IntTag.valueOf(it) }
inline fun shorts(vararg value: Int): List<ShortTag> = value.map { ShortTag.valueOf(it.toShort()) }
inline fun shorts(vararg value: Short): List<ShortTag> = value.map { ShortTag.valueOf(it) }
inline fun bytes(vararg value: Int): List<ByteTag> = value.map { ByteTag.valueOf(it.toByte()) }
inline fun bytes(vararg value: Byte): List<ByteTag> = value.map { ByteTag.valueOf(it) }
fun strings(vararg value: String): List<StringTag> = value.map { StringTag.valueOf(it) }
}

View file

@ -223,6 +223,7 @@ public class HexAdditionalRenderers {
if (text.isEmpty()) { if (text.isEmpty()) {
ps.translate(0, mc.font.lineHeight, 0); ps.translate(0, mc.font.lineHeight, 0);
} }
ps.translate(0, 6, 0);
} }
ps.popPose(); ps.popPose();

View file

@ -1,8 +1,10 @@
@file:JvmName("RenderLib")
package at.petrak.hexcasting.client package at.petrak.hexcasting.client
import at.petrak.hexcasting.api.mod.HexConfig import at.petrak.hexcasting.api.mod.HexConfig
import at.petrak.hexcasting.api.spell.math.HexPattern import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.utils.HexUtils import at.petrak.hexcasting.api.utils.TAU
import at.petrak.hexcasting.client.gui.GuiSpellcasting
import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.DefaultVertexFormat import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.PoseStack import com.mojang.blaze3d.vertex.PoseStack
@ -12,6 +14,7 @@ import com.mojang.math.Matrix4f
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.gui.screens.Screen import net.minecraft.client.gui.screens.Screen
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.util.FastColor
import net.minecraft.util.Mth import net.minecraft.util.Mth
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.levelgen.XoroshiroRandomSource import net.minecraft.world.level.levelgen.XoroshiroRandomSource
@ -19,271 +22,258 @@ import net.minecraft.world.level.levelgen.synth.PerlinNoise
import net.minecraft.world.phys.Vec2 import net.minecraft.world.phys.Vec2
import kotlin.math.floor import kotlin.math.floor
import kotlin.math.min import kotlin.math.min
import net.minecraft.util.FastColor.ARGB32 as FC
/** /**
* Common draw code * Source of perlin noise
*/ */
object RenderLib { val NOISE: PerlinNoise = PerlinNoise.create(XoroshiroRandomSource(9001L), listOf(0, 1, 2, 3, 4))
/**
* Source of perlin noise
*/
val NOISE = PerlinNoise.create(XoroshiroRandomSource(9001L), listOf(0, 1, 2, 3, 4))
/** /**
* Draw a sequence of linePoints spanning the given points. * Draw a sequence of linePoints spanning the given points.
* *
* Please make sure to enable the right asinine shaders; see [GuiSpellcasting][at.petrak.hexcasting.client.gui.GuiSpellcasting] * Please make sure to enable the right asinine shaders; see [GuiSpellcasting]
*/ */
@JvmStatic @JvmOverloads
@JvmOverloads fun drawLineSeq(
fun drawLineSeq( mat: Matrix4f,
mat: Matrix4f, points: List<Vec2>,
points: List<Vec2>, width: Float,
width: Float, z: Float,
z: Float, tail: Int,
tail: Int, head: Int,
head: Int, animTime: Float? = null,
animTime: Float? = null, ) {
) { if (points.size <= 1) return
if (points.size <= 1) return
val r1 = FC.red(tail).toFloat() val r1 = FastColor.ARGB32.red(tail).toFloat()
val g1 = FC.green(tail).toFloat() val g1 = FastColor.ARGB32.green(tail).toFloat()
val b1 = FC.blue(tail).toFloat() val b1 = FastColor.ARGB32.blue(tail).toFloat()
val a = FC.alpha(tail) val a = FastColor.ARGB32.alpha(tail)
val headSource = if (Screen.hasControlDown() != HexConfig.client().ctrlTogglesOffStrokeOrder()) val headSource = if (Screen.hasControlDown() != HexConfig.client().ctrlTogglesOffStrokeOrder())
head head
else else
tail tail
val r2 = FC.red(headSource).toFloat() val r2 = FastColor.ARGB32.red(headSource).toFloat()
val g2 = FC.green(headSource).toFloat() val g2 = FastColor.ARGB32.green(headSource).toFloat()
val b2 = FC.blue(headSource).toFloat() val b2 = FastColor.ARGB32.blue(headSource).toFloat()
// they spell it wrong at mojang lmao // they spell it wrong at mojang lmao
val tess = Tesselator.getInstance() val tess = Tesselator.getInstance()
val buf = tess.builder val buf = tess.builder
// We use one single TRIANGLE_STRIP // We use one single TRIANGLE_STRIP
// in order to connect adjacent segments together and not get the weird hinge effect. // in order to connect adjacent segments together and not get the weird hinge effect.
// There's still some artifacting but this is passable, at least. // There's still some artifacting but this is passable, at least.
buf.begin(VertexFormat.Mode.TRIANGLE_STRIP, DefaultVertexFormat.POSITION_COLOR) buf.begin(VertexFormat.Mode.TRIANGLE_STRIP, DefaultVertexFormat.POSITION_COLOR)
val n = points.size val n = points.size
for ((i, pair) in points.zipWithNext().withIndex()) { for ((i, pair) in points.zipWithNext().withIndex()) {
val (p1, p2) = pair val (p1, p2) = pair
// https://github.com/not-fl3/macroquad/blob/master/src/shapes.rs#L163 // https://github.com/not-fl3/macroquad/blob/master/src/shapes.rs#L163
// GuiComponent::innerFill line 52 // GuiComponent::innerFill line 52
// fedor have useful variable names challenge (99% can't beat) // fedor have useful variable names challenge (99% can't beat)
val dx = p2.x - p1.x val dx = p2.x - p1.x
val dy = p2.y - p1.y val dy = p2.y - p1.y
// normal x and y, presumably? // normal x and y, presumably?
val nx = -dy val nx = -dy
val ny = dx val ny = dx
// thickness? // thickness?
val tlen = Mth.sqrt(nx * nx + ny * ny) / (width * 0.5f) val tlen = Mth.sqrt(nx * nx + ny * ny) / (width * 0.5f)
val tx = nx / tlen val tx = nx / tlen
val ty = ny / tlen val ty = ny / tlen
fun color(time: Float): BlockPos = fun color(time: Float): BlockPos =
BlockPos(Mth.lerp(time, r1, r2).toInt(), Mth.lerp(time, g1, g2).toInt(), Mth.lerp(time, b1, b2).toInt()) BlockPos(Mth.lerp(time, r1, r2).toInt(), Mth.lerp(time, g1, g2).toInt(), Mth.lerp(time, b1, b2).toInt())
val color1 = color(i.toFloat() / n) val color1 = color(i.toFloat() / n)
val color2 = color((i + 1f) / n) val color2 = color((i + 1f) / n)
buf.vertex(mat, p1.x + tx, p1.y + ty, z).color(color1.x, color1.y, color1.z, a).endVertex() buf.vertex(mat, p1.x + tx, p1.y + ty, z).color(color1.x, color1.y, color1.z, a).endVertex()
buf.vertex(mat, p1.x - tx, p1.y - ty, z).color(color1.x, color1.y, color1.z, a).endVertex() buf.vertex(mat, p1.x - tx, p1.y - ty, z).color(color1.x, color1.y, color1.z, a).endVertex()
buf.vertex(mat, p2.x + tx, p2.y + ty, z).color(color2.x, color2.y, color2.z, a).endVertex() buf.vertex(mat, p2.x + tx, p2.y + ty, z).color(color2.x, color2.y, color2.z, a).endVertex()
buf.vertex(mat, p2.x - tx, p2.y - ty, z).color(color2.x, color2.y, color2.z, a).endVertex() buf.vertex(mat, p2.x - tx, p2.y - ty, z).color(color2.x, color2.y, color2.z, a).endVertex()
}
tess.end()
if (animTime != null) {
val pointCircuit =
(animTime * 30f * HexConfig.client().patternPointSpeedMultiplier().toFloat()) % (points.size + 10)
// subtract 1 to avoid the point appearing between the end and start for 1 frame
if (pointCircuit < points.size - 1) {
val pointMacro = floor(pointCircuit).toInt()
val pointMicro = pointCircuit - pointMacro
val p1 = points[pointMacro]
val p2 = points[(pointMacro + 1) % points.size]
val drawPos = Vec2(
p1.x + (p2.x - p1.x) * pointMicro,
p1.y + (p2.y - p1.y) * pointMicro,
)
drawSpot(
mat,
drawPos,
2f,
(r1 + 255) / 2f / 255f,
(g1 + 255) / 2f / 255f,
(b1 + 255) / 2f / 255f,
a / 1.2f / 255f
)
}
}
} }
tess.end()
/** if (animTime != null) {
* Draw a hex pattern from the given list of non-zappy points (as in, do the *style* of drawing it, val pointCircuit =
* you have to do the conversion yourself.) (animTime * 30f * HexConfig.client().patternPointSpeedMultiplier().toFloat()) % (points.size + 10)
*/ // subtract 1 to avoid the point appearing between the end and start for 1 frame
@JvmStatic if (pointCircuit < points.size - 1) {
fun drawPatternFromPoints( val pointMacro = floor(pointCircuit).toInt()
mat: Matrix4f, val pointMicro = pointCircuit - pointMacro
points: List<Vec2>,
drawLast: Boolean, val p1 = points[pointMacro]
tail: Int, val p2 = points[(pointMacro + 1) % points.size]
head: Int, val drawPos = Vec2(
flowIrregular: Float, p1.x + (p2.x - p1.x) * pointMicro,
animTime: Float? = null p1.y + (p2.y - p1.y) * pointMicro,
) { )
val zappyPts = makeZappy(points, 10f, 2.5f, 0.1f, flowIrregular)
val nodes = if (drawLast) {
points
} else {
points.dropLast(1)
}
drawLineSeq(mat, zappyPts, 5f, 0f, tail, head, null)
drawLineSeq(mat, zappyPts, 2f, 1f, screenCol(tail), screenCol(head), animTime)
for (node in nodes) {
drawSpot( drawSpot(
mat, mat,
node, drawPos,
2f, 2f,
dodge(FC.red(head)) / 255f, (r1 + 255) / 2f / 255f,
dodge(FC.green(head)) / 255f, (g1 + 255) / 2f / 255f,
dodge(FC.blue(head)) / 255f, (b1 + 255) / 2f / 255f,
FC.alpha(head) / 255f a / 1.2f / 255f
); )
} }
} }
}
/**
* Split up a sequence of linePoints with a lightning effect /**
* @param hops: rough number of points to subdivide each segment into * * Draw a hex pattern from the given list of non-zappy points (as in, do the *style* of drawing it,
* @param speed: rate at which the lightning effect should move/shake/etc * * you have to do the conversion yourself.)
*/ * */
@JvmStatic @JvmOverloads
fun makeZappy(points: List<Vec2>, hops: Float, variance: Float, speed: Float, flowIrregular: Float): List<Vec2> { fun drawPatternFromPoints(
// Nothing in, nothing out mat: Matrix4f,
if (points.isEmpty()) { points: List<Vec2>,
return emptyList() drawLast: Boolean,
} tail: Int,
val scaleVariance = { it: Double -> Math.min(1.0, 8 * (0.5 - Math.abs(0.5 - it))) } head: Int,
val hops = hops.toInt() flowIrregular: Float,
val zSeed = ClientTickCounter.total.toDouble() * speed animTime: Float? = null
// Create our output list of zap points ) {
val zappyPts = mutableListOf(points[0]) val zappyPts = makeZappy(points, 10f, 2.5f, 0.1f, flowIrregular)
// For each segment in the original... val nodes = if (drawLast) {
for ((i, pair) in points.zipWithNext().withIndex()) { points
val (src, target) = pair } else {
val delta = target.add(src.negated()) points.dropLast(1)
// Take hop distance }
val hopDist = Mth.sqrt(src.distanceToSqr(target)) / hops drawLineSeq(mat, zappyPts, 5f, 0f, tail, head, null)
// Compute how big the radius of variance should be drawLineSeq(mat, zappyPts, 2f, 1f, screenCol(tail), screenCol(head), animTime)
val maxVariance = hopDist * variance for (node in nodes) {
drawSpot(
for (j in 1..hops) { mat,
val progress = j.toDouble() / (hops + 1) node,
// Add the next hop... 2f,
val pos = src.add(delta.scale(progress.toFloat())) dodge(FastColor.ARGB32.red(head)) / 255f,
// as well as some random variance... dodge(FastColor.ARGB32.green(head)) / 255f,
// (We use i, j (segment #, subsegment #) as seeds for the Perlin noise, dodge(FastColor.ARGB32.blue(head)) / 255f,
// and zSeed (i.e. time elapsed) to perturb the shape gradually over time) FastColor.ARGB32.alpha(head) / 255f
val minorPerturb = NOISE.getValue(i.toDouble(), j.toDouble(), Math.sin(zSeed)) * flowIrregular );
val theta = (3 * NOISE.getValue(i.toDouble() + j.toDouble() / (hops + 1) + minorPerturb - zSeed, 1337.0, 0.0) * HexUtils.TAU).toFloat() }
val r = (NOISE.getValue(i.toDouble() + j.toDouble() / (hops + 1) - zSeed, 69420.0, 0.0) * maxVariance * scaleVariance(progress)).toFloat() }
val randomHop = Vec2(r * Mth.cos(theta), r * Mth.sin(theta))
// Then record the new location. /**
zappyPts.add(pos.add(randomHop)) * Split up a sequence of linePoints with a lightning effect
} * @param hops: rough number of points to subdivide each segment into
// Finally, we hit the destination, add that too * @param speed: rate at which the lightning effect should move/shake/etc
zappyPts.add(target) */
} fun makeZappy(points: List<Vec2>, hops: Float, variance: Float, speed: Float, flowIrregular: Float): List<Vec2> {
return zappyPts // Nothing in, nothing out
} if (points.isEmpty()) {
return emptyList()
/** }
* Draw a little circle, because Minecraft rendering code is a nightmare and doesn't val scaleVariance = { it: Double -> Math.min(1.0, 8 * (0.5 - Math.abs(0.5 - it))) }
* include primitive drawing code... val hops = hops.toInt()
*/ val zSeed = ClientTickCounter.total.toDouble() * speed
@JvmStatic // Create our output list of zap points
fun drawSpot(mat: Matrix4f, point: Vec2, radius: Float, r: Float, g: Float, b: Float, a: Float) { val zappyPts = mutableListOf(points[0])
val tess = Tesselator.getInstance() // For each segment in the original...
val buf = tess.builder for ((i, pair) in points.zipWithNext().withIndex()) {
// https://stackoverflow.com/questions/20394727/gl-triangle-strip-vs-gl-triangle-fan val (src, target) = pair
// Starting point is the center val delta = target.add(src.negated())
buf.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR) // Take hop distance
buf.vertex(mat, point.x, point.y, 1f).color(r, g, b, a).endVertex() val hopDist = Mth.sqrt(src.distanceToSqr(target)) / hops
// Compute how big the radius of variance should be
// https://github.com/not-fl3/macroquad/blob/master/src/shapes.rs#L98 val maxVariance = hopDist * variance
// yes they are gonna be little hexagons fite me
val fracOfCircle = 6 for (j in 1..hops) {
// run 0 AND last; this way the circle closes val progress = j.toDouble() / (hops + 1)
for (i in 0..fracOfCircle) { // Add the next hop...
val theta = i.toFloat() / fracOfCircle * HexUtils.TAU.toFloat() val pos = src.add(delta.scale(progress.toFloat()))
val rx = Mth.cos(theta) * radius + point.x // as well as some random variance...
val ry = Mth.sin(theta) * radius + point.y // (We use i, j (segment #, subsegment #) as seeds for the Perlin noise,
buf.vertex(mat, rx, ry, 1f).color(r, g, b, a).endVertex() // and zSeed (i.e. time elapsed) to perturb the shape gradually over time)
} val minorPerturb = NOISE.getValue(i.toDouble(), j.toDouble(), Math.sin(zSeed)) * flowIrregular
val theta = (3 * NOISE.getValue(i.toDouble() + j.toDouble() / (hops + 1) + minorPerturb - zSeed, 1337.0, 0.0) * TAU).toFloat()
tess.end() val r = (NOISE.getValue(i.toDouble() + j.toDouble() / (hops + 1) - zSeed, 69420.0, 0.0) * maxVariance * scaleVariance(progress)).toFloat()
} val randomHop = Vec2(r * Mth.cos(theta), r * Mth.sin(theta))
// Then record the new location.
fun dodge(n: Int): Float = n * 0.9f zappyPts.add(pos.add(randomHop))
fun screen(n: Int): Int = (n + 255) / 2 }
// Finally, we hit the destination, add that too
@JvmStatic zappyPts.add(target)
fun screenCol(n: Int): Int { }
return FC.color( return zappyPts
FC.alpha(n), }
screen(FC.red(n)),
screen(FC.green(n)), /**
screen(FC.blue(n)), * Draw a little circle, because Minecraft rendering code is a nightmare and doesn't
) * include primitive drawing code...
} */
fun drawSpot(mat: Matrix4f, point: Vec2, radius: Float, r: Float, g: Float, b: Float, a: Float) {
/** val tess = Tesselator.getInstance()
* Return the scale and dots formed by the pattern when centered. val buf = tess.builder
*/ // https://stackoverflow.com/questions/20394727/gl-triangle-strip-vs-gl-triangle-fan
@JvmStatic // Starting point is the center
fun getCenteredPattern(pattern: HexPattern, width: Float, height: Float, minSize: Float): Pair<Float, List<Vec2>> { buf.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR)
// Do two passes: one with a random size to find a good COM and one with the real calculation buf.vertex(mat, point.x, point.y, 1f).color(r, g, b, a).endVertex()
val com1: Vec2 = pattern.getCenter(1f)
val lines1: List<Vec2> = pattern.toLines(1f, Vec2.ZERO) // https://github.com/not-fl3/macroquad/blob/master/src/shapes.rs#L98
var maxDx = -1f // yes they are gonna be little hexagons fite me
var maxDy = -1f val fracOfCircle = 6
for (dot in lines1) { // run 0 AND last; this way the circle closes
val dx = Mth.abs(dot.x - com1.x) for (i in 0..fracOfCircle) {
if (dx > maxDx) { val theta = i.toFloat() / fracOfCircle * TAU.toFloat()
maxDx = dx val rx = Mth.cos(theta) * radius + point.x
} val ry = Mth.sin(theta) * radius + point.y
val dy = Mth.abs(dot.y - com1.y) buf.vertex(mat, rx, ry, 1f).color(r, g, b, a).endVertex()
if (dy > maxDy) { }
maxDy = dy
} tess.end()
} }
val scale =
min(minSize, min(width / 3f / maxDx, height / 3f / maxDy)) fun screenCol(n: Int): Int {
val com2: Vec2 = pattern.getCenter(scale) return FastColor.ARGB32.color(
val lines2: List<Vec2> = pattern.toLines(scale, com2.negated()) FastColor.ARGB32.alpha(n),
return Pair(scale, lines2) screen(FastColor.ARGB32.red(n)),
} screen(FastColor.ARGB32.green(n)),
screen(FastColor.ARGB32.blue(n)),
@JvmStatic )
fun renderItemStackInGui(ms: PoseStack, stack: ItemStack, x: Int, y: Int) { }
transferMsToGl(ms) { Minecraft.getInstance().itemRenderer.renderAndDecorateItem(stack, x, y) }
} fun screen(n: Int) = (n + 255) / 2
fun dodge(n: Int) = n * 0.9f
@JvmStatic
fun transferMsToGl(ms: PoseStack, toRun: Runnable) { /**
val mvs = RenderSystem.getModelViewStack() * Return the scale and dots formed by the pattern when centered.
mvs.pushPose() */
mvs.mulPoseMatrix(ms.last().pose()) fun getCenteredPattern(pattern: HexPattern, width: Float, height: Float, minSize: Float): Pair<Float, List<Vec2>> {
RenderSystem.applyModelViewMatrix() // Do two passes: one with a random size to find a good COM and one with the real calculation
toRun.run() val com1: Vec2 = pattern.getCenter(1f)
mvs.popPose() val lines1: List<Vec2> = pattern.toLines(1f, Vec2.ZERO)
RenderSystem.applyModelViewMatrix() var maxDx = -1f
} var maxDy = -1f
for (dot in lines1) {
val dx = Mth.abs(dot.x - com1.x)
if (dx > maxDx) {
maxDx = dx
}
val dy = Mth.abs(dot.y - com1.y)
if (dy > maxDy) {
maxDy = dy
}
}
val scale =
min(minSize, min(width / 3f / maxDx, height / 3f / maxDy))
val com2: Vec2 = pattern.getCenter(scale)
val lines2: List<Vec2> = pattern.toLines(scale, com2.negated())
return scale to lines2
}
fun renderItemStackInGui(ms: PoseStack, stack: ItemStack, x: Int, y: Int) {
transferMsToGl(ms) { Minecraft.getInstance().itemRenderer.renderAndDecorateItem(stack, x, y) }
}
fun transferMsToGl(ms: PoseStack, toRun: Runnable) {
val mvs = RenderSystem.getModelViewStack()
mvs.pushPose()
mvs.mulPoseMatrix(ms.last().pose())
RenderSystem.applyModelViewMatrix()
toRun.run()
mvs.popPose()
RenderSystem.applyModelViewMatrix()
} }

View file

@ -8,8 +8,9 @@ import at.petrak.hexcasting.api.spell.math.HexAngle
import at.petrak.hexcasting.api.spell.math.HexCoord import at.petrak.hexcasting.api.spell.math.HexCoord
import at.petrak.hexcasting.api.spell.math.HexDir import at.petrak.hexcasting.api.spell.math.HexDir
import at.petrak.hexcasting.api.spell.math.HexPattern import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.utils.HexUtils import at.petrak.hexcasting.api.utils.otherHand
import at.petrak.hexcasting.client.RenderLib import at.petrak.hexcasting.client.drawPatternFromPoints
import at.petrak.hexcasting.client.drawSpot
import at.petrak.hexcasting.client.sound.GridSoundInstance import at.petrak.hexcasting.client.sound.GridSoundInstance
import at.petrak.hexcasting.common.items.ItemSpellbook import at.petrak.hexcasting.common.items.ItemSpellbook
import at.petrak.hexcasting.common.lib.HexItems import at.petrak.hexcasting.common.lib.HexItems
@ -231,7 +232,7 @@ class GuiSpellcasting(
override fun mouseScrolled(pMouseX: Double, pMouseY: Double, pDelta: Double): Boolean { override fun mouseScrolled(pMouseX: Double, pMouseY: Double, pDelta: Double): Boolean {
super.mouseScrolled(pMouseX, pMouseY, pDelta) super.mouseScrolled(pMouseX, pMouseY, pDelta)
val otherHand = HexUtils.OtherHand(this.handOpenedWith) val otherHand = otherHand(this.handOpenedWith)
if (Minecraft.getInstance().player!!.getItemInHand(otherHand).item is ItemSpellbook) if (Minecraft.getInstance().player!!.getItemInHand(otherHand).item is ItemSpellbook)
IClientXplatAbstractions.INSTANCE.sendPacketToServer( IClientXplatAbstractions.INSTANCE.sendPacketToServer(
MsgShiftScrollSyn( MsgShiftScrollSyn(
@ -279,7 +280,7 @@ class GuiSpellcasting(
0f, 0f,
1f 1f
) )
RenderLib.drawSpot( drawSpot(
mat, mat,
dotPx, dotPx,
scaledDist * 2f, scaledDist * 2f,
@ -293,7 +294,7 @@ class GuiSpellcasting(
RenderSystem.defaultBlendFunc() RenderSystem.defaultBlendFunc()
for ((pat, origin, valid) in this.patterns) { for ((pat, origin, valid) in this.patterns) {
RenderLib.drawPatternFromPoints(mat, pat.toLines( drawPatternFromPoints(mat, pat.toLines(
this.hexSize(), this.hexSize(),
this.coordToPx(origin) this.coordToPx(origin)
), true, valid.color or (0xC8 shl 24), valid.fadeColor or (0xC8 shl 24), if (valid.success) 0.2f else 0.9f) ), true, valid.color or (0xC8 shl 24), valid.fadeColor or (0xC8 shl 24), if (valid.success) 0.2f else 0.9f)
@ -315,7 +316,7 @@ class GuiSpellcasting(
} }
points.add(mousePos) points.add(mousePos)
RenderLib.drawPatternFromPoints(mat, points, false, 0xff_64c8ff_u.toInt(), 0xff_fecbe6_u.toInt(), 0.2f) drawPatternFromPoints(mat, points, false, 0xff_64c8ff_u.toInt(), 0xff_fecbe6_u.toInt(), 0.1f)
} }
RenderSystem.setShader { prevShader } RenderSystem.setShader { prevShader }
@ -338,7 +339,7 @@ class GuiSpellcasting(
/** Distance between adjacent hex centers */ /** Distance between adjacent hex centers */
fun hexSize(): Float { fun hexSize(): Float {
val hasLens = Minecraft.getInstance().player!! val hasLens = Minecraft.getInstance().player!!
.getItemInHand(HexUtils.OtherHand(this.handOpenedWith)).`is`(HexItems.SCRYING_LENS) .getItemInHand(otherHand(this.handOpenedWith)).`is`(HexItems.SCRYING_LENS)
// Originally, we allowed 32 dots across. Assuming a 1920x1080 screen this allowed like 500-odd area. // Originally, we allowed 32 dots across. Assuming a 1920x1080 screen this allowed like 500-odd area.
// Let's be generous and give them 512. // Let's be generous and give them 512.
@ -348,8 +349,9 @@ class GuiSpellcasting(
fun coordsOffset(): Vec2 = Vec2(this.width.toFloat() * 0.5f, this.height.toFloat() * 0.5f) fun coordsOffset(): Vec2 = Vec2(this.width.toFloat() * 0.5f, this.height.toFloat() * 0.5f)
fun coordToPx(coord: HexCoord) = HexUtils.coordToPx(coord, this.hexSize(), this.coordsOffset()) fun coordToPx(coord: HexCoord) =
fun pxToCoord(px: Vec2) = HexUtils.pxToCoord(px, this.hexSize(), this.coordsOffset()) at.petrak.hexcasting.api.utils.coordToPx(coord, this.hexSize(), this.coordsOffset())
fun pxToCoord(px: Vec2) = at.petrak.hexcasting.api.utils.pxToCoord(px, this.hexSize(), this.coordsOffset())
private sealed class PatternDrawState { private sealed class PatternDrawState {

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.client.gui; package at.petrak.hexcasting.client.gui;
import at.petrak.hexcasting.client.ClientTickCounter; import at.petrak.hexcasting.client.ClientTickCounter;
import at.petrak.hexcasting.client.RenderLib;
import at.petrak.hexcasting.api.spell.math.HexPattern; import at.petrak.hexcasting.api.spell.math.HexPattern;
import at.petrak.hexcasting.client.RenderLib;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*; import com.mojang.blaze3d.vertex.*;

View file

@ -70,8 +70,8 @@ public class BlockEntityAkashicBookshelf extends HexBlockEntity {
} else { } else {
this.recordPos = null; this.recordPos = null;
} }
if (HexPattern.IsHexPattern(pattern)) { if (HexPattern.isPattern(pattern)) {
this.pattern = HexPattern.DeserializeFromNBT(pattern); this.pattern = HexPattern.fromNBT(pattern);
} else { } else {
this.pattern = null; this.pattern = null;
} }

View file

@ -81,14 +81,14 @@ public class BlockEntityAkashicRecord extends HexBlockEntity {
if (entry == null) { if (entry == null) {
return null; return null;
} else { } else {
return SpellDatum.DeserializeFromNBT(entry.datum, slevel); return SpellDatum.fromNBT(entry.datum, slevel);
} }
} }
public Component getDisplayAt(HexPattern key) { public Component getDisplayAt(HexPattern key) {
var entry = this.entries.get(getKey(key)); var entry = this.entries.get(getKey(key));
if (entry != null) { if (entry != null) {
return SpellDatum.DisplayFromTag(entry.datum); return SpellDatum.displayFromNBT(entry.datum);
} else { } else {
return new TranslatableComponent("hexcasting.spelldata.akashic.nopos").withStyle(ChatFormatting.RED); return new TranslatableComponent("hexcasting.spelldata.akashic.nopos").withStyle(ChatFormatting.RED);
} }

View file

@ -32,8 +32,8 @@ public class BlockEntitySlate extends HexBlockEntity {
protected void loadModData(CompoundTag tag) { protected void loadModData(CompoundTag tag) {
if (tag.contains(TAG_PATTERN, Tag.TAG_COMPOUND)) { if (tag.contains(TAG_PATTERN, Tag.TAG_COMPOUND)) {
CompoundTag patternTag = tag.getCompound(TAG_PATTERN); CompoundTag patternTag = tag.getCompound(TAG_PATTERN);
if (HexPattern.IsHexPattern(patternTag)) { if (HexPattern.isPattern(patternTag)) {
this.pattern = HexPattern.DeserializeFromNBT(patternTag); this.pattern = HexPattern.fromNBT(patternTag);
} else { } else {
this.pattern = null; this.pattern = null;
} }

View file

@ -90,12 +90,12 @@ public class BlockEntityConjured extends HexBlockEntity {
@Override @Override
protected void saveModData(CompoundTag tag) { protected void saveModData(CompoundTag tag) {
tag.put(TAG_COLORIZER, this.colorizer.serialize()); tag.put(TAG_COLORIZER, this.colorizer.serializeToNBT());
} }
@Override @Override
protected void loadModData(CompoundTag tag) { protected void loadModData(CompoundTag tag) {
this.colorizer = FrozenColorizer.deserialize(tag.getCompound(TAG_COLORIZER)); this.colorizer = FrozenColorizer.fromNBT(tag.getCompound(TAG_COLORIZER));
} }
public FrozenColorizer getColorizer() { public FrozenColorizer getColorizer() {

View file

@ -16,7 +16,6 @@ import at.petrak.hexcasting.common.casting.operators.circles.OpCircleBounds;
import at.petrak.hexcasting.common.casting.operators.circles.OpImpetusDir; import at.petrak.hexcasting.common.casting.operators.circles.OpImpetusDir;
import at.petrak.hexcasting.common.casting.operators.circles.OpImpetusPos; import at.petrak.hexcasting.common.casting.operators.circles.OpImpetusPos;
import at.petrak.hexcasting.common.casting.operators.eval.OpEval; import at.petrak.hexcasting.common.casting.operators.eval.OpEval;
import at.petrak.hexcasting.common.casting.operators.eval.OpEvalDelay;
import at.petrak.hexcasting.common.casting.operators.eval.OpForEach; import at.petrak.hexcasting.common.casting.operators.eval.OpForEach;
import at.petrak.hexcasting.common.casting.operators.eval.OpHalt; import at.petrak.hexcasting.common.casting.operators.eval.OpHalt;
import at.petrak.hexcasting.common.casting.operators.lists.*; import at.petrak.hexcasting.common.casting.operators.lists.*;
@ -52,417 +51,417 @@ public class RegisterPatterns {
// - CW is the special or destruction version // - CW is the special or destruction version
// == Getters == // == Getters ==
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qaq", HexDir.NORTH_EAST), modLoc("get_caster"), PatternRegistry.mapPattern(HexPattern.fromAngles("qaq", HexDir.NORTH_EAST), modLoc("get_caster"),
OpGetCaster.INSTANCE); OpGetCaster.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aa", HexDir.EAST), modLoc("get_entity_pos"), PatternRegistry.mapPattern(HexPattern.fromAngles("aa", HexDir.EAST), modLoc("get_entity_pos"),
OpEntityPos.INSTANCE); OpEntityPos.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wa", HexDir.EAST), modLoc("get_entity_look"), PatternRegistry.mapPattern(HexPattern.fromAngles("wa", HexDir.EAST), modLoc("get_entity_look"),
OpEntityLook.INSTANCE); OpEntityLook.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("awq", HexDir.NORTH_EAST), modLoc("get_entity_height"), PatternRegistry.mapPattern(HexPattern.fromAngles("awq", HexDir.NORTH_EAST), modLoc("get_entity_height"),
OpEntityHeight.INSTANCE); OpEntityHeight.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wq", HexDir.EAST), modLoc("get_entity_velocity"), PatternRegistry.mapPattern(HexPattern.fromAngles("wq", HexDir.EAST), modLoc("get_entity_velocity"),
OpEntityVelocity.INSTANCE); OpEntityVelocity.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wqaawdd", HexDir.EAST), modLoc("raycast"), PatternRegistry.mapPattern(HexPattern.fromAngles("wqaawdd", HexDir.EAST), modLoc("raycast"),
OpBlockRaycast.INSTANCE); OpBlockRaycast.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("weddwaa", HexDir.EAST), modLoc("raycast/axis"), PatternRegistry.mapPattern(HexPattern.fromAngles("weddwaa", HexDir.EAST), modLoc("raycast/axis"),
OpBlockAxisRaycast.INSTANCE); OpBlockAxisRaycast.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("weaqa", HexDir.EAST), modLoc("raycast/entity"), PatternRegistry.mapPattern(HexPattern.fromAngles("weaqa", HexDir.EAST), modLoc("raycast/entity"),
OpEntityRaycast.INSTANCE); OpEntityRaycast.INSTANCE);
// == spell circle getters == // == spell circle getters ==
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eaqwqae", HexDir.SOUTH_WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("eaqwqae", HexDir.SOUTH_WEST),
modLoc("circle/impetus_pos"), OpImpetusPos.INSTANCE); modLoc("circle/impetus_pos"), OpImpetusPos.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eaqwqaewede", HexDir.SOUTH_WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("eaqwqaewede", HexDir.SOUTH_WEST),
modLoc("circle/impetus_dir"), OpImpetusDir.INSTANCE); modLoc("circle/impetus_dir"), OpImpetusDir.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eaqwqaewdd", HexDir.SOUTH_WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("eaqwqaewdd", HexDir.SOUTH_WEST),
modLoc("circle/bounds/min"), new OpCircleBounds(false)); modLoc("circle/bounds/min"), new OpCircleBounds(false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aqwqawaaqa", HexDir.WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("aqwqawaaqa", HexDir.WEST),
modLoc("circle/bounds/max"), new OpCircleBounds(true)); modLoc("circle/bounds/max"), new OpCircleBounds(true));
// == Modify Stack == // == Modify Stack ==
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aadaa", HexDir.EAST), modLoc("duplicate"), PatternRegistry.mapPattern(HexPattern.fromAngles("aadaa", HexDir.EAST), modLoc("duplicate"),
OpDuplicate.INSTANCE); OpDuplicate.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aadaadaa", HexDir.EAST), modLoc("duplicate_n"), PatternRegistry.mapPattern(HexPattern.fromAngles("aadaadaa", HexDir.EAST), modLoc("duplicate_n"),
OpDuplicateN.INSTANCE); OpDuplicateN.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qwaeawqaeaqa", HexDir.NORTH_WEST), modLoc("stack_len"), PatternRegistry.mapPattern(HexPattern.fromAngles("qwaeawqaeaqa", HexDir.NORTH_WEST), modLoc("stack_len"),
OpStackSize.INSTANCE); OpStackSize.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aawdd", HexDir.EAST), modLoc("swap"), OpSwap.INSTANCE); PatternRegistry.mapPattern(HexPattern.fromAngles("aawdd", HexDir.EAST), modLoc("swap"), OpSwap.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ddad", HexDir.WEST), modLoc("fisherman"), PatternRegistry.mapPattern(HexPattern.fromAngles("ddad", HexDir.WEST), modLoc("fisherman"),
OpFisherman.INSTANCE); OpFisherman.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qaawdde", HexDir.SOUTH_EAST), modLoc("swizzle"), PatternRegistry.mapPattern(HexPattern.fromAngles("qaawdde", HexDir.SOUTH_EAST), modLoc("swizzle"),
OpAlwinfyHasAscendedToABeingOfPureMath.INSTANCE); OpAlwinfyHasAscendedToABeingOfPureMath.INSTANCE);
// == Math == // == Math ==
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waaw", HexDir.NORTH_EAST), modLoc("add"), PatternRegistry.mapPattern(HexPattern.fromAngles("waaw", HexDir.NORTH_EAST), modLoc("add"),
OpAdd.INSTANCE); OpAdd.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wddw", HexDir.NORTH_WEST), modLoc("sub"), PatternRegistry.mapPattern(HexPattern.fromAngles("wddw", HexDir.NORTH_WEST), modLoc("sub"),
OpSub.INSTANCE); OpSub.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waqaw", HexDir.SOUTH_EAST), modLoc("mul_dot"), PatternRegistry.mapPattern(HexPattern.fromAngles("waqaw", HexDir.SOUTH_EAST), modLoc("mul_dot"),
OpMulDot.INSTANCE); OpMulDot.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wdedw", HexDir.NORTH_EAST), modLoc("div_cross"), PatternRegistry.mapPattern(HexPattern.fromAngles("wdedw", HexDir.NORTH_EAST), modLoc("div_cross"),
OpDivCross.INSTANCE); OpDivCross.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wqaqw", HexDir.NORTH_EAST), modLoc("abs_len"), PatternRegistry.mapPattern(HexPattern.fromAngles("wqaqw", HexDir.NORTH_EAST), modLoc("abs_len"),
OpAbsLen.INSTANCE); OpAbsLen.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wedew", HexDir.NORTH_WEST), modLoc("pow_proj"), PatternRegistry.mapPattern(HexPattern.fromAngles("wedew", HexDir.NORTH_WEST), modLoc("pow_proj"),
OpPowProj.INSTANCE); OpPowProj.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ewq", HexDir.EAST), modLoc("floor"), PatternRegistry.mapPattern(HexPattern.fromAngles("ewq", HexDir.EAST), modLoc("floor"),
OpFloor.INSTANCE); OpFloor.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qwe", HexDir.EAST), modLoc("ceil"), PatternRegistry.mapPattern(HexPattern.fromAngles("qwe", HexDir.EAST), modLoc("ceil"),
OpCeil.INSTANCE); OpCeil.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eqqqqq", HexDir.EAST), modLoc("construct_vec"), PatternRegistry.mapPattern(HexPattern.fromAngles("eqqqqq", HexDir.EAST), modLoc("construct_vec"),
OpConstructVec.INSTANCE); OpConstructVec.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qeeeee", HexDir.EAST), modLoc("deconstruct_vec"), PatternRegistry.mapPattern(HexPattern.fromAngles("qeeeee", HexDir.EAST), modLoc("deconstruct_vec"),
OpDeconstructVec.INSTANCE); OpDeconstructVec.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqaww", HexDir.NORTH_WEST), modLoc("coerce_axial"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqaww", HexDir.NORTH_WEST), modLoc("coerce_axial"),
OpCoerceToAxial.INSTANCE); OpCoerceToAxial.INSTANCE);
// == Logic == // == Logic ==
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wdw", HexDir.NORTH_EAST), modLoc("and"), PatternRegistry.mapPattern(HexPattern.fromAngles("wdw", HexDir.NORTH_EAST), modLoc("and"),
OpBoolAnd.INSTANCE); OpBoolAnd.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waw", HexDir.SOUTH_EAST), modLoc("or"), PatternRegistry.mapPattern(HexPattern.fromAngles("waw", HexDir.SOUTH_EAST), modLoc("or"),
OpBoolOr.INSTANCE); OpBoolOr.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dwa", HexDir.NORTH_WEST), modLoc("xor"), PatternRegistry.mapPattern(HexPattern.fromAngles("dwa", HexDir.NORTH_WEST), modLoc("xor"),
OpBoolXor.INSTANCE); OpBoolXor.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("e", HexDir.SOUTH_EAST), modLoc("greater"), PatternRegistry.mapPattern(HexPattern.fromAngles("e", HexDir.SOUTH_EAST), modLoc("greater"),
new OpCompare(false, (a, b) -> a > b)); new OpCompare(false, (a, b) -> a > b));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("q", HexDir.SOUTH_WEST), modLoc("less"), PatternRegistry.mapPattern(HexPattern.fromAngles("q", HexDir.SOUTH_WEST), modLoc("less"),
new OpCompare(false, (a, b) -> a < b)); new OpCompare(false, (a, b) -> a < b));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ee", HexDir.SOUTH_EAST), modLoc("greater_eq"), PatternRegistry.mapPattern(HexPattern.fromAngles("ee", HexDir.SOUTH_EAST), modLoc("greater_eq"),
new OpCompare(true, (a, b) -> a >= b)); new OpCompare(true, (a, b) -> a >= b));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qq", HexDir.SOUTH_WEST), modLoc("less_eq"), PatternRegistry.mapPattern(HexPattern.fromAngles("qq", HexDir.SOUTH_WEST), modLoc("less_eq"),
new OpCompare(true, (a, b) -> a <= b)); new OpCompare(true, (a, b) -> a <= b));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ad", HexDir.EAST), modLoc("equals"), PatternRegistry.mapPattern(HexPattern.fromAngles("ad", HexDir.EAST), modLoc("equals"),
new OpEquality(false)); new OpEquality(false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("da", HexDir.EAST), modLoc("not_equals"), PatternRegistry.mapPattern(HexPattern.fromAngles("da", HexDir.EAST), modLoc("not_equals"),
new OpEquality(true)); new OpEquality(true));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dw", HexDir.NORTH_WEST), modLoc("not"), PatternRegistry.mapPattern(HexPattern.fromAngles("dw", HexDir.NORTH_WEST), modLoc("not"),
OpBoolNot.INSTANCE); OpBoolNot.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aw", HexDir.NORTH_EAST), modLoc("identity"), PatternRegistry.mapPattern(HexPattern.fromAngles("aw", HexDir.NORTH_EAST), modLoc("identity"),
OpBoolIdentityKindOf.INSTANCE); OpBoolIdentityKindOf.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eqqq", HexDir.NORTH_WEST), modLoc("random"), PatternRegistry.mapPattern(HexPattern.fromAngles("eqqq", HexDir.NORTH_WEST), modLoc("random"),
OpRandom.INSTANCE); OpRandom.INSTANCE);
// == Advanced Math == // == Advanced Math ==
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqaa", HexDir.SOUTH_EAST), modLoc("sin"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqaa", HexDir.SOUTH_EAST), modLoc("sin"),
OpSin.INSTANCE); OpSin.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqad", HexDir.SOUTH_EAST), modLoc("cos"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqad", HexDir.SOUTH_EAST), modLoc("cos"),
OpCos.INSTANCE); OpCos.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wqqqqqadq", HexDir.SOUTH_WEST), modLoc("tan"), PatternRegistry.mapPattern(HexPattern.fromAngles("wqqqqqadq", HexDir.SOUTH_WEST), modLoc("tan"),
OpTan.INSTANCE); OpTan.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ddeeeee", HexDir.SOUTH_EAST), modLoc("arcsin"), PatternRegistry.mapPattern(HexPattern.fromAngles("ddeeeee", HexDir.SOUTH_EAST), modLoc("arcsin"),
OpArcSin.INSTANCE); OpArcSin.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("adeeeee", HexDir.NORTH_EAST), modLoc("arccos"), PatternRegistry.mapPattern(HexPattern.fromAngles("adeeeee", HexDir.NORTH_EAST), modLoc("arccos"),
OpArcCos.INSTANCE); OpArcCos.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eadeeeeew", HexDir.NORTH_EAST), modLoc("arctan"), PatternRegistry.mapPattern(HexPattern.fromAngles("eadeeeeew", HexDir.NORTH_EAST), modLoc("arctan"),
OpArcTan.INSTANCE); OpArcTan.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eqaqe", HexDir.NORTH_WEST), modLoc("logarithm"), PatternRegistry.mapPattern(HexPattern.fromAngles("eqaqe", HexDir.NORTH_WEST), modLoc("logarithm"),
OpLog.INSTANCE); OpLog.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("addwaad", HexDir.NORTH_EAST), modLoc("modulo"), PatternRegistry.mapPattern(HexPattern.fromAngles("addwaad", HexDir.NORTH_EAST), modLoc("modulo"),
OpModulo.INSTANCE); OpModulo.INSTANCE);
// == Sets == // == Sets ==
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wdweaqa", HexDir.NORTH_EAST), modLoc("and_bit"), PatternRegistry.mapPattern(HexPattern.fromAngles("wdweaqa", HexDir.NORTH_EAST), modLoc("and_bit"),
OpAnd.INSTANCE); OpAnd.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waweaqa", HexDir.SOUTH_EAST), modLoc("or_bit"), PatternRegistry.mapPattern(HexPattern.fromAngles("waweaqa", HexDir.SOUTH_EAST), modLoc("or_bit"),
OpOr.INSTANCE); OpOr.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dwaeaqa", HexDir.NORTH_WEST), modLoc("xor_bit"), PatternRegistry.mapPattern(HexPattern.fromAngles("dwaeaqa", HexDir.NORTH_WEST), modLoc("xor_bit"),
OpXor.INSTANCE); OpXor.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dweaqa", HexDir.NORTH_WEST), modLoc("not_bit"), PatternRegistry.mapPattern(HexPattern.fromAngles("dweaqa", HexDir.NORTH_WEST), modLoc("not_bit"),
OpNot.INSTANCE); OpNot.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aweaqa", HexDir.NORTH_EAST), modLoc("to_set"), PatternRegistry.mapPattern(HexPattern.fromAngles("aweaqa", HexDir.NORTH_EAST), modLoc("to_set"),
OpToSet.INSTANCE); OpToSet.INSTANCE);
// == Spells == // == Spells ==
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("de", HexDir.NORTH_EAST), modLoc("print"), PatternRegistry.mapPattern(HexPattern.fromAngles("de", HexDir.NORTH_EAST), modLoc("print"),
OpPrint.INSTANCE); OpPrint.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aawaawaa", HexDir.EAST), modLoc("explode"), PatternRegistry.mapPattern(HexPattern.fromAngles("aawaawaa", HexDir.EAST), modLoc("explode"),
new OpExplode(false)); new OpExplode(false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ddwddwdd", HexDir.EAST), modLoc("explode/fire"), PatternRegistry.mapPattern(HexPattern.fromAngles("ddwddwdd", HexDir.EAST), modLoc("explode/fire"),
new OpExplode(true)); new OpExplode(true));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("awqqqwaqw", HexDir.SOUTH_WEST), modLoc("add_motion"), PatternRegistry.mapPattern(HexPattern.fromAngles("awqqqwaqw", HexDir.SOUTH_WEST), modLoc("add_motion"),
OpAddMotion.INSTANCE); OpAddMotion.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("awqqqwaq", HexDir.SOUTH_WEST), modLoc("blink"), PatternRegistry.mapPattern(HexPattern.fromAngles("awqqqwaq", HexDir.SOUTH_WEST), modLoc("blink"),
OpBlink.INSTANCE); OpBlink.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qaqqqqq", HexDir.EAST), modLoc("break_block"), PatternRegistry.mapPattern(HexPattern.fromAngles("qaqqqqq", HexDir.EAST), modLoc("break_block"),
OpBreakBlock.INSTANCE); OpBreakBlock.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eeeeede", HexDir.SOUTH_WEST), modLoc("place_block"), PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeede", HexDir.SOUTH_WEST), modLoc("place_block"),
OpPlaceBlock.INSTANCE); OpPlaceBlock.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("awddwqawqwawq", HexDir.EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("awddwqawqwawq", HexDir.EAST),
modLoc("colorize"), modLoc("colorize"),
OpColorize.INSTANCE); OpColorize.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aqawqadaq", HexDir.SOUTH_EAST), modLoc("create_water"), PatternRegistry.mapPattern(HexPattern.fromAngles("aqawqadaq", HexDir.SOUTH_EAST), modLoc("create_water"),
OpCreateWater.INSTANCE); OpCreateWater.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dedwedade", HexDir.SOUTH_WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("dedwedade", HexDir.SOUTH_WEST),
modLoc("destroy_water"), modLoc("destroy_water"),
OpDestroyWater.INSTANCE); OpDestroyWater.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aaqawawa", HexDir.SOUTH_EAST), modLoc("ignite"), PatternRegistry.mapPattern(HexPattern.fromAngles("aaqawawa", HexDir.SOUTH_EAST), modLoc("ignite"),
OpIgnite.INSTANCE); OpIgnite.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ddedwdwd", HexDir.SOUTH_WEST), modLoc("extinguish"), PatternRegistry.mapPattern(HexPattern.fromAngles("ddedwdwd", HexDir.SOUTH_WEST), modLoc("extinguish"),
OpExtinguish.INSTANCE); OpExtinguish.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqa", HexDir.NORTH_EAST), modLoc("conjure_block"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqa", HexDir.NORTH_EAST), modLoc("conjure_block"),
new OpConjure(false)); new OpConjure(false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqd", HexDir.NORTH_EAST), modLoc("conjure_light"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqd", HexDir.NORTH_EAST), modLoc("conjure_light"),
new OpConjure(true)); new OpConjure(true));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wqaqwawqaqw", HexDir.NORTH_EAST), modLoc("bonemeal"), PatternRegistry.mapPattern(HexPattern.fromAngles("wqaqwawqaqw", HexDir.NORTH_EAST), modLoc("bonemeal"),
OpTheOnlyReasonAnyoneDownloadedPsi.INSTANCE); OpTheOnlyReasonAnyoneDownloadedPsi.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqwaeaeaeaeaea", HexDir.NORTH_WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqwaeaeaeaeaea", HexDir.NORTH_WEST),
modLoc("recharge"), modLoc("recharge"),
OpRecharge.INSTANCE); OpRecharge.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qdqawwaww", HexDir.EAST), modLoc("erase"), PatternRegistry.mapPattern(HexPattern.fromAngles("qdqawwaww", HexDir.EAST), modLoc("erase"),
new OpErase()); new OpErase());
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wqaqwd", HexDir.NORTH_EAST), modLoc("edify"), PatternRegistry.mapPattern(HexPattern.fromAngles("wqaqwd", HexDir.NORTH_EAST), modLoc("edify"),
OpEdifySapling.INSTANCE); OpEdifySapling.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("adaa", HexDir.WEST), modLoc("beep"), PatternRegistry.mapPattern(HexPattern.fromAngles("adaa", HexDir.WEST), modLoc("beep"),
OpBeep.INSTANCE); OpBeep.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waqqqqq", HexDir.EAST), modLoc("craft/cypher"), PatternRegistry.mapPattern(HexPattern.fromAngles("waqqqqq", HexDir.EAST), modLoc("craft/cypher"),
new OpMakePackagedSpell<>(HexItems.CYPHER, ManaConstants.CRYSTAL_UNIT)); new OpMakePackagedSpell<>(HexItems.CYPHER, ManaConstants.CRYSTAL_UNIT));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wwaqqqqqeaqeaeqqqeaeq", HexDir.EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("wwaqqqqqeaqeaeqqqeaeq", HexDir.EAST),
modLoc("craft/trinket"), modLoc("craft/trinket"),
new OpMakePackagedSpell<>(HexItems.TRINKET, 5 * ManaConstants.CRYSTAL_UNIT)); new OpMakePackagedSpell<>(HexItems.TRINKET, 5 * ManaConstants.CRYSTAL_UNIT));
PatternRegistry.mapPattern( PatternRegistry.mapPattern(
HexPattern.FromAnglesSig("wwaqqqqqeawqwqwqwqwqwwqqeadaeqqeqqeadaeqq", HexDir.EAST), HexPattern.fromAngles("wwaqqqqqeawqwqwqwqwqwwqqeadaeqqeqqeadaeqq", HexDir.EAST),
modLoc("craft/artifact"), modLoc("craft/artifact"),
new OpMakePackagedSpell<>(HexItems.ARTIFACT, 10 * ManaConstants.CRYSTAL_UNIT)); new OpMakePackagedSpell<>(HexItems.ARTIFACT, 10 * ManaConstants.CRYSTAL_UNIT));
PatternRegistry.mapPattern( PatternRegistry.mapPattern(
HexPattern.FromAnglesSig("aqqqaqwwaqqqqqeqaqqqawwqwqwqwqwqw", HexDir.SOUTH_WEST), HexPattern.fromAngles("aqqqaqwwaqqqqqeqaqqqawwqwqwqwqwqw", HexDir.SOUTH_WEST),
modLoc("craft/battery"), modLoc("craft/battery"),
OpMakeBattery.INSTANCE, OpMakeBattery.INSTANCE,
true); true);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqaqwawaw", HexDir.NORTH_WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqaqwawaw", HexDir.NORTH_WEST),
modLoc("potion/weakness"), modLoc("potion/weakness"),
new OpPotionEffect(MobEffects.WEAKNESS, ManaConstants.DUST_UNIT / 10, true, false, false)); new OpPotionEffect(MobEffects.WEAKNESS, ManaConstants.DUST_UNIT / 10, true, false, false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqawwawawd", HexDir.WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqawwawawd", HexDir.WEST),
modLoc("potion/levitation"), modLoc("potion/levitation"),
new OpPotionEffect(MobEffects.LEVITATION, ManaConstants.DUST_UNIT / 5, false, false, false)); new OpPotionEffect(MobEffects.LEVITATION, ManaConstants.DUST_UNIT / 5, false, false, false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqaewawawe", HexDir.SOUTH_WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqaewawawe", HexDir.SOUTH_WEST),
modLoc("potion/wither"), modLoc("potion/wither"),
new OpPotionEffect(MobEffects.WITHER, ManaConstants.DUST_UNIT, true, false, false)); new OpPotionEffect(MobEffects.WITHER, ManaConstants.DUST_UNIT, true, false, false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqadwawaww", HexDir.SOUTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqadwawaww", HexDir.SOUTH_EAST),
modLoc("potion/poison"), modLoc("potion/poison"),
new OpPotionEffect(MobEffects.POISON, ManaConstants.DUST_UNIT / 3, true, false, false)); new OpPotionEffect(MobEffects.POISON, ManaConstants.DUST_UNIT / 3, true, false, false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqadwawaw", HexDir.SOUTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqadwawaw", HexDir.SOUTH_EAST),
modLoc("potion/slowness"), modLoc("potion/slowness"),
new OpPotionEffect(MobEffects.MOVEMENT_SLOWDOWN, ManaConstants.DUST_UNIT / 3, true, false, false)); new OpPotionEffect(MobEffects.MOVEMENT_SLOWDOWN, ManaConstants.DUST_UNIT / 3, true, false, false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqaawawaedd", HexDir.NORTH_WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqaawawaedd", HexDir.NORTH_WEST),
modLoc("potion/regeneration"), modLoc("potion/regeneration"),
new OpPotionEffect(MobEffects.REGENERATION, ManaConstants.DUST_UNIT, true, true, true), true); new OpPotionEffect(MobEffects.REGENERATION, ManaConstants.DUST_UNIT, true, true, true), true);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqaawawaeqdd", HexDir.WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqaawawaeqdd", HexDir.WEST),
modLoc("potion/night_vision"), modLoc("potion/night_vision"),
new OpPotionEffect(MobEffects.NIGHT_VISION, ManaConstants.DUST_UNIT / 5, false, true, true), true); new OpPotionEffect(MobEffects.NIGHT_VISION, ManaConstants.DUST_UNIT / 5, false, true, true), true);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqaawawaeqqdd", HexDir.SOUTH_WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqaawawaeqqdd", HexDir.SOUTH_WEST),
modLoc("potion/absorption"), modLoc("potion/absorption"),
new OpPotionEffect(MobEffects.ABSORPTION, ManaConstants.DUST_UNIT, true, true, true), true); new OpPotionEffect(MobEffects.ABSORPTION, ManaConstants.DUST_UNIT, true, true, true), true);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qaawawaeqqqdd", HexDir.SOUTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qaawawaeqqqdd", HexDir.SOUTH_EAST),
modLoc("potion/haste"), modLoc("potion/haste"),
new OpPotionEffect(MobEffects.DIG_SPEED, ManaConstants.DUST_UNIT / 3, true, true, true), true); new OpPotionEffect(MobEffects.DIG_SPEED, ManaConstants.DUST_UNIT / 3, true, true, true), true);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aawawaeqqqqdd", HexDir.EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("aawawaeqqqqdd", HexDir.EAST),
modLoc("potion/strength"), modLoc("potion/strength"),
new OpPotionEffect(MobEffects.DAMAGE_BOOST, ManaConstants.DUST_UNIT / 3, true, true, true), true); new OpPotionEffect(MobEffects.DAMAGE_BOOST, ManaConstants.DUST_UNIT / 3, true, true, true), true);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waeawae", HexDir.EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("waeawae", HexDir.EAST),
modLoc("sentinel/create"), modLoc("sentinel/create"),
new OpCreateSentinel(false)); new OpCreateSentinel(false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qdwdqdw", HexDir.NORTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qdwdqdw", HexDir.NORTH_EAST),
modLoc("sentinel/destroy"), modLoc("sentinel/destroy"),
OpDestroySentinel.INSTANCE); OpDestroySentinel.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waeawaede", HexDir.EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("waeawaede", HexDir.EAST),
modLoc("sentinel/get_pos"), modLoc("sentinel/get_pos"),
OpGetSentinelPos.INSTANCE); OpGetSentinelPos.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waeawaedwa", HexDir.EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("waeawaedwa", HexDir.EAST),
modLoc("sentinel/wayfind"), modLoc("sentinel/wayfind"),
OpGetSentinelWayfind.INSTANCE); OpGetSentinelWayfind.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waadwawdaaweewq", HexDir.EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("waadwawdaaweewq", HexDir.EAST),
modLoc("lightning"), OpLightning.INSTANCE, true); modLoc("lightning"), OpLightning.INSTANCE, true);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eawwaeawawaa", HexDir.NORTH_WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("eawwaeawawaa", HexDir.NORTH_WEST),
modLoc("flight"), OpFlight.INSTANCE, true); modLoc("flight"), OpFlight.INSTANCE, true);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eaqawqadaqd", HexDir.EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("eaqawqadaqd", HexDir.EAST),
modLoc("create_lava"), OpCreateLava.INSTANCE, true); modLoc("create_lava"), OpCreateLava.INSTANCE, true);
PatternRegistry.mapPattern( PatternRegistry.mapPattern(
HexPattern.FromAnglesSig("wwwqqqwwwqqeqqwwwqqwqqdqqqqqdqq", HexDir.EAST), HexPattern.fromAngles("wwwqqqwwwqqeqqwwwqqwqqdqqqqqdqq", HexDir.EAST),
modLoc("teleport"), OpTeleport.INSTANCE, true); modLoc("teleport"), OpTeleport.INSTANCE, true);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waeawaeqqqwqwqqwq", HexDir.EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("waeawaeqqqwqwqqwq", HexDir.EAST),
modLoc("sentinel/create/great"), modLoc("sentinel/create/great"),
new OpCreateSentinel(true), true); new OpCreateSentinel(true), true);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eeewwweeewwaqqddqdqd", HexDir.EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("eeewwweeewwaqqddqdqd", HexDir.EAST),
modLoc("dispel_rain"), modLoc("dispel_rain"),
new OpWeather(false), true); new OpWeather(false), true);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wwweeewwweewdawdwad", HexDir.WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("wwweeewwweewdawdwad", HexDir.WEST),
modLoc("summon_rain"), modLoc("summon_rain"),
new OpWeather(true), true); new OpWeather(true), true);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qeqwqwqwqwqeqaeqeaqeqaeqaqded", HexDir.NORTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qeqwqwqwqwqeqaeqeaqeqaeqaqded", HexDir.NORTH_EAST),
modLoc("brainsweep"), modLoc("brainsweep"),
OpBrainsweep.INSTANCE, true); OpBrainsweep.INSTANCE, true);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqwqqqqqaq", HexDir.WEST), modLoc("akashic/read"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqwqqqqqaq", HexDir.WEST), modLoc("akashic/read"),
OpAkashicRead.INSTANCE); OpAkashicRead.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eeeweeeeede", HexDir.EAST), modLoc("akashic/write"), PatternRegistry.mapPattern(HexPattern.fromAngles("eeeweeeeede", HexDir.EAST), modLoc("akashic/write"),
OpAkashicWrite.INSTANCE); OpAkashicWrite.INSTANCE);
// == Meta stuff == // == Meta stuff ==
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqq", HexDir.WEST), modLoc("open_paren"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqq", HexDir.WEST), modLoc("open_paren"),
Widget.OPEN_PAREN); Widget.OPEN_PAREN);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eee", HexDir.EAST), modLoc("close_paren"), PatternRegistry.mapPattern(HexPattern.fromAngles("eee", HexDir.EAST), modLoc("close_paren"),
Widget.CLOSE_PAREN); Widget.CLOSE_PAREN);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqaw", HexDir.WEST), modLoc("escape"), Widget.ESCAPE); PatternRegistry.mapPattern(HexPattern.fromAngles("qqqaw", HexDir.WEST), modLoc("escape"), Widget.ESCAPE);
// http://www.toroidalsnark.net/mkss3-pix/CalderheadJMM2014.pdf // http://www.toroidalsnark.net/mkss3-pix/CalderheadJMM2014.pdf
// eval being a space filling curve feels apt doesn't it // eval being a space filling curve feels apt doesn't it
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("deaqq", HexDir.SOUTH_EAST), modLoc("eval"), PatternRegistry.mapPattern(HexPattern.fromAngles("deaqq", HexDir.SOUTH_EAST), modLoc("eval"),
OpEval.INSTANCE); OpEval.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aqdee", HexDir.SOUTH_WEST), modLoc("halt"), PatternRegistry.mapPattern(HexPattern.fromAngles("aqdee", HexDir.SOUTH_WEST), modLoc("halt"),
OpHalt.INSTANCE); OpHalt.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aqqqqq", HexDir.EAST), modLoc("read"), PatternRegistry.mapPattern(HexPattern.fromAngles("aqqqqq", HexDir.EAST), modLoc("read"),
OpRead.INSTANCE); OpRead.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("deeeee", HexDir.EAST), modLoc("write"), PatternRegistry.mapPattern(HexPattern.fromAngles("deeeee", HexDir.EAST), modLoc("write"),
OpWrite.INSTANCE); OpWrite.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aqqqqqe", HexDir.EAST), modLoc("readable"), PatternRegistry.mapPattern(HexPattern.fromAngles("aqqqqqe", HexDir.EAST), modLoc("readable"),
OpReadable.INSTANCE); OpReadable.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("deeeeeq", HexDir.EAST), modLoc("writable"), PatternRegistry.mapPattern(HexPattern.fromAngles("deeeeeq", HexDir.EAST), modLoc("writable"),
OpWritable.INSTANCE); OpWritable.INSTANCE);
// lorge boyes // lorge boyes
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wawqwqwqwqwqw", HexDir.EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("wawqwqwqwqwqw", HexDir.EAST),
modLoc("read/entity"), OpTheCoolerRead.INSTANCE); modLoc("read/entity"), OpTheCoolerRead.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wawqwqwqwqwqwew", HexDir.EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("wawqwqwqwqwqwew", HexDir.EAST),
modLoc("readable/entity"), OpTheCoolerReadable.INSTANCE); modLoc("readable/entity"), OpTheCoolerReadable.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qeewdweddw", HexDir.NORTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qeewdweddw", HexDir.NORTH_EAST),
modLoc("read/local"), OpPeekLocal.INSTANCE); modLoc("read/local"), OpPeekLocal.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eqqwawqaaw", HexDir.NORTH_WEST), PatternRegistry.mapPattern(HexPattern.fromAngles("eqqwawqaaw", HexDir.NORTH_WEST),
modLoc("write/local"), OpPushLocal.INSTANCE); modLoc("write/local"), OpPushLocal.INSTANCE);
// == Consts == // == Consts ==
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("d", HexDir.EAST), modLoc("const/null"), Widget.NULL); PatternRegistry.mapPattern(HexPattern.fromAngles("d", HexDir.EAST), modLoc("const/null"), Widget.NULL);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqea", HexDir.NORTH_WEST), modLoc("const/vec/px"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqea", HexDir.NORTH_WEST), modLoc("const/vec/px"),
Operator.makeConstantOp(SpellDatum.make(new Vec3(1.0, 0.0, 0.0)))); Operator.makeConstantOp(SpellDatum.make(new Vec3(1.0, 0.0, 0.0))));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqew", HexDir.NORTH_WEST), modLoc("const/vec/py"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqew", HexDir.NORTH_WEST), modLoc("const/vec/py"),
Operator.makeConstantOp(SpellDatum.make(new Vec3(0.0, 1.0, 0.0)))); Operator.makeConstantOp(SpellDatum.make(new Vec3(0.0, 1.0, 0.0))));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqed", HexDir.NORTH_WEST), modLoc("const/vec/pz"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqed", HexDir.NORTH_WEST), modLoc("const/vec/pz"),
Operator.makeConstantOp(SpellDatum.make(new Vec3(0.0, 0.0, 1.0)))); Operator.makeConstantOp(SpellDatum.make(new Vec3(0.0, 0.0, 1.0))));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eeeeeqa", HexDir.SOUTH_WEST), modLoc("const/vec/nx"), PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeeqa", HexDir.SOUTH_WEST), modLoc("const/vec/nx"),
Operator.makeConstantOp(SpellDatum.make(new Vec3(-1.0, 0.0, 0.0)))); Operator.makeConstantOp(SpellDatum.make(new Vec3(-1.0, 0.0, 0.0))));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eeeeeqw", HexDir.SOUTH_WEST), modLoc("const/vec/ny"), PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeeqw", HexDir.SOUTH_WEST), modLoc("const/vec/ny"),
Operator.makeConstantOp(SpellDatum.make(new Vec3(0.0, -1.0, 0.0)))); Operator.makeConstantOp(SpellDatum.make(new Vec3(0.0, -1.0, 0.0))));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eeeeeqd", HexDir.SOUTH_WEST), modLoc("const/vec/nz"), PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeeqd", HexDir.SOUTH_WEST), modLoc("const/vec/nz"),
Operator.makeConstantOp(SpellDatum.make(new Vec3(0.0, 0.0, -1.0)))); Operator.makeConstantOp(SpellDatum.make(new Vec3(0.0, 0.0, -1.0))));
// Yep, this is what I spend the "plain hexagon" pattern on. // Yep, this is what I spend the "plain hexagon" pattern on.
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqq", HexDir.NORTH_WEST), modLoc("const/vec/0"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqq", HexDir.NORTH_WEST), modLoc("const/vec/0"),
Operator.makeConstantOp(SpellDatum.make(new Vec3(0.0, 0.0, 0.0)))); Operator.makeConstantOp(SpellDatum.make(new Vec3(0.0, 0.0, 0.0))));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qdwdq", HexDir.NORTH_EAST), modLoc("const/double/pi"), PatternRegistry.mapPattern(HexPattern.fromAngles("qdwdq", HexDir.NORTH_EAST), modLoc("const/double/pi"),
Operator.makeConstantOp(SpellDatum.make(Math.PI))); Operator.makeConstantOp(SpellDatum.make(Math.PI)));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eawae", HexDir.NORTH_WEST), modLoc("const/double/tau"), PatternRegistry.mapPattern(HexPattern.fromAngles("eawae", HexDir.NORTH_WEST), modLoc("const/double/tau"),
Operator.makeConstantOp(SpellDatum.make(HexUtils.TAU))); Operator.makeConstantOp(SpellDatum.make(HexUtils.TAU)));
// e // e
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aaq", HexDir.EAST), modLoc("const/double/e"), PatternRegistry.mapPattern(HexPattern.fromAngles("aaq", HexDir.EAST), modLoc("const/double/e"),
Operator.makeConstantOp(SpellDatum.make(Math.E))); Operator.makeConstantOp(SpellDatum.make(Math.E)));
// == Entities == // == Entities ==
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqdaqa", HexDir.SOUTH_EAST), modLoc("get_entity"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqdaqa", HexDir.SOUTH_EAST), modLoc("get_entity"),
new OpGetEntityAt(e -> true)); new OpGetEntityAt(e -> true));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqdaqaawa", HexDir.SOUTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqdaqaawa", HexDir.SOUTH_EAST),
modLoc("get_entity/animal"), modLoc("get_entity/animal"),
new OpGetEntityAt(OpGetEntitiesBy::isAnimal)); new OpGetEntityAt(OpGetEntitiesBy::isAnimal));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqdaqaawq", HexDir.SOUTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqdaqaawq", HexDir.SOUTH_EAST),
modLoc("get_entity/monster"), modLoc("get_entity/monster"),
new OpGetEntityAt(OpGetEntitiesBy::isMonster)); new OpGetEntityAt(OpGetEntitiesBy::isMonster));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqdaqaaww", HexDir.SOUTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqdaqaaww", HexDir.SOUTH_EAST),
modLoc("get_entity/item"), modLoc("get_entity/item"),
new OpGetEntityAt(OpGetEntitiesBy::isItem)); new OpGetEntityAt(OpGetEntitiesBy::isItem));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqdaqaawe", HexDir.SOUTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqdaqaawe", HexDir.SOUTH_EAST),
modLoc("get_entity/player"), modLoc("get_entity/player"),
new OpGetEntityAt(OpGetEntitiesBy::isPlayer)); new OpGetEntityAt(OpGetEntitiesBy::isPlayer));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqdaqaawd", HexDir.SOUTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqdaqaawd", HexDir.SOUTH_EAST),
modLoc("get_entity/living"), modLoc("get_entity/living"),
new OpGetEntityAt(OpGetEntitiesBy::isLiving)); new OpGetEntityAt(OpGetEntitiesBy::isLiving));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqwded", HexDir.SOUTH_EAST), modLoc("zone_entity"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqwded", HexDir.SOUTH_EAST), modLoc("zone_entity"),
new OpGetEntitiesBy(e -> true, false)); new OpGetEntitiesBy(e -> true, false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqwdeddwa", HexDir.SOUTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqwdeddwa", HexDir.SOUTH_EAST),
modLoc("zone_entity/animal"), modLoc("zone_entity/animal"),
new OpGetEntitiesBy(OpGetEntitiesBy::isAnimal, false)); new OpGetEntitiesBy(OpGetEntitiesBy::isAnimal, false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eeeeewaqaawa", HexDir.NORTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeewaqaawa", HexDir.NORTH_EAST),
modLoc("zone_entity/not_animal"), modLoc("zone_entity/not_animal"),
new OpGetEntitiesBy(OpGetEntitiesBy::isAnimal, true)); new OpGetEntitiesBy(OpGetEntitiesBy::isAnimal, true));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqwdeddwq", HexDir.SOUTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqwdeddwq", HexDir.SOUTH_EAST),
modLoc("zone_entity/monster"), modLoc("zone_entity/monster"),
new OpGetEntitiesBy(OpGetEntitiesBy::isMonster, false)); new OpGetEntitiesBy(OpGetEntitiesBy::isMonster, false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eeeeewaqaawq", HexDir.NORTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeewaqaawq", HexDir.NORTH_EAST),
modLoc("zone_entity/not_monster"), modLoc("zone_entity/not_monster"),
new OpGetEntitiesBy(OpGetEntitiesBy::isMonster, true)); new OpGetEntitiesBy(OpGetEntitiesBy::isMonster, true));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqwdeddww", HexDir.SOUTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqwdeddww", HexDir.SOUTH_EAST),
modLoc("zone_entity/item"), modLoc("zone_entity/item"),
new OpGetEntitiesBy(OpGetEntitiesBy::isItem, false)); new OpGetEntitiesBy(OpGetEntitiesBy::isItem, false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eeeeewaqaaww", HexDir.NORTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeewaqaaww", HexDir.NORTH_EAST),
modLoc("zone_entity/not_item"), modLoc("zone_entity/not_item"),
new OpGetEntitiesBy(OpGetEntitiesBy::isItem, true)); new OpGetEntitiesBy(OpGetEntitiesBy::isItem, true));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqwdeddwe", HexDir.SOUTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqwdeddwe", HexDir.SOUTH_EAST),
modLoc("zone_entity/player"), modLoc("zone_entity/player"),
new OpGetEntitiesBy(OpGetEntitiesBy::isPlayer, false)); new OpGetEntitiesBy(OpGetEntitiesBy::isPlayer, false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eeeeewaqaawe", HexDir.NORTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeewaqaawe", HexDir.NORTH_EAST),
modLoc("zone_entity/not_player"), modLoc("zone_entity/not_player"),
new OpGetEntitiesBy(OpGetEntitiesBy::isPlayer, true)); new OpGetEntitiesBy(OpGetEntitiesBy::isPlayer, true));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqwdeddwd", HexDir.SOUTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqwdeddwd", HexDir.SOUTH_EAST),
modLoc("zone_entity/living"), modLoc("zone_entity/living"),
new OpGetEntitiesBy(OpGetEntitiesBy::isLiving, false)); new OpGetEntitiesBy(OpGetEntitiesBy::isLiving, false));
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eeeeewaqaawd", HexDir.NORTH_EAST), PatternRegistry.mapPattern(HexPattern.fromAngles("eeeeewaqaawd", HexDir.NORTH_EAST),
modLoc("zone_entity/not_living"), modLoc("zone_entity/not_living"),
new OpGetEntitiesBy(OpGetEntitiesBy::isLiving, true)); new OpGetEntitiesBy(OpGetEntitiesBy::isLiving, true));
// == Lists == // == Lists ==
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("edqde", HexDir.SOUTH_WEST), modLoc("append"), PatternRegistry.mapPattern(HexPattern.fromAngles("edqde", HexDir.SOUTH_WEST), modLoc("append"),
OpAppend.INSTANCE); OpAppend.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qaeaq", HexDir.NORTH_WEST), modLoc("concat"), PatternRegistry.mapPattern(HexPattern.fromAngles("qaeaq", HexDir.NORTH_WEST), modLoc("concat"),
OpConcat.INSTANCE); OpConcat.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("deeed", HexDir.NORTH_WEST), modLoc("index"), PatternRegistry.mapPattern(HexPattern.fromAngles("deeed", HexDir.NORTH_WEST), modLoc("index"),
OpIndex.INSTANCE); OpIndex.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dadad", HexDir.NORTH_EAST), modLoc("for_each"), PatternRegistry.mapPattern(HexPattern.fromAngles("dadad", HexDir.NORTH_EAST), modLoc("for_each"),
OpForEach.INSTANCE); OpForEach.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aqaeaq", HexDir.EAST), modLoc("list_size"), PatternRegistry.mapPattern(HexPattern.fromAngles("aqaeaq", HexDir.EAST), modLoc("list_size"),
OpListSize.INSTANCE); OpListSize.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("adeeed", HexDir.EAST), modLoc("singleton"), PatternRegistry.mapPattern(HexPattern.fromAngles("adeeed", HexDir.EAST), modLoc("singleton"),
OpSingleton.INSTANCE); OpSingleton.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqaeaae", HexDir.NORTH_EAST), modLoc("empty_list"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqaeaae", HexDir.NORTH_EAST), modLoc("empty_list"),
OpEmptyList.INSTANCE); OpEmptyList.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqaede", HexDir.EAST), modLoc("reverse_list"), PatternRegistry.mapPattern(HexPattern.fromAngles("qqqaede", HexDir.EAST), modLoc("reverse_list"),
OpReverski.INSTANCE); OpReverski.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ewdqdwe", HexDir.SOUTH_WEST), modLoc("last_n_list"), PatternRegistry.mapPattern(HexPattern.fromAngles("ewdqdwe", HexDir.SOUTH_WEST), modLoc("last_n_list"),
OpLastNToList.INSTANCE); OpLastNToList.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qwaeawq", HexDir.NORTH_WEST), modLoc("splat"), PatternRegistry.mapPattern(HexPattern.fromAngles("qwaeawq", HexDir.NORTH_WEST), modLoc("splat"),
OpSplat.INSTANCE); OpSplat.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dedqde", HexDir.EAST), modLoc("index_of"), PatternRegistry.mapPattern(HexPattern.fromAngles("dedqde", HexDir.EAST), modLoc("index_of"),
OpIndexOf.INSTANCE); OpIndexOf.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("edqdewaqa", HexDir.SOUTH_WEST), modLoc("list_remove"), PatternRegistry.mapPattern(HexPattern.fromAngles("edqdewaqa", HexDir.SOUTH_WEST), modLoc("list_remove"),
OpRemove.INSTANCE); OpRemove.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qaeaqwded", HexDir.NORTH_WEST), modLoc("slice"), PatternRegistry.mapPattern(HexPattern.fromAngles("qaeaqwded", HexDir.NORTH_WEST), modLoc("slice"),
OpSlice.INSTANCE); OpSlice.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wqaeaqw", HexDir.NORTH_WEST), modLoc("modify_in_place"), PatternRegistry.mapPattern(HexPattern.fromAngles("wqaeaqw", HexDir.NORTH_WEST), modLoc("modify_in_place"),
OpModifyInPlace.INSTANCE); OpModifyInPlace.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ddewedd", HexDir.SOUTH_EAST), modLoc("construct"), PatternRegistry.mapPattern(HexPattern.fromAngles("ddewedd", HexDir.SOUTH_EAST), modLoc("construct"),
OpCons.INSTANCE); OpCons.INSTANCE);
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aaqwqaa", HexDir.SOUTH_WEST), modLoc("deconstruct"), PatternRegistry.mapPattern(HexPattern.fromAngles("aaqwqaa", HexDir.SOUTH_WEST), modLoc("deconstruct"),
OpUnCons.INSTANCE); OpUnCons.INSTANCE);
} catch (PatternRegistry.RegisterPatternException exn) { } catch (PatternRegistry.RegisterPatternException exn) {

View file

@ -1,14 +1,8 @@
package at.petrak.hexcasting.common.casting.operators.eval package at.petrak.hexcasting.common.casting.operators.eval
import at.petrak.hexcasting.api.spell.OperationResult import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.api.spell.getChecked
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.SpellList
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.casting.CastingHarness
import at.petrak.hexcasting.api.spell.casting.ContinuationFrame import at.petrak.hexcasting.api.spell.casting.ContinuationFrame
import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect
import at.petrak.hexcasting.api.spell.casting.SpellContinuation import at.petrak.hexcasting.api.spell.casting.SpellContinuation
object OpEval : Operator { object OpEval : Operator {
@ -22,7 +16,7 @@ object OpEval : Operator {
val newCont = if (continuation is SpellContinuation.NotDone && continuation.frame is ContinuationFrame.FinishEval) { val newCont = if (continuation is SpellContinuation.NotDone && continuation.frame is ContinuationFrame.FinishEval) {
continuation continuation
} else { } else {
continuation.pushFrame(ContinuationFrame.FinishEval()) // install a break-boundary after eval continuation.pushFrame(ContinuationFrame.FinishEval) // install a break-boundary after eval
} }
val frame = ContinuationFrame.Evaluate(instrs) val frame = ContinuationFrame.Evaluate(instrs)

View file

@ -1,7 +1,7 @@
package at.petrak.hexcasting.common.casting.operators.math package at.petrak.hexcasting.common.casting.operators.math
import at.petrak.hexcasting.api.spell.ConstManaOperator import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.GetNumOrVec import at.petrak.hexcasting.api.spell.numOrVec
import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.asSpellResult import at.petrak.hexcasting.api.spell.asSpellResult
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
@ -12,7 +12,7 @@ object OpAbsLen : ConstManaOperator {
get() = 1 get() = 1
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> { override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val x = GetNumOrVec(args[0], 0) val x = numOrVec(args[0], 0)
return x.map({ num -> num.absoluteValue }, { vec -> vec.length() }).asSpellResult return x.map({ num -> num.absoluteValue }, { vec -> vec.length() }).asSpellResult
} }

View file

@ -1,7 +1,7 @@
package at.petrak.hexcasting.common.casting.operators.math package at.petrak.hexcasting.common.casting.operators.math
import at.petrak.hexcasting.api.spell.ConstManaOperator import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.GetNumOrVec import at.petrak.hexcasting.api.spell.numOrVec
import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.spellListOf import at.petrak.hexcasting.api.spell.spellListOf
@ -11,8 +11,8 @@ object OpAdd : ConstManaOperator {
get() = 2 get() = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> { override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val lhs = GetNumOrVec(args[0], 1) val lhs = numOrVec(args[0], 1)
val rhs = GetNumOrVec(args[1], 0) val rhs = numOrVec(args[1], 0)
return spellListOf( return spellListOf(
lhs.map({ lnum -> lhs.map({ lnum ->

View file

@ -1,7 +1,7 @@
package at.petrak.hexcasting.common.casting.operators.math package at.petrak.hexcasting.common.casting.operators.math
import at.petrak.hexcasting.api.spell.ConstManaOperator import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.GetNumOrVec import at.petrak.hexcasting.api.spell.numOrVec
import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.mishaps.MishapDivideByZero import at.petrak.hexcasting.api.spell.mishaps.MishapDivideByZero
@ -13,8 +13,8 @@ object OpDivCross : ConstManaOperator {
get() = 2 get() = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> { override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val lhs = GetNumOrVec(args[0], 1) val lhs = numOrVec(args[0], 1)
val rhs = GetNumOrVec(args[1], 0) val rhs = numOrVec(args[1], 0)
return spellListOf( return spellListOf(
lhs.map({ lnum -> lhs.map({ lnum ->

View file

@ -1,7 +1,7 @@
package at.petrak.hexcasting.common.casting.operators.math package at.petrak.hexcasting.common.casting.operators.math
import at.petrak.hexcasting.api.spell.ConstManaOperator import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.GetNumOrVec import at.petrak.hexcasting.api.spell.numOrVec
import at.petrak.hexcasting.api.spell.spellListOf import at.petrak.hexcasting.api.spell.spellListOf
import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
@ -11,8 +11,8 @@ object OpMulDot : ConstManaOperator {
get() = 2 get() = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> { override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val lhs = GetNumOrVec(args[0], 1) val lhs = numOrVec(args[0], 1)
val rhs = GetNumOrVec(args[1], 0) val rhs = numOrVec(args[1], 0)
return spellListOf( return spellListOf(
lhs.map({ lnum -> lhs.map({ lnum ->

View file

@ -1,7 +1,7 @@
package at.petrak.hexcasting.common.casting.operators.math package at.petrak.hexcasting.common.casting.operators.math
import at.petrak.hexcasting.api.spell.ConstManaOperator import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.GetNumOrVec import at.petrak.hexcasting.api.spell.numOrVec
import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.mishaps.MishapDivideByZero import at.petrak.hexcasting.api.spell.mishaps.MishapDivideByZero
@ -14,8 +14,8 @@ object OpPowProj : ConstManaOperator {
get() = 2 get() = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> { override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val lhs = GetNumOrVec(args[0], 1) val lhs = numOrVec(args[0], 1)
val rhs = GetNumOrVec(args[1], 0) val rhs = numOrVec(args[1], 0)
return spellListOf( return spellListOf(
lhs.map({ lnum -> lhs.map({ lnum ->

View file

@ -1,7 +1,7 @@
package at.petrak.hexcasting.common.casting.operators.math package at.petrak.hexcasting.common.casting.operators.math
import at.petrak.hexcasting.api.spell.ConstManaOperator import at.petrak.hexcasting.api.spell.ConstManaOperator
import at.petrak.hexcasting.api.spell.GetNumOrVec import at.petrak.hexcasting.api.spell.numOrVec
import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.spellListOf import at.petrak.hexcasting.api.spell.spellListOf
@ -12,8 +12,8 @@ object OpSub : ConstManaOperator {
get() = 2 get() = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> { override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val lhs = GetNumOrVec(args[0], 1) val lhs = numOrVec(args[0], 1)
val rhs = GetNumOrVec(args[1], 0) val rhs = numOrVec(args[1], 0)
return spellListOf( return spellListOf(
lhs.map({ lnum -> lhs.map({ lnum ->

View file

@ -8,7 +8,7 @@ object OpAnd : ConstManaOperator {
override val argc = 2 override val argc = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> { override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val firstParam = GetNumOrList(args[0], 0) val firstParam = numOrList(args[0], 0)
if (firstParam.right().isPresent) { if (firstParam.right().isPresent) {
val list1 = firstParam.right().get() val list1 = firstParam.right().get()

View file

@ -8,7 +8,7 @@ object OpOr : ConstManaOperator {
override val argc = 2 override val argc = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> { override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val firstParam = GetNumOrList(args[0], 0) val firstParam = numOrList(args[0], 0)
if (firstParam.right().isPresent) { if (firstParam.right().isPresent) {
val list1 = firstParam.right().get() val list1 = firstParam.right().get()

View file

@ -8,7 +8,7 @@ object OpXor : ConstManaOperator {
override val argc = 2 override val argc = 2
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> { override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
val firstParam = GetNumOrList(args[0], 0) val firstParam = numOrList(args[0], 0)
if (firstParam.right().isPresent) { if (firstParam.right().isPresent) {
val list1 = firstParam.right().get() val list1 = firstParam.right().get()

View file

@ -27,7 +27,7 @@ object OpBeep : SpellOperator {
return Triple( return Triple(
Spell(target, note, NoteBlockInstrument.values()[instrument]), Spell(target, note, NoteBlockInstrument.values()[instrument]),
ManaConstants.DUST_UNIT / 10, ManaConstants.DUST_UNIT / 10,
listOf(ParticleSpray.Cloud(target, 1.0)) listOf(ParticleSpray.cloud(target, 1.0))
) )
} }

View file

@ -39,8 +39,8 @@ object OpBlink : SpellOperator {
Spell(target, delta), Spell(target, delta),
ManaConstants.SHARD_UNIT * delta.roundToInt(), ManaConstants.SHARD_UNIT * delta.roundToInt(),
listOf( listOf(
ParticleSpray.Cloud(targetMiddlePos, 2.0, 50), ParticleSpray.cloud(targetMiddlePos, 2.0, 50),
ParticleSpray.Burst(targetMiddlePos.add(dvec), 2.0, 100) ParticleSpray.burst(targetMiddlePos.add(dvec), 2.0, 100)
) )
) )
} }

View file

@ -27,7 +27,7 @@ object OpBreakBlock : SpellOperator {
return Triple( return Triple(
Spell(pos), Spell(pos),
ManaConstants.DUST_UNIT * 2, ManaConstants.DUST_UNIT * 2,
listOf(ParticleSpray.Burst(centered, 1.0)) listOf(ParticleSpray.burst(centered, 1.0))
) )
} }

View file

@ -36,7 +36,7 @@ class OpConjure(val light: Boolean) : SpellOperator {
return Triple( return Triple(
Spell(target, light), Spell(target, light),
ManaConstants.DUST_UNIT, ManaConstants.DUST_UNIT,
listOf(ParticleSpray.Cloud(Vec3.atCenterOf(pos), 1.0)) listOf(ParticleSpray.cloud(Vec3.atCenterOf(pos), 1.0))
) )
} }

View file

@ -31,7 +31,7 @@ object OpCreateWater : SpellOperator {
return Triple( return Triple(
Spell(target), Spell(target),
ManaConstants.DUST_UNIT, ManaConstants.DUST_UNIT,
listOf(ParticleSpray.Burst(Vec3.atCenterOf(BlockPos(target)), 1.0)) listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0))
) )
} }

View file

@ -29,7 +29,7 @@ object OpDestroyWater : SpellOperator {
return Triple( return Triple(
Spell(target), Spell(target),
2 * ManaConstants.CRYSTAL_UNIT, 2 * ManaConstants.CRYSTAL_UNIT,
listOf(ParticleSpray.Burst(target, 3.0)) listOf(ParticleSpray.burst(target, 3.0))
) )
} }

View file

@ -22,7 +22,7 @@ class OpExplode(val fire: Boolean) : SpellOperator {
return Triple( return Triple(
Spell(pos, strength, this.fire), Spell(pos, strength, this.fire),
((1 + Mth.clamp(strength.toFloat(), 0f, 10f) + if (this.fire) 2 else 0) * ManaConstants.SHARD_UNIT).toInt(), ((1 + Mth.clamp(strength.toFloat(), 0f, 10f) + if (this.fire) 2 else 0) * ManaConstants.SHARD_UNIT).toInt(),
listOf(ParticleSpray.Burst(pos, strength, 50)) listOf(ParticleSpray.burst(pos, strength, 50))
) )
} }

View file

@ -28,7 +28,7 @@ object OpExtinguish : SpellOperator {
return Triple( return Triple(
Spell(target), Spell(target),
ManaConstants.CRYSTAL_UNIT, ManaConstants.CRYSTAL_UNIT,
listOf(ParticleSpray.Burst(target, 1.0)) listOf(ParticleSpray.burst(target, 1.0))
) )
} }

View file

@ -31,7 +31,7 @@ object OpIgnite : SpellOperator {
return Triple( return Triple(
Spell(target), Spell(target),
ManaConstants.DUST_UNIT, ManaConstants.DUST_UNIT,
listOf(ParticleSpray.Burst(Vec3.atCenterOf(BlockPos(target)), 1.0)) listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0))
) )
} }

View file

@ -10,7 +10,8 @@ import at.petrak.hexcasting.api.spell.SpellOperator
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem
import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.api.utils.ManaHelper import at.petrak.hexcasting.api.utils.extractMana
import at.petrak.hexcasting.api.utils.isManaItem
import at.petrak.hexcasting.common.items.magic.ItemManaHolder import at.petrak.hexcasting.common.items.magic.ItemManaHolder
import at.petrak.hexcasting.common.lib.HexItems import at.petrak.hexcasting.common.lib.HexItems
import net.minecraft.world.entity.item.ItemEntity import net.minecraft.world.entity.item.ItemEntity
@ -46,7 +47,7 @@ object OpMakeBattery : SpellOperator {
ctx.assertEntityInRange(entity) ctx.assertEntityInRange(entity)
if (!ManaHelper.isManaItem(entity.item) || ManaHelper.extractMana( if (!isManaItem(entity.item) || extractMana(
entity.item, entity.item,
drainForBatteries = true, drainForBatteries = true,
simulate = true simulate = true
@ -59,7 +60,7 @@ object OpMakeBattery : SpellOperator {
} }
return Triple(Spell(entity), return Triple(Spell(entity),
ManaConstants.CRYSTAL_UNIT, listOf(ParticleSpray.Burst(entity.position(), 0.5))) ManaConstants.CRYSTAL_UNIT, listOf(ParticleSpray.burst(entity.position(), 0.5)))
} }
private data class Spell(val itemEntity: ItemEntity) : RenderedSpell { private data class Spell(val itemEntity: ItemEntity) : RenderedSpell {
@ -67,7 +68,7 @@ object OpMakeBattery : SpellOperator {
val (handStack, hand) = ctx.getHeldItemToOperateOn { it.`is`(HexItemTags.PHIAL_BASE) } val (handStack, hand) = ctx.getHeldItemToOperateOn { it.`is`(HexItemTags.PHIAL_BASE) }
if (handStack.`is`(HexItemTags.PHIAL_BASE) && itemEntity.isAlive) { if (handStack.`is`(HexItemTags.PHIAL_BASE) && itemEntity.isAlive) {
val entityStack = itemEntity.item.copy() val entityStack = itemEntity.item.copy()
val manaAmt = ManaHelper.extractMana(entityStack, drainForBatteries = true) val manaAmt = extractMana(entityStack, drainForBatteries = true)
if (manaAmt > 0) { if (manaAmt > 0) {
ctx.caster.setItemInHand( ctx.caster.setItemInHand(
hand, hand,

View file

@ -10,7 +10,8 @@ import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem
import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.api.spell.mishaps.MishapOthersName import at.petrak.hexcasting.api.spell.mishaps.MishapOthersName
import at.petrak.hexcasting.api.utils.ManaHelper import at.petrak.hexcasting.api.utils.extractMana
import at.petrak.hexcasting.api.utils.isManaItem
import at.petrak.hexcasting.common.items.magic.ItemPackagedHex import at.petrak.hexcasting.common.items.magic.ItemPackagedHex
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.world.entity.item.ItemEntity import net.minecraft.world.entity.item.ItemEntity
@ -36,7 +37,7 @@ class OpMakePackagedSpell<T : ItemPackagedHex>(val itemType: T, val cost: Int) :
} }
ctx.assertEntityInRange(entity) ctx.assertEntityInRange(entity)
if (!ManaHelper.isManaItem(entity.item) || ManaHelper.extractMana( if (!isManaItem(entity.item) || extractMana(
entity.item, entity.item,
drainForBatteries = true, drainForBatteries = true,
simulate = true simulate = true
@ -52,7 +53,7 @@ class OpMakePackagedSpell<T : ItemPackagedHex>(val itemType: T, val cost: Int) :
if (trueName != null) if (trueName != null)
throw MishapOthersName(trueName) throw MishapOthersName(trueName)
return Triple(Spell(entity, patterns), cost, listOf(ParticleSpray.Burst(entity.position(), 0.5))) return Triple(Spell(entity, patterns), cost, listOf(ParticleSpray.burst(entity.position(), 0.5)))
} }
private inner class Spell(val itemEntity: ItemEntity, val patterns: List<SpellDatum<*>>) : RenderedSpell { private inner class Spell(val itemEntity: ItemEntity, val patterns: List<SpellDatum<*>>) : RenderedSpell {
@ -64,7 +65,7 @@ class OpMakePackagedSpell<T : ItemPackagedHex>(val itemType: T, val cost: Int) :
&& itemEntity.isAlive && itemEntity.isAlive
) { ) {
val entityStack = itemEntity.item.copy() val entityStack = itemEntity.item.copy()
val manaAmt = ManaHelper.extractMana(entityStack, drainForBatteries = true) val manaAmt = extractMana(entityStack, drainForBatteries = true)
if (manaAmt > 0) { if (manaAmt > 0) {
hexHolder.writeHex(patterns, manaAmt) hexHolder.writeHex(patterns, manaAmt)
} }

View file

@ -45,7 +45,7 @@ object OpPlaceBlock : SpellOperator {
return Triple( return Triple(
Spell(target), Spell(target),
ManaConstants.DUST_UNIT, ManaConstants.DUST_UNIT,
listOf(ParticleSpray.Cloud(Vec3.atCenterOf(pos), 1.0)) listOf(ParticleSpray.cloud(Vec3.atCenterOf(pos), 1.0))
) )
} }

View file

@ -44,7 +44,7 @@ class OpPotionEffect(
return Triple( return Triple(
Spell(effect, target, duration, potency), Spell(effect, target, duration, potency),
cost.toInt(), cost.toInt(),
listOf(ParticleSpray.Cloud(target.position().add(0.0, target.eyeHeight / 2.0, 0.0), 1.0)) listOf(ParticleSpray.cloud(target.position().add(0.0, target.eyeHeight / 2.0, 0.0), 1.0))
) )
} }

View file

@ -10,7 +10,8 @@ import at.petrak.hexcasting.api.spell.SpellOperator
import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem
import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem
import at.petrak.hexcasting.api.utils.ManaHelper import at.petrak.hexcasting.api.utils.extractMana
import at.petrak.hexcasting.api.utils.isManaItem
import at.petrak.hexcasting.xplat.IXplatAbstractions import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.world.entity.item.ItemEntity import net.minecraft.world.entity.item.ItemEntity
@ -37,7 +38,7 @@ object OpRecharge : SpellOperator {
val entity = args.getChecked<ItemEntity>(0, argc) val entity = args.getChecked<ItemEntity>(0, argc)
ctx.assertEntityInRange(entity) ctx.assertEntityInRange(entity)
if (!ManaHelper.isManaItem(entity.item)) { if (!isManaItem(entity.item)) {
throw MishapBadItem.of( throw MishapBadItem.of(
entity, entity,
"mana" "mana"
@ -48,7 +49,7 @@ object OpRecharge : SpellOperator {
return null return null
return Triple(Spell(entity), return Triple(Spell(entity),
ManaConstants.CRYSTAL_UNIT, listOf(ParticleSpray.Burst(entity.position(), 0.5))) ManaConstants.CRYSTAL_UNIT, listOf(ParticleSpray.burst(entity.position(), 0.5)))
} }
private data class Spell(val itemEntity: ItemEntity) : RenderedSpell { private data class Spell(val itemEntity: ItemEntity) : RenderedSpell {
@ -65,7 +66,7 @@ object OpRecharge : SpellOperator {
val maxMana = mana.maxMana val maxMana = mana.maxMana
val existingMana = mana.mana val existingMana = mana.mana
val manaAmt = ManaHelper.extractMana(entityStack, maxMana - existingMana) val manaAmt = extractMana(entityStack, maxMana - existingMana)
mana.mana = manaAmt + existingMana mana.mana = manaAmt + existingMana

View file

@ -29,7 +29,7 @@ object OpTheOnlyReasonAnyoneDownloadedPsi : SpellOperator {
return Triple( return Triple(
Spell(target), Spell(target),
ManaConstants.DUST_UNIT, ManaConstants.DUST_UNIT,
listOf(ParticleSpray.Burst(Vec3.atCenterOf(BlockPos(target)), 1.0)) listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0))
) )
} }

View file

@ -47,7 +47,7 @@ object OpBrainsweep : SpellOperator {
return Triple( return Triple(
Spell(bpos, state, sacrifice, recipe), Spell(bpos, state, sacrifice, recipe),
10 * ManaConstants.CRYSTAL_UNIT, 10 * ManaConstants.CRYSTAL_UNIT,
listOf(ParticleSpray.Cloud(sacrifice.position(), 1.0), ParticleSpray.Burst(Vec3.atCenterOf(bpos), 0.3, 100)) listOf(ParticleSpray.cloud(sacrifice.position(), 1.0), ParticleSpray.burst(Vec3.atCenterOf(bpos), 0.3, 100))
) )
} }

View file

@ -31,7 +31,7 @@ object OpCreateLava : SpellOperator {
return Triple( return Triple(
Spell(target), Spell(target),
ManaConstants.CRYSTAL_UNIT, ManaConstants.CRYSTAL_UNIT,
listOf(ParticleSpray.Burst(Vec3.atCenterOf(BlockPos(target)), 1.0)), listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0)),
) )
} }

View file

@ -36,7 +36,7 @@ object OpTeleport : SpellOperator {
return Triple( return Triple(
Spell(teleportee, delta), Spell(teleportee, delta),
10 * ManaConstants.CRYSTAL_UNIT, 10 * ManaConstants.CRYSTAL_UNIT,
listOf(ParticleSpray.Cloud(targetMiddlePos, 2.0), ParticleSpray.Burst(targetMiddlePos.add(delta), 2.0)) listOf(ParticleSpray.cloud(targetMiddlePos, 2.0), ParticleSpray.burst(targetMiddlePos.add(delta), 2.0))
) )
} }

View file

@ -26,7 +26,7 @@ class OpCreateSentinel(val extendsRange: Boolean) : SpellOperator {
return Triple( return Triple(
Spell(target, this.extendsRange), Spell(target, this.extendsRange),
ManaConstants.DUST_UNIT, ManaConstants.DUST_UNIT,
listOf(ParticleSpray.Burst(target, 2.0)) listOf(ParticleSpray.burst(target, 2.0))
) )
} }

View file

@ -22,7 +22,7 @@ object OpDestroySentinel : SpellOperator {
// TODO why can't you remove things from other dimensions? // TODO why can't you remove things from other dimensions?
if (sentinel.dimension != ctx.world.dimension()) if (sentinel.dimension != ctx.world.dimension())
throw MishapLocationInWrongDimension(sentinel.dimension.location()) throw MishapLocationInWrongDimension(sentinel.dimension.location())
particles.add(ParticleSpray.Cloud(sentinel.position, 2.0)) particles.add(ParticleSpray.cloud(sentinel.position, 2.0))
return Triple( return Triple(
Spell, Spell,

View file

@ -32,7 +32,7 @@ public class ListPatternsCommand {
for (var pair : listing) { for (var pair : listing) {
ctx.getSource().sendSuccess(new TextComponent(pair.getValue().getFirst().toString()) ctx.getSource().sendSuccess(new TextComponent(pair.getValue().getFirst().toString())
.append(": ") .append(": ")
.append(SpellDatum.make(HexPattern.FromAnglesSig(pair.getKey(), pair.getValue().getSecond())) .append(SpellDatum.make(HexPattern.fromAngles(pair.getKey(), pair.getValue().getSecond()))
.display()), false); .display()), false);
} }
@ -86,7 +86,7 @@ public class ListPatternsCommand {
var tag = new CompoundTag(); var tag = new CompoundTag();
tag.putString(ItemScroll.TAG_OP_ID, opId.toString()); tag.putString(ItemScroll.TAG_OP_ID, opId.toString());
tag.put(ItemScroll.TAG_PATTERN, tag.put(ItemScroll.TAG_PATTERN,
HexPattern.FromAnglesSig(pattern, startDir).serializeToNBT()); HexPattern.fromAngles(pattern, startDir).serializeToNBT());
var stack = new ItemStack(HexItems.SCROLL); var stack = new ItemStack(HexItems.SCROLL);
stack.setTag(tag); stack.setTag(tag);

View file

@ -38,7 +38,7 @@ public class PatternResLocArgument extends ResourceLocationArgument {
for (var key : lookup.keySet()) { for (var key : lookup.keySet()) {
var rhs = lookup.get(key); var rhs = lookup.get(key);
if (rhs.getFirst().equals(targetId)) { if (rhs.getFirst().equals(targetId)) {
foundPat = HexPattern.FromAnglesSig(key, rhs.getSecond()); foundPat = HexPattern.fromAngles(key, rhs.getSecond());
break; break;
} }
} }

View file

@ -1,6 +1,5 @@
package at.petrak.hexcasting.common.entities; package at.petrak.hexcasting.common.entities;
import at.petrak.hexcasting.annotations.SoftImplement;
import at.petrak.hexcasting.api.spell.math.HexPattern; import at.petrak.hexcasting.api.spell.math.HexPattern;
import at.petrak.hexcasting.api.utils.HexUtils; import at.petrak.hexcasting.api.utils.HexUtils;
import at.petrak.hexcasting.api.utils.NBTHelper; import at.petrak.hexcasting.api.utils.NBTHelper;
@ -27,7 +26,6 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.GameRules; import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -60,7 +58,7 @@ public class EntityWallScroll extends HangingEntity {
CompoundTag patternTag = NBTHelper.getCompound(scroll, ItemScroll.TAG_PATTERN); CompoundTag patternTag = NBTHelper.getCompound(scroll, ItemScroll.TAG_PATTERN);
if (patternTag != null) { if (patternTag != null) {
this.pattern = HexPattern.DeserializeFromNBT(patternTag); this.pattern = HexPattern.fromNBT(patternTag);
if (this.level.isClientSide) { if (this.level.isClientSide) {
var pair = RenderLib.getCenteredPattern(pattern, 128, 128, 16f); var pair = RenderLib.getCenteredPattern(pattern, 128, 128, 16f);
var dots = pair.getSecond(); var dots = pair.getSecond();
@ -160,7 +158,7 @@ public class EntityWallScroll extends HangingEntity {
@Override @Override
public void addAdditionalSaveData(CompoundTag tag) { public void addAdditionalSaveData(CompoundTag tag) {
tag.putByte("direction", (byte) this.direction.ordinal()); tag.putByte("direction", (byte) this.direction.ordinal());
tag.put("scroll", HexUtils.serialize(this.scroll)); tag.put("scroll", HexUtils.serializeToNBT(this.scroll));
tag.putBoolean("showsStrokeOrder", this.getShowsStrokeOrder()); tag.putBoolean("showsStrokeOrder", this.getShowsStrokeOrder());
super.addAdditionalSaveData(tag); super.addAdditionalSaveData(tag);
} }

View file

@ -125,7 +125,7 @@ public class ItemScroll extends Item implements DataHolderItem {
public Optional<TooltipComponent> getTooltipImage(ItemStack stack) { public Optional<TooltipComponent> getTooltipImage(ItemStack stack) {
var compound = NBTHelper.getCompound(stack, ItemScroll.TAG_PATTERN); var compound = NBTHelper.getCompound(stack, ItemScroll.TAG_PATTERN);
if (compound != null) { if (compound != null) {
var pattern = HexPattern.DeserializeFromNBT(compound); var pattern = HexPattern.fromNBT(compound);
return Optional.of(new PatternTooltipGreeble( return Optional.of(new PatternTooltipGreeble(
pattern, pattern,
NBTHelper.hasString(stack, ItemScroll.TAG_OP_ID) ? PatternTooltipGreeble.ANCIENT_BG : PatternTooltipGreeble.PRISTINE_BG)); NBTHelper.hasString(stack, ItemScroll.TAG_OP_ID) ? PatternTooltipGreeble.ANCIENT_BG : PatternTooltipGreeble.PRISTINE_BG));

View file

@ -106,7 +106,7 @@ public class ItemSlate extends BlockItem implements DataHolderItem {
if (bet != null && bet.contains(BlockEntitySlate.TAG_PATTERN, Tag.TAG_COMPOUND)) { if (bet != null && bet.contains(BlockEntitySlate.TAG_PATTERN, Tag.TAG_COMPOUND)) {
var patTag = bet.getCompound(BlockEntitySlate.TAG_PATTERN); var patTag = bet.getCompound(BlockEntitySlate.TAG_PATTERN);
if (!patTag.isEmpty()) { if (!patTag.isEmpty()) {
var pattern = HexPattern.DeserializeFromNBT(patTag); var pattern = HexPattern.fromNBT(patTag);
return Optional.of(new PatternTooltipGreeble( return Optional.of(new PatternTooltipGreeble(
pattern, pattern,
PatternTooltipGreeble.SLATE_BG)); PatternTooltipGreeble.SLATE_BG));

View file

@ -57,14 +57,14 @@ public abstract class ItemManaHolder extends Item implements ManaHolderItem {
public int getBarColor(ItemStack pStack) { public int getBarColor(ItemStack pStack) {
var mana = getMana(pStack); var mana = getMana(pStack);
var maxMana = getMaxMana(pStack); var maxMana = getMaxMana(pStack);
return ManaHelper.barColor(mana, maxMana); return ManaHelper.manaBarColor(mana, maxMana);
} }
@Override @Override
public int getBarWidth(ItemStack pStack) { public int getBarWidth(ItemStack pStack) {
var mana = getMana(pStack); var mana = getMana(pStack);
var maxMana = getMaxMana(pStack); var maxMana = getMaxMana(pStack);
return ManaHelper.barWidth(mana, maxMana); return ManaHelper.manaBarWidth(mana, maxMana);
} }
@Override @Override

View file

@ -68,9 +68,9 @@ public abstract class ItemPackagedHex extends ItemManaHolder implements HexHolde
for (var patTag : patsTag) { for (var patTag : patsTag) {
CompoundTag tag = NBTHelper.getAsCompound(patTag); CompoundTag tag = NBTHelper.getAsCompound(patTag);
if (tag.size() != 1) if (tag.size() != 1)
out.add(SpellDatum.make(HexPattern.DeserializeFromNBT(tag))); out.add(SpellDatum.make(HexPattern.fromNBT(tag)));
else else
out.add(SpellDatum.DeserializeFromNBT(tag, level)); out.add(SpellDatum.fromNBT(tag, level));
} }
return out; return out;
} }

View file

@ -32,7 +32,7 @@ public class PatternScrollFunc extends LootItemConditionalFunction {
var startDir = entry.component2(); var startDir = entry.component2();
var tag = new CompoundTag(); var tag = new CompoundTag();
tag.putString(ItemScroll.TAG_OP_ID, opId.toString()); tag.putString(ItemScroll.TAG_OP_ID, opId.toString());
tag.put(ItemScroll.TAG_PATTERN, HexPattern.FromAnglesSig(sig, startDir).serializeToNBT()); tag.put(ItemScroll.TAG_PATTERN, HexPattern.fromAngles(sig, startDir).serializeToNBT());
stack.getOrCreateTag().merge(tag); stack.getOrCreateTag().merge(tag);

View file

@ -37,7 +37,7 @@ public record MsgCastParticleAck(ParticleSpray spray, FrozenColorizer colorizer)
var spread = buf.readDouble(); var spread = buf.readDouble();
var count = buf.readInt(); var count = buf.readInt();
var tag = buf.readAnySizeNbt(); var tag = buf.readAnySizeNbt();
var colorizer = FrozenColorizer.deserialize(tag); var colorizer = FrozenColorizer.fromNBT(tag);
return new MsgCastParticleAck( return new MsgCastParticleAck(
new ParticleSpray(new Vec3(posX, posY, posZ), new Vec3(velX, velY, velZ), fuzziness, spread, count), new ParticleSpray(new Vec3(posX, posY, posZ), new Vec3(velX, velY, velZ), fuzziness, spread, count),
colorizer); colorizer);
@ -54,7 +54,7 @@ public record MsgCastParticleAck(ParticleSpray spray, FrozenColorizer colorizer)
buf.writeDouble(this.spray.getFuzziness()); buf.writeDouble(this.spray.getFuzziness());
buf.writeDouble(this.spray.getSpread()); buf.writeDouble(this.spray.getSpread());
buf.writeInt(this.spray.getCount()); buf.writeInt(this.spray.getCount());
buf.writeNbt(this.colorizer.serialize()); buf.writeNbt(this.colorizer.serializeToNBT());
} }

View file

@ -39,12 +39,12 @@ public record MsgNewSpellPatternSyn(InteractionHand handUsed, HexPattern pattern
public static MsgNewSpellPatternSyn deserialize(ByteBuf buffer) { public static MsgNewSpellPatternSyn deserialize(ByteBuf buffer) {
var buf = new FriendlyByteBuf(buffer); var buf = new FriendlyByteBuf(buffer);
var hand = buf.readEnum(InteractionHand.class); var hand = buf.readEnum(InteractionHand.class);
var pattern = HexPattern.DeserializeFromNBT(buf.readAnySizeNbt()); var pattern = HexPattern.fromNBT(buf.readAnySizeNbt());
var resolvedPatternsLen = buf.readInt(); var resolvedPatternsLen = buf.readInt();
var resolvedPatterns = new ArrayList<ResolvedPattern>(resolvedPatternsLen); var resolvedPatterns = new ArrayList<ResolvedPattern>(resolvedPatternsLen);
for (int i = 0; i < resolvedPatternsLen; i++) { for (int i = 0; i < resolvedPatternsLen; i++) {
resolvedPatterns.add(ResolvedPattern.DeserializeFromNBT(buf.readAnySizeNbt())); resolvedPatterns.add(ResolvedPattern.fromNBT(buf.readAnySizeNbt()));
} }
return new MsgNewSpellPatternSyn(hand, pattern, resolvedPatterns); return new MsgNewSpellPatternSyn(hand, pattern, resolvedPatterns);
} }

View file

@ -34,7 +34,7 @@ public record MsgOpenSpellGuiAck(InteractionHand hand, List<ResolvedPattern> pat
var patternsLen = buf.readInt(); var patternsLen = buf.readInt();
var patterns = new ArrayList<ResolvedPattern>(patternsLen); var patterns = new ArrayList<ResolvedPattern>(patternsLen);
for (int i = 0; i < patternsLen; i++) { for (int i = 0; i < patternsLen; i++) {
patterns.add(ResolvedPattern.DeserializeFromNBT(buf.readAnySizeNbt())); patterns.add(ResolvedPattern.fromNBT(buf.readAnySizeNbt()));
} }
var descsLen = buf.readInt(); var descsLen = buf.readInt();

View file

@ -121,7 +121,7 @@ public record MsgShiftScrollSyn(InteractionHand hand, double scrollDelta, boolea
var datumTag = HexItems.ABACUS.readDatumTag(stack); var datumTag = HexItems.ABACUS.readDatumTag(stack);
if (datumTag != null) { if (datumTag != null) {
var popup = SpellDatum.DisplayFromTag(datumTag); var popup = SpellDatum.displayFromNBT(datumTag);
sender.displayClientMessage( sender.displayClientMessage(
new TranslatableComponent("hexcasting.tooltip.abacus", popup).withStyle(ChatFormatting.GREEN), true); new TranslatableComponent("hexcasting.tooltip.abacus", popup).withStyle(ChatFormatting.GREEN), true);
} }

View file

@ -35,7 +35,7 @@ public class ManualPatternComponent extends AbstractPatternComponent {
RawPattern raw = new Gson().fromJson(json, RawPattern.class); RawPattern raw = new Gson().fromJson(json, RawPattern.class);
var dir = HexDir.valueOf(raw.startdir); var dir = HexDir.valueOf(raw.startdir);
var pat = HexPattern.FromAnglesSig(raw.signature, dir); var pat = HexPattern.fromAngles(raw.signature, dir);
var origin = new HexCoord(raw.q, raw.r); var origin = new HexCoord(raw.q, raw.r);
out.add(new Pair<>(pat, origin)); out.add(new Pair<>(pat, origin));
} }

View file

@ -77,7 +77,7 @@ public final class PatternDrawingUtil {
patternEntries.add(new PatternEntry(pattern, origin, new ArrayList<>())); patternEntries.add(new PatternEntry(pattern, origin, new ArrayList<>()));
seenCoords.addAll(pattern.positions(origin)); seenCoords.addAll(pattern.positions(origin));
} }
var fakeCom = HexUtils.FindCenter(seenFakePoints); var fakeCom = HexUtils.findCenter(seenFakePoints);
var maxDx = -1f; var maxDx = -1f;
var maxDy = -1f; var maxDy = -1f;
@ -100,7 +100,7 @@ public final class PatternDrawingUtil {
seenRealPoints.add(px); seenRealPoints.add(px);
} }
} }
var realCom = HexUtils.FindCenter(seenRealPoints); var realCom = HexUtils.findCenter(seenRealPoints);
// and NOW for real! // and NOW for real!
for (var pat : patternEntries) { for (var pat : patternEntries) {

View file

@ -1,13 +1,13 @@
import at.petrak.hexcasting.api.spell.math.EulerPathFinder.findAltDrawing import at.petrak.hexcasting.api.spell.math.EulerPathFinder.findAltDrawing
import at.petrak.hexcasting.api.spell.math.HexDir import at.petrak.hexcasting.api.spell.math.HexDir
import at.petrak.hexcasting.api.spell.math.HexPattern.Companion.FromAnglesSig import at.petrak.hexcasting.api.spell.math.HexPattern.Companion.fromAngles
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
internal class EulerPathFinderTest { internal class EulerPathFinderTest {
@Test @Test
fun findAltDrawing() { fun findAltDrawing() {
val sig = "dadaddwwaadada" val sig = "dadaddwwaadada"
val pat = FromAnglesSig(sig, HexDir.NORTH_EAST) val pat = fromAngles(sig, HexDir.NORTH_EAST)
for (i in 0 until 8) { for (i in 0 until 8) {
val scrungled = findAltDrawing(pat, i.toLong()) val scrungled = findAltDrawing(pat, i.toLong())
println(scrungled) println(scrungled)

View file

@ -31,11 +31,11 @@ public class CCFavoredColorizer implements Component, AutoSyncedComponent {
@Override @Override
public void readFromNbt(CompoundTag tag) { public void readFromNbt(CompoundTag tag) {
this.colorizer = FrozenColorizer.deserialize(tag.getCompound(TAG_COLORIZER)); this.colorizer = FrozenColorizer.fromNBT(tag.getCompound(TAG_COLORIZER));
} }
@Override @Override
public void writeToNbt(CompoundTag tag) { public void writeToNbt(CompoundTag tag) {
tag.put(TAG_COLORIZER, this.colorizer.serialize()); tag.put(TAG_COLORIZER, this.colorizer.serializeToNBT());
} }
} }

View file

@ -42,7 +42,7 @@ public class CCFlight implements Component {
var timeLeft = tag.getInt(TAG_TIME_LEFT); var timeLeft = tag.getInt(TAG_TIME_LEFT);
var dim = ResourceKey.create(Registry.DIMENSION_REGISTRY, var dim = ResourceKey.create(Registry.DIMENSION_REGISTRY,
new ResourceLocation(tag.getString(TAG_DIMENSION))); new ResourceLocation(tag.getString(TAG_DIMENSION)));
var origin = HexUtils.DeserializeVec3FromNBT(tag.getLongArray(TAG_ORIGIN)); var origin = HexUtils.vecFromNBT(tag.getLongArray(TAG_ORIGIN));
var radius = tag.getDouble(TAG_RADIUS); var radius = tag.getDouble(TAG_RADIUS);
this.flight = new FlightAbility(true, timeLeft, dim, origin, radius); this.flight = new FlightAbility(true, timeLeft, dim, origin, radius);
} }

View file

@ -17,13 +17,13 @@ public class CCHarness implements Component {
public CCHarness(ServerPlayer owner) { public CCHarness(ServerPlayer owner) {
this.owner = owner; this.owner = owner;
} }
public CastingHarness getHarness(InteractionHand hand) { public CastingHarness getHarness(InteractionHand hand) {
var ctx = new CastingContext(this.owner, hand); var ctx = new CastingContext(this.owner, hand);
if (this.lazyLoadedTag.isEmpty()) { if (this.lazyLoadedTag.isEmpty()) {
return new CastingHarness(ctx); return new CastingHarness(ctx);
} else { } else {
return CastingHarness.DeserializeFromNBT(this.lazyLoadedTag, ctx); return CastingHarness.fromNBT(this.lazyLoadedTag, ctx);
} }
} }

View file

@ -39,7 +39,7 @@ public class CCPatterns implements Component {
List<ResolvedPattern> patterns = new ArrayList<>(patternsTag.size()); List<ResolvedPattern> patterns = new ArrayList<>(patternsTag.size());
for (int i = 0; i < patternsTag.size(); i++) { for (int i = 0; i < patternsTag.size(); i++) {
patterns.add(ResolvedPattern.DeserializeFromNBT(patternsTag.getCompound(i))); patterns.add(ResolvedPattern.fromNBT(patternsTag.getCompound(i)));
} }
this.patterns = patterns; this.patterns = patterns;
} }

View file

@ -38,7 +38,7 @@ public class CCSentinel implements Component, AutoSyncedComponent {
var hasSentinel = tag.getBoolean(TAG_HAS_SENTINEL); var hasSentinel = tag.getBoolean(TAG_HAS_SENTINEL);
if (hasSentinel) { if (hasSentinel) {
var extendsRange = tag.getBoolean(TAG_EXTENDS_RANGE); var extendsRange = tag.getBoolean(TAG_EXTENDS_RANGE);
var position = HexUtils.DeserializeVec3FromNBT(tag.getLongArray(TAG_POSITION)); var position = HexUtils.vecFromNBT(tag.getLongArray(TAG_POSITION));
var dim = ResourceKey.create(Registry.DIMENSION_REGISTRY, var dim = ResourceKey.create(Registry.DIMENSION_REGISTRY,
new ResourceLocation(tag.getString(TAG_DIMENSION))); new ResourceLocation(tag.getString(TAG_DIMENSION)));
this.sentinel = new Sentinel(true, extendsRange, position, dim); this.sentinel = new Sentinel(true, extendsRange, position, dim);

View file

@ -33,7 +33,7 @@ public class FabricUnsealedIngredient extends Ingredient {
.filter((it) -> it != DatumType.EMPTY && it != DatumType.OTHER) .filter((it) -> it != DatumType.EMPTY && it != DatumType.OTHER)
.map((type) -> { .map((type) -> {
ItemStack newStack = stack.copy(); ItemStack newStack = stack.copy();
NBTHelper.putString(newStack, DataHolderItem.TAG_OVERRIDE_VISUALLY, SpellDatum.GetTagName(type)); NBTHelper.putString(newStack, DataHolderItem.TAG_OVERRIDE_VISUALLY, SpellDatum.tagForType(type));
return new Ingredient.ItemValue(newStack); return new Ingredient.ItemValue(newStack);
})); }));
this.stack = stack; this.stack = stack;

View file

@ -22,8 +22,10 @@ public class ForgeHexClientInitializer {
evBus.addListener((RenderLevelLastEvent e) -> evBus.addListener((RenderLevelLastEvent e) ->
HexAdditionalRenderers.overlayLevel(e.getPoseStack(), e.getPartialTick())); HexAdditionalRenderers.overlayLevel(e.getPoseStack(), e.getPartialTick()));
evBus.addListener((RenderGameOverlayEvent.PreLayer e) -> evBus.addListener((RenderGameOverlayEvent.Post e) -> {
HexAdditionalRenderers.overlayGui(e.getMatrixStack(), e.getPartialTicks())); if (e.getType() == RenderGameOverlayEvent.ElementType.ALL)
HexAdditionalRenderers.overlayGui(e.getMatrixStack(), e.getPartialTicks());
});
evBus.addListener((TickEvent.RenderTickEvent e) -> { evBus.addListener((TickEvent.RenderTickEvent e) -> {

View file

@ -25,13 +25,13 @@ public record MsgColorizerUpdateAck(FrozenColorizer update) implements IMessage
var buf = new FriendlyByteBuf(buffer); var buf = new FriendlyByteBuf(buffer);
var tag = buf.readAnySizeNbt(); var tag = buf.readAnySizeNbt();
var colorizer = FrozenColorizer.deserialize(tag); var colorizer = FrozenColorizer.fromNBT(tag);
return new MsgColorizerUpdateAck(colorizer); return new MsgColorizerUpdateAck(colorizer);
} }
@Override @Override
public void serialize(FriendlyByteBuf buf) { public void serialize(FriendlyByteBuf buf) {
buf.writeNbt(this.update.serialize()); buf.writeNbt(this.update.serializeToNBT());
} }
public static void handle(MsgColorizerUpdateAck self) { public static void handle(MsgColorizerUpdateAck self) {

View file

@ -30,7 +30,7 @@ public class ForgeUnsealedIngredient extends AbstractIngredient {
.filter((it) -> it != DatumType.EMPTY && it != DatumType.OTHER) .filter((it) -> it != DatumType.EMPTY && it != DatumType.OTHER)
.map((type) -> { .map((type) -> {
ItemStack newStack = stack.copy(); ItemStack newStack = stack.copy();
NBTHelper.putString(newStack, DataHolderItem.TAG_OVERRIDE_VISUALLY, SpellDatum.GetTagName(type)); NBTHelper.putString(newStack, DataHolderItem.TAG_OVERRIDE_VISUALLY, SpellDatum.tagForType(type));
return new Ingredient.ItemValue(newStack); return new Ingredient.ItemValue(newStack);
})); }));
this.stack = stack; this.stack = stack;

View file

@ -124,7 +124,7 @@ public class ForgeXplatImpl implements IXplatAbstractions {
@Override @Override
public void setColorizer(Player player, FrozenColorizer colorizer) { public void setColorizer(Player player, FrozenColorizer colorizer) {
CompoundTag tag = player.getPersistentData(); CompoundTag tag = player.getPersistentData();
tag.put(TAG_COLOR, colorizer.serialize()); tag.put(TAG_COLOR, colorizer.serializeToNBT());
if (player instanceof ServerPlayer serverPlayer) { if (player instanceof ServerPlayer serverPlayer) {
CapSyncers.syncColorizer(serverPlayer); CapSyncers.syncColorizer(serverPlayer);
@ -175,7 +175,7 @@ public class ForgeXplatImpl implements IXplatAbstractions {
boolean allowed = tag.getBoolean(TAG_FLIGHT_ALLOWED); boolean allowed = tag.getBoolean(TAG_FLIGHT_ALLOWED);
if (allowed) { if (allowed) {
var timeLeft = tag.getInt(TAG_FLIGHT_TIME); var timeLeft = tag.getInt(TAG_FLIGHT_TIME);
var origin = HexUtils.DeserializeVec3FromNBT(tag.getLongArray(TAG_FLIGHT_ORIGIN)); var origin = HexUtils.vecFromNBT(tag.getLongArray(TAG_FLIGHT_ORIGIN));
var radius = tag.getDouble(TAG_FLIGHT_RADIUS); var radius = tag.getDouble(TAG_FLIGHT_RADIUS);
var dimension = ResourceKey.create(Registry.DIMENSION_REGISTRY, var dimension = ResourceKey.create(Registry.DIMENSION_REGISTRY,
new ResourceLocation(tag.getString(TAG_FLIGHT_DIMENSION))); new ResourceLocation(tag.getString(TAG_FLIGHT_DIMENSION)));
@ -186,7 +186,7 @@ public class ForgeXplatImpl implements IXplatAbstractions {
@Override @Override
public FrozenColorizer getColorizer(Player player) { public FrozenColorizer getColorizer(Player player) {
return FrozenColorizer.deserialize(player.getPersistentData().getCompound(TAG_COLOR)); return FrozenColorizer.fromNBT(player.getPersistentData().getCompound(TAG_COLOR));
} }
@Override @Override
@ -197,7 +197,7 @@ public class ForgeXplatImpl implements IXplatAbstractions {
return Sentinel.none(); return Sentinel.none();
} }
var extendsRange = tag.getBoolean(TAG_SENTINEL_GREATER); var extendsRange = tag.getBoolean(TAG_SENTINEL_GREATER);
var position = HexUtils.DeserializeVec3FromNBT(tag.getLongArray(TAG_SENTINEL_POSITION)); var position = HexUtils.vecFromNBT(tag.getLongArray(TAG_SENTINEL_POSITION));
var dimension = ResourceKey.create(Registry.DIMENSION_REGISTRY, var dimension = ResourceKey.create(Registry.DIMENSION_REGISTRY,
new ResourceLocation(tag.getString(TAG_SENTINEL_DIMENSION))); new ResourceLocation(tag.getString(TAG_SENTINEL_DIMENSION)));
@ -207,7 +207,7 @@ public class ForgeXplatImpl implements IXplatAbstractions {
@Override @Override
public CastingHarness getHarness(ServerPlayer player, InteractionHand hand) { public CastingHarness getHarness(ServerPlayer player, InteractionHand hand) {
var ctx = new CastingContext(player, hand); var ctx = new CastingContext(player, hand);
return CastingHarness.DeserializeFromNBT(player.getPersistentData().getCompound(TAG_HARNESS), ctx); return CastingHarness.fromNBT(player.getPersistentData().getCompound(TAG_HARNESS), ctx);
} }
@Override @Override
@ -217,7 +217,7 @@ public class ForgeXplatImpl implements IXplatAbstractions {
List<ResolvedPattern> patterns = new ArrayList<>(patternsTag.size()); List<ResolvedPattern> patterns = new ArrayList<>(patternsTag.size());
for (int i = 0; i < patternsTag.size(); i++) { for (int i = 0; i < patternsTag.size(); i++) {
patterns.add(ResolvedPattern.DeserializeFromNBT(patternsTag.getCompound(i))); patterns.add(ResolvedPattern.fromNBT(patternsTag.getCompound(i)));
} }
return patterns; return patterns;
} }

View file

@ -1,4 +1,4 @@
# Hex # Hex Casting
A minecraft mod about casting Hexes, powerful and programmable magical effects, inspired by PSI. A minecraft mod about casting Hexes, powerful and programmable magical effects, inspired by PSI.
@ -6,3 +6,4 @@ A minecraft mod about casting Hexes, powerful and programmable magical effects,
This mod requires PAUCAL, Patchouli and Kotlin for Forge! This mod requires PAUCAL, Patchouli and Kotlin for Forge!
## [Read the documentation online here!](https://gamma-delta.github.io/HexMod/)

562
doc/collate_data.py Executable file
View file

@ -0,0 +1,562 @@
#!/usr/bin/env python3
from sys import argv, stdout
from collections import namedtuple
import json # codec
import re # parsing
import os # listdir
# TO USE: put in Hexcasting root dir, collate_data.py src/main/resources hexcasting thehexbook out.html
# extra info :(
lang = "en_us"
repo_names = {
"hexcasting": "https://raw.githubusercontent.com/gamma-delta/HexMod/main/Common/src/main/resources",
}
extra_i18n = {
"item.minecraft.amethyst_shard": "Amethyst Shard",
"item.minecraft.budding_amethyst": "Budding Amethyst",
"block.hexcasting.slate": "Blank Slate",
}
default_macros = {
"$(obf)": "$(k)",
"$(bold)": "$(l)",
"$(strike)": "$(m)",
"$(italic)": "$(o)",
"$(italics)": "$(o)",
"$(list": "$(li",
"$(reset)": "$()",
"$(clear)": "$()",
"$(2br)": "$(br2)",
"$(p)": "$(br2)",
"/$": "$()",
"<br>": "$(br)",
"$(nocolor)": "$(0)",
"$(item)": "$(#b0b)",
"$(thing)": "$(#490)",
}
colors = {
"0": None,
"1": "00a",
"2": "0a0",
"3": "0aa",
"4": "a00",
"5": "a0a",
"6": "fa0",
"7": "aaa",
"8": "555",
"9": "55f",
"a": "5f5",
"b": "5ff",
"c": "f55",
"d": "f5f",
"e": "ff5",
"f": "fff",
}
types = {
"k": "obf",
"l": "bold",
"m": "strikethrough",
"n": "underline",
"o": "italic",
}
keys = {
"use": "Right Click",
"sneak": "Left Shift",
}
bind1 = (lambda: None).__get__(0).__class__
def slurp(filename):
with open(filename, "r") as fh:
return json.load(fh)
FormatTree = namedtuple("FormatTree", ["style", "children"])
Style = namedtuple("Style", ["type", "value"])
def parse_style(sty):
if sty == "br":
return "<br />", None
if sty == "br2":
return "", Style("para", {})
if sty == "li":
return "", Style("para", {"clazz": "fake-li"})
if sty[:2] == "k:":
return keys[sty[2:]], None
if sty[:2] == "l:":
return "", Style("link", sty[2:])
if sty == "/l":
return "", Style("link", None)
if sty == "playername":
return "[Playername]", None
if sty[:2] == "t:":
return "", Style("tooltip", sty[2:])
if sty == "/t":
return "", Style("tooltip", None)
if sty[:2] == "c:":
return "", Style("cmd_click", sty[2:])
if sty == "/c":
return "", Style("cmd_click", None)
if sty == "r" or not sty:
return "", Style("base", None)
if sty in types:
return "", Style(types[sty], True)
if sty in colors:
return "", Style("color", colors[sty])
if sty.startswith("#") and len(sty) in [4, 7]:
return "", Style("color", sty[1:])
# TODO more style parse
raise ValueError("Unknown style: " + sty)
def localize(i18n, string):
return i18n.get(string, string) if i18n else string
format_re = re.compile(r"\$\(([^)]*)\)")
def format_string(root_data, string):
# resolve lang
string = localize(root_data["i18n"], string)
# resolve macros
old_string = None
while old_string != string:
old_string = string
for macro, replace in root_data["macros"].items():
string = string.replace(macro, replace)
else: break
# lex out parsed styles
text_nodes = []
styles = []
last_end = 0
extra_text = ""
for mobj in re.finditer(format_re, string):
bonus_text, sty = parse_style(mobj.group(1))
text = string[last_end:mobj.start()] + bonus_text
if sty:
styles.append(sty)
text_nodes.append(extra_text + text)
extra_text = ""
else:
extra_text += text
last_end = mobj.end()
text_nodes.append(extra_text + string[last_end:])
first_node, *text_nodes = text_nodes
# parse
style_stack = [FormatTree(Style("base", True), []), FormatTree(Style("para", {}), [first_node])]
for style, text in zip(styles, text_nodes):
tmp_stylestack = []
if style.type == "base":
while style_stack[-1].style.type != "para":
last_node = style_stack.pop()
style_stack[-1].children.append(last_node)
elif any(tree.style.type == style.type for tree in style_stack):
while len(style_stack) >= 2:
last_node = style_stack.pop()
style_stack[-1].children.append(last_node)
if last_node.style.type == style.type:
break
tmp_stylestack.append(last_node.style)
for sty in tmp_stylestack:
style_stack.append(FormatTree(sty, []))
if style.value is None:
if text: style_stack[-1].children.append(text)
else:
style_stack.append(FormatTree(style, [text] if text else []))
while len(style_stack) >= 2:
last_node = style_stack.pop()
style_stack[-1].children.append(last_node)
return style_stack[0]
test_root = {"i18n": {}, "macros": default_macros, "resource_dir": "Common/src/main/resources", "modid": "hexcasting"}
test_str = "Write the given iota to my $(l:patterns/readwrite#hexcasting:write/local)$(#490)local$().$(br)The $(l:patterns/readwrite#hexcasting:write/local)$(#490)local$() is a lot like a $(l:items/focus)$(#b0b)Focus$(). It's cleared when I stop casting a Hex, starts with $(l:casting/influences)$(#490)Null$() in it, and is preserved between casts of $(l:patterns/meta#hexcasting:for_each)$(#fc77be)Thoth's Gambit$(). "
def do_localize(root_data, obj, *names):
for name in names:
if name in obj:
obj[name] = localize(root_data["i18n"], obj[name])
def do_format(root_data, obj, *names):
for name in names:
if name in obj:
obj[name] = format_string(root_data, obj[name])
def identity(x): return x
pattern_pat = re.compile(r'HexPattern\.fromAngles\("([qweasd]+)", HexDir\.(\w+)\),\s*modLoc\("([^"]+)"\)([^;]*true\);)?')
def fetch_patterns(root_data):
filename = f"{root_data['resource_dir']}/../java/at/petrak/hexcasting/common/casting/RegisterPatterns.java"
registry = {}
with open(filename, "r") as fh:
pattern_data = fh.read()
for mobj in re.finditer(pattern_pat, pattern_data):
string, start_angle, name, is_per_world = mobj.groups()
registry[root_data["modid"] + ":" + name] = (string, start_angle, bool(is_per_world))
return registry
def resolve_pattern(root_data, page):
if "pattern_reg" not in root_data:
root_data["pattern_reg"] = fetch_patterns(root_data)
page["op"] = [root_data["pattern_reg"][page["op_id"]]]
page["name"] = localize(root_data["i18n"], "hexcasting.spell." + page["op_id"])
def fixup_pattern(do_sig, root_data, page):
patterns = page["patterns"]
if not isinstance(patterns, list): patterns = [patterns]
if do_sig:
inp = page.get("input", None) or ""
oup = page.get("output", None) or ""
pipe = f"{inp} \u2192 {oup}".strip()
suffix = f" ({pipe})" if inp or oup else ""
page["header"] += suffix
page["op"] = [(p["signature"], p["startdir"], False) for p in patterns]
def fetch_recipe(root_data, recipe):
modid, recipeid = recipe.split(":")
gen_resource_dir = root_data["resource_dir"].replace("/main/", "/generated/").replace("Common/", "Forge/") # TODO hack
recipe_path = f"{gen_resource_dir}/data/{modid}/recipes/{recipeid}.json"
return slurp(recipe_path)
def fetch_recipe_result(root_data, recipe):
return fetch_recipe(root_data, recipe)["result"]["item"]
def fetch_bswp_recipe_result(root_data, recipe):
return fetch_recipe(root_data, recipe)["result"]["name"]
def localize_item(root_data, item):
# TODO hack
item = re.sub("{.*", "", item.replace(":", "."))
block = "block." + item
block_l = localize(root_data["i18n"], block)
if block_l != block: return block_l
return localize(root_data["i18n"], "item." + item)
page_types = {
"hexcasting:pattern": resolve_pattern,
"hexcasting:manual_pattern": bind1(fixup_pattern, True),
"hexcasting:manual_pattern_nosig": bind1(fixup_pattern, False),
"hexcasting:brainsweep": lambda rd, page: page.__setitem__("output_name", localize_item(rd, fetch_bswp_recipe_result(rd, page["recipe"]))),
"patchouli:link": lambda rd, page: do_localize(rd, page, "link_text"),
"patchouli:crafting": lambda rd, page: page.__setitem__("item_name", [localize_item(rd, fetch_recipe_result(rd, page[ty])) for ty in ("recipe", "recipe2") if ty in page]),
"hexcasting:crafting_multi": lambda rd, page: page.__setitem__("item_name", [localize_item(rd, fetch_recipe_result(rd, recipe)) for recipe in page["recipes"]]),
"patchouli:spotlight": lambda rd, page: page.__setitem__("item_name", localize_item(rd, page["item"]))
}
def walk_dir(root_dir, prefix):
search_dir = root_dir + '/' + prefix
for fh in os.scandir(search_dir):
if fh.is_dir():
yield from walk_dir(root_dir, prefix + fh.name + '/')
elif fh.name.endswith(".json"):
yield prefix + fh.name
def parse_entry(root_data, entry_path, ent_name):
data = slurp(f"{entry_path}")
do_localize(root_data, data, "name")
for page in data["pages"]:
do_localize(root_data, page, "title", "header")
do_format(root_data, page, "text")
if page["type"] in page_types:
page_types[page["type"]](root_data, page)
data["id"] = ent_name
return data
def parse_category(root_data, base_dir, cat_name):
data = slurp(f"{base_dir}/categories/{cat_name}.json")
do_localize(root_data, data, "name")
do_format(root_data, data, "description")
entry_dir = f"{base_dir}/entries/{cat_name}"
entries = []
for filename in os.listdir(entry_dir):
if filename.endswith(".json"):
basename = filename[:-5]
entries.append(parse_entry(root_data, f"{entry_dir}/{filename}", cat_name + "/" + basename))
entries.sort(key=lambda ent: (not ent.get("priority", False), ent.get("sortnum", 0), ent["name"]))
data["entries"] = entries
data["id"] = cat_name
return data
def parse_sortnum(cats, name):
if '/' in name:
ix = name.rindex('/')
return parse_sortnum(cats, name[:ix]) + (cats[name].get("sortnum", 0),)
return cats[name].get("sortnum", 0),
def parse_book(root, mod_name, book_name):
base_dir = f"{root}/data/{mod_name}/patchouli_books/{book_name}"
root_info = slurp(f"{base_dir}/book.json")
root_info["resource_dir"] = root
root_info["modid"] = mod_name
root_info.setdefault("macros", {}).update(default_macros)
if root_info.setdefault("i18n", {}):
root_info["i18n"] = slurp(f"{root}/assets/{mod_name}/lang/{lang}.json")
root_info["i18n"].update(extra_i18n)
book_dir = f"{base_dir}/{lang}"
categories = []
for filename in walk_dir(f"{book_dir}/categories", ""):
basename = filename[:-5]
categories.append(parse_category(root_info, book_dir, basename))
cats = {cat["id"]: cat for cat in categories}
categories.sort(key=lambda cat: (parse_sortnum(cats, cat["id"]), cat["name"]))
do_localize(root_info, root_info, "name")
do_format(root_info, root_info, "landing_text")
root_info["categories"] = categories
root_info["blacklist"] = set()
root_info["spoilers"] = set()
return root_info
def tag_args(kwargs):
return "".join(f" {'class' if key == 'clazz' else key.replace('_', '-')}={repr(value)}" for key, value in kwargs.items())
class PairTag:
__slots__ = ["stream", "name", "kwargs"]
def __init__(self, stream, name, **kwargs):
self.stream = stream
self.name = name
self.kwargs = tag_args(kwargs)
def __enter__(self):
print(f"<{self.name}{self.kwargs}>", file=self.stream, end="")
def __exit__(self, _1, _2, _3):
print(f"</{self.name}>", file=self.stream, end="")
class Empty:
def __enter__(self): pass
def __exit__(self, _1, _2, _3): pass
class Stream:
__slots__ = ["stream", "thunks"]
def __init__(self, stream):
self.stream = stream
self.thunks = []
def tag(self, name, **kwargs):
keywords = tag_args(kwargs)
print(f"<{name}{keywords} />", file=self.stream, end="")
return self
def pair_tag(self, name, **kwargs):
return PairTag(self.stream, name, **kwargs)
def pair_tag_if(self, cond, name, **kwargs):
return self.pair_tag(name, **kwargs) if cond else Empty()
def empty_pair_tag(self, name, **kwargs):
with self.pair_tag(name, **kwargs): pass
def text(self, txt):
print(txt, file=self.stream, end="")
return self
def get_format(out, ty, value):
if ty == "para":
return out.pair_tag("p", **value)
if ty == "color":
return out.pair_tag("span", style=f"color: #{value}")
if ty == "link":
link = value
if "://" not in link:
link = "#" + link.replace("#", "@")
return out.pair_tag("a", href=link)
if ty == "tooltip":
return out.pair_tag("span", clazz="has-tooltip", title=value)
if ty == "cmd_click":
return out.pair_tag("span", clazz="has-cmd_click", title="When clicked, would execute: "+value)
if ty == "obf":
return out.pair_tag("span", clazz="obfuscated")
if ty == "bold":
return out.pair_tag("strong")
if ty == "italic":
return out.pair_tag("i")
if ty == "strikethrough":
return out.pair_tag("s")
if ty == "underline":
return out.pair_tag("span", style="text-decoration: underline")
raise ValueError("Unknown format type: " + ty)
def entry_spoilered(root_info, entry):
return entry.get("advancement", None) in root_info["spoilers"]
def category_spoilered(root_info, category):
return all(entry_spoilered(root_info, ent) for ent in category["entries"])
def write_block(out, block):
if isinstance(block, str):
out.text(block)
return
sty_type = block.style.type
if sty_type == "base":
for child in block.children: write_block(out, child)
return
tag = get_format(out, sty_type, block.style.value)
with tag:
for child in block.children:
write_block(out, child)
# TODO modularize
def write_page(out, pageid, page):
if "anchor" in page:
anchor_id = pageid + "@" + page["anchor"]
else: anchor_id = None
with out.pair_tag_if(anchor_id, "div", id=anchor_id):
if "header" in page or "title" in page:
with out.pair_tag("h4"):
out.text(page.get("header", page.get("title", None)))
if anchor_id:
with out.pair_tag("a", href="#" + anchor_id, clazz="permalink small"):
out.empty_pair_tag("i", clazz="bi bi-link-45deg")
ty = page["type"]
if ty == "patchouli:text":
write_block(out, page["text"])
elif ty == "patchouli:empty": pass
elif ty == "patchouli:link":
write_block(out, page["text"])
with out.pair_tag("h4", clazz="linkout"):
with out.pair_tag("a", href=page["url"]):
out.text(page["link_text"])
elif ty == "patchouli:spotlight":
with out.pair_tag("h4", clazz="spotlight-title page-header"):
out.text(page["item_name"])
if "text" in page: write_block(out, page["text"])
elif ty == "patchouli:crafting":
with out.pair_tag("blockquote", clazz="crafting-info"):
out.text(f"Depicted in the book: The crafting recipe for the ")
first = True
for name in page["item_name"]:
if not first: out.text(" and ")
first = False
with out.pair_tag("code"): out.text(name)
out.text(".")
if "text" in page: write_block(out, page["text"])
elif ty == "patchouli:image":
with out.pair_tag("p", clazz="img-wrapper"):
for img in page["images"]:
modid, coords = img.split(":")
out.empty_pair_tag("img", src=f"{repo_names[modid]}/assets/{modid}/{coords}")
if "text" in page: write_block(out, page["text"])
elif ty == "hexcasting:crafting_multi":
recipes = page["item_name"]
with out.pair_tag("blockquote", clazz="crafting-info"):
out.text(f"Depicted in the book: Several crafting recipes, for the ")
with out.pair_tag("code"): out.text(recipes[0])
for i in recipes[1:]:
out.text(", ")
with out.pair_tag("code"): out.text(i)
out.text(".")
if "text" in page: write_block(out, page["text"])
elif ty == "hexcasting:brainsweep":
with out.pair_tag("blockquote", clazz="crafting-info"):
out.text(f"Depicted in the book: A mind-flaying recipe producing the ")
with out.pair_tag("code"): out.text(page["output_name"])
out.text(".")
if "text" in page: write_block(out, page["text"])
elif ty in ("hexcasting:pattern", "hexcasting:manual_pattern_nosig", "hexcasting:manual_pattern"):
if "name" in page:
with out.pair_tag("h4", clazz="pattern-title"):
inp = page.get("input", None) or ""
oup = page.get("output", None) or ""
pipe = f"{inp} \u2192 {oup}".strip()
suffix = f" ({pipe})" if inp or oup else ""
out.text(f"{page['name']}{suffix}")
if anchor_id:
with out.pair_tag("a", href="#" + anchor_id, clazz="permalink small"):
out.empty_pair_tag("i", clazz="bi bi-link-45deg")
with out.pair_tag("details", clazz="spell-collapsible"):
out.empty_pair_tag("summary", clazz="collapse-spell")
for string, start_angle, per_world in page["op"]:
with out.pair_tag("canvas", clazz="spell-viz", width=216, height=216, data_string=string, data_start=start_angle.lower(), data_per_world=per_world):
out.text("Your browser does not support visualizing patterns. Pattern code: " + string)
write_block(out, page["text"])
else:
with out.pair_tag("p", clazz="todo-note"):
out.text("TODO: Missing processor for type: " + ty)
if "text" in page:
write_block(out, page["text"])
out.tag("br")
def write_entry(out, book, entry):
with out.pair_tag("div", id=entry["id"]):
with out.pair_tag_if(entry_spoilered(book, entry), "div", clazz="spoilered"):
with out.pair_tag("h3", clazz="entry-title page-header"):
write_block(out, entry["name"])
with out.pair_tag("a", href="#" + entry["id"], clazz="permalink small"):
out.empty_pair_tag("i", clazz="bi bi-link-45deg")
for page in entry["pages"]:
write_page(out, entry["id"], page)
def write_category(out, book, category):
with out.pair_tag("section", id=category["id"]):
with out.pair_tag_if(category_spoilered(book, category), "div", clazz="spoilered"):
with out.pair_tag("h2", clazz="category-title page-header"):
write_block(out, category["name"])
with out.pair_tag("a", href="#" + category["id"], clazz="permalink small"):
out.empty_pair_tag("i", clazz="bi bi-link-45deg")
write_block(out, category["description"])
for entry in category["entries"]:
if entry["id"] not in book["blacklist"]:
write_entry(out, book, entry)
def write_toc(out, book):
with out.pair_tag("h2", id="table-of-contents", clazz="page-header"):
out.text("Table of Contents")
with out.pair_tag("a", href="javascript:void(0)", clazz="toggle-link small", data_target="toc-category"):
out.text("(toggle all)")
with out.pair_tag("a", href="#table-of-contents", clazz="permalink small"):
out.empty_pair_tag("i", clazz="bi bi-link-45deg")
for category in book["categories"]:
with out.pair_tag("details", clazz="toc-category"):
with out.pair_tag("summary"):
with out.pair_tag("a", href="#" + category["id"], clazz="spoilered" if category_spoilered(book, category) else ""):
out.text(category["name"])
with out.pair_tag("ul"):
for entry in category["entries"]:
with out.pair_tag("li"):
with out.pair_tag("a", href="#" + entry["id"], clazz="spoilered" if entry_spoilered(book, entry) else ""):
out.text(entry["name"])
def write_book(out, book):
with out.pair_tag("div", clazz="container"):
with out.pair_tag("header", clazz="jumbotron"):
with out.pair_tag("h1", clazz="book-title"):
write_block(out, book["name"])
write_block(out, book["landing_text"])
with out.pair_tag("nav"):
write_toc(out, book)
with out.pair_tag("main", clazz="book-body"):
for category in book["categories"]:
write_category(out, book, category)
def main(argv):
if len(argv) < 5:
print(f"Usage: {argv[0]} <resources dir> <mod name> <book name> <template file> [<output>]")
return
root = argv[1]
mod_name = argv[2]
book_name = argv[3]
book = parse_book(root, mod_name, book_name)
template_file = argv[4]
with open(template_file, "r") as fh:
with stdout if len(argv) < 6 else open(argv[5], "w") as out:
for line in fh:
if line.startswith("#DO_NOT_RENDER"):
_, *blacklist = line.split()
book["blacklist"].update(blacklist)
if line.startswith("#SPOILER"):
_, *spoilers = line.split()
book["spoilers"].update(spoilers)
elif line == "#DUMP_BODY_HERE\n":
write_book(Stream(out), book)
print('', file=out)
else: print(line, end='', file=out)
if __name__ == "__main__":
main(argv)

363
doc/template.html Normal file
View file

@ -0,0 +1,363 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="The Hex Book, all in one place.">
<meta name="author" content="petrak@, Alwinfy">
<link rel="icon" href="../../favicon.ico">
<title>Hex Book</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.3.0/font/bootstrap-icons.css">
<style>
summary { display: list-item; }
details.spell-collapsible {
display: inline-block;
border: 1px solid #aaa;
border-radius: 4px;
padding: .5em .5em 0;
margin-bottom: .5em;
}
summary.collapse-spell {
font-weight: bold;
margin: -.5em -.5em 0;
padding: .5em;
}
details.spell-collapsible[open] {
padding: .5em;
}
details[open] summary.collapse-spell {
border-bottom: 1px solid #aaa;
margin-bottom: .5em;
}
details .collapse-spell::before {
content: "Click to show spell";
}
details[open] .collapse-spell::before {
content: "Click to hide spell";
}
blockquote.crafting-info {
font-size: inherit;
}
a.toggle-link {
margin-left: 0.5em;
}
a.permalink {
margin-left: 0.5em;
}
a.permalink:hover {
color: lightgray;
}
p {
margin: 0.5ex 0;
}
p.fake-li {
margin: 0;
}
p.fake-li::before {
content: "\2022";
margin: 1ex;
}
.linkout::before {
content: "Link: ";
}
p.todo-note {
font-style: italic;
color: lightgray;
}
.obfuscated {
filter: blur(1em);
}
.spoilered {
filter: blur(1ex);
-moz-transition: filter 0.04s linear;
}
.spoilered:hover {
filter: blur(0.5ex);
}
.spoilered.unspoilered {
filter: blur(0);
}
canvas.spell-viz {
--dot-color: #777f;
--start-dot-color: #f009;
--moving-dot-color: #0fa9;
--path-color: darkgray;
--visited-path-color: #0c8;
--dot-scale: 0.0625;
--moving-dot-scale: 0.125;
--line-scale: 0.08333;
--pausetext-scale: 0.5;
}
</style>
<noscript>
<style>
/* for accessibility */
.spoilered {
filter: none !important;
}
</style>
</noscript>
<script>
"use strict";
const speeds = [0, 0.25, 0.5, 1, 2, 4];
const scrollThreshold = 100;
const rfaQueue = [];
function startAngle(str) {
switch (str) {
case "east": return 0;
case "north_east": return 1;
case "north_west": return 2;
case "west": return 3;
case "south_west": return 4;
case "south_east": return 5;
default: return 0;
}
}
function offsetAngle(str) {
switch (str) {
case "w": return 0;
case "q": return 1;
case "a": return 2;
case "s": return 3;
case "d": return 4;
case "e": return 5;
default: return -1;
}
}
function initializeElem(canvas) {
const str = canvas.dataset.string;
let angle = startAngle(canvas.dataset.start);
const perWorld = canvas.dataset.perWorld === "True";
// build geometry
const points = [[0, 0]];
let lastPoint = points[0];
let minPoint = lastPoint, maxPoint = lastPoint;
for (const ch of "w" + str) {
const addAngle = offsetAngle(ch);
if (addAngle < 0) continue;
angle = (angle + addAngle) % 6;
const trueAngle = Math.PI / 3 * angle;
const [lx, ly] = lastPoint;
const newPoint = [lx + Math.cos(trueAngle), ly - Math.sin(trueAngle)];
points.push(newPoint);
lastPoint = newPoint;
const [mix, miy] = minPoint;
minPoint = [Math.min(mix, newPoint[0]), Math.min(miy, newPoint[1])];
const [max, may] = maxPoint;
maxPoint = [Math.max(max, newPoint[0]), Math.max(may, newPoint[1])];
}
const size = Math.min(canvas.width, canvas.height) * 0.8;
const scale = size / Math.max(3, Math.max(maxPoint[1] - minPoint[1], maxPoint[0] - minPoint[0]));
const center = [(minPoint[0] + maxPoint[0]) * 0.5, (minPoint[1] + maxPoint[1]) * 0.5];
const truePoints = points.map(p => [canvas.width * 0.5 + scale * (p[0] - center[0]), canvas.height * 0.5 + scale * (p[1] - center[1])]);
let uniqPoints = [];
l1: for (const point of truePoints) {
for (const pt of uniqPoints) {
if (Math.abs(point[0] - pt[0]) < 0.00001 && Math.abs(point[1] - pt[1]) < 0.00001) {
continue l1;
}
}
uniqPoints.push(point);
}
// rendering code
const speed = 0.0025;
const context = canvas.getContext("2d");
const negaProgress = -3;
let progress = 0;
let scrollTimeout = 1e309;
let speedLevel = 3;
let speedIncrement = 0;
function speedScale() {
return speeds[speedLevel];
}
const style = getComputedStyle(canvas);
const getProp = n => style.getPropertyValue(n);
const tick = dt => {
scrollTimeout += dt;
if (canvas.offsetParent === null) return;
const strokeStyle = getProp("--path-color");
const strokeVisitedStyle = getProp("--visited-path-color");
const startDotStyle = getProp("--start-dot-color");
const dotStyle = getProp("--dot-color");
const movDotStyle = getProp("--moving-dot-color");
const strokeWidth = scale * +getProp("--line-scale");
const dotRadius = scale * +getProp("--dot-scale");
const movDotRadius = scale * +getProp("--moving-dot-scale");
const pauseScale = scale * +getProp("--pausetext-scale");
if (!perWorld) {
progress += speed * dt * (progress > 0 ? speedScale() : Math.sqrt(speedScale()));
}
if (progress >= truePoints.length - 1) {
progress = negaProgress;
}
let ix = Math.floor(progress), frac = progress - ix, core = null, fadeColor = 0;
if (ix < 0) {
const rawFade = 2 * progress / negaProgress - 1;
fadeColor = 1 - Math.abs(rawFade);
context.strokeStyle = rawFade > 0 ? strokeVisitedStyle : strokeStyle;
ix = rawFade > 0 ? truePoints.length - 2 : 0;
frac = +(rawFade > 0);
} else {
context.strokeStyle = strokeVisitedStyle;
}
const [lx, ly] = truePoints[ix];
const [rx, ry] = truePoints[ix + 1];
core = [lx + (rx - lx) * frac, ly + (ry - ly) * frac];
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.lineWidth = strokeWidth;
context.moveTo(truePoints[0][0], truePoints[0][1]);
for (let i = 1; i < ix + 1; i++) {
context.lineTo(truePoints[i][0], truePoints[i][1]);
}
context.lineTo(core[0], core[1]);
context.stroke();
context.beginPath();
context.strokeStyle = strokeStyle;
context.moveTo(core[0], core[1]);
for (let i = ix + 1; i < truePoints.length; i++) {
context.lineTo(truePoints[i][0], truePoints[i][1]);
}
context.stroke();
for (let i = 0; i < uniqPoints.length; i++) {
context.beginPath();
context.fillStyle = (i == 0 && !perWorld) ? startDotStyle : dotStyle;
const radius = (i == 0 && !perWorld) ? movDotRadius : dotRadius;
context.arc(uniqPoints[i][0], uniqPoints[i][1], radius, 0, 2 * Math.PI);
context.fill();
}
if (!perWorld) {
context.beginPath();
context.fillStyle = movDotStyle;
context.arc(core[0], core[1], movDotRadius, 0, 2 * Math.PI);
context.fill();
}
if (fadeColor) {
context.fillStyle = `rgba(255, 255, 255, ${fadeColor})`;
context.fillRect(0, 0, canvas.width, canvas.height);
}
if (scrollTimeout <= 2000) {
context.fillStyle = `rgba(200, 200, 200, ${(2000 - scrollTimeout) / 1000})`;
context.font = `${pauseScale}px sans-serif`;
context.fillText(speedScale() ? speedScale() + "x" : "Paused", 0.2 * scale, canvas.height - 0.2 * scale);
}
};
rfaQueue.push(tick);
// scrolling input
if (!perWorld) {
canvas.addEventListener("wheel", ev => {
speedIncrement += ev.deltaY;
const oldSpeedLevel = speedLevel;
if (speedIncrement >= scrollThreshold) {
speedLevel--;
} else if (speedIncrement <= -scrollThreshold) {
speedLevel++;
}
if (oldSpeedLevel != speedLevel) {
speedIncrement = 0;
speedLevel = Math.max(0, Math.min(speeds.length - 1, speedLevel));
scrollTimeout = 0;
}
ev.preventDefault();
});
}
}
function hookLoad(elem) {
let init = false;
const canvases = elem.querySelectorAll("canvas");
elem.addEventListener("toggle", () => {
if (!init) {
canvases.forEach(initializeElem);
init = true;
}
});
}
function hookToggle(elem) {
const details = Array.from(document.querySelectorAll("details." + elem.dataset.target));
elem.addEventListener("click", () => {
if (details.some(x => x.open)) {
details.forEach(x => x.open = false);
} else {
details.forEach(x => x.open = true);
}
});
}
const params = new URLSearchParams(document.location.search);
function hookSpoiler(elem) {
if (params.get("nospoiler") !== null) {
elem.classList.add("unspoilered");
} else {
const thunk = ev => {
if (!elem.classList.contains("unspoilered")) {
ev.preventDefault();
ev.stopImmediatePropagation();
elem.classList.add("unspoilered");
}
elem.removeEventListener("click", thunk);
};
elem.addEventListener("click", thunk);
if (elem instanceof HTMLAnchorElement) {
const href = elem.getAttribute("href");
if (href.startsWith("#")) {
elem.addEventListener("click", () => document.getElementById(href.substring(1)).querySelector(".spoilered").classList.add("unspoilered"));
}
}
}
}
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('details.spell-collapsible').forEach(hookLoad);
document.querySelectorAll('a.toggle-link').forEach(hookToggle);
document.querySelectorAll('.spoilered').forEach(hookSpoiler);
function tick(prevTime, time) {
const dt = time - prevTime;
for (const q of rfaQueue) {
q(dt);
}
requestAnimationFrame(t => tick(time, t));
}
requestAnimationFrame(t => tick(t, t));
});
</script>
</head>
<body>
<div class="container" style="margin-top: 3em;">
<blockquote>
<h1>This is the online version of the Hexcasting documentation.</h1>
<p>Embedded images and patterns are included, but not crafting recipes or items. There's an in-game book for those.</p>
<p>Additionally, this is built from the latest code on GitHub. It may describe <b>newer</b> features that you may not necessarily have, even on the latest CurseForge version!</p>
<p><b>Entries which are blurred are spoilers</b>. Click to reveal them, but be aware that they may spoil endgame progression. Alternatively, click <a href="?nospoiler">here</a> to get a version with all spoilers showing.</p>
</blockquote>
</div>
#SPOILER hexcasting:opened_eyes hexcasting:y_u_no_cast_angy hexcasting:enlightenment
#DUMP_BODY_HERE
</body>
</html>