Merge branch 'main' into fancy-lightning
This commit is contained in:
commit
0a85f08877
90 changed files with 2003 additions and 852 deletions
29
.github/workflows/build_docs.yml
vendored
Normal file
29
.github/workflows/build_docs.yml
vendored
Normal 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
|
|
@ -86,14 +86,14 @@ object PatternRegistry {
|
|||
// when we try to look
|
||||
for (handler in specialHandlers) {
|
||||
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?
|
||||
val sig = pat.anglesSignature()
|
||||
this.regularPatternLookup[sig]?.let {
|
||||
val op = this.operatorLookup[it.opId] ?: throw MishapInvalidPattern()
|
||||
return Pair(op, it.opId)
|
||||
return op to it.opId
|
||||
}
|
||||
|
||||
// Look it up in the world?
|
||||
|
@ -102,7 +102,7 @@ object PatternRegistry {
|
|||
ds.computeIfAbsent(Save.Companion::load, { Save.create(overworld.seed) }, TAG_SAVED_DATA)
|
||||
perWorldPatterns.lookup[sig]?.let {
|
||||
val op = this.operatorLookup[it.first]!!
|
||||
return Pair(op, it.first)
|
||||
return op to it.first
|
||||
}
|
||||
|
||||
throw MishapInvalidPattern()
|
||||
|
@ -129,7 +129,7 @@ object PatternRegistry {
|
|||
}
|
||||
for ((sig, entry) in this.regularPatternLookup) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ object PatternRegistry {
|
|||
val entry = tag.getCompound(sig)
|
||||
val opId = ResourceLocation.tryParse(entry.getString(TAG_OP_ID))!!
|
||||
val startDir = HexDir.values()[entry.getInt(TAG_START_DIR)]
|
||||
map[sig] = Pair(opId, startDir)
|
||||
map[sig] = opId to startDir
|
||||
}
|
||||
return Save(map)
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ object PatternRegistry {
|
|||
for ((opId, entry) in PatternRegistry.perWorldPatternLookup) {
|
||||
// waugh why doesn't kotlin recursively destructure things
|
||||
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)
|
||||
save.setDirty()
|
||||
|
|
|
@ -13,7 +13,7 @@ public interface DataHolder {
|
|||
default SpellDatum<?> readDatum(ServerLevel world) {
|
||||
var tag = readRawDatum();
|
||||
if (tag != null) {
|
||||
return SpellDatum.DeserializeFromNBT(tag, world);
|
||||
return SpellDatum.fromNBT(tag, world);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen
|
|||
if (this.activator != null && this.colorizer != null && this.nextBlock != null && this.trackedBlocks != null) {
|
||||
tag.putUUID(TAG_ACTIVATOR, this.activator);
|
||||
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);
|
||||
|
||||
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_TRACKED_BLOCKS, Tag.TAG_LIST)) {
|
||||
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.foundAll = tag.getBoolean(TAG_FOUND_ALL);
|
||||
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
|
||||
public boolean stillValid(Player player) {
|
||||
return false;
|
||||
|
|
|
@ -28,7 +28,7 @@ public interface DataHolderItem {
|
|||
|
||||
var tag = dh.readDatumTag(stack);
|
||||
if (tag != null) {
|
||||
return SpellDatum.DeserializeFromNBT(tag, world);
|
||||
return SpellDatum.fromNBT(tag, world);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ public interface DataHolderItem {
|
|||
TooltipFlag pIsAdvanced) {
|
||||
var datumTag = self.readDatumTag(pStack);
|
||||
if (datumTag != null) {
|
||||
var component = SpellDatum.DisplayFromTag(datumTag);
|
||||
var component = SpellDatum.displayFromNBT(datumTag);
|
||||
pTooltipComponents.add(new TranslatableComponent("hexcasting.spelldata.onitem", component));
|
||||
|
||||
if (pIsAdvanced.isAdvanced()) {
|
||||
|
|
|
@ -29,14 +29,14 @@ public record FrozenColorizer(ItemStack item, UUID owner) {
|
|||
public static final Supplier<FrozenColorizer> DEFAULT =
|
||||
() -> new FrozenColorizer(new ItemStack(HexItems.DYE_COLORIZERS.get(DyeColor.WHITE)), Util.NIL_UUID);
|
||||
|
||||
public CompoundTag serialize() {
|
||||
public CompoundTag serializeToNBT() {
|
||||
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);
|
||||
return out;
|
||||
}
|
||||
|
||||
public static FrozenColorizer deserialize(CompoundTag tag) {
|
||||
public static FrozenColorizer fromNBT(CompoundTag tag) {
|
||||
if (tag.isEmpty()) {
|
||||
return FrozenColorizer.DEFAULT.get();
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import net.minecraft.world.entity.Entity
|
|||
import net.minecraft.world.phys.Vec3
|
||||
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) {
|
||||
is Double -> Either.left(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) {
|
||||
is Double -> Either.left(datum.payload)
|
||||
is SpellList -> Either.right(datum.payload)
|
||||
|
|
|
@ -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) {
|
||||
companion object {
|
||||
@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)
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@ package at.petrak.hexcasting.api.spell
|
|||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.math.HexPattern
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidSpellDatumType
|
||||
import at.petrak.hexcasting.api.utils.HexUtils
|
||||
import at.petrak.hexcasting.api.utils.HexUtils.serializeToNBT
|
||||
import at.petrak.hexcasting.api.utils.getList
|
||||
import at.petrak.hexcasting.api.utils.*
|
||||
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.TextComponent
|
||||
import net.minecraft.network.chat.TranslatableComponent
|
||||
|
@ -22,7 +22,7 @@ import java.util.*
|
|||
* We use the following types:
|
||||
* * [Entity]
|
||||
* * [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
|
||||
* * [SpellList]
|
||||
* * [HexPattern]! Yes, we have meta-evaluation everyone.
|
||||
|
@ -33,39 +33,19 @@ import java.util.*
|
|||
class SpellDatum<T : Any> private constructor(val payload: T) {
|
||||
val clazz: Class<T> = payload.javaClass
|
||||
|
||||
fun serializeToNBT(): CompoundTag {
|
||||
val out = CompoundTag()
|
||||
when (val pl = this.payload) {
|
||||
is Entity -> {
|
||||
val subtag = CompoundTag()
|
||||
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())
|
||||
fun serializeToNBT() = NBTBuilder {
|
||||
when (val pl = payload) {
|
||||
is Entity -> TAG_ENTITY %= compound {
|
||||
TAG_ENTITY_UUID %= NbtUtils.createUUID(pl.uuid)
|
||||
TAG_ENTITY_NAME_CHEATY %= Component.Serializer.toJson(pl.displayName)
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
override fun toString(): String =
|
||||
|
@ -85,7 +65,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
|
||||
fun display(): Component {
|
||||
val nbt = this.serializeToNBT()
|
||||
return DisplayFromTag(nbt)
|
||||
return displayFromNBT(nbt)
|
||||
}
|
||||
|
||||
fun getType(): DatumType =
|
||||
|
@ -101,6 +81,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||
fun make(payload: Any): SpellDatum<*> =
|
||||
if (payload is SpellDatum<*>) {
|
||||
payload
|
||||
|
@ -114,23 +95,23 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
} else if (payload is Vec3) {
|
||||
SpellDatum(
|
||||
Vec3(
|
||||
HexUtils.FixNANs(payload.x),
|
||||
HexUtils.FixNANs(payload.y),
|
||||
HexUtils.FixNANs(payload.z),
|
||||
fixNAN(payload.x),
|
||||
fixNAN(payload.y),
|
||||
fixNAN(payload.z),
|
||||
)
|
||||
)
|
||||
} else if (IsValidType(payload)) {
|
||||
} else if (isValidType(payload)) {
|
||||
SpellDatum(payload)
|
||||
} else if (payload is java.lang.Double) {
|
||||
// Check to see if it's a java *boxed* double, for when we call this from Java
|
||||
val num = payload.toDouble()
|
||||
SpellDatum(HexUtils.FixNANs(num))
|
||||
SpellDatum(fixNAN(num))
|
||||
} else {
|
||||
throw MishapInvalidSpellDatumType(payload)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun DeserializeFromNBT(nbt: CompoundTag, world: ServerLevel): SpellDatum<*> {
|
||||
fun fromNBT(nbt: CompoundTag, world: ServerLevel): SpellDatum<*> {
|
||||
val keys = nbt.allKeys
|
||||
if (keys.size != 1)
|
||||
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)
|
||||
}
|
||||
TAG_DOUBLE -> SpellDatum(nbt.getDouble(key))
|
||||
TAG_VEC3 -> SpellDatum(HexUtils.DeserializeVec3FromNBT(nbt.getLongArray(key)))
|
||||
TAG_VEC3 -> SpellDatum(vecFromNBT(nbt.getLongArray(key)))
|
||||
TAG_LIST -> {
|
||||
val arr = nbt.getList(key, Tag.TAG_COMPOUND)
|
||||
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))
|
||||
SpellDatum(SpellList.fromNBT(nbt.getList(key, Tag.TAG_COMPOUND), world))
|
||||
}
|
||||
TAG_WIDGET -> {
|
||||
SpellDatum(Widget.valueOf(nbt.getString(key)))
|
||||
}
|
||||
TAG_PATTERN -> {
|
||||
SpellDatum(HexPattern.DeserializeFromNBT(nbt.getCompound(TAG_PATTERN)))
|
||||
SpellDatum(HexPattern.fromNBT(nbt.getCompound(TAG_PATTERN)))
|
||||
}
|
||||
else -> throw IllegalArgumentException("Unknown key $key: $nbt")
|
||||
}
|
||||
|
@ -171,11 +146,11 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
)
|
||||
)
|
||||
@JvmStatic
|
||||
fun DeserializeFromNBT(nbt: CompoundTag, ctx: CastingContext): SpellDatum<*> =
|
||||
DeserializeFromNBT(nbt, ctx.world)
|
||||
fun fromNBT(nbt: CompoundTag, ctx: CastingContext): SpellDatum<*> =
|
||||
fromNBT(nbt, ctx.world)
|
||||
|
||||
@JvmStatic
|
||||
fun DisplayFromTag(nbt: CompoundTag): Component {
|
||||
fun displayFromNBT(nbt: CompoundTag): Component {
|
||||
val keys = nbt.allKeys
|
||||
if (keys.size != 1)
|
||||
throw IllegalArgumentException("Expected exactly one kv pair: $nbt")
|
||||
|
@ -188,7 +163,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
)
|
||||
).withStyle(ChatFormatting.GREEN)
|
||||
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
|
||||
TextComponent(
|
||||
String.format(
|
||||
|
@ -205,7 +180,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
val arr = nbt.getList(key, Tag.TAG_COMPOUND)
|
||||
for ((i, subtag) in arr.withIndex()) {
|
||||
// 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) {
|
||||
out.append(", ")
|
||||
}
|
||||
|
@ -223,7 +198,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
else TextComponent(widget.toString()).withStyle(ChatFormatting.DARK_PURPLE)
|
||||
}
|
||||
TAG_PATTERN -> {
|
||||
val pat = HexPattern.DeserializeFromNBT(nbt.getCompound(TAG_PATTERN))
|
||||
val pat = HexPattern.fromNBT(nbt.getCompound(TAG_PATTERN))
|
||||
var angleDesc = pat.anglesSignature()
|
||||
if (angleDesc.isNotBlank()) angleDesc = " $angleDesc";
|
||||
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
|
||||
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) }
|
||||
|
||||
@JvmStatic
|
||||
fun GetTagName(datumType: DatumType): String {
|
||||
fun tagForType(datumType: DatumType): String {
|
||||
return when (datumType) {
|
||||
DatumType.ENTITY -> TAG_ENTITY
|
||||
DatumType.WIDGET -> TAG_WIDGET
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
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.
|
||||
*
|
||||
|
@ -73,4 +77,16 @@ sealed class SpellList: Iterable<SpellDatum<*>> {
|
|||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.MishapEvalTooDeep
|
||||
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 net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
|
@ -33,7 +33,7 @@ data class CastingContext(
|
|||
private var depth: Int = 0
|
||||
|
||||
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()
|
||||
|
||||
private val entitiesGivenMotion = mutableSetOf<Entity>()
|
||||
|
|
|
@ -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.HexPattern
|
||||
import at.petrak.hexcasting.api.spell.mishaps.*
|
||||
import at.petrak.hexcasting.api.utils.ManaHelper
|
||||
import at.petrak.hexcasting.api.utils.asCompound
|
||||
import at.petrak.hexcasting.api.utils.getList
|
||||
import at.petrak.hexcasting.api.utils.*
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.network.chat.Component
|
||||
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.
|
||||
var continuation = SpellContinuation.Done.pushFrame(ContinuationFrame.Evaluate(SpellList.LList(0, iotas)))
|
||||
// Begin aggregating info
|
||||
val info = TempControllerInfo(false, false)
|
||||
val info = TempControllerInfo(playSound = false, earlyExit = false)
|
||||
var lastResolutionType = ResolvedPatternType.UNRESOLVED
|
||||
while (continuation is SpellContinuation.NotDone && !info.earlyExit) {
|
||||
// Take the top of the continuation stack...
|
||||
|
@ -388,10 +385,10 @@ class CastingHarness private constructor(
|
|||
}
|
||||
if (casterStack.`is`(HexItemTags.WANDS) || ipsCanDrawFromInv) {
|
||||
val manableItems = this.ctx.caster.inventory.items
|
||||
.filter(ManaHelper::isManaItem)
|
||||
.sortedWith(Comparator(ManaHelper::compare).reversed())
|
||||
.filter(::isManaItem)
|
||||
.sortedWith(Comparator(::compareManaItem).reversed())
|
||||
for (stack in manableItems) {
|
||||
costLeft -= ManaHelper.extractMana(stack, costLeft)
|
||||
costLeft -= extractMana(stack, costLeft)
|
||||
if (costLeft <= 0)
|
||||
break
|
||||
}
|
||||
|
@ -431,29 +428,17 @@ class CastingHarness private constructor(
|
|||
}
|
||||
|
||||
|
||||
fun serializeToNBT(): CompoundTag {
|
||||
val out = CompoundTag()
|
||||
fun serializeToNBT() = NBTBuilder {
|
||||
TAG_STACK %= stack.serializeToNBT()
|
||||
|
||||
val stackTag = ListTag()
|
||||
for (datum in this.stack)
|
||||
stackTag.add(datum.serializeToNBT())
|
||||
out.put(TAG_STACK, stackTag)
|
||||
TAG_LOCAL %= localIota.serializeToNBT()
|
||||
TAG_PAREN_COUNT %= parenCount
|
||||
TAG_ESCAPE_NEXT %= escapeNext
|
||||
|
||||
out.put(TAG_LOCAL, localIota.serializeToNBT())
|
||||
TAG_PARENTHESIZED %= parenthesized.serializeToNBT()
|
||||
|
||||
out.putInt(TAG_PAREN_COUNT, this.parenCount)
|
||||
out.putBoolean(TAG_ESCAPE_NEXT, this.escapeNext)
|
||||
|
||||
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
|
||||
if (prepackagedColorizer != null)
|
||||
TAG_PREPACKAGED_COLORIZER %= prepackagedColorizer.serializeToNBT()
|
||||
}
|
||||
|
||||
|
||||
|
@ -466,18 +451,18 @@ class CastingHarness private constructor(
|
|||
const val TAG_PREPACKAGED_COLORIZER = "prepackaged_colorizer"
|
||||
|
||||
@JvmStatic
|
||||
fun DeserializeFromNBT(nbt: CompoundTag, ctx: CastingContext): CastingHarness {
|
||||
fun fromNBT(nbt: CompoundTag, ctx: CastingContext): CastingHarness {
|
||||
return try {
|
||||
val stack = mutableListOf<SpellDatum<*>>()
|
||||
val stackTag = nbt.getList(TAG_STACK, Tag.TAG_COMPOUND)
|
||||
for (subtag in stackTag) {
|
||||
val datum = SpellDatum.DeserializeFromNBT(subtag.asCompound, ctx.world)
|
||||
val datum = SpellDatum.fromNBT(subtag.asCompound, ctx.world)
|
||||
stack.add(datum)
|
||||
}
|
||||
|
||||
val localTag = nbt.getCompound(TAG_LOCAL)
|
||||
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
|
||||
)
|
||||
|
||||
|
@ -485,16 +470,16 @@ class CastingHarness private constructor(
|
|||
val parenTag = nbt.getList(TAG_PARENTHESIZED, Tag.TAG_COMPOUND)
|
||||
for (subtag in parenTag) {
|
||||
if (subtag.asCompound.size() != 1)
|
||||
parenthesized.add(SpellDatum.make(HexPattern.DeserializeFromNBT(subtag.asCompound)))
|
||||
parenthesized.add(SpellDatum.make(HexPattern.fromNBT(subtag.asCompound)))
|
||||
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 escapeNext = nbt.getBoolean(TAG_ESCAPE_NEXT)
|
||||
|
||||
val colorizer = if (nbt.contains(TAG_PREPACKAGED_COLORIZER)) {
|
||||
FrozenColorizer.deserialize(nbt.getCompound(TAG_PREPACKAGED_COLORIZER))
|
||||
FrozenColorizer.fromNBT(nbt.getCompound(TAG_PREPACKAGED_COLORIZER))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
|
|
@ -3,6 +3,12 @@ package at.petrak.hexcasting.api.spell.casting
|
|||
import at.petrak.hexcasting.api.spell.SpellDatum
|
||||
import at.petrak.hexcasting.api.spell.SpellList
|
||||
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
|
||||
|
||||
/**
|
||||
|
@ -32,13 +38,18 @@ sealed interface ContinuationFrame {
|
|||
*/
|
||||
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.
|
||||
* @property list the *remaining* list of patterns to be evaluated
|
||||
*/
|
||||
data class Evaluate(val list: SpellList) : ContinuationFrame {
|
||||
// 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.
|
||||
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,
|
||||
* 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.
|
||||
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.
|
||||
override fun evaluate(
|
||||
|
@ -83,6 +98,10 @@ sealed interface ContinuationFrame {
|
|||
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. */
|
||||
override fun breakDownwards(stack: List<SpellDatum<*>>): Pair<Boolean, List<SpellDatum<*>>> {
|
||||
val newStack = baseStack!!.toMutableList()
|
||||
val newStack = baseStack?.toMutableList() ?: mutableListOf()
|
||||
acc.addAll(stack)
|
||||
newStack.add(SpellDatum.make(acc))
|
||||
return Pair(true, newStack)
|
||||
return true to newStack
|
||||
}
|
||||
|
||||
/** Step the Thoth computation, enqueueing one code evaluation. */
|
||||
|
@ -127,17 +146,15 @@ sealed interface ContinuationFrame {
|
|||
|
||||
// If we still have data to process...
|
||||
val (stackTop, newCont) = if (data.nonEmpty) {
|
||||
Pair(
|
||||
data.car, // Push the next datum to the top of the stack,
|
||||
continuation
|
||||
// put the next Thoth object back on the stack for the next Thoth cycle,
|
||||
.pushFrame(ForEach(data.cdr, code, stack, acc))
|
||||
// and prep the Thoth'd code block for evaluation.
|
||||
.pushFrame(Evaluate(code))
|
||||
)
|
||||
// Push the next datum to the top of the stack,
|
||||
data.car to continuation
|
||||
// put the next Thoth object back on the stack for the next Thoth cycle,
|
||||
.pushFrame(ForEach(data.cdr, code, stack, acc))
|
||||
// and prep the Thoth'd code block for evaluation.
|
||||
.pushFrame(Evaluate(code))
|
||||
} else {
|
||||
// Else, dump our final list onto the stack.
|
||||
Pair(SpellDatum.make(acc), continuation)
|
||||
SpellDatum.make(acc) to continuation
|
||||
}
|
||||
val tStack = stack.toMutableList()
|
||||
tStack.add(stackTop)
|
||||
|
@ -148,5 +165,31 @@ sealed interface ContinuationFrame {
|
|||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@ import at.petrak.hexcasting.api.spell.SpellDatum
|
|||
|
||||
/**
|
||||
* A change to the data in a CastHarness after a pattern is drawn.
|
||||
*
|
||||
* [wasThisPatternInvalid] is for the benefit of the controller.
|
||||
*/
|
||||
data class FunctionalData(
|
||||
val stack: List<SpellDatum<*>>,
|
||||
|
|
|
@ -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.HexPattern
|
||||
import at.petrak.hexcasting.api.utils.NBTBuilder
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import java.util.*
|
||||
|
||||
|
||||
data class ResolvedPattern(val pattern: HexPattern, val origin: HexCoord, var type: ResolvedPatternType) {
|
||||
fun serializeToNBT(): CompoundTag {
|
||||
val tag = CompoundTag()
|
||||
tag.put("Pattern", pattern.serializeToNBT())
|
||||
tag.putInt("OriginQ", origin.q)
|
||||
tag.putInt("OriginR", origin.r)
|
||||
tag.putString("Valid", type.name.lowercase(Locale.ROOT))
|
||||
return tag
|
||||
fun serializeToNBT() = NBTBuilder {
|
||||
"Pattern" %= pattern.serializeToNBT()
|
||||
"OriginQ" %= origin.q
|
||||
"OriginR" %= origin.r
|
||||
"Valid" %= type.name.lowercase(Locale.ROOT)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun DeserializeFromNBT(tag: CompoundTag): ResolvedPattern {
|
||||
val pattern = HexPattern.DeserializeFromNBT(tag.getCompound("Pattern"))
|
||||
fun fromNBT(tag: CompoundTag): ResolvedPattern {
|
||||
val pattern = HexPattern.fromNBT(tag.getCompound("Pattern"))
|
||||
val origin = HexCoord(tag.getInt("OriginQ"), tag.getInt("OriginR"))
|
||||
val valid = try {
|
||||
ResolvedPatternType.valueOf(tag.getString("Valid").uppercase(Locale.ROOT))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package at.petrak.hexcasting.api.spell.casting
|
||||
|
||||
import at.petrak.hexcasting.api.utils.NBTBuilder
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
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
|
||||
*/
|
||||
data class SpellCircleContext(val impetusPos: BlockPos, val aabb: AABB, val activatorAlwaysInRange: Boolean) {
|
||||
fun serializeToNBT(): CompoundTag {
|
||||
val out = CompoundTag()
|
||||
fun serializeToNBT() = NBTBuilder {
|
||||
TAG_IMPETUS_X %= impetusPos.x
|
||||
TAG_IMPETUS_Y %= impetusPos.y
|
||||
TAG_IMPETUS_Z %= impetusPos.z
|
||||
|
||||
out.putInt(TAG_IMPETUS_X, impetusPos.x)
|
||||
out.putInt(TAG_IMPETUS_Y, impetusPos.y)
|
||||
out.putInt(TAG_IMPETUS_Z, impetusPos.z)
|
||||
TAG_MIN_X %= aabb.minX
|
||||
TAG_MIN_Y %= aabb.minY
|
||||
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)
|
||||
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
|
||||
TAG_PLAYER_ALWAYS_IN_RANGE %= activatorAlwaysInRange
|
||||
}
|
||||
|
||||
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_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 impY = tag.getInt(TAG_IMPETUS_Y)
|
||||
val impZ = tag.getInt(TAG_IMPETUS_Z)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package at.petrak.hexcasting.api.spell.math
|
||||
|
||||
import at.petrak.hexcasting.api.utils.HexUtils
|
||||
import net.minecraft.nbt.ByteArrayTag
|
||||
import net.minecraft.nbt.ByteTag
|
||||
import at.petrak.hexcasting.api.utils.NBTBuilder
|
||||
import at.petrak.hexcasting.api.utils.coordToPx
|
||||
import at.petrak.hexcasting.api.utils.findCenter
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.Tag
|
||||
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 cursor = HexCoord.Origin
|
||||
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
|
||||
linesSeen.add(Pair(cursor + compass, compass.rotatedBy(HexAngle.BACK)))
|
||||
linesSeen.add(cursor + compass to compass.rotatedBy(HexAngle.BACK))
|
||||
cursor += compass
|
||||
compass *= a
|
||||
}
|
||||
cursor += compass
|
||||
|
||||
val potentialNewLine = Pair(cursor, newDir)
|
||||
val potentialNewLine = cursor to newDir
|
||||
if (potentialNewLine in linesSeen) return false
|
||||
val nextAngle = newDir - compass
|
||||
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 }
|
||||
|
||||
|
||||
fun serializeToNBT(): CompoundTag {
|
||||
val out = CompoundTag()
|
||||
out.put(TAG_START_DIR, ByteTag.valueOf(this.startDir.ordinal.toByte()))
|
||||
val anglesTag = ByteArrayTag(this.angles.map { it.ordinal.toByte() })
|
||||
out.put(TAG_ANGLES, anglesTag)
|
||||
return out
|
||||
fun serializeToNBT() = NBTBuilder {
|
||||
TAG_START_DIR %= byte(startDir.ordinal)
|
||||
TAG_ANGLES %= byteArray(angles.map(HexAngle::ordinal))
|
||||
}
|
||||
|
||||
// Terrible shorthand method for easy matching
|
||||
|
@ -103,9 +100,9 @@ data class HexPattern(public val startDir: HexDir, public val angles: MutableLis
|
|||
*/
|
||||
@JvmOverloads
|
||||
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)
|
||||
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.
|
||||
*/
|
||||
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 {
|
||||
append("HexPattern[")
|
||||
|
@ -128,7 +125,7 @@ data class HexPattern(public val startDir: HexDir, public val angles: MutableLis
|
|||
const val TAG_ANGLES = "angles"
|
||||
|
||||
@JvmStatic
|
||||
fun IsHexPattern(tag: CompoundTag): Boolean {
|
||||
fun isPattern(tag: CompoundTag): Boolean {
|
||||
return tag.contains(TAG_START_DIR, Tag.TAG_ANY_NUMERIC.toInt()) && tag.contains(
|
||||
TAG_ANGLES,
|
||||
Tag.TAG_BYTE_ARRAY.toInt()
|
||||
|
@ -136,14 +133,14 @@ data class HexPattern(public val startDir: HexDir, public val angles: MutableLis
|
|||
}
|
||||
|
||||
@JvmStatic
|
||||
fun DeserializeFromNBT(tag: CompoundTag): HexPattern {
|
||||
fun fromNBT(tag: CompoundTag): HexPattern {
|
||||
val startDir = HexDir.values()[tag.getByte(TAG_START_DIR).toInt()]
|
||||
val angles = tag.getByteArray(TAG_ANGLES).map { HexAngle.values()[it.toInt()] }
|
||||
return HexPattern(startDir, angles.toMutableList())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun FromAnglesSig(signature: String, startDir: HexDir): HexPattern {
|
||||
fun fromAngles(signature: String, startDir: HexDir): HexPattern {
|
||||
val out = HexPattern(startDir)
|
||||
var compass = startDir
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ class MishapAlreadyBrainswept(val villager: Villager) : Mishap() {
|
|||
}
|
||||
|
||||
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 =
|
||||
|
|
|
@ -20,7 +20,7 @@ class MishapBadBlock(val pos: BlockPos, val expected: Component) : Mishap() {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -20,7 +20,7 @@ class MishapBadBrainsweep(val villager: Villager, val pos: BlockPos) : Mishap()
|
|||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
@file:JvmName("HexUtils")
|
||||
package at.petrak.hexcasting.api.utils
|
||||
|
||||
import at.petrak.hexcasting.api.spell.SpellDatum
|
||||
import at.petrak.hexcasting.api.spell.math.HexCoord
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.LongArrayTag
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
@ -12,88 +15,82 @@ import kotlin.math.max
|
|||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
object HexUtils {
|
||||
const val SQRT_3 = 1.7320508f
|
||||
const val TAU = Math.PI * 2.0
|
||||
const val SQRT_3 = 1.7320508f
|
||||
|
||||
@JvmStatic
|
||||
fun Vec3.serializeToNBT(): LongArrayTag =
|
||||
LongArrayTag(longArrayOf(this.x.toRawBits(), this.y.toRawBits(), this.z.toRawBits()))
|
||||
fun Vec3.serializeToNBT(): LongArrayTag =
|
||||
LongArrayTag(longArrayOf(this.x.toRawBits(), this.y.toRawBits(), this.z.toRawBits()))
|
||||
|
||||
@JvmStatic
|
||||
fun DeserializeVec3FromNBT(tag: LongArray): Vec3 = if (tag.size != 3) Vec3.ZERO else
|
||||
Vec3(
|
||||
Double.fromBits(tag[0]),
|
||||
Double.fromBits(tag[1]),
|
||||
Double.fromBits(tag[2])
|
||||
)
|
||||
fun vecFromNBT(tag: LongArray): Vec3 = if (tag.size != 3) Vec3.ZERO else
|
||||
Vec3(
|
||||
Double.fromBits(tag[0]),
|
||||
Double.fromBits(tag[1]),
|
||||
Double.fromBits(tag[2])
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun Vec2.serializeToNBT(): LongArrayTag =
|
||||
LongArrayTag(longArrayOf(this.x.toDouble().toRawBits(), this.y.toDouble().toRawBits()))
|
||||
fun Vec2.serializeToNBT(): LongArrayTag =
|
||||
LongArrayTag(longArrayOf(this.x.toDouble().toRawBits(), this.y.toDouble().toRawBits()))
|
||||
|
||||
@JvmStatic
|
||||
fun DeserializeVec2FromNBT(tag: LongArray): Vec2 = if (tag.size != 2) Vec2.ZERO else
|
||||
Vec2(
|
||||
Double.fromBits(tag[0]).toFloat(),
|
||||
Double.fromBits(tag[1]).toFloat(),
|
||||
)
|
||||
fun vec2FromNBT(tag: LongArray): Vec2 = if (tag.size != 2) Vec2.ZERO else
|
||||
Vec2(
|
||||
Double.fromBits(tag[0]).toFloat(),
|
||||
Double.fromBits(tag[1]).toFloat(),
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun OtherHand(hand: InteractionHand) =
|
||||
if (hand == InteractionHand.MAIN_HAND) InteractionHand.OFF_HAND else InteractionHand.MAIN_HAND
|
||||
fun otherHand(hand: InteractionHand) =
|
||||
if (hand == InteractionHand.MAIN_HAND) InteractionHand.OFF_HAND else InteractionHand.MAIN_HAND
|
||||
|
||||
@JvmStatic
|
||||
fun FixNANs(x: Double): Double = if (x.isFinite()) x else 0.0
|
||||
fun fixNAN(x: Double): Double = if (x.isFinite()) x else 0.0
|
||||
|
||||
@JvmStatic
|
||||
fun FindCenter(points: List<Vec2>): Vec2 {
|
||||
var minX = Float.POSITIVE_INFINITY
|
||||
var minY = Float.POSITIVE_INFINITY
|
||||
var maxX = Float.NEGATIVE_INFINITY
|
||||
var maxY = Float.NEGATIVE_INFINITY
|
||||
fun findCenter(points: List<Vec2>): Vec2 {
|
||||
var minX = Float.POSITIVE_INFINITY
|
||||
var minY = Float.POSITIVE_INFINITY
|
||||
var maxX = Float.NEGATIVE_INFINITY
|
||||
var maxY = Float.NEGATIVE_INFINITY
|
||||
|
||||
for (pos in points) {
|
||||
minX = min(minX, pos.x)
|
||||
minY = min(minY, pos.y)
|
||||
maxX = max(maxX, pos.x)
|
||||
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
|
||||
for (pos in points) {
|
||||
minX = min(minX, pos.x)
|
||||
minY = min(minY, pos.y)
|
||||
maxX = max(maxX, pos.x)
|
||||
maxY = max(maxY, pos.y)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@file:JvmName("ManaHelper")
|
||||
package at.petrak.hexcasting.api.utils
|
||||
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
|
@ -5,76 +6,70 @@ import net.minecraft.util.Mth
|
|||
import net.minecraft.world.item.ItemStack
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
object ManaHelper {
|
||||
@JvmStatic
|
||||
fun isManaItem(stack: ItemStack): Boolean {
|
||||
val manaHolder = IXplatAbstractions.INSTANCE.findManaHolder(stack) ?: return false
|
||||
if (!manaHolder.canProvide())
|
||||
return false
|
||||
return manaHolder.withdrawMana(-1, true) > 0
|
||||
}
|
||||
fun isManaItem(stack: ItemStack): Boolean {
|
||||
val manaHolder = IXplatAbstractions.INSTANCE.findManaHolder(stack) ?: return false
|
||||
if (!manaHolder.canProvide())
|
||||
return false
|
||||
return manaHolder.withdrawMana(-1, true) > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun extractMana(
|
||||
stack: ItemStack,
|
||||
cost: Int = -1,
|
||||
drainForBatteries: Boolean = false,
|
||||
simulate: Boolean = false
|
||||
): Int {
|
||||
val manaHolder = IXplatAbstractions.INSTANCE.findManaHolder(stack) ?: return 0
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun extractMana(
|
||||
stack: ItemStack,
|
||||
cost: Int = -1,
|
||||
drainForBatteries: Boolean = false,
|
||||
simulate: Boolean = false
|
||||
): Int {
|
||||
val manaHolder = IXplatAbstractions.INSTANCE.findManaHolder(stack) ?: return 0
|
||||
|
||||
if (drainForBatteries && !manaHolder.canConstructBattery())
|
||||
return 0
|
||||
if (drainForBatteries && !manaHolder.canConstructBattery())
|
||||
return 0
|
||||
|
||||
return manaHolder.withdrawMana(cost, simulate)
|
||||
}
|
||||
return manaHolder.withdrawMana(cost, simulate)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorted from least important to most important
|
||||
*/
|
||||
fun compare(astack: ItemStack, bstack: ItemStack): Int {
|
||||
val aMana = IXplatAbstractions.INSTANCE.findManaHolder(astack)
|
||||
val bMana = IXplatAbstractions.INSTANCE.findManaHolder(bstack)
|
||||
/**
|
||||
* Sorted from least important to most important
|
||||
*/
|
||||
fun compareManaItem(astack: ItemStack, bstack: ItemStack): Int {
|
||||
val aMana = IXplatAbstractions.INSTANCE.findManaHolder(astack)
|
||||
val bMana = IXplatAbstractions.INSTANCE.findManaHolder(bstack)
|
||||
|
||||
return if (astack.item != bstack.item) {
|
||||
(aMana?.consumptionPriority ?: 0) - (bMana?.consumptionPriority ?: 0)
|
||||
} else if (aMana != null && bMana != null) {
|
||||
aMana.mana - bMana.mana
|
||||
} else {
|
||||
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()
|
||||
return if (astack.item != bstack.item) {
|
||||
(aMana?.consumptionPriority ?: 0) - (bMana?.consumptionPriority ?: 0)
|
||||
} else if (aMana != null && bMana != null) {
|
||||
aMana.mana - bMana.mana
|
||||
} else {
|
||||
astack.count - bstack.count
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
|
210
Common/src/main/java/at/petrak/hexcasting/api/utils/NBTDsl.kt
Normal file
210
Common/src/main/java/at/petrak/hexcasting/api/utils/NBTDsl.kt
Normal 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) }
|
||||
}
|
|
@ -223,6 +223,7 @@ public class HexAdditionalRenderers {
|
|||
if (text.isEmpty()) {
|
||||
ps.translate(0, mc.font.lineHeight, 0);
|
||||
}
|
||||
ps.translate(0, 6, 0);
|
||||
}
|
||||
|
||||
ps.popPose();
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
@file:JvmName("RenderLib")
|
||||
package at.petrak.hexcasting.client
|
||||
|
||||
import at.petrak.hexcasting.api.mod.HexConfig
|
||||
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.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
|
@ -12,6 +14,7 @@ import com.mojang.math.Matrix4f
|
|||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.util.FastColor
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.item.ItemStack
|
||||
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 kotlin.math.floor
|
||||
import kotlin.math.min
|
||||
import net.minecraft.util.FastColor.ARGB32 as FC
|
||||
|
||||
/**
|
||||
* Common draw code
|
||||
* Source of perlin noise
|
||||
*/
|
||||
object RenderLib {
|
||||
/**
|
||||
* Source of perlin noise
|
||||
*/
|
||||
val NOISE = PerlinNoise.create(XoroshiroRandomSource(9001L), listOf(0, 1, 2, 3, 4))
|
||||
val NOISE: PerlinNoise = PerlinNoise.create(XoroshiroRandomSource(9001L), listOf(0, 1, 2, 3, 4))
|
||||
|
||||
/**
|
||||
* 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]
|
||||
*/
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun drawLineSeq(
|
||||
mat: Matrix4f,
|
||||
points: List<Vec2>,
|
||||
width: Float,
|
||||
z: Float,
|
||||
tail: Int,
|
||||
head: Int,
|
||||
animTime: Float? = null,
|
||||
) {
|
||||
if (points.size <= 1) return
|
||||
/**
|
||||
* Draw a sequence of linePoints spanning the given points.
|
||||
*
|
||||
* Please make sure to enable the right asinine shaders; see [GuiSpellcasting]
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun drawLineSeq(
|
||||
mat: Matrix4f,
|
||||
points: List<Vec2>,
|
||||
width: Float,
|
||||
z: Float,
|
||||
tail: Int,
|
||||
head: Int,
|
||||
animTime: Float? = null,
|
||||
) {
|
||||
if (points.size <= 1) return
|
||||
|
||||
val r1 = FC.red(tail).toFloat()
|
||||
val g1 = FC.green(tail).toFloat()
|
||||
val b1 = FC.blue(tail).toFloat()
|
||||
val a = FC.alpha(tail)
|
||||
val headSource = if (Screen.hasControlDown() != HexConfig.client().ctrlTogglesOffStrokeOrder())
|
||||
head
|
||||
else
|
||||
tail
|
||||
val r2 = FC.red(headSource).toFloat()
|
||||
val g2 = FC.green(headSource).toFloat()
|
||||
val b2 = FC.blue(headSource).toFloat()
|
||||
val r1 = FastColor.ARGB32.red(tail).toFloat()
|
||||
val g1 = FastColor.ARGB32.green(tail).toFloat()
|
||||
val b1 = FastColor.ARGB32.blue(tail).toFloat()
|
||||
val a = FastColor.ARGB32.alpha(tail)
|
||||
val headSource = if (Screen.hasControlDown() != HexConfig.client().ctrlTogglesOffStrokeOrder())
|
||||
head
|
||||
else
|
||||
tail
|
||||
val r2 = FastColor.ARGB32.red(headSource).toFloat()
|
||||
val g2 = FastColor.ARGB32.green(headSource).toFloat()
|
||||
val b2 = FastColor.ARGB32.blue(headSource).toFloat()
|
||||
|
||||
// they spell it wrong at mojang lmao
|
||||
val tess = Tesselator.getInstance()
|
||||
val buf = tess.builder
|
||||
// they spell it wrong at mojang lmao
|
||||
val tess = Tesselator.getInstance()
|
||||
val buf = tess.builder
|
||||
|
||||
// We use one single TRIANGLE_STRIP
|
||||
// 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.
|
||||
buf.begin(VertexFormat.Mode.TRIANGLE_STRIP, DefaultVertexFormat.POSITION_COLOR)
|
||||
// We use one single TRIANGLE_STRIP
|
||||
// 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.
|
||||
buf.begin(VertexFormat.Mode.TRIANGLE_STRIP, DefaultVertexFormat.POSITION_COLOR)
|
||||
|
||||
val n = points.size
|
||||
for ((i, pair) in points.zipWithNext().withIndex()) {
|
||||
val (p1, p2) = pair
|
||||
// https://github.com/not-fl3/macroquad/blob/master/src/shapes.rs#L163
|
||||
// GuiComponent::innerFill line 52
|
||||
// fedor have useful variable names challenge (99% can't beat)
|
||||
val dx = p2.x - p1.x
|
||||
val dy = p2.y - p1.y
|
||||
// normal x and y, presumably?
|
||||
val nx = -dy
|
||||
val ny = dx
|
||||
// thickness?
|
||||
val tlen = Mth.sqrt(nx * nx + ny * ny) / (width * 0.5f)
|
||||
val tx = nx / tlen
|
||||
val ty = ny / tlen
|
||||
val n = points.size
|
||||
for ((i, pair) in points.zipWithNext().withIndex()) {
|
||||
val (p1, p2) = pair
|
||||
// https://github.com/not-fl3/macroquad/blob/master/src/shapes.rs#L163
|
||||
// GuiComponent::innerFill line 52
|
||||
// fedor have useful variable names challenge (99% can't beat)
|
||||
val dx = p2.x - p1.x
|
||||
val dy = p2.y - p1.y
|
||||
// normal x and y, presumably?
|
||||
val nx = -dy
|
||||
val ny = dx
|
||||
// thickness?
|
||||
val tlen = Mth.sqrt(nx * nx + ny * ny) / (width * 0.5f)
|
||||
val tx = nx / tlen
|
||||
val ty = ny / tlen
|
||||
|
||||
fun color(time: Float): BlockPos =
|
||||
BlockPos(Mth.lerp(time, r1, r2).toInt(), Mth.lerp(time, g1, g2).toInt(), Mth.lerp(time, b1, b2).toInt())
|
||||
fun color(time: Float): BlockPos =
|
||||
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 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, 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
|
||||
)
|
||||
}
|
||||
}
|
||||
val color1 = color(i.toFloat() / 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, 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()
|
||||
|
||||
/**
|
||||
* Draw a hex pattern from the given list of non-zappy points (as in, do the *style* of drawing it,
|
||||
* you have to do the conversion yourself.)
|
||||
*/
|
||||
@JvmStatic
|
||||
fun drawPatternFromPoints(
|
||||
mat: Matrix4f,
|
||||
points: List<Vec2>,
|
||||
drawLast: Boolean,
|
||||
tail: Int,
|
||||
head: Int,
|
||||
flowIrregular: Float,
|
||||
animTime: Float? = null
|
||||
) {
|
||||
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) {
|
||||
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,
|
||||
node,
|
||||
drawPos,
|
||||
2f,
|
||||
dodge(FC.red(head)) / 255f,
|
||||
dodge(FC.green(head)) / 255f,
|
||||
dodge(FC.blue(head)) / 255f,
|
||||
FC.alpha(head) / 255f
|
||||
);
|
||||
(r1 + 255) / 2f / 255f,
|
||||
(g1 + 255) / 2f / 255f,
|
||||
(b1 + 255) / 2f / 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
|
||||
* @param speed: rate at which the lightning effect should move/shake/etc
|
||||
*/
|
||||
@JvmStatic
|
||||
fun makeZappy(points: List<Vec2>, hops: Float, variance: Float, speed: Float, flowIrregular: Float): List<Vec2> {
|
||||
// Nothing in, nothing out
|
||||
if (points.isEmpty()) {
|
||||
return emptyList()
|
||||
}
|
||||
val scaleVariance = { it: Double -> Math.min(1.0, 8 * (0.5 - Math.abs(0.5 - it))) }
|
||||
val hops = hops.toInt()
|
||||
val zSeed = ClientTickCounter.total.toDouble() * speed
|
||||
// Create our output list of zap points
|
||||
val zappyPts = mutableListOf(points[0])
|
||||
// For each segment in the original...
|
||||
for ((i, pair) in points.zipWithNext().withIndex()) {
|
||||
val (src, target) = pair
|
||||
val delta = target.add(src.negated())
|
||||
// Take hop distance
|
||||
val hopDist = Mth.sqrt(src.distanceToSqr(target)) / hops
|
||||
// Compute how big the radius of variance should be
|
||||
val maxVariance = hopDist * variance
|
||||
|
||||
for (j in 1..hops) {
|
||||
val progress = j.toDouble() / (hops + 1)
|
||||
// Add the next hop...
|
||||
val pos = src.add(delta.scale(progress.toFloat()))
|
||||
// as well as some random variance...
|
||||
// (We use i, j (segment #, subsegment #) as seeds for the Perlin noise,
|
||||
// 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) * 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))
|
||||
}
|
||||
// Finally, we hit the destination, add that too
|
||||
zappyPts.add(target)
|
||||
}
|
||||
return zappyPts
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a little circle, because Minecraft rendering code is a nightmare and doesn't
|
||||
* include primitive drawing code...
|
||||
*/
|
||||
@JvmStatic
|
||||
fun drawSpot(mat: Matrix4f, point: Vec2, radius: Float, r: Float, g: Float, b: Float, a: Float) {
|
||||
val tess = Tesselator.getInstance()
|
||||
val buf = tess.builder
|
||||
// https://stackoverflow.com/questions/20394727/gl-triangle-strip-vs-gl-triangle-fan
|
||||
// Starting point is the center
|
||||
buf.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR)
|
||||
buf.vertex(mat, point.x, point.y, 1f).color(r, g, b, a).endVertex()
|
||||
|
||||
// https://github.com/not-fl3/macroquad/blob/master/src/shapes.rs#L98
|
||||
// yes they are gonna be little hexagons fite me
|
||||
val fracOfCircle = 6
|
||||
// run 0 AND last; this way the circle closes
|
||||
for (i in 0..fracOfCircle) {
|
||||
val theta = i.toFloat() / fracOfCircle * HexUtils.TAU.toFloat()
|
||||
val rx = Mth.cos(theta) * radius + point.x
|
||||
val ry = Mth.sin(theta) * radius + point.y
|
||||
buf.vertex(mat, rx, ry, 1f).color(r, g, b, a).endVertex()
|
||||
}
|
||||
|
||||
tess.end()
|
||||
}
|
||||
|
||||
fun dodge(n: Int): Float = n * 0.9f
|
||||
fun screen(n: Int): Int = (n + 255) / 2
|
||||
|
||||
@JvmStatic
|
||||
fun screenCol(n: Int): Int {
|
||||
return FC.color(
|
||||
FC.alpha(n),
|
||||
screen(FC.red(n)),
|
||||
screen(FC.green(n)),
|
||||
screen(FC.blue(n)),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the scale and dots formed by the pattern when centered.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getCenteredPattern(pattern: HexPattern, width: Float, height: Float, minSize: Float): Pair<Float, List<Vec2>> {
|
||||
// Do two passes: one with a random size to find a good COM and one with the real calculation
|
||||
val com1: Vec2 = pattern.getCenter(1f)
|
||||
val lines1: List<Vec2> = pattern.toLines(1f, Vec2.ZERO)
|
||||
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 Pair(scale, lines2)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun renderItemStackInGui(ms: PoseStack, stack: ItemStack, x: Int, y: Int) {
|
||||
transferMsToGl(ms) { Minecraft.getInstance().itemRenderer.renderAndDecorateItem(stack, x, y) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * Draw a hex pattern from the given list of non-zappy points (as in, do the *style* of drawing it,
|
||||
* * you have to do the conversion yourself.)
|
||||
* */
|
||||
@JvmOverloads
|
||||
fun drawPatternFromPoints(
|
||||
mat: Matrix4f,
|
||||
points: List<Vec2>,
|
||||
drawLast: Boolean,
|
||||
tail: Int,
|
||||
head: Int,
|
||||
flowIrregular: Float,
|
||||
animTime: Float? = null
|
||||
) {
|
||||
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(
|
||||
mat,
|
||||
node,
|
||||
2f,
|
||||
dodge(FastColor.ARGB32.red(head)) / 255f,
|
||||
dodge(FastColor.ARGB32.green(head)) / 255f,
|
||||
dodge(FastColor.ARGB32.blue(head)) / 255f,
|
||||
FastColor.ARGB32.alpha(head) / 255f
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Split up a sequence of linePoints with a lightning effect
|
||||
* @param hops: rough number of points to subdivide each segment into
|
||||
* @param speed: rate at which the lightning effect should move/shake/etc
|
||||
*/
|
||||
fun makeZappy(points: List<Vec2>, hops: Float, variance: Float, speed: Float, flowIrregular: Float): List<Vec2> {
|
||||
// Nothing in, nothing out
|
||||
if (points.isEmpty()) {
|
||||
return emptyList()
|
||||
}
|
||||
val scaleVariance = { it: Double -> Math.min(1.0, 8 * (0.5 - Math.abs(0.5 - it))) }
|
||||
val hops = hops.toInt()
|
||||
val zSeed = ClientTickCounter.total.toDouble() * speed
|
||||
// Create our output list of zap points
|
||||
val zappyPts = mutableListOf(points[0])
|
||||
// For each segment in the original...
|
||||
for ((i, pair) in points.zipWithNext().withIndex()) {
|
||||
val (src, target) = pair
|
||||
val delta = target.add(src.negated())
|
||||
// Take hop distance
|
||||
val hopDist = Mth.sqrt(src.distanceToSqr(target)) / hops
|
||||
// Compute how big the radius of variance should be
|
||||
val maxVariance = hopDist * variance
|
||||
|
||||
for (j in 1..hops) {
|
||||
val progress = j.toDouble() / (hops + 1)
|
||||
// Add the next hop...
|
||||
val pos = src.add(delta.scale(progress.toFloat()))
|
||||
// as well as some random variance...
|
||||
// (We use i, j (segment #, subsegment #) as seeds for the Perlin noise,
|
||||
// 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()
|
||||
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))
|
||||
}
|
||||
// Finally, we hit the destination, add that too
|
||||
zappyPts.add(target)
|
||||
}
|
||||
return zappyPts
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
val buf = tess.builder
|
||||
// https://stackoverflow.com/questions/20394727/gl-triangle-strip-vs-gl-triangle-fan
|
||||
// Starting point is the center
|
||||
buf.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR)
|
||||
buf.vertex(mat, point.x, point.y, 1f).color(r, g, b, a).endVertex()
|
||||
|
||||
// https://github.com/not-fl3/macroquad/blob/master/src/shapes.rs#L98
|
||||
// yes they are gonna be little hexagons fite me
|
||||
val fracOfCircle = 6
|
||||
// run 0 AND last; this way the circle closes
|
||||
for (i in 0..fracOfCircle) {
|
||||
val theta = i.toFloat() / fracOfCircle * TAU.toFloat()
|
||||
val rx = Mth.cos(theta) * radius + point.x
|
||||
val ry = Mth.sin(theta) * radius + point.y
|
||||
buf.vertex(mat, rx, ry, 1f).color(r, g, b, a).endVertex()
|
||||
}
|
||||
|
||||
tess.end()
|
||||
}
|
||||
|
||||
fun screenCol(n: Int): Int {
|
||||
return FastColor.ARGB32.color(
|
||||
FastColor.ARGB32.alpha(n),
|
||||
screen(FastColor.ARGB32.red(n)),
|
||||
screen(FastColor.ARGB32.green(n)),
|
||||
screen(FastColor.ARGB32.blue(n)),
|
||||
)
|
||||
}
|
||||
|
||||
fun screen(n: Int) = (n + 255) / 2
|
||||
fun dodge(n: Int) = n * 0.9f
|
||||
|
||||
/**
|
||||
* Return the scale and dots formed by the pattern when centered.
|
||||
*/
|
||||
fun getCenteredPattern(pattern: HexPattern, width: Float, height: Float, minSize: Float): Pair<Float, List<Vec2>> {
|
||||
// Do two passes: one with a random size to find a good COM and one with the real calculation
|
||||
val com1: Vec2 = pattern.getCenter(1f)
|
||||
val lines1: List<Vec2> = pattern.toLines(1f, Vec2.ZERO)
|
||||
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()
|
||||
}
|
||||
|
|
|
@ -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.HexDir
|
||||
import at.petrak.hexcasting.api.spell.math.HexPattern
|
||||
import at.petrak.hexcasting.api.utils.HexUtils
|
||||
import at.petrak.hexcasting.client.RenderLib
|
||||
import at.petrak.hexcasting.api.utils.otherHand
|
||||
import at.petrak.hexcasting.client.drawPatternFromPoints
|
||||
import at.petrak.hexcasting.client.drawSpot
|
||||
import at.petrak.hexcasting.client.sound.GridSoundInstance
|
||||
import at.petrak.hexcasting.common.items.ItemSpellbook
|
||||
import at.petrak.hexcasting.common.lib.HexItems
|
||||
|
@ -231,7 +232,7 @@ class GuiSpellcasting(
|
|||
override fun mouseScrolled(pMouseX: Double, pMouseY: Double, pDelta: Double): Boolean {
|
||||
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)
|
||||
IClientXplatAbstractions.INSTANCE.sendPacketToServer(
|
||||
MsgShiftScrollSyn(
|
||||
|
@ -279,7 +280,7 @@ class GuiSpellcasting(
|
|||
0f,
|
||||
1f
|
||||
)
|
||||
RenderLib.drawSpot(
|
||||
drawSpot(
|
||||
mat,
|
||||
dotPx,
|
||||
scaledDist * 2f,
|
||||
|
@ -293,7 +294,7 @@ class GuiSpellcasting(
|
|||
RenderSystem.defaultBlendFunc()
|
||||
|
||||
for ((pat, origin, valid) in this.patterns) {
|
||||
RenderLib.drawPatternFromPoints(mat, pat.toLines(
|
||||
drawPatternFromPoints(mat, pat.toLines(
|
||||
this.hexSize(),
|
||||
this.coordToPx(origin)
|
||||
), 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)
|
||||
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 }
|
||||
|
@ -338,7 +339,7 @@ class GuiSpellcasting(
|
|||
/** Distance between adjacent hex centers */
|
||||
fun hexSize(): Float {
|
||||
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.
|
||||
// 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 coordToPx(coord: HexCoord) = HexUtils.coordToPx(coord, this.hexSize(), this.coordsOffset())
|
||||
fun pxToCoord(px: Vec2) = HexUtils.pxToCoord(px, this.hexSize(), this.coordsOffset())
|
||||
fun coordToPx(coord: HexCoord) =
|
||||
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 {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package at.petrak.hexcasting.client.gui;
|
||||
|
||||
import at.petrak.hexcasting.client.ClientTickCounter;
|
||||
import at.petrak.hexcasting.client.RenderLib;
|
||||
import at.petrak.hexcasting.api.spell.math.HexPattern;
|
||||
import at.petrak.hexcasting.client.RenderLib;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.*;
|
||||
|
|
|
@ -70,8 +70,8 @@ public class BlockEntityAkashicBookshelf extends HexBlockEntity {
|
|||
} else {
|
||||
this.recordPos = null;
|
||||
}
|
||||
if (HexPattern.IsHexPattern(pattern)) {
|
||||
this.pattern = HexPattern.DeserializeFromNBT(pattern);
|
||||
if (HexPattern.isPattern(pattern)) {
|
||||
this.pattern = HexPattern.fromNBT(pattern);
|
||||
} else {
|
||||
this.pattern = null;
|
||||
}
|
||||
|
|
|
@ -81,14 +81,14 @@ public class BlockEntityAkashicRecord extends HexBlockEntity {
|
|||
if (entry == null) {
|
||||
return null;
|
||||
} else {
|
||||
return SpellDatum.DeserializeFromNBT(entry.datum, slevel);
|
||||
return SpellDatum.fromNBT(entry.datum, slevel);
|
||||
}
|
||||
}
|
||||
|
||||
public Component getDisplayAt(HexPattern key) {
|
||||
var entry = this.entries.get(getKey(key));
|
||||
if (entry != null) {
|
||||
return SpellDatum.DisplayFromTag(entry.datum);
|
||||
return SpellDatum.displayFromNBT(entry.datum);
|
||||
} else {
|
||||
return new TranslatableComponent("hexcasting.spelldata.akashic.nopos").withStyle(ChatFormatting.RED);
|
||||
}
|
||||
|
|
|
@ -32,8 +32,8 @@ public class BlockEntitySlate extends HexBlockEntity {
|
|||
protected void loadModData(CompoundTag tag) {
|
||||
if (tag.contains(TAG_PATTERN, Tag.TAG_COMPOUND)) {
|
||||
CompoundTag patternTag = tag.getCompound(TAG_PATTERN);
|
||||
if (HexPattern.IsHexPattern(patternTag)) {
|
||||
this.pattern = HexPattern.DeserializeFromNBT(patternTag);
|
||||
if (HexPattern.isPattern(patternTag)) {
|
||||
this.pattern = HexPattern.fromNBT(patternTag);
|
||||
} else {
|
||||
this.pattern = null;
|
||||
}
|
||||
|
|
|
@ -90,12 +90,12 @@ public class BlockEntityConjured extends HexBlockEntity {
|
|||
|
||||
@Override
|
||||
protected void saveModData(CompoundTag tag) {
|
||||
tag.put(TAG_COLORIZER, this.colorizer.serialize());
|
||||
tag.put(TAG_COLORIZER, this.colorizer.serializeToNBT());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadModData(CompoundTag tag) {
|
||||
this.colorizer = FrozenColorizer.deserialize(tag.getCompound(TAG_COLORIZER));
|
||||
this.colorizer = FrozenColorizer.fromNBT(tag.getCompound(TAG_COLORIZER));
|
||||
}
|
||||
|
||||
public FrozenColorizer getColorizer() {
|
||||
|
|
|
@ -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.OpImpetusPos;
|
||||
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.OpHalt;
|
||||
import at.petrak.hexcasting.common.casting.operators.lists.*;
|
||||
|
@ -52,417 +51,417 @@ public class RegisterPatterns {
|
|||
// - CW is the special or destruction version
|
||||
// == 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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aa", HexDir.EAST), modLoc("get_entity_pos"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aa", HexDir.EAST), modLoc("get_entity_pos"),
|
||||
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);
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wq", HexDir.EAST), modLoc("get_entity_velocity"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("wq", HexDir.EAST), modLoc("get_entity_velocity"),
|
||||
OpEntityVelocity.INSTANCE);
|
||||
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wqaawdd", HexDir.EAST), modLoc("raycast"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("wqaawdd", HexDir.EAST), modLoc("raycast"),
|
||||
OpBlockRaycast.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("weddwaa", HexDir.EAST), modLoc("raycast/axis"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("weddwaa", HexDir.EAST), modLoc("raycast/axis"),
|
||||
OpBlockAxisRaycast.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("weaqa", HexDir.EAST), modLoc("raycast/entity"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("weaqa", HexDir.EAST), modLoc("raycast/entity"),
|
||||
OpEntityRaycast.INSTANCE);
|
||||
|
||||
// == 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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eaqwqaewede", HexDir.SOUTH_WEST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("eaqwqaewede", HexDir.SOUTH_WEST),
|
||||
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));
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aqwqawaaqa", HexDir.WEST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aqwqawaaqa", HexDir.WEST),
|
||||
modLoc("circle/bounds/max"), new OpCircleBounds(true));
|
||||
|
||||
// == Modify Stack ==
|
||||
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aadaa", HexDir.EAST), modLoc("duplicate"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aadaa", HexDir.EAST), modLoc("duplicate"),
|
||||
OpDuplicate.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aadaadaa", HexDir.EAST), modLoc("duplicate_n"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aadaadaa", HexDir.EAST), modLoc("duplicate_n"),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aawdd", HexDir.EAST), modLoc("swap"), OpSwap.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ddad", HexDir.WEST), modLoc("fisherman"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aawdd", HexDir.EAST), modLoc("swap"), OpSwap.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("ddad", HexDir.WEST), modLoc("fisherman"),
|
||||
OpFisherman.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qaawdde", HexDir.SOUTH_EAST), modLoc("swizzle"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qaawdde", HexDir.SOUTH_EAST), modLoc("swizzle"),
|
||||
OpAlwinfyHasAscendedToABeingOfPureMath.INSTANCE);
|
||||
|
||||
// == Math ==
|
||||
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waaw", HexDir.NORTH_EAST), modLoc("add"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("waaw", HexDir.NORTH_EAST), modLoc("add"),
|
||||
OpAdd.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wddw", HexDir.NORTH_WEST), modLoc("sub"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("wddw", HexDir.NORTH_WEST), modLoc("sub"),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wdedw", HexDir.NORTH_EAST), modLoc("div_cross"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("wdedw", HexDir.NORTH_EAST), modLoc("div_cross"),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wedew", HexDir.NORTH_WEST), modLoc("pow_proj"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("wedew", HexDir.NORTH_WEST), modLoc("pow_proj"),
|
||||
OpPowProj.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ewq", HexDir.EAST), modLoc("floor"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("ewq", HexDir.EAST), modLoc("floor"),
|
||||
OpFloor.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qwe", HexDir.EAST), modLoc("ceil"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qwe", HexDir.EAST), modLoc("ceil"),
|
||||
OpCeil.INSTANCE);
|
||||
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eqqqqq", HexDir.EAST), modLoc("construct_vec"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("eqqqqq", HexDir.EAST), modLoc("construct_vec"),
|
||||
OpConstructVec.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qeeeee", HexDir.EAST), modLoc("deconstruct_vec"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qeeeee", HexDir.EAST), modLoc("deconstruct_vec"),
|
||||
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);
|
||||
|
||||
// == Logic ==
|
||||
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wdw", HexDir.NORTH_EAST), modLoc("and"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("wdw", HexDir.NORTH_EAST), modLoc("and"),
|
||||
OpBoolAnd.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waw", HexDir.SOUTH_EAST), modLoc("or"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("waw", HexDir.SOUTH_EAST), modLoc("or"),
|
||||
OpBoolOr.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dwa", HexDir.NORTH_WEST), modLoc("xor"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("dwa", HexDir.NORTH_WEST), modLoc("xor"),
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ad", HexDir.EAST), modLoc("equals"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("ad", HexDir.EAST), modLoc("equals"),
|
||||
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));
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dw", HexDir.NORTH_WEST), modLoc("not"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("dw", HexDir.NORTH_WEST), modLoc("not"),
|
||||
OpBoolNot.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aw", HexDir.NORTH_EAST), modLoc("identity"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aw", HexDir.NORTH_EAST), modLoc("identity"),
|
||||
OpBoolIdentityKindOf.INSTANCE);
|
||||
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eqqq", HexDir.NORTH_WEST), modLoc("random"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("eqqq", HexDir.NORTH_WEST), modLoc("random"),
|
||||
OpRandom.INSTANCE);
|
||||
|
||||
// == Advanced Math ==
|
||||
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqaa", HexDir.SOUTH_EAST), modLoc("sin"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqaa", HexDir.SOUTH_EAST), modLoc("sin"),
|
||||
OpSin.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqad", HexDir.SOUTH_EAST), modLoc("cos"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqad", HexDir.SOUTH_EAST), modLoc("cos"),
|
||||
OpCos.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wqqqqqadq", HexDir.SOUTH_WEST), modLoc("tan"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("wqqqqqadq", HexDir.SOUTH_WEST), modLoc("tan"),
|
||||
OpTan.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ddeeeee", HexDir.SOUTH_EAST), modLoc("arcsin"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("ddeeeee", HexDir.SOUTH_EAST), modLoc("arcsin"),
|
||||
OpArcSin.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("adeeeee", HexDir.NORTH_EAST), modLoc("arccos"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("adeeeee", HexDir.NORTH_EAST), modLoc("arccos"),
|
||||
OpArcCos.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eadeeeeew", HexDir.NORTH_EAST), modLoc("arctan"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("eadeeeeew", HexDir.NORTH_EAST), modLoc("arctan"),
|
||||
OpArcTan.INSTANCE);
|
||||
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eqaqe", HexDir.NORTH_WEST), modLoc("logarithm"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("eqaqe", HexDir.NORTH_WEST), modLoc("logarithm"),
|
||||
OpLog.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("addwaad", HexDir.NORTH_EAST), modLoc("modulo"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("addwaad", HexDir.NORTH_EAST), modLoc("modulo"),
|
||||
OpModulo.INSTANCE);
|
||||
|
||||
// == 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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waweaqa", HexDir.SOUTH_EAST), modLoc("or_bit"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("waweaqa", HexDir.SOUTH_EAST), modLoc("or_bit"),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dweaqa", HexDir.NORTH_WEST), modLoc("not_bit"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("dweaqa", HexDir.NORTH_WEST), modLoc("not_bit"),
|
||||
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);
|
||||
|
||||
// == Spells ==
|
||||
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("de", HexDir.NORTH_EAST), modLoc("print"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("de", HexDir.NORTH_EAST), modLoc("print"),
|
||||
OpPrint.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aawaawaa", HexDir.EAST), modLoc("explode"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aawaawaa", HexDir.EAST), modLoc("explode"),
|
||||
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));
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("awqqqwaqw", HexDir.SOUTH_WEST), modLoc("add_motion"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("awqqqwaqw", HexDir.SOUTH_WEST), modLoc("add_motion"),
|
||||
OpAddMotion.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("awqqqwaq", HexDir.SOUTH_WEST), modLoc("blink"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("awqqqwaq", HexDir.SOUTH_WEST), modLoc("blink"),
|
||||
OpBlink.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qaqqqqq", HexDir.EAST), modLoc("break_block"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qaqqqqq", HexDir.EAST), modLoc("break_block"),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("awddwqawqwawq", HexDir.EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("awddwqawqwawq", HexDir.EAST),
|
||||
modLoc("colorize"),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dedwedade", HexDir.SOUTH_WEST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("dedwedade", HexDir.SOUTH_WEST),
|
||||
modLoc("destroy_water"),
|
||||
OpDestroyWater.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aaqawawa", HexDir.SOUTH_EAST), modLoc("ignite"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aaqawawa", HexDir.SOUTH_EAST), modLoc("ignite"),
|
||||
OpIgnite.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ddedwdwd", HexDir.SOUTH_WEST), modLoc("extinguish"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("ddedwdwd", HexDir.SOUTH_WEST), modLoc("extinguish"),
|
||||
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));
|
||||
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));
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wqaqwawqaqw", HexDir.NORTH_EAST), modLoc("bonemeal"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("wqaqwawqaqw", HexDir.NORTH_EAST), modLoc("bonemeal"),
|
||||
OpTheOnlyReasonAnyoneDownloadedPsi.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqwaeaeaeaeaea", HexDir.NORTH_WEST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqwaeaeaeaeaea", HexDir.NORTH_WEST),
|
||||
modLoc("recharge"),
|
||||
OpRecharge.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qdqawwaww", HexDir.EAST), modLoc("erase"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qdqawwaww", HexDir.EAST), modLoc("erase"),
|
||||
new OpErase());
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wqaqwd", HexDir.NORTH_EAST), modLoc("edify"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("wqaqwd", HexDir.NORTH_EAST), modLoc("edify"),
|
||||
OpEdifySapling.INSTANCE);
|
||||
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("adaa", HexDir.WEST), modLoc("beep"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("adaa", HexDir.WEST), modLoc("beep"),
|
||||
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));
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wwaqqqqqeaqeaeqqqeaeq", HexDir.EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("wwaqqqqqeaqeaeqqqeaeq", HexDir.EAST),
|
||||
modLoc("craft/trinket"),
|
||||
new OpMakePackagedSpell<>(HexItems.TRINKET, 5 * ManaConstants.CRYSTAL_UNIT));
|
||||
PatternRegistry.mapPattern(
|
||||
HexPattern.FromAnglesSig("wwaqqqqqeawqwqwqwqwqwwqqeadaeqqeqqeadaeqq", HexDir.EAST),
|
||||
HexPattern.fromAngles("wwaqqqqqeawqwqwqwqwqwwqqeadaeqqeqqeadaeqq", HexDir.EAST),
|
||||
modLoc("craft/artifact"),
|
||||
new OpMakePackagedSpell<>(HexItems.ARTIFACT, 10 * ManaConstants.CRYSTAL_UNIT));
|
||||
PatternRegistry.mapPattern(
|
||||
HexPattern.FromAnglesSig("aqqqaqwwaqqqqqeqaqqqawwqwqwqwqwqw", HexDir.SOUTH_WEST),
|
||||
HexPattern.fromAngles("aqqqaqwwaqqqqqeqaqqqawwqwqwqwqwqw", HexDir.SOUTH_WEST),
|
||||
modLoc("craft/battery"),
|
||||
OpMakeBattery.INSTANCE,
|
||||
true);
|
||||
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqaqwawaw", HexDir.NORTH_WEST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqaqwawaw", HexDir.NORTH_WEST),
|
||||
modLoc("potion/weakness"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
new OpCreateSentinel(false));
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qdwdqdw", HexDir.NORTH_EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qdwdqdw", HexDir.NORTH_EAST),
|
||||
modLoc("sentinel/destroy"),
|
||||
OpDestroySentinel.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waeawaede", HexDir.EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("waeawaede", HexDir.EAST),
|
||||
modLoc("sentinel/get_pos"),
|
||||
OpGetSentinelPos.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waeawaedwa", HexDir.EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("waeawaedwa", HexDir.EAST),
|
||||
modLoc("sentinel/wayfind"),
|
||||
OpGetSentinelWayfind.INSTANCE);
|
||||
|
||||
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waadwawdaaweewq", HexDir.EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("waadwawdaaweewq", HexDir.EAST),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eaqawqadaqd", HexDir.EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("eaqawqadaqd", HexDir.EAST),
|
||||
modLoc("create_lava"), OpCreateLava.INSTANCE, true);
|
||||
PatternRegistry.mapPattern(
|
||||
HexPattern.FromAnglesSig("wwwqqqwwwqqeqqwwwqqwqqdqqqqqdqq", HexDir.EAST),
|
||||
HexPattern.fromAngles("wwwqqqwwwqqeqqwwwqqwqqdqqqqqdqq", HexDir.EAST),
|
||||
modLoc("teleport"), OpTeleport.INSTANCE, true);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("waeawaeqqqwqwqqwq", HexDir.EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("waeawaeqqqwqwqqwq", HexDir.EAST),
|
||||
modLoc("sentinel/create/great"),
|
||||
new OpCreateSentinel(true), true);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eeewwweeewwaqqddqdqd", HexDir.EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("eeewwweeewwaqqddqdqd", HexDir.EAST),
|
||||
modLoc("dispel_rain"),
|
||||
new OpWeather(false), true);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wwweeewwweewdawdwad", HexDir.WEST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("wwweeewwweewdawdwad", HexDir.WEST),
|
||||
modLoc("summon_rain"),
|
||||
new OpWeather(true), true);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qeqwqwqwqwqeqaeqeaqeqaeqaqded", HexDir.NORTH_EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qeqwqwqwqwqeqaeqeaqeqaeqaqded", HexDir.NORTH_EAST),
|
||||
modLoc("brainsweep"),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eeeweeeeede", HexDir.EAST), modLoc("akashic/write"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("eeeweeeeede", HexDir.EAST), modLoc("akashic/write"),
|
||||
OpAkashicWrite.INSTANCE);
|
||||
|
||||
// == 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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eee", HexDir.EAST), modLoc("close_paren"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("eee", HexDir.EAST), modLoc("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
|
||||
// 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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aqdee", HexDir.SOUTH_WEST), modLoc("halt"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aqdee", HexDir.SOUTH_WEST), modLoc("halt"),
|
||||
OpHalt.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aqqqqq", HexDir.EAST), modLoc("read"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aqqqqq", HexDir.EAST), modLoc("read"),
|
||||
OpRead.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("deeeee", HexDir.EAST), modLoc("write"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("deeeee", HexDir.EAST), modLoc("write"),
|
||||
OpWrite.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aqqqqqe", HexDir.EAST), modLoc("readable"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aqqqqqe", HexDir.EAST), modLoc("readable"),
|
||||
OpReadable.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("deeeeeq", HexDir.EAST), modLoc("writable"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("deeeeeq", HexDir.EAST), modLoc("writable"),
|
||||
OpWritable.INSTANCE);
|
||||
|
||||
// lorge boyes
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wawqwqwqwqwqw", HexDir.EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("wawqwqwqwqwqw", HexDir.EAST),
|
||||
modLoc("read/entity"), OpTheCoolerRead.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("wawqwqwqwqwqwew", HexDir.EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("wawqwqwqwqwqwew", HexDir.EAST),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("eqqwawqaaw", HexDir.NORTH_WEST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("eqqwawqaaw", HexDir.NORTH_WEST),
|
||||
modLoc("write/local"), OpPushLocal.INSTANCE);
|
||||
|
||||
// == 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))));
|
||||
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))));
|
||||
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))));
|
||||
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))));
|
||||
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))));
|
||||
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))));
|
||||
// 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))));
|
||||
|
||||
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)));
|
||||
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)));
|
||||
|
||||
// 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)));
|
||||
|
||||
// == 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));
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqdaqaawa", HexDir.SOUTH_EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqdaqaawa", HexDir.SOUTH_EAST),
|
||||
modLoc("get_entity/animal"),
|
||||
new OpGetEntityAt(OpGetEntitiesBy::isAnimal));
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqdaqaawq", HexDir.SOUTH_EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqdaqaawq", HexDir.SOUTH_EAST),
|
||||
modLoc("get_entity/monster"),
|
||||
new OpGetEntityAt(OpGetEntitiesBy::isMonster));
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqdaqaaww", HexDir.SOUTH_EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqdaqaaww", HexDir.SOUTH_EAST),
|
||||
modLoc("get_entity/item"),
|
||||
new OpGetEntityAt(OpGetEntitiesBy::isItem));
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqdaqaawe", HexDir.SOUTH_EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqdaqaawe", HexDir.SOUTH_EAST),
|
||||
modLoc("get_entity/player"),
|
||||
new OpGetEntityAt(OpGetEntitiesBy::isPlayer));
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqdaqaawd", HexDir.SOUTH_EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqdaqaawd", HexDir.SOUTH_EAST),
|
||||
modLoc("get_entity/living"),
|
||||
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));
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqqqwdeddwa", HexDir.SOUTH_EAST),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqqqwdeddwa", HexDir.SOUTH_EAST),
|
||||
modLoc("zone_entity/animal"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
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"),
|
||||
new OpGetEntitiesBy(OpGetEntitiesBy::isLiving, true));
|
||||
|
||||
// == Lists ==
|
||||
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("edqde", HexDir.SOUTH_WEST), modLoc("append"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("edqde", HexDir.SOUTH_WEST), modLoc("append"),
|
||||
OpAppend.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qaeaq", HexDir.NORTH_WEST), modLoc("concat"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qaeaq", HexDir.NORTH_WEST), modLoc("concat"),
|
||||
OpConcat.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("deeed", HexDir.NORTH_WEST), modLoc("index"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("deeed", HexDir.NORTH_WEST), modLoc("index"),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aqaeaq", HexDir.EAST), modLoc("list_size"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aqaeaq", HexDir.EAST), modLoc("list_size"),
|
||||
OpListSize.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("adeeed", HexDir.EAST), modLoc("singleton"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("adeeed", HexDir.EAST), modLoc("singleton"),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qqqaede", HexDir.EAST), modLoc("reverse_list"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qqqaede", HexDir.EAST), modLoc("reverse_list"),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qwaeawq", HexDir.NORTH_WEST), modLoc("splat"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qwaeawq", HexDir.NORTH_WEST), modLoc("splat"),
|
||||
OpSplat.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("dedqde", HexDir.EAST), modLoc("index_of"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("dedqde", HexDir.EAST), modLoc("index_of"),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("qaeaqwded", HexDir.NORTH_WEST), modLoc("slice"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("qaeaqwded", HexDir.NORTH_WEST), modLoc("slice"),
|
||||
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);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("ddewedd", HexDir.SOUTH_EAST), modLoc("construct"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("ddewedd", HexDir.SOUTH_EAST), modLoc("construct"),
|
||||
OpCons.INSTANCE);
|
||||
PatternRegistry.mapPattern(HexPattern.FromAnglesSig("aaqwqaa", HexDir.SOUTH_WEST), modLoc("deconstruct"),
|
||||
PatternRegistry.mapPattern(HexPattern.fromAngles("aaqwqaa", HexDir.SOUTH_WEST), modLoc("deconstruct"),
|
||||
OpUnCons.INSTANCE);
|
||||
|
||||
} catch (PatternRegistry.RegisterPatternException exn) {
|
||||
|
|
|
@ -1,14 +1,8 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.eval
|
||||
|
||||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
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.*
|
||||
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.OperatorSideEffect
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
|
||||
object OpEval : Operator {
|
||||
|
@ -22,7 +16,7 @@ object OpEval : Operator {
|
|||
val newCont = if (continuation is SpellContinuation.NotDone && continuation.frame is ContinuationFrame.FinishEval) {
|
||||
continuation
|
||||
} 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)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.math
|
||||
|
||||
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.asSpellResult
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
|
@ -12,7 +12,7 @@ object OpAbsLen : ConstManaOperator {
|
|||
get() = 1
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.math
|
||||
|
||||
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.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.spellListOf
|
||||
|
@ -11,8 +11,8 @@ object OpAdd : ConstManaOperator {
|
|||
get() = 2
|
||||
|
||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
||||
val lhs = GetNumOrVec(args[0], 1)
|
||||
val rhs = GetNumOrVec(args[1], 0)
|
||||
val lhs = numOrVec(args[0], 1)
|
||||
val rhs = numOrVec(args[1], 0)
|
||||
|
||||
return spellListOf(
|
||||
lhs.map({ lnum ->
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.math
|
||||
|
||||
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.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapDivideByZero
|
||||
|
@ -13,8 +13,8 @@ object OpDivCross : ConstManaOperator {
|
|||
get() = 2
|
||||
|
||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
||||
val lhs = GetNumOrVec(args[0], 1)
|
||||
val rhs = GetNumOrVec(args[1], 0)
|
||||
val lhs = numOrVec(args[0], 1)
|
||||
val rhs = numOrVec(args[1], 0)
|
||||
|
||||
return spellListOf(
|
||||
lhs.map({ lnum ->
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.math
|
||||
|
||||
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.SpellDatum
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
|
@ -11,8 +11,8 @@ object OpMulDot : ConstManaOperator {
|
|||
get() = 2
|
||||
|
||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
||||
val lhs = GetNumOrVec(args[0], 1)
|
||||
val rhs = GetNumOrVec(args[1], 0)
|
||||
val lhs = numOrVec(args[0], 1)
|
||||
val rhs = numOrVec(args[1], 0)
|
||||
|
||||
return spellListOf(
|
||||
lhs.map({ lnum ->
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.math
|
||||
|
||||
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.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapDivideByZero
|
||||
|
@ -14,8 +14,8 @@ object OpPowProj : ConstManaOperator {
|
|||
get() = 2
|
||||
|
||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
||||
val lhs = GetNumOrVec(args[0], 1)
|
||||
val rhs = GetNumOrVec(args[1], 0)
|
||||
val lhs = numOrVec(args[0], 1)
|
||||
val rhs = numOrVec(args[1], 0)
|
||||
|
||||
return spellListOf(
|
||||
lhs.map({ lnum ->
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.math
|
||||
|
||||
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.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.spellListOf
|
||||
|
@ -12,8 +12,8 @@ object OpSub : ConstManaOperator {
|
|||
get() = 2
|
||||
|
||||
override fun execute(args: List<SpellDatum<*>>, ctx: CastingContext): List<SpellDatum<*>> {
|
||||
val lhs = GetNumOrVec(args[0], 1)
|
||||
val rhs = GetNumOrVec(args[1], 0)
|
||||
val lhs = numOrVec(args[0], 1)
|
||||
val rhs = numOrVec(args[1], 0)
|
||||
|
||||
return spellListOf(
|
||||
lhs.map({ lnum ->
|
||||
|
|
|
@ -8,7 +8,7 @@ object OpAnd : ConstManaOperator {
|
|||
override val argc = 2
|
||||
|
||||
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) {
|
||||
val list1 = firstParam.right().get()
|
||||
|
|
|
@ -8,7 +8,7 @@ object OpOr : ConstManaOperator {
|
|||
override val argc = 2
|
||||
|
||||
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) {
|
||||
val list1 = firstParam.right().get()
|
||||
|
|
|
@ -8,7 +8,7 @@ object OpXor : ConstManaOperator {
|
|||
override val argc = 2
|
||||
|
||||
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) {
|
||||
val list1 = firstParam.right().get()
|
||||
|
|
|
@ -27,7 +27,7 @@ object OpBeep : SpellOperator {
|
|||
return Triple(
|
||||
Spell(target, note, NoteBlockInstrument.values()[instrument]),
|
||||
ManaConstants.DUST_UNIT / 10,
|
||||
listOf(ParticleSpray.Cloud(target, 1.0))
|
||||
listOf(ParticleSpray.cloud(target, 1.0))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ object OpBlink : SpellOperator {
|
|||
Spell(target, delta),
|
||||
ManaConstants.SHARD_UNIT * delta.roundToInt(),
|
||||
listOf(
|
||||
ParticleSpray.Cloud(targetMiddlePos, 2.0, 50),
|
||||
ParticleSpray.Burst(targetMiddlePos.add(dvec), 2.0, 100)
|
||||
ParticleSpray.cloud(targetMiddlePos, 2.0, 50),
|
||||
ParticleSpray.burst(targetMiddlePos.add(dvec), 2.0, 100)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ object OpBreakBlock : SpellOperator {
|
|||
return Triple(
|
||||
Spell(pos),
|
||||
ManaConstants.DUST_UNIT * 2,
|
||||
listOf(ParticleSpray.Burst(centered, 1.0))
|
||||
listOf(ParticleSpray.burst(centered, 1.0))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ class OpConjure(val light: Boolean) : SpellOperator {
|
|||
return Triple(
|
||||
Spell(target, light),
|
||||
ManaConstants.DUST_UNIT,
|
||||
listOf(ParticleSpray.Cloud(Vec3.atCenterOf(pos), 1.0))
|
||||
listOf(ParticleSpray.cloud(Vec3.atCenterOf(pos), 1.0))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ object OpCreateWater : SpellOperator {
|
|||
return Triple(
|
||||
Spell(target),
|
||||
ManaConstants.DUST_UNIT,
|
||||
listOf(ParticleSpray.Burst(Vec3.atCenterOf(BlockPos(target)), 1.0))
|
||||
listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ object OpDestroyWater : SpellOperator {
|
|||
return Triple(
|
||||
Spell(target),
|
||||
2 * ManaConstants.CRYSTAL_UNIT,
|
||||
listOf(ParticleSpray.Burst(target, 3.0))
|
||||
listOf(ParticleSpray.burst(target, 3.0))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class OpExplode(val fire: Boolean) : SpellOperator {
|
|||
return Triple(
|
||||
Spell(pos, strength, this.fire),
|
||||
((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))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ object OpExtinguish : SpellOperator {
|
|||
return Triple(
|
||||
Spell(target),
|
||||
ManaConstants.CRYSTAL_UNIT,
|
||||
listOf(ParticleSpray.Burst(target, 1.0))
|
||||
listOf(ParticleSpray.burst(target, 1.0))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ object OpIgnite : SpellOperator {
|
|||
return Triple(
|
||||
Spell(target),
|
||||
ManaConstants.DUST_UNIT,
|
||||
listOf(ParticleSpray.Burst(Vec3.atCenterOf(BlockPos(target)), 1.0))
|
||||
listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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.mishaps.MishapBadItem
|
||||
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.lib.HexItems
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
|
@ -46,7 +47,7 @@ object OpMakeBattery : SpellOperator {
|
|||
|
||||
ctx.assertEntityInRange(entity)
|
||||
|
||||
if (!ManaHelper.isManaItem(entity.item) || ManaHelper.extractMana(
|
||||
if (!isManaItem(entity.item) || extractMana(
|
||||
entity.item,
|
||||
drainForBatteries = true,
|
||||
simulate = true
|
||||
|
@ -59,7 +60,7 @@ object OpMakeBattery : SpellOperator {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
@ -67,7 +68,7 @@ object OpMakeBattery : SpellOperator {
|
|||
val (handStack, hand) = ctx.getHeldItemToOperateOn { it.`is`(HexItemTags.PHIAL_BASE) }
|
||||
if (handStack.`is`(HexItemTags.PHIAL_BASE) && itemEntity.isAlive) {
|
||||
val entityStack = itemEntity.item.copy()
|
||||
val manaAmt = ManaHelper.extractMana(entityStack, drainForBatteries = true)
|
||||
val manaAmt = extractMana(entityStack, drainForBatteries = true)
|
||||
if (manaAmt > 0) {
|
||||
ctx.caster.setItemInHand(
|
||||
hand,
|
||||
|
|
|
@ -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.MishapBadOffhandItem
|
||||
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.xplat.IXplatAbstractions
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
|
@ -36,7 +37,7 @@ class OpMakePackagedSpell<T : ItemPackagedHex>(val itemType: T, val cost: Int) :
|
|||
}
|
||||
|
||||
ctx.assertEntityInRange(entity)
|
||||
if (!ManaHelper.isManaItem(entity.item) || ManaHelper.extractMana(
|
||||
if (!isManaItem(entity.item) || extractMana(
|
||||
entity.item,
|
||||
drainForBatteries = true,
|
||||
simulate = true
|
||||
|
@ -52,7 +53,7 @@ class OpMakePackagedSpell<T : ItemPackagedHex>(val itemType: T, val cost: Int) :
|
|||
if (trueName != null)
|
||||
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 {
|
||||
|
@ -64,7 +65,7 @@ class OpMakePackagedSpell<T : ItemPackagedHex>(val itemType: T, val cost: Int) :
|
|||
&& itemEntity.isAlive
|
||||
) {
|
||||
val entityStack = itemEntity.item.copy()
|
||||
val manaAmt = ManaHelper.extractMana(entityStack, drainForBatteries = true)
|
||||
val manaAmt = extractMana(entityStack, drainForBatteries = true)
|
||||
if (manaAmt > 0) {
|
||||
hexHolder.writeHex(patterns, manaAmt)
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ object OpPlaceBlock : SpellOperator {
|
|||
return Triple(
|
||||
Spell(target),
|
||||
ManaConstants.DUST_UNIT,
|
||||
listOf(ParticleSpray.Cloud(Vec3.atCenterOf(pos), 1.0))
|
||||
listOf(ParticleSpray.cloud(Vec3.atCenterOf(pos), 1.0))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ class OpPotionEffect(
|
|||
return Triple(
|
||||
Spell(effect, target, duration, potency),
|
||||
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))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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.mishaps.MishapBadItem
|
||||
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 net.minecraft.world.entity.item.ItemEntity
|
||||
|
||||
|
@ -37,7 +38,7 @@ object OpRecharge : SpellOperator {
|
|||
val entity = args.getChecked<ItemEntity>(0, argc)
|
||||
ctx.assertEntityInRange(entity)
|
||||
|
||||
if (!ManaHelper.isManaItem(entity.item)) {
|
||||
if (!isManaItem(entity.item)) {
|
||||
throw MishapBadItem.of(
|
||||
entity,
|
||||
"mana"
|
||||
|
@ -48,7 +49,7 @@ object OpRecharge : SpellOperator {
|
|||
return null
|
||||
|
||||
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 {
|
||||
|
@ -65,7 +66,7 @@ object OpRecharge : SpellOperator {
|
|||
val maxMana = mana.maxMana
|
||||
val existingMana = mana.mana
|
||||
|
||||
val manaAmt = ManaHelper.extractMana(entityStack, maxMana - existingMana)
|
||||
val manaAmt = extractMana(entityStack, maxMana - existingMana)
|
||||
|
||||
mana.mana = manaAmt + existingMana
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ object OpTheOnlyReasonAnyoneDownloadedPsi : SpellOperator {
|
|||
return Triple(
|
||||
Spell(target),
|
||||
ManaConstants.DUST_UNIT,
|
||||
listOf(ParticleSpray.Burst(Vec3.atCenterOf(BlockPos(target)), 1.0))
|
||||
listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ object OpBrainsweep : SpellOperator {
|
|||
return Triple(
|
||||
Spell(bpos, state, sacrifice, recipe),
|
||||
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))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ object OpCreateLava : SpellOperator {
|
|||
return Triple(
|
||||
Spell(target),
|
||||
ManaConstants.CRYSTAL_UNIT,
|
||||
listOf(ParticleSpray.Burst(Vec3.atCenterOf(BlockPos(target)), 1.0)),
|
||||
listOf(ParticleSpray.burst(Vec3.atCenterOf(BlockPos(target)), 1.0)),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ object OpTeleport : SpellOperator {
|
|||
return Triple(
|
||||
Spell(teleportee, delta),
|
||||
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))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ class OpCreateSentinel(val extendsRange: Boolean) : SpellOperator {
|
|||
return Triple(
|
||||
Spell(target, this.extendsRange),
|
||||
ManaConstants.DUST_UNIT,
|
||||
listOf(ParticleSpray.Burst(target, 2.0))
|
||||
listOf(ParticleSpray.burst(target, 2.0))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ object OpDestroySentinel : SpellOperator {
|
|||
// TODO why can't you remove things from other dimensions?
|
||||
if (sentinel.dimension != ctx.world.dimension())
|
||||
throw MishapLocationInWrongDimension(sentinel.dimension.location())
|
||||
particles.add(ParticleSpray.Cloud(sentinel.position, 2.0))
|
||||
particles.add(ParticleSpray.cloud(sentinel.position, 2.0))
|
||||
|
||||
return Triple(
|
||||
Spell,
|
||||
|
|
|
@ -32,7 +32,7 @@ public class ListPatternsCommand {
|
|||
for (var pair : listing) {
|
||||
ctx.getSource().sendSuccess(new TextComponent(pair.getValue().getFirst().toString())
|
||||
.append(": ")
|
||||
.append(SpellDatum.make(HexPattern.FromAnglesSig(pair.getKey(), pair.getValue().getSecond()))
|
||||
.append(SpellDatum.make(HexPattern.fromAngles(pair.getKey(), pair.getValue().getSecond()))
|
||||
.display()), false);
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ public class ListPatternsCommand {
|
|||
var tag = new CompoundTag();
|
||||
tag.putString(ItemScroll.TAG_OP_ID, opId.toString());
|
||||
tag.put(ItemScroll.TAG_PATTERN,
|
||||
HexPattern.FromAnglesSig(pattern, startDir).serializeToNBT());
|
||||
HexPattern.fromAngles(pattern, startDir).serializeToNBT());
|
||||
|
||||
var stack = new ItemStack(HexItems.SCROLL);
|
||||
stack.setTag(tag);
|
||||
|
|
|
@ -38,7 +38,7 @@ public class PatternResLocArgument extends ResourceLocationArgument {
|
|||
for (var key : lookup.keySet()) {
|
||||
var rhs = lookup.get(key);
|
||||
if (rhs.getFirst().equals(targetId)) {
|
||||
foundPat = HexPattern.FromAnglesSig(key, rhs.getSecond());
|
||||
foundPat = HexPattern.fromAngles(key, rhs.getSecond());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
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.utils.HexUtils;
|
||||
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.level.GameRules;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec2;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -60,7 +58,7 @@ public class EntityWallScroll extends HangingEntity {
|
|||
|
||||
CompoundTag patternTag = NBTHelper.getCompound(scroll, ItemScroll.TAG_PATTERN);
|
||||
if (patternTag != null) {
|
||||
this.pattern = HexPattern.DeserializeFromNBT(patternTag);
|
||||
this.pattern = HexPattern.fromNBT(patternTag);
|
||||
if (this.level.isClientSide) {
|
||||
var pair = RenderLib.getCenteredPattern(pattern, 128, 128, 16f);
|
||||
var dots = pair.getSecond();
|
||||
|
@ -160,7 +158,7 @@ public class EntityWallScroll extends HangingEntity {
|
|||
@Override
|
||||
public void addAdditionalSaveData(CompoundTag tag) {
|
||||
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());
|
||||
super.addAdditionalSaveData(tag);
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ public class ItemScroll extends Item implements DataHolderItem {
|
|||
public Optional<TooltipComponent> getTooltipImage(ItemStack stack) {
|
||||
var compound = NBTHelper.getCompound(stack, ItemScroll.TAG_PATTERN);
|
||||
if (compound != null) {
|
||||
var pattern = HexPattern.DeserializeFromNBT(compound);
|
||||
var pattern = HexPattern.fromNBT(compound);
|
||||
return Optional.of(new PatternTooltipGreeble(
|
||||
pattern,
|
||||
NBTHelper.hasString(stack, ItemScroll.TAG_OP_ID) ? PatternTooltipGreeble.ANCIENT_BG : PatternTooltipGreeble.PRISTINE_BG));
|
||||
|
|
|
@ -106,7 +106,7 @@ public class ItemSlate extends BlockItem implements DataHolderItem {
|
|||
if (bet != null && bet.contains(BlockEntitySlate.TAG_PATTERN, Tag.TAG_COMPOUND)) {
|
||||
var patTag = bet.getCompound(BlockEntitySlate.TAG_PATTERN);
|
||||
if (!patTag.isEmpty()) {
|
||||
var pattern = HexPattern.DeserializeFromNBT(patTag);
|
||||
var pattern = HexPattern.fromNBT(patTag);
|
||||
return Optional.of(new PatternTooltipGreeble(
|
||||
pattern,
|
||||
PatternTooltipGreeble.SLATE_BG));
|
||||
|
|
|
@ -57,14 +57,14 @@ public abstract class ItemManaHolder extends Item implements ManaHolderItem {
|
|||
public int getBarColor(ItemStack pStack) {
|
||||
var mana = getMana(pStack);
|
||||
var maxMana = getMaxMana(pStack);
|
||||
return ManaHelper.barColor(mana, maxMana);
|
||||
return ManaHelper.manaBarColor(mana, maxMana);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBarWidth(ItemStack pStack) {
|
||||
var mana = getMana(pStack);
|
||||
var maxMana = getMaxMana(pStack);
|
||||
return ManaHelper.barWidth(mana, maxMana);
|
||||
return ManaHelper.manaBarWidth(mana, maxMana);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -68,9 +68,9 @@ public abstract class ItemPackagedHex extends ItemManaHolder implements HexHolde
|
|||
for (var patTag : patsTag) {
|
||||
CompoundTag tag = NBTHelper.getAsCompound(patTag);
|
||||
if (tag.size() != 1)
|
||||
out.add(SpellDatum.make(HexPattern.DeserializeFromNBT(tag)));
|
||||
out.add(SpellDatum.make(HexPattern.fromNBT(tag)));
|
||||
else
|
||||
out.add(SpellDatum.DeserializeFromNBT(tag, level));
|
||||
out.add(SpellDatum.fromNBT(tag, level));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ public class PatternScrollFunc extends LootItemConditionalFunction {
|
|||
var startDir = entry.component2();
|
||||
var tag = new CompoundTag();
|
||||
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);
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ public record MsgCastParticleAck(ParticleSpray spray, FrozenColorizer colorizer)
|
|||
var spread = buf.readDouble();
|
||||
var count = buf.readInt();
|
||||
var tag = buf.readAnySizeNbt();
|
||||
var colorizer = FrozenColorizer.deserialize(tag);
|
||||
var colorizer = FrozenColorizer.fromNBT(tag);
|
||||
return new MsgCastParticleAck(
|
||||
new ParticleSpray(new Vec3(posX, posY, posZ), new Vec3(velX, velY, velZ), fuzziness, spread, count),
|
||||
colorizer);
|
||||
|
@ -54,7 +54,7 @@ public record MsgCastParticleAck(ParticleSpray spray, FrozenColorizer colorizer)
|
|||
buf.writeDouble(this.spray.getFuzziness());
|
||||
buf.writeDouble(this.spray.getSpread());
|
||||
buf.writeInt(this.spray.getCount());
|
||||
buf.writeNbt(this.colorizer.serialize());
|
||||
buf.writeNbt(this.colorizer.serializeToNBT());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -39,12 +39,12 @@ public record MsgNewSpellPatternSyn(InteractionHand handUsed, HexPattern pattern
|
|||
public static MsgNewSpellPatternSyn deserialize(ByteBuf buffer) {
|
||||
var buf = new FriendlyByteBuf(buffer);
|
||||
var hand = buf.readEnum(InteractionHand.class);
|
||||
var pattern = HexPattern.DeserializeFromNBT(buf.readAnySizeNbt());
|
||||
var pattern = HexPattern.fromNBT(buf.readAnySizeNbt());
|
||||
|
||||
var resolvedPatternsLen = buf.readInt();
|
||||
var resolvedPatterns = new ArrayList<ResolvedPattern>(resolvedPatternsLen);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public record MsgOpenSpellGuiAck(InteractionHand hand, List<ResolvedPattern> pat
|
|||
var patternsLen = buf.readInt();
|
||||
var patterns = new ArrayList<ResolvedPattern>(patternsLen);
|
||||
for (int i = 0; i < patternsLen; i++) {
|
||||
patterns.add(ResolvedPattern.DeserializeFromNBT(buf.readAnySizeNbt()));
|
||||
patterns.add(ResolvedPattern.fromNBT(buf.readAnySizeNbt()));
|
||||
}
|
||||
|
||||
var descsLen = buf.readInt();
|
||||
|
|
|
@ -121,7 +121,7 @@ public record MsgShiftScrollSyn(InteractionHand hand, double scrollDelta, boolea
|
|||
|
||||
var datumTag = HexItems.ABACUS.readDatumTag(stack);
|
||||
if (datumTag != null) {
|
||||
var popup = SpellDatum.DisplayFromTag(datumTag);
|
||||
var popup = SpellDatum.displayFromNBT(datumTag);
|
||||
sender.displayClientMessage(
|
||||
new TranslatableComponent("hexcasting.tooltip.abacus", popup).withStyle(ChatFormatting.GREEN), true);
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public class ManualPatternComponent extends AbstractPatternComponent {
|
|||
RawPattern raw = new Gson().fromJson(json, RawPattern.class);
|
||||
|
||||
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);
|
||||
out.add(new Pair<>(pat, origin));
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ public final class PatternDrawingUtil {
|
|||
patternEntries.add(new PatternEntry(pattern, origin, new ArrayList<>()));
|
||||
seenCoords.addAll(pattern.positions(origin));
|
||||
}
|
||||
var fakeCom = HexUtils.FindCenter(seenFakePoints);
|
||||
var fakeCom = HexUtils.findCenter(seenFakePoints);
|
||||
|
||||
var maxDx = -1f;
|
||||
var maxDy = -1f;
|
||||
|
@ -100,7 +100,7 @@ public final class PatternDrawingUtil {
|
|||
seenRealPoints.add(px);
|
||||
}
|
||||
}
|
||||
var realCom = HexUtils.FindCenter(seenRealPoints);
|
||||
var realCom = HexUtils.findCenter(seenRealPoints);
|
||||
|
||||
// and NOW for real!
|
||||
for (var pat : patternEntries) {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import at.petrak.hexcasting.api.spell.math.EulerPathFinder.findAltDrawing
|
||||
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
|
||||
|
||||
internal class EulerPathFinderTest {
|
||||
@Test
|
||||
fun findAltDrawing() {
|
||||
val sig = "dadaddwwaadada"
|
||||
val pat = FromAnglesSig(sig, HexDir.NORTH_EAST)
|
||||
val pat = fromAngles(sig, HexDir.NORTH_EAST)
|
||||
for (i in 0 until 8) {
|
||||
val scrungled = findAltDrawing(pat, i.toLong())
|
||||
println(scrungled)
|
||||
|
|
|
@ -31,11 +31,11 @@ public class CCFavoredColorizer implements Component, AutoSyncedComponent {
|
|||
|
||||
@Override
|
||||
public void readFromNbt(CompoundTag tag) {
|
||||
this.colorizer = FrozenColorizer.deserialize(tag.getCompound(TAG_COLORIZER));
|
||||
this.colorizer = FrozenColorizer.fromNBT(tag.getCompound(TAG_COLORIZER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNbt(CompoundTag tag) {
|
||||
tag.put(TAG_COLORIZER, this.colorizer.serialize());
|
||||
tag.put(TAG_COLORIZER, this.colorizer.serializeToNBT());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ public class CCFlight implements Component {
|
|||
var timeLeft = tag.getInt(TAG_TIME_LEFT);
|
||||
var dim = ResourceKey.create(Registry.DIMENSION_REGISTRY,
|
||||
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);
|
||||
this.flight = new FlightAbility(true, timeLeft, dim, origin, radius);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ public class CCHarness implements Component {
|
|||
if (this.lazyLoadedTag.isEmpty()) {
|
||||
return new CastingHarness(ctx);
|
||||
} else {
|
||||
return CastingHarness.DeserializeFromNBT(this.lazyLoadedTag, ctx);
|
||||
return CastingHarness.fromNBT(this.lazyLoadedTag, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ public class CCPatterns implements Component {
|
|||
List<ResolvedPattern> patterns = new ArrayList<>(patternsTag.size());
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class CCSentinel implements Component, AutoSyncedComponent {
|
|||
var hasSentinel = tag.getBoolean(TAG_HAS_SENTINEL);
|
||||
if (hasSentinel) {
|
||||
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,
|
||||
new ResourceLocation(tag.getString(TAG_DIMENSION)));
|
||||
this.sentinel = new Sentinel(true, extendsRange, position, dim);
|
||||
|
|
|
@ -33,7 +33,7 @@ public class FabricUnsealedIngredient extends Ingredient {
|
|||
.filter((it) -> it != DatumType.EMPTY && it != DatumType.OTHER)
|
||||
.map((type) -> {
|
||||
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);
|
||||
}));
|
||||
this.stack = stack;
|
||||
|
|
|
@ -22,8 +22,10 @@ public class ForgeHexClientInitializer {
|
|||
evBus.addListener((RenderLevelLastEvent e) ->
|
||||
HexAdditionalRenderers.overlayLevel(e.getPoseStack(), e.getPartialTick()));
|
||||
|
||||
evBus.addListener((RenderGameOverlayEvent.PreLayer e) ->
|
||||
HexAdditionalRenderers.overlayGui(e.getMatrixStack(), e.getPartialTicks()));
|
||||
evBus.addListener((RenderGameOverlayEvent.Post e) -> {
|
||||
if (e.getType() == RenderGameOverlayEvent.ElementType.ALL)
|
||||
HexAdditionalRenderers.overlayGui(e.getMatrixStack(), e.getPartialTicks());
|
||||
});
|
||||
|
||||
|
||||
evBus.addListener((TickEvent.RenderTickEvent e) -> {
|
||||
|
|
|
@ -25,13 +25,13 @@ public record MsgColorizerUpdateAck(FrozenColorizer update) implements IMessage
|
|||
var buf = new FriendlyByteBuf(buffer);
|
||||
|
||||
var tag = buf.readAnySizeNbt();
|
||||
var colorizer = FrozenColorizer.deserialize(tag);
|
||||
var colorizer = FrozenColorizer.fromNBT(tag);
|
||||
return new MsgColorizerUpdateAck(colorizer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(FriendlyByteBuf buf) {
|
||||
buf.writeNbt(this.update.serialize());
|
||||
buf.writeNbt(this.update.serializeToNBT());
|
||||
}
|
||||
|
||||
public static void handle(MsgColorizerUpdateAck self) {
|
||||
|
|
|
@ -30,7 +30,7 @@ public class ForgeUnsealedIngredient extends AbstractIngredient {
|
|||
.filter((it) -> it != DatumType.EMPTY && it != DatumType.OTHER)
|
||||
.map((type) -> {
|
||||
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);
|
||||
}));
|
||||
this.stack = stack;
|
||||
|
|
|
@ -124,7 +124,7 @@ public class ForgeXplatImpl implements IXplatAbstractions {
|
|||
@Override
|
||||
public void setColorizer(Player player, FrozenColorizer colorizer) {
|
||||
CompoundTag tag = player.getPersistentData();
|
||||
tag.put(TAG_COLOR, colorizer.serialize());
|
||||
tag.put(TAG_COLOR, colorizer.serializeToNBT());
|
||||
|
||||
if (player instanceof ServerPlayer serverPlayer) {
|
||||
CapSyncers.syncColorizer(serverPlayer);
|
||||
|
@ -175,7 +175,7 @@ public class ForgeXplatImpl implements IXplatAbstractions {
|
|||
boolean allowed = tag.getBoolean(TAG_FLIGHT_ALLOWED);
|
||||
if (allowed) {
|
||||
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 dimension = ResourceKey.create(Registry.DIMENSION_REGISTRY,
|
||||
new ResourceLocation(tag.getString(TAG_FLIGHT_DIMENSION)));
|
||||
|
@ -186,7 +186,7 @@ public class ForgeXplatImpl implements IXplatAbstractions {
|
|||
|
||||
@Override
|
||||
public FrozenColorizer getColorizer(Player player) {
|
||||
return FrozenColorizer.deserialize(player.getPersistentData().getCompound(TAG_COLOR));
|
||||
return FrozenColorizer.fromNBT(player.getPersistentData().getCompound(TAG_COLOR));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -197,7 +197,7 @@ public class ForgeXplatImpl implements IXplatAbstractions {
|
|||
return Sentinel.none();
|
||||
}
|
||||
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,
|
||||
new ResourceLocation(tag.getString(TAG_SENTINEL_DIMENSION)));
|
||||
|
||||
|
@ -207,7 +207,7 @@ public class ForgeXplatImpl implements IXplatAbstractions {
|
|||
@Override
|
||||
public CastingHarness getHarness(ServerPlayer player, InteractionHand 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
|
||||
|
@ -217,7 +217,7 @@ public class ForgeXplatImpl implements IXplatAbstractions {
|
|||
List<ResolvedPattern> patterns = new ArrayList<>(patternsTag.size());
|
||||
|
||||
for (int i = 0; i < patternsTag.size(); i++) {
|
||||
patterns.add(ResolvedPattern.DeserializeFromNBT(patternsTag.getCompound(i)));
|
||||
patterns.add(ResolvedPattern.fromNBT(patternsTag.getCompound(i)));
|
||||
}
|
||||
return patterns;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Hex
|
||||
# Hex Casting
|
||||
|
||||
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!
|
||||
|
||||
## [Read the documentation online here!](https://gamma-delta.github.io/HexMod/)
|
||||
|
|
562
doc/collate_data.py
Executable file
562
doc/collate_data.py
Executable 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
363
doc/template.html
Normal 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>
|
Loading…
Reference in a new issue