repo for my hex addons :3
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

advance log

+232 -298
+19 -17
project/hexic/build.gradle.kts
··· 159 159 modImplementation("net.beholderface.oneironaut:oneironaut-fabric-1.20.1-fabric-fabric:1.20.1-SNAPSHOT") 160 160 compat("maven.modrinth:hexcassettes:1.1.4") 161 161 modLocalRuntime("maven.modrinth:trinkets:3.7.2") 162 - modImplementation("maven.modrinth:spasm:0.2.2") 163 162 // modImplementation("maven.modrinth:slate-works:1.0.5") 164 163 compat("miyucomics.hexical:hexical:2.0.0+a3c47ad9") 165 164 compat("miyucomics.overevaluate:overevaluate:main-SNAPSHOT") ··· 171 170 modImplementation("com.github.mattidragon:ConfigToolkit:v1.0.0") // trans maven.modrinth:jsonpatcher 172 171 modImplementation("miyucomics.hexpose:hexpose:1.0.0") 173 172 include(modApi("xyz.nucleoid:fantasy:0.4.11+1.20-rc1")!!) 173 + modImplementation("dev.emi:trinkets:3.7.2") 174 174 // modImplementation("miyucomics:hexpose:1.0.0") 175 175 // modImplementation(files("hexical-2.0.0.jar")) 176 176 include(implementation("net.bytebuddy:byte-buddy:1.17.7")!!) ··· 179 179 modImplementation("dev.onyxstudios.cardinal-components-api:cardinal-components-entity:5.2.3") 180 180 modImplementation("dev.onyxstudios.cardinal-components-api:cardinal-components-level:5.2.3") 181 181 modRuntimeOnly("dev.onyxstudios.cardinal-components-api:cardinal-components-api:5.2.3") 182 - 183 - modRuntimeOnly("gay.object.hexdebug:hexdebug-fabric:0.5.0+1.20.1-SNAPSHOT") 182 + modRuntimeOnly("com.unascribed:lib39-core:[2.0.0,)!!2.0.27+1.20.1") 183 + modRuntimeOnly("com.unascribed:lib39-avant:[2.0.0,)!!2.0.27+1.20.1") 184 + modRuntimeOnly("com.unascribed:lib39-phantom:[2.0.0,)!!2.0.27+1.20.1") 185 + modLocalRuntime("gay.object.hexdebug:hexdebug-fabric:0.5.0+1.20.1-SNAPSHOT") 186 + modLocalRuntime("maven.modrinth:hexcessible:0.2.0") 187 + modLocalRuntime("maven.modrinth:complex-hex:0.1.3-beta") 184 188 } 185 189 186 190 val colors = mapOf( ··· 223 227 224 228 depends("mixinextras", "*") 225 229 depends("mm", "^2.3") 226 - depends("spasm", ">=0.2.2") 227 230 depends("moreiotas", ">=0.1.1") 228 231 depends("hexal", ">=0.3.0") 229 232 depends("hexcellular", "^1.1.0") 230 233 depends("jsonpatcher", "^1.0.0-beta.4+mc.1.20.1") 231 234 depends("hexpose", "^1.0.0") 235 + depends("trinkets", "^3.7.2") 232 236 conflicts("valkyrienskies", "*") // need to figure out how to create dimensions without causing a crash 233 237 234 238 entrypoint("org.eu.net.pool.hexic.main\$package::init") ··· 245 249 dependsOn(cloth) 246 250 dependsOn(*downloadedBags.values.toTypedArray()) 247 251 val itemsRoot = destinationDir.resolve("assets/hexic/textures/item") 252 + val jxlOpts = arrayOf("-quality", "100", "-define", "jxl:effort=11", "-define", "jxl:lossless=true", "-define", "jxl:modular=true") 248 253 doLast { 249 254 for ((name, color) in colors) { 250 255 exec { 251 - commandLine("env", "magick", cloth.dest, "-channel", "red,green,blue", "-fx", "u*#${color.toString(16)}", itemsRoot.resolve("${name}_mediaweave.png")) 256 + commandLine("env", "magick", cloth.dest, "-channel", "red,green,blue", "-fx", "u*#${color.toString(16)}", *jxlOpts, "jxl:${itemsRoot.resolve("${name}_mediaweave.png")}") 252 257 } 253 258 val bag = downloadedBags[name]!!.dest 254 259 exec { 255 - commandLine("env", "magick", bag, "-write", itemsRoot.resolve("large_${name}_bundle.png"), "-sample", "14x14", "-background", "transparent", "-extent", "16x16-1-2", itemsRoot.resolve("small_${name}_bundle.png")) 260 + commandLine("env", "magick", bag, *jxlOpts, "-write", "jxl:${itemsRoot.resolve("large_${name}_bundle.png")}", "-sample", "14x14", "-background", "transparent", "-extent", "16x16-1-2", "jxl:${itemsRoot.resolve("small_${name}_bundle.png")}") 256 261 } 257 262 } 258 263 exec { 259 - commandLine("env", "magick", "wizard:", itemsRoot.resolve("wizard.png")) 264 + commandLine("env", "magick", "wizard:", *jxlOpts, "jxl:${itemsRoot.resolve("wizard.png")}") 260 265 } 261 266 exec { 262 - commandLine("env", "magick", "null:", itemsRoot.resolve("no.png")) 267 + commandLine("env", "magick", "null:", *jxlOpts, "jxl:${itemsRoot.resolve("no.jxl")}") 263 268 } 264 269 exec { 265 270 commandLine("env", "magick", ··· 287 292 "pure" to "u", 288 293 )) { 289 294 exec { 290 - commandLine("env", "magick", itemsRoot.resolve("stringworm.miff"), "-channel", "rgb", "-fx", expr, "$itemsRoot/stringworm_$name.png") 295 + commandLine("env", "magick", itemsRoot.resolve("stringworm.miff"), "-channel", "rgb", "-fx", expr, *jxlOpts, "jxl:$itemsRoot/stringworm_$name.png") 291 296 } 292 297 } 293 298 // people will hate this 294 299 for (i in 0..31) { 295 - itemsRoot.resolve("stringworm_tinted_$i.png").outputStream().use { 296 - exec { 297 - commandLine("env", "magick", itemsRoot.resolve("stringworm.miff"), "-fx", "i+j == $i ? u : Transparent", "png:-") 298 - standardOutput = it 299 - } 300 + exec { 301 + commandLine("env", "magick", itemsRoot.resolve("stringworm.miff"), "-fx", "i+j == $i ? u : Transparent", *jxlOpts, "jxl:${itemsRoot.resolve("stringworm_tinted_$i.png")}") 300 302 } 301 303 } 302 304 file("$itemsRoot/../block").mkdir() 303 305 exec { 304 - commandLine("env", "magick", "xc:#ffffff[16x16]", itemsRoot.resolveSibling("block/border.png")) 306 + commandLine("env", "magick", "xc:#ffffff[16x16]", *jxlOpts, "jxl:${itemsRoot.resolveSibling("block/border.png")}") 305 307 } 306 - //file("$itemsRoot/stringworm.miff").delete() 308 + file("$itemsRoot/stringworm.miff").delete() 307 309 exec { 308 - commandLine("env", "magick", "https://www.masterbuilt.com/cdn/shop/articles/162_20-_20Voodoo_20Baked_20Beans.jpg", "-sample", "256x256", itemsRoot.resolve("beans.png")) 310 + commandLine("env", "magick", "https://www.masterbuilt.com/cdn/shop/articles/162_20-_20Voodoo_20Baked_20Beans.jpg", "-sample", "256x256", *jxlOpts, "jxl:${itemsRoot.resolve("beans.png")}") 309 311 } 310 312 } 311 313
+4
project/hexic/changelog
··· 1 1 2.0.0 engulfed hexxychests 2 2 2.0.0 load config from config/*.properties instead of config/jvm.properties 3 + 2.0.0 mediaweave now applies to all chat messages 4 + 2.0.0 !mediaweave now uses trinket slots 3 5 2.0.0 murmur and reveal now use separate components 6 + 2.0.0 !only one mediaweave can be equipped at a time 4 7 2.0.0 !removed NBT iotas 5 8 2.0.0 !removed tripwires 9 + 2.0.0 textures now use JPEG XL
+1 -3
project/hexic/src/client/resources/hexic.client.mixins.json
··· 5 5 "compatibilityLevel": "JAVA_17", 6 6 "client": [ 7 7 "ChatHudMixin", 8 - "ChatInputSuggestorMixin", 9 8 "ChatScreenAccess", 10 - "ChatScreenMixin", 11 - "InventoryScreenMixin" 9 + "ChatScreenMixin" 12 10 ], 13 11 "injectors": { 14 12 "defaultRequire": 1
+10 -34
project/hexic/src/client/scala/org/eu/net/pool/hexic/client.scala
··· 7 7 import com.google.gson.reflect.TypeToken 8 8 import com.google.gson.{Gson, JsonArray, JsonObject} 9 9 import com.llamalad7.mixinextras.injector.wrapoperation.Operation 10 + import dev.emi.trinkets.api.{TrinketComponent, TrinketsApi} 10 11 import kotlin.jvm.JvmField 11 12 import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking 12 13 import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry ··· 48 49 import scala.util.boundary 49 50 import scala.util.boundary.Label 50 51 import scala.util.chaining.scalaUtilChainingOps 51 - 52 - import phlib.{_, given} 52 + import phlib.{*, given} 53 53 54 54 given client: MinecraftClient = MinecraftClient.getInstance 55 55 ··· 59 59 case player => ifPresent(player) 60 60 61 61 object ClientHooks: 62 - def provideRenderText(string: String, firstCharacterIndex: Int, field: TextFieldWidget, original: OrderedText): OrderedText = 63 - foldLocalPlayer(original): p => 64 - val c = p.getComponent(PlayerInfoComponent.key) 65 - boundary[OrderedText]: 66 - if c.rightWeave.hasCustomName && c.rightWeave.getItem.isInstanceOf[Mediaweave] then 67 - val wake = c.rightWeave.getName.getString.toLowerCase 68 - if field.getText.toLowerCase.startsWith(s"$wake:") then 69 - boundary.break[OrderedText]: v => 70 - original.accept: (idx, style, p) => 71 - v.accept(idx, if idx + firstCharacterIndex <= wake.length then style.withColor(c.rightWeave.getItem.asInstanceOf[Mediaweave].color.getSignColor) else style, p) 72 - if c.leftWeave.hasCustomName && c.leftWeave.getItem.isInstanceOf[Mediaweave] then 73 - val wake = c.leftWeave.getName.getString.toLowerCase 74 - if field.getText.toLowerCase.startsWith(s"$wake:") then 75 - boundary.break[OrderedText]: v => 76 - original.accept: (idx, style, p) => 77 - v.accept(idx, if idx + firstCharacterIndex <= wake.length then style.withColor(c.leftWeave.getItem.asInstanceOf[Mediaweave].color.getSignColor) else style, p) 78 - original 79 62 def interceptSendMessage(handler: ClientPlayNetworkHandler, msg: String): Boolean = 80 63 foldLocalPlayer(false): p => 81 - boundary[Boolean]: 82 - val c = p.getComponent(PlayerInfoComponent.key) 83 - val (left, text) = boundary[(Boolean, String)]: 84 - if c.rightWeave.hasCustomName && c.rightWeave.getItem.isInstanceOf[Mediaweave] then 85 - val wake = c.rightWeave.getName.getString.toLowerCase 86 - if msg.toLowerCase.startsWith(s"$wake:") then 87 - boundary.break((false, msg.substring(wake.length + 1))) 88 - if c.leftWeave.hasCustomName && c.leftWeave.getItem.isInstanceOf[Mediaweave] then 89 - val wake = c.leftWeave.getName.getString.toLowerCase 90 - if msg.toLowerCase.startsWith(s"$wake:") then 91 - boundary.break((true, msg.substring(wake.length + 1))) 92 - boundary.break(false) 64 + if p.validMediaweave.isDefined then 93 65 val buf = PacketByteBufs.create() 94 - buf.writeByte(if left then 12 else 8) 95 - buf.writeString(text.trim) 96 - ClientPlayNetworking.send("sync_mediaweave", buf) 66 + buf.writeByte(0) 67 + buf.writeString(msg) 68 + ClientPlayNetworking.send("message", buf) 97 69 true 70 + else false 98 71 99 72 def init(): Unit = 100 73 BlockEntityRendererFactories.register( ··· 336 309 "moveconcept" -> "Transfer Substance", 337 310 "moveentity" -> "Transfer Creature", 338 311 "murmur" -> "Murmur Reflection", 312 + "omni_close" -> "Cessation", 313 + "omni_open" -> "Resumption", 339 314 "reveal" -> "Greater Reveal", 340 315 "rotate" -> "Ferris Distillation", 341 316 "staffcast_factory" -> "Lani's Greater Gambit", ··· 394 369 gen.add("hexic.spell_memory", "Hex memorized") 395 370 gen.add("tag.item.hexic.mediaweaves", "Mediaweave") 396 371 gen.add("text.hexic.pigment_holder_item", "an item storing a pigment") 372 + gen.add("trinkets.slot.chest.hexic_mediaweave", "Mediaweave") 397 373 pack.addProvider: 398 374 new FabricRecipeProvider(_): 399 375 override def generate(consumer: Consumer[RecipeJsonProvider]): Unit =
-21
project/hexic/src/client/scala/org/eu/net/pool/hexic/mixin/ChatInputSuggestorMixin.java
··· 1 - package org.eu.net.pool.hexic.mixin; 2 - 3 - import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; 4 - import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 5 - import net.minecraft.client.gui.screen.ChatInputSuggestor; 6 - import net.minecraft.client.gui.widget.TextFieldWidget; 7 - import net.minecraft.text.OrderedText; 8 - import org.eu.net.pool.hexic.ClientHooks; 9 - import org.spongepowered.asm.mixin.Final; 10 - import org.spongepowered.asm.mixin.Mixin; 11 - import org.spongepowered.asm.mixin.Shadow; 12 - 13 - @Mixin(ChatInputSuggestor.class) 14 - public class ChatInputSuggestorMixin { 15 - @Shadow @Final TextFieldWidget textField; 16 - 17 - @WrapMethod(method = "provideRenderText") 18 - OrderedText provideRenderText(String string, int firstCharacterIndex, Operation<OrderedText> original) { 19 - return ClientHooks.provideRenderText(string, firstCharacterIndex, textField, original.call(string, firstCharacterIndex)); 20 - } 21 - }
-83
project/hexic/src/client/scala/org/eu/net/pool/hexic/mixin/InventoryScreenMixin.java
··· 1 - package org.eu.net.pool.hexic.mixin; 2 - 3 - import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 4 - import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; 5 - import net.fabricmc.loader.api.FabricLoader; 6 - import net.minecraft.client.gui.screen.ingame.AbstractInventoryScreen; 7 - import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen; 8 - import net.minecraft.client.gui.screen.ingame.InventoryScreen; 9 - import net.minecraft.entity.player.PlayerInventory; 10 - import net.minecraft.item.ItemStack; 11 - import net.minecraft.screen.ScreenHandler; 12 - import net.minecraft.text.Text; 13 - import net.minecraft.util.Identifier; 14 - import org.eu.net.pool.hexic.PlayerInfoComponent; 15 - import org.spongepowered.asm.mixin.Mixin; 16 - import org.spongepowered.asm.mixin.injection.At; 17 - import org.spongepowered.asm.mixin.injection.Inject; 18 - import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 19 - 20 - @Mixin({InventoryScreen.class, CreativeInventoryScreen.class}) 21 - public abstract class InventoryScreenMixin extends AbstractInventoryScreen<ScreenHandler> { 22 - public InventoryScreenMixin(ScreenHandler screenHandler, PlayerInventory playerInventory, Text text) { 23 - super(screenHandler, playerInventory, text); 24 - } 25 - 26 - @Inject(method = "mouseClicked", at = @At(value = "HEAD"), cancellable = true) 27 - void mouseClicked(double mouseX, double mouseY, int button, CallbackInfoReturnable<Boolean> cir) { 28 - boolean creative = false; 29 - if ((AbstractInventoryScreen<?>) this instanceof CreativeInventoryScreen c) { 30 - if (!c.isInventoryTabSelected()) return; 31 - creative = true; 32 - } 33 - mouseX -= x; 34 - mouseY -= y; 35 - double lx = creative ? mouseX - 89 : mouseX - 50; 36 - double ly = creative ? mouseY - 42 : mouseY - 65; 37 - double w = creative ? 15 : 20; 38 - double h = creative ? 35 : 60; 39 - if (FabricLoader.getInstance().isDevelopmentEnvironment()) 40 - System.out.printf("s=(%d, %d) m=(%f, %f) l=(%f, %f)\n", x, y, mouseX, mouseY, lx, ly); 41 - if (lx < w && lx > -w && ly < 0 && ly > -h) { 42 - byte flags = 0; 43 - var c = client.player.getComponent(PlayerInfoComponent.key()); 44 - var held = handler.getCursorStack(); 45 - if (lx < 0) { 46 - var right = c.rightWeave(); 47 - if (right.isEmpty() && !held.isEmpty() && held.getItem() instanceof org.eu.net.pool.hexic.Mediaweave) { 48 - c.rightWeave_$eq(held); 49 - handler.setCursorStack(ItemStack.EMPTY); 50 - flags |= 3; 51 - } else if (held.isEmpty() && !right.isEmpty()) { 52 - handler.setCursorStack(right); 53 - c.rightWeave_$eq(ItemStack.EMPTY); 54 - flags |= 3; 55 - } else return; 56 - } else { 57 - var left = c.leftWeave(); 58 - if (left.isEmpty() && !held.isEmpty() && held.getItem() instanceof org.eu.net.pool.hexic.Mediaweave) { 59 - c.leftWeave_$eq(held); 60 - handler.setCursorStack(ItemStack.EMPTY); 61 - flags |= 7; 62 - } else if (held.isEmpty() && !left.isEmpty()) { 63 - handler.setCursorStack(left); 64 - c.leftWeave_$eq(ItemStack.EMPTY); 65 - flags |= 7; 66 - } else return; 67 - } 68 - // submit our changes to the server 69 - if (flags != 0) { 70 - var buf = PacketByteBufs.create(); 71 - buf.writeByte(flags); 72 - if ((flags & 1) != 0) buf.writeItemStack(handler.getCursorStack()); 73 - if ((flags & 2) != 0) 74 - if ((flags & 4) != 0) 75 - buf.writeItemStack(c.leftWeave()); 76 - else 77 - buf.writeItemStack(c.rightWeave()); 78 - ClientPlayNetworking.send(Identifier.of("hexic", "sync_mediaweave"), buf); 79 - cir.setReturnValue(true); 80 - } 81 - } 82 - } 83 - }
project/hexic/src/main/resources/assets/hexic/textures/gui/mediaweave.png

This is a binary file and will not be displayed.

project/hexic/src/main/resources/assets/hexic/textures/item/coconut.jpg

This is a binary file and will not be displayed.

project/hexic/src/main/resources/assets/hexic/textures/item/coconut.png

This is a binary file and will not be displayed.

project/hexic/src/main/resources/assets/hexic/textures/item/echo.png

This is a binary file and will not be displayed.

+8
project/hexic/src/main/resources/data/trinkets/entities/hexic.json
··· 1 + { 2 + "entities": [ 3 + "player" 4 + ], 5 + "slots": [ 6 + "chest/hexic_mediaweave" 7 + ] 8 + }
+4
project/hexic/src/main/resources/data/trinkets/slots/chest/hexic_mediaweave.json
··· 1 + { 2 + "icon": "hexic:gui/mediaweave", 3 + "drop_rule": "keep" 4 + }
+5
project/hexic/src/main/resources/data/trinkets/tags/items/chest/hexic_mediaweave.json
··· 1 + { 2 + "values": [ 3 + "#hexic:mediaweaves" 4 + ] 5 + }
+88 -7
project/hexic/src/main/scala/org/eu/net/pool/hexic/chat.scala
··· 1 1 package org.eu.net.pool 2 2 package hexic 3 3 4 - import at.petrak.hexcasting.api.casting.eval.CastingEnvironment 5 - import at.petrak.hexcasting.api.casting.iota.{Iota, IotaType, ListIota, NullIota} 6 - import at.petrak.hexcasting.api.casting.mishaps.MishapBadCaster 4 + import at.petrak.hexcasting.api.casting.RenderedSpell 5 + import at.petrak.hexcasting.api.casting.eval.env.PlayerBasedCastEnv 6 + import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect 7 + import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect.DoMishap 8 + import at.petrak.hexcasting.api.casting.eval.{CastResult, CastingEnvironment, ResolvedPatternType} 9 + import at.petrak.hexcasting.api.casting.eval.vm.{CastingImage, CastingVM, ContinuationFrame, SpellContinuation} 10 + import at.petrak.hexcasting.api.casting.iota.{ContinuationIota, Iota, IotaType, ListIota, NullIota} 11 + import at.petrak.hexcasting.api.casting.mishaps.{Mishap, MishapBadCaster, MishapInvalidIota, MishapNotEnoughArgs} 12 + import at.petrak.hexcasting.api.pigment.FrozenPigment 13 + import at.petrak.hexcasting.common.lib.HexItems 14 + import at.petrak.hexcasting.common.lib.hex.HexEvalSounds 7 15 import com.google.gson.JsonElement 8 16 import com.mojang.serialization.JsonOps 17 + import dev.emi.trinkets.api.{TrinketComponent, TrinketsApi} 9 18 import dev.onyxstudios.cca.api.v3.component.sync.AutoSyncedComponent 10 19 import dev.onyxstudios.cca.api.v3.component.{Component, ComponentAccess, ComponentKey, ComponentRegistry} 11 20 import dev.onyxstudios.cca.api.v3.entity.{EntityComponentFactoryRegistry, EntityComponentInitializer, RespawnCopyStrategy} 12 - import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking 13 - import net.minecraft.nbt.{NbtCompound, NbtElement} 21 + import net.fabricmc.fabric.api.networking.v1.{PacketByteBufs, ServerPlayNetworking} 22 + import net.minecraft.entity.player.PlayerEntity 23 + import net.minecraft.item.ItemStack 24 + import net.minecraft.nbt.{NbtCompound, NbtElement, NbtOps} 14 25 import net.minecraft.server.network.ServerPlayerEntity 26 + import net.minecraft.server.world.ServerWorld 15 27 import net.minecraft.text.Text 16 - import net.minecraft.util.Identifier 28 + import net.minecraft.util.{DyeColor, Hand, Identifier, Pair, Util, Uuids} 17 29 import org.eu.net.pool.phlib.{Events as PhEvents, *, given} 18 30 import org.slf4j.{Logger, LoggerFactory} 19 31 import ram.talia.moreiotas.api.casting.iota.StringIota 20 32 33 + import java.util.UUID 21 34 import scala.collection.immutable.* 35 + import scala.jdk.CollectionConverters.* 22 36 import scala.language.implicitConversions 37 + import scala.util.boundary 23 38 24 39 private[hexic] case class MurmurCache(var value: Option[String]) extends Component: 25 40 override def readFromNbt(tag: NbtCompound): Unit = ··· 50 65 def component[C <: Component: ComponentKey as key]: C = c.getComponent(key) 51 66 def syncComponent[C <: Component: ComponentKey as key](): Unit = c.syncComponent(key) 52 67 68 + extension (p: PlayerEntity) 69 + def validMediaweave: Option[(NbtCompound, DyeColor, ItemStack)] = 70 + TrinketsApi.getTrinketComponent(p) 71 + .pipe(o => Option.when[TrinketComponent](o.isPresent)(o.get())) 72 + .flatMap: (c: TrinketComponent) => 73 + c.getEquipped(_.getItem.isInstanceOf[Mediaweave]).asScala.collectFirst: 74 + Function.unlift: p => 75 + p.getRight.getItem match 76 + case m@Mediaweave(color) => Option(m.readIotaTag(p.getRight)).map((_, color, p.getRight)) 77 + case _ => None 78 + extension (p: ServerPlayerEntity) 79 + def executeMediaweave(text: String, ctx: Seq[Iota]): Boolean = 80 + p.validMediaweave match 81 + case Some(hex, color, stack) => 82 + given world: ServerWorld = p.getWorld.asInstanceOf[ServerWorld] 83 + lazy val env = new PlayerBasedCastEnv(p, Hand.OFF_HAND): 84 + override def extractMediaEnvironment(cost: Long, simulate: Boolean): Long = 85 + if p.isCreative then 0L else extractMediaFromInventory(cost, canOvercast, simulate) 86 + override def getCastingHand: Hand = castingHand 87 + override def getPigment = FrozenPigment(ItemStack(HexItems.DYE_PIGMENTS.get(color)), Util.NIL_UUID) 88 + val image = CastingImage(ctx :+ StringIota.make(text), 0, Seq(), false, 0, NbtCompound(), null) 89 + val instrs = IotaType.deserialize(hex, world) match 90 + case list: ListIota => list.getList.asScala.toSeq 91 + case iota => Seq(iota) 92 + val vm = CastingVM(image, env) 93 + val view = vm.queueExecuteAndWrapIotas(instrs :+ ContinuationIota(SpellContinuation.NotDone(MessageFrame(p.getUuid, stack.getName, p), SpellContinuation.Done.INSTANCE)), world) 94 + true 95 + case _ => false 96 + object MessageFrame extends ContinuationFrame.Type[MessageFrame]: 97 + override def deserializeFromNBT(c: NbtCompound, world: ServerWorld): MessageFrame = 98 + val id = Uuids.toUuid(c.getIntArray("id")) 99 + MessageFrame(id, Text.Serializer.fromJson(NbtOps.INSTANCE.convertTo(JsonOps.INSTANCE, c.getCompound("t"))), world.getServer.getPlayerManager.getPlayer(id)) 100 + class MessageFrame(id: UUID, text: Text, player: => ServerPlayerEntity) extends ContinuationFrame: 101 + override def getType: ContinuationFrame.Type[MessageFrame] = MessageFrame 102 + override def evaluate(rest: SpellContinuation, world: ServerWorld, vm: CastingVM): CastResult = 103 + boundary: 104 + def mishap(m: Mishap) = boundary.break(CastResult(NullIota(), rest, vm.getImage, Seq(DoMishap(m, Mishap.Context(null, text))), ResolvedPatternType.EVALUATED, HexEvalSounds.NORMAL_EXECUTE)) 105 + vm.getImage.getStack.toSeq.reverse match 106 + case Seq() => 107 + mishap(MishapNotEnoughArgs(1, 0)) 108 + case Seq(s: StringIota, stack*) => 109 + CastResult(NullIota(), rest, vm.getImage.withStack(_ => stack), Seq( 110 + OperatorSideEffect.AttemptSpell( 111 + new RenderedSpell: 112 + override def cast(env: CastingEnvironment): Unit = 113 + ServerPlayNetworking.send(player, "msg", PacketByteBufs.create.tap(_.writeString(s.getString))) 114 + override def cast(env: CastingEnvironment, img: CastingImage): CastingImage = { cast(env); img } 115 + , false, false 116 + ) 117 + ), ResolvedPatternType.EVALUATED, HexEvalSounds.NORMAL_EXECUTE) 118 + case Seq(i, _*) => 119 + mishap(MishapInvalidIota.ofType(i, 0, "string")) 120 + override def serializeToNBT(): NbtCompound = NbtCompound() 121 + .tap(_.putIntArray("id", Uuids.toIntArray(id))) 122 + .tap(_.put("t", JsonOps.INSTANCE.convertTo(NbtOps.INSTANCE, Text.Serializer.toJsonTree(text)))) 123 + override def breakDownwards(stack: java.util.List[? <: Iota]): kotlin.Pair[java.lang.Boolean, java.util.List[Iota]] = kotlin.Pair(false, stack.toSeq) 124 + override def size = 0 125 + 53 126 object hasComponent: 54 127 def unapply[C <: Component: ComponentKey](ctx: ComponentAccess): Option[C] = 55 128 try ··· 75 148 Patterns.register("murmur", e"wwaqwa"): 76 149 Patterns.mkLiteral: (env, _) ?=> 77 150 hasComponent.unapply[MurmurCache](env.getCastingEntity).fold(throw MishapBadCaster())(_.value.fold(NullIota())(StringIota.make)) 78 - ServerPlayNetworking.registerGlobalReceiver("murmur", { case (_, hasComponent[MurmurCache](c), _, buf, _) => c.value = Option.when(buf.readBoolean())(buf.readString()) }: ServerPlayNetworking.PlayChannelHandler) 151 + hexXplat.getContinuationTypeRegistry("send_message") = MessageFrame 152 + ServerPlayNetworking.registerGlobalReceiver("murmur", { case (_, hasComponent[MurmurCache](c), _, buf, _) => c.value = Option.when(buf.readBoolean())(buf.readString()) }: ServerPlayNetworking.PlayChannelHandler) 153 + ServerPlayNetworking.registerGlobalReceiver("message", (_, player, _, buf, _) => 154 + val context = buf.readByte() 155 + if context != 0 then 156 + throw IllegalArgumentException("Nonzero context is reserved for future use") 157 + val text = buf.readString() 158 + player.executeMediaweave(text, Seq()) 159 + )
+54 -133
project/hexic/src/main/scala/org/eu/net/pool/hexic/main.scala
··· 3 3 package hexic 4 4 5 5 import at.petrak.hexcasting.api.addldata.ADMediaHolder 6 - import at.petrak.hexcasting.api.casting.{ActionRegistryEntry, ParticleSpray, RenderedSpell, SpellList} 6 + import at.petrak.hexcasting.api.casting.{ActionRegistryEntry, OperatorUtils, ParticleSpray, RenderedSpell, SpellList} 7 7 import at.petrak.hexcasting.api.casting.arithmetic.Arithmetic 8 8 import at.petrak.hexcasting.api.casting.arithmetic.operator.Operator 9 9 import at.petrak.hexcasting.api.casting.castables.{Action, ConstMediaAction, OperationAction, SpecialHandler, SpellAction} ··· 170 170 171 171 import scala.util.matching.Regex 172 172 import at.petrak.hexcasting.api.casting.eval.vm.CastingImage.ParenthesizedIota 173 + import dev.emi.trinkets.api.{TrinketComponent, TrinketsApi} 173 174 import net.beholderface.oneironaut.casting.iotatypes.DimIota 174 175 import net.fabricmc.fabric.api.dimension.v1.FabricDimensions 175 176 import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents ··· 187 188 import scala.concurrent.duration.Duration 188 189 import phlib.{Events as PhEvents, *, given} 189 190 190 - given Logger = LoggerFactory.getLogger("hexic") 191 - given Conversion[String, Identifier] = Identifier.of("hexic", _) 191 + private[hexic] given Logger = LoggerFactory.getLogger("hexic") 192 + private[hexic] given Conversion[String, Identifier] = Identifier.of("hexic", _) 192 193 193 194 extension (i: Iota) 194 195 def asIotaType[T <: Iota: ClassTag](idx: Int, expected: => Text): T = i match ··· 367 368 val player: PlayerEntity, 368 369 var leftWeave: ItemStack = ItemStack.EMPTY, 369 370 var rightWeave: ItemStack = ItemStack.EMPTY, 370 - var chatLines: Seq[Text] = Seq(), 371 371 var foxType: Option[FoxEntity.Type] = None, 372 372 ) extends Component, AutoSyncedComponent: 373 373 override def readFromNbt(c: NbtCompound): Unit = ··· 379 379 rightWeave = ItemStack.fromNbt(c.getCompound("shr")) 380 380 else 381 381 rightWeave = ItemStack.EMPTY 382 - chatLines = c.getList("chat", NbtElement.COMPOUND_TYPE).map(NbtOps.INSTANCE.convertTo(JsonOps.INSTANCE, _)).map(Text.Serializer.fromJson).toSeq 383 382 if c.contains("fox", NbtElement.STRING_TYPE) then 384 383 foxType = Some(FoxEntity.Type.valueOf(c.getString("fox"))) 385 384 else ··· 387 386 override def writeToNbt(c: NbtCompound): Unit = 388 387 if !leftWeave.isEmpty then c.put("shl", NbtCompound().tap(leftWeave.writeNbt)) 389 388 if !rightWeave.isEmpty then c.put("shr", NbtCompound().tap(rightWeave.writeNbt)) 390 - c.put("chat", NbtList().tap(_.addAll(chatLines.map(Text.Serializer.toJsonTree).map(JsonOps.INSTANCE.convertTo(NbtOps.INSTANCE, _))))) 391 389 foxType.fold(c.remove("fox"))(f => c.putString("fox", f.name)) 392 390 object PlayerInfoComponent: 393 391 given key: ComponentKey[PlayerInfoComponent] = ComponentRegistry.getOrCreate("player_wisp", classOf[PlayerInfoComponent]) ··· 497 495 case c => c.get("Hex") match 498 496 case c: NbtCompound => c 499 497 case _ => null 500 - override def writeable(stack: ItemStack): Boolean = readIotaTag(stack) == null 501 - override def canWrite(stack: ItemStack, iota: Iota): Boolean = writeable(stack) && (iota match 502 - case l: ListIota => 503 - val i = l.getList.asScala 504 - i.isEmpty || i.head.executable && i.last.executable 505 - case _ => false) 498 + override def writeable(stack: ItemStack): Boolean = true 499 + override def canWrite(stack: ItemStack, iota: Iota): Boolean = iota match 500 + case l: ListIota => true 501 + case _ => iota.executable 506 502 override def writeDatum(stack: ItemStack, iota: Iota): Unit = 507 - assume(canWrite(stack, iota)) 508 503 stack.getOrCreateNbt.put("Hex", IotaType.serialize(iota)) 509 504 override def appendTooltip(stack: ItemStack, world: World, tooltip: util.List[Text], context: TooltipContext): Unit = 510 505 IotaHolderItem.appendHoverText(this, stack, tooltip, context) ··· 701 696 val p = iota match 702 697 case p: PatternIota => p.getPattern 703 698 case _ => boundary.break(None) 704 - val measure = p.anglesSignature match 705 - case introPattern (measure) => measure 706 - case _ => boundary.break(None) 707 - val size = measure.length + 1 708 - def mishap(m: Mishap) = 709 - val safeVM = CastingVM(vm.getImage, vm.getEnv) 710 - OperatorSideEffect.DoMishap(m, Mishap.Context(p, Text.translatable("hexcasting.action.hexic:parenthesize"))).performEffect(safeVM) 711 - boundary.break(Some(safeVM.getImage, ResolvedPatternType.ERRORED)) 712 - val img = vm.getImage 713 - val parens = img.getParenCount 714 - if parens == size then 715 - img.getStack.toSeq match 716 - case Seq() => mishap(MishapNotEnoughArgs(1, 0)) 717 - case tail :+ head => Some(( 718 - CastingImage( 719 - stack = tail, 720 - parenCount = parens, 721 - parenthesized = img.getParenthesized :+ ParenthesizedIota(head, false), 722 - escapeNext = false, 723 - opsConsumed = img.getOpsConsumed, 724 - userData = img.getUserData, 725 - null 726 - ), 727 - ResolvedPatternType.EVALUATED 728 - )) 729 - else if parens > size then 730 - None // leave unescaped, so a nested hex can introject 731 - else 732 - mishap(new Mishap: 733 - override def accentColor(env: CastingEnvironment, ctx: Context): FrozenPigment = dyeColor(DyeColor.ORANGE) 734 - override def errorMessage(env: CastingEnvironment, ctx: Context): Text = ??? 735 - override def execute(env: CastingEnvironment, ctx: Context, stack: util.List[Iota]): Unit = 736 - stack.add(PatternIota(p)) 737 - ) 699 + p.anglesSignature match 700 + case introPattern (measure) => 701 + val size = measure.length + 1 702 + def mishap(m: Mishap) = 703 + val safeVM = CastingVM(vm.getImage, vm.getEnv) 704 + OperatorSideEffect.DoMishap(m, Mishap.Context(p, Text.translatable("hexcasting.action.hexic:parenthesize"))).performEffect(safeVM) 705 + boundary.break(Some(safeVM.getImage, ResolvedPatternType.ERRORED)) 706 + val img = vm.getImage 707 + val parens = img.getParenCount 708 + if parens == size then 709 + img.getStack.toSeq match 710 + case Seq() => mishap(MishapNotEnoughArgs(1, 0)) 711 + case tail :+ head => Some(( 712 + CastingImage( 713 + stack = tail, 714 + parenCount = parens, 715 + parenthesized = img.getParenthesized :+ ParenthesizedIota(head, false), 716 + escapeNext = false, 717 + opsConsumed = img.getOpsConsumed, 718 + userData = img.getUserData, 719 + null 720 + ), 721 + ResolvedPatternType.EVALUATED 722 + )) 723 + else if parens > size then 724 + None // leave unescaped, so a nested hex can introject 725 + else 726 + mishap(new Mishap: 727 + override def accentColor(env: CastingEnvironment, ctx: Context): FrozenPigment = dyeColor(DyeColor.ORANGE) 728 + override def errorMessage(env: CastingEnvironment, ctx: Context): Text = ??? 729 + override def execute(env: CastingEnvironment, ctx: Context, stack: util.List[Iota]): Unit = 730 + stack.add(PatternIota(p)) 731 + ) 732 + case "eadedae" => 733 + val img = vm.getImage 734 + Some(CastingImage(img.getStack:+ListIota(img.getParenthesized.map(_.getIota)):+DoubleIota(img.getParenCount), 0, Seq(), false, img.getOpsConsumed, img.getUserData, null), ResolvedPatternType.EVALUATED) 735 + case _ => None 738 736 private [hexic] def getPocketName(pocket: String) = Text.of(pocketNames(getPocketID(Identifier.tryParse(pocket)).get)) 739 737 740 738 val _ = ··· 1362 1360 override def executeWithUserdata(list: util.List[? <: Iota], env: CastingEnvironment, data: NbtCompound): SpellAction.Result = SpellAction.DefaultImpls.executeWithUserdata(this, list, env, data) 1363 1361 override def hasCastingSound(env: CastingEnvironment): Boolean = true 1364 1362 override def operate(env: CastingEnvironment, castingImage: CastingImage, cont: SpellContinuation): OperationResult = SpellAction.DefaultImpls.operate(this, env, castingImage, cont) 1363 + Patterns.register("omni_open", w"qdaqadq"): 1364 + Patterns.mkAction: (img, cont) => 1365 + (img.getStack.toSeq: Seq[Iota]) match 1366 + case stack:+allegedCount => 1367 + val count = OperatorUtils.getPositiveInt(Seq(allegedCount), 0, 1) 1368 + (new CastingImage(stack, count, Seq(), false, img.getOpsConsumed, img.getUserData, null), cont, HexEvalSounds.NORMAL_EXECUTE, Seq()) 1369 + Patterns.register("omni_close", e"eadedae"): 1370 + Patterns.mkConstAction(0): 1371 + case Seq() => Seq(ListIota(Seq()), DoubleIota(0)) 1365 1372 Patterns.register("staffcast_factory", ne"wwwwwaqqqqqeaqeaeaeaeaeq"): 1366 1373 Patterns.mkAction: (img, cont) => 1367 1374 summon[CastingEnvironment].getCastingEntity match ··· 1630 1637 case Seq(i, _: ListIota, _*) => throw MishapInvalidIota.ofType(i, 0, "list") 1631 1638 case Seq(_, i, _*) => throw MishapInvalidIota.ofType(i, 1, "list") 1632 1639 case s => throw MishapNotEnoughArgs(2, s.size) 1633 - lazy val messageFrameType: ContinuationFrame.Type[MessageFrame] = (c: NbtCompound, world: ServerWorld) => 1634 - val id = Uuids.toUuid(c.getIntArray("id")) 1635 - MessageFrame(id, Text.Serializer.fromJson(NbtOps.INSTANCE.convertTo(JsonOps.INSTANCE, c.getCompound("t"))), world.getServer.getPlayerManager.getPlayer(id)) 1636 - class MessageFrame(id: UUID, text: Text, player: => ServerPlayerEntity) extends ContinuationFrame: 1637 - override def getType: ContinuationFrame.Type[MessageFrame] = messageFrameType 1638 - override def evaluate(rest: SpellContinuation, world: ServerWorld, vm: CastingVM): CastResult = 1639 - boundary: 1640 - def mishap(m: Mishap) = boundary.break(CastResult(NullIota(), rest, vm.getImage, Seq(DoMishap(m, Mishap.Context(null, text))), ResolvedPatternType.EVALUATED, HexEvalSounds.NORMAL_EXECUTE)) 1641 - vm.getImage.getStack.toSeq.reverse match 1642 - case Seq() => 1643 - mishap(MishapNotEnoughArgs(1, 0)) 1644 - case Seq(s: StringIota, stack*) => 1645 - CastResult(NullIota(), rest, vm.getImage.withStack(_ => stack), Seq( 1646 - OperatorSideEffect.AttemptSpell( 1647 - new RenderedSpell: 1648 - override def cast(env: CastingEnvironment): Unit = 1649 - ServerPlayNetworking.send(player, "msg", PacketByteBufs.create.tap(_.writeString(s.getString))) 1650 - override def cast(env: CastingEnvironment, img: CastingImage): CastingImage = { cast(env); img } 1651 - , false, false 1652 - ) 1653 - ), ResolvedPatternType.EVALUATED, HexEvalSounds.NORMAL_EXECUTE) 1654 - case Seq(i, _*) => 1655 - mishap(MishapInvalidIota.ofType(i, 0, "string")) 1656 - override def serializeToNBT(): NbtCompound = NbtCompound() 1657 - .tap(_.putIntArray("id", Uuids.toIntArray(id))) 1658 - .tap(_.put("t", JsonOps.INSTANCE.convertTo(NbtOps.INSTANCE, Text.Serializer.toJsonTree(text)))) 1659 - override def breakDownwards(stack: ju.List[? <: Iota]): Pair[java.lang.Boolean, ju.List[Iota]] = Pair(false, stack.toSeq) 1660 - override def size = 0 1661 - hexXplat.getContinuationTypeRegistry("send_message") = messageFrameType 1662 1640 CastingEnvironment.addCreateEventListener: (env: CastingEnvironment, data: NbtCompound) => 1663 1641 val id = env.getWorld.getRegistryKey.getValue 1664 1642 if isDev then println(s"Environment created in $id") ··· 1677 1655 val x = pos.getComponentAlongAxis(axis) 1678 1656 if x < 0 || x >= 11 then boundary.break(false) 1679 1657 true 1680 - ServerPlayNetworking.registerGlobalReceiver("sync_mediaweave", (_, player, _, buf, _) => 1681 - val flags = buf.readByte() 1682 - val c = player.getComponent(PlayerInfoComponent.key) 1683 - val cursorStack = player.playerScreenHandler.getCursorStack() 1684 - def currentWeave = 1685 - if (flags & 4) != 0 then 1686 - c.leftWeave 1687 - else 1688 - c.rightWeave 1689 - lazy val lastWeave = currentWeave 1690 - if (flags & 1) != 0 && (flags & 8) == 0 then 1691 - assume(cursorStack.isEmpty || (flags & 2) != 0, "if this isn't empty, the player's held item gets voided") 1692 - buf.readItemStack() 1693 - player.playerScreenHandler.setCursorStack(lastWeave.copyAndEmpty()) 1694 - PlayerInfoComponent.key.sync(player) 1695 - if (flags & 2) != 0 then 1696 - buf.readItemStack() 1697 - assume(currentWeave.isEmpty, "if this isn't empty, an equipped mediaweave gets voided") 1698 - if (flags & 4) != 0 then 1699 - c.leftWeave = cursorStack 1700 - else 1701 - c.rightWeave = cursorStack 1702 - PlayerInfoComponent.key.sync(player) 1703 - if (flags & 8) != 0 then 1704 - val text = buf.readString() 1705 - val c = player.getComponent(PlayerInfoComponent.key) 1706 - val stack = if (flags & 4) != 0 then c.leftWeave else c.rightWeave 1707 - stack.getItem match 1708 - case m@Mediaweave(color) => m.readIotaTag(stack) match 1709 - case t: NbtCompound => IotaType.deserialize(t, player.getServerWorld) match 1710 - case s: ListIota => 1711 - given ServerWorld = env.getWorld 1712 - lazy val env = new PlayerBasedCastEnv(player, 1713 - if player.getMainArm match 1714 - case Arm.LEFT => (flags & 4) != 0 1715 - case Arm.RIGHT => (flags & 4) == 0 1716 - then Hand.MAIN_HAND else Hand.OFF_HAND 1717 - ): 1718 - override def extractMediaEnvironment(cost: Long, simulate: Boolean): Long = 1719 - if player.isCreative then 0L else extractMediaFromInventory(cost, canOvercast, simulate) 1720 - override def getCastingHand: Hand = castingHand 1721 - override def getPigment = FrozenPigment(ItemStack(HexItems.DYE_PIGMENTS.get(color)), Util.NIL_UUID) 1722 - val context = 1723 - if (flags & 1) != 0 then 1724 - Seq.fill(buf.readInt)(buf.readUnlimitedNbt: Iota) 1725 - else 1726 - Seq() 1727 - val image = CastingImage(context :+ StringIota.make(text), 0, Seq(), false, 0, NbtCompound(), null) 1728 - val instrs = s.getList.asScala.toSeq 1729 - val vm = CastingVM(image, env) 1730 - val view = vm.queueExecuteAndWrapIotas(instrs :+ ContinuationIota(SpellContinuation.NotDone(MessageFrame(player.getUuid, stack.getName, player), SpellContinuation.Done.INSTANCE)), player.getServerWorld) 1731 - val packet = MsgNewSpiralPatternsS2C(player.getUuid, instrs.collect { case p: PatternIota => p.getPattern }.asJava, 140) 1732 - hexXplat.sendPacketToPlayer(player, packet) 1733 - hexXplat.sendPacketTracking(player, packet) 1734 - case _ => 1735 - case null => 1736 - case _ =>) 1737 1658 // dump patterns 1738 1659 val out = Files.newOutputStream(Path.of("patterns.csv")) 1739 1660 try
+4
util/build.gradle.kts
··· 52 52 } 53 53 } 54 54 55 + tasks.jar { 56 + duplicatesStrategy = DuplicatesStrategy.WARN 57 + } 58 + 55 59 publishing { 56 60 publications { 57 61 create<MavenPublication>("mavenJava") {
+1
util/changelog
··· 1 + 0.1.2 add portals 1 2 0.1.2 intrusive holder allocation tracking
+34
util/src/main/scala/org/eu/net/pool/phlib/aperture.scala
··· 1 + package org.eu.net.pool 2 + package phlib 3 + 4 + import java.util.NoSuchElementException 5 + import scala.util.{Failure, Success, Try, boundary} 6 + 7 + class Scope[T](initial: T): 8 + private object local extends InheritableThreadLocal[Option[T]]: 9 + override def initialValue: Option[T] = None 10 + def enter[R](newValue: T)(body: => R): R = 11 + val oldValue = local.get 12 + try 13 + local.set(Some(newValue)) 14 + body 15 + finally 16 + local.set(oldValue) 17 + def value: T = local.get.getOrElse(initial) 18 + def valueIfChanged: Option[T] = local.get 19 + def isChanged: Boolean = local.get.isDefined 20 + object Scope: 21 + given [T] => Conversion[Scope[T], T] = _.value 22 + 23 + class Portal[T]: 24 + private val scope = Scope[Try[T] => Nothing]: 25 + case Success(value) => sys.exit(0) 26 + case Failure(exc) => { exc.printStackTrace(); sys.exit(1) } 27 + def enter[R](body: => R): Either[T, R] = 28 + def wrap: Either[Try[T], R] = scope.enter(x => return Left(x))(Right(body)) 29 + wrap.left.map(_.get) 30 + def isEntered: Boolean = scope.isChanged 31 + def exit(value: T): Nothing = scope(Success(value)) 32 + def abort(error: Throwable): Nothing = scope(Failure(error)) 33 + def tryExit(value: T): Unit = for jump <- scope.valueIfChanged do jump(Success(value)) 34 + def tryAbort(error: Throwable): Unit = for jump <- scope.valueIfChanged do jump(Failure(error))