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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- Added Simulate, which causes the next pattern drawn to be simulated (to check for mishaps) rather than executed ([#1194](https://github.com/FallingColors/HexMod/pull/1194)) @Robotgiggle
- Added the `hex_unbreakable` tag for blocks that should be immune to Break Block regardless of the configured mining tier ([#1186](https://github.com/FallingColors/HexMod/pull/1186)) @Robotgiggle @slava110
- Added a new Ancient Cypher hex that impulses nearby items towards the caster ([#1106](https://github.com/FallingColors/HexMod/pull/1106)) @IridescentVoid
- Added automatic item fixing for items carried over from 1.20.x (might not work on items stored inside modded containers) ([#1226](https://github.com/FallingColors/HexMod/pull/1226)) @Olfi01

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
public class EntityIota extends Iota {
private final UUID entityId;
@Nullable
private final Component entityName;
private Component entityName;
private boolean isPlayer;

public EntityIota(@NotNull Entity e) {
Expand Down Expand Up @@ -115,6 +115,8 @@ public boolean validate(EntityIota iota, ServerLevel level) {
var entity = iota.getEntity(level);
// update isPlayer so older non-player entity iotas are not protected
iota.isPlayer = (entity instanceof Player);
if (iota.entityName == null)
iota.entityName = getEntityNameWithInline(entity);
return entity != null;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package at.petrak.hexcasting.mixin.datafixer;

import at.petrak.hexcasting.api.casting.math.HexPattern;
import at.petrak.hexcasting.api.item.IotaHolderItem;
import at.petrak.hexcasting.api.item.VariantItem;
import at.petrak.hexcasting.common.items.magic.ItemMediaHolder;
import at.petrak.hexcasting.common.items.magic.ItemPackagedHex;
import com.mojang.serialization.Dynamic;

import java.util.*;
import java.util.function.Function;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix;
import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix.ItemStackData;
import net.minecraft.world.item.Item;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(ItemStackComponentizationFix.class)
public class MixinItemStackComponentizationFix {
@Unique
private static final String HEX_TYPE = "hexcasting:type";
@Unique
private static final String HEX_DATA = "hexcasting:data";

@Inject(method = "fixItemStack", at = @At("HEAD"))
private static void preFixHexItemStack(ItemStackData itemStackData, Dynamic<?> dynamic, CallbackInfo ci) {
if (itemStackData.is("hexcasting:slate")) {
itemStackData.fixSubTag("BlockEntityTag", false, dynamic0 ->
hexCasting$mapPattern(dynamic0.get("pattern").orElseEmptyMap()));
itemStackData.moveTagToComponent("BlockEntityTag", "hexcasting:pattern");
}
}

@Inject(method = "fixItemStack", at = @At("TAIL"))
private static void fixHexItemStack(ItemStackData itemStackData, Dynamic<?> dynamic, CallbackInfo ci) {
Item item = BuiltInRegistries.ITEM.get(ResourceLocation.parse(itemStackData.item));

if (itemStackData.is(Set.of("hexcasting:focus", "hexcasting:thought_knot"))) {
hexCasting$fixIotaHolder(itemStackData, dynamic);
}
if (itemStackData.is(Set.of("hexcasting:scroll_small", "hexcasting:scroll_medium", "hexcasting:scroll"))) {
hexCasting$fixScroll(itemStackData);
}
if (itemStackData.is("hexcasting:ancient_cypher")) {
itemStackData.moveTagToComponent("hex_name", "hexcasting:hex_name");
}
if (itemStackData.is("hexcasting:abacus")) {
itemStackData.moveTagToComponent("value", "hexcasting:abacus_value");
}
if (itemStackData.is("hexcasting:spellbook")) {
hexCasting$fixSpellbook(itemStackData);
}
if (item instanceof IotaHolderItem) {
itemStackData.moveTagToComponent("VisualOverride", "hexcasting:visual_override");
}
if (item instanceof VariantItem) {
itemStackData.moveTagToComponent("variant", "hexcasting:variant");
}
if (item instanceof ItemPackagedHex) {
hexCasting$fixPackagedHex(itemStackData, dynamic);
}
if (item instanceof ItemMediaHolder) {
itemStackData.moveTagToComponent("hexcasting:media", "hexcasting:media");
itemStackData.moveTagToComponent("hexcasting:start_media", "hexcasting:start_media");
}
}

@Unique
private static void hexCasting$fixIotaHolder(ItemStackData itemStackData, Dynamic<?> dynamic) {
itemStackData.fixSubTag("data", true, MixinItemStackComponentizationFix::hexCasting$mapIotaData);
itemStackData.moveTagToComponent("data", "hexcasting:iota");

if (itemStackData.removeTag("sealed").asBoolean(false))
itemStackData.setComponent("hexcasting:sealed", dynamic.createMap(Map.of()));
}

@Unique
private static Dynamic<?> hexCasting$mapIotaData(Dynamic<?> iota) {
String iotaType = iota.get(HEX_TYPE).asString("");
Dynamic<?> iotaData = iota.get(HEX_DATA).orElseEmptyMap();
Map<Dynamic<?>, Dynamic<?>> component = new HashMap<>();
component.put(iota.createString("type"), iota.createString(iotaType));
switch (iotaType) {
case "hexcasting:entity":
IntStream uuid = iotaData.get("uuid").asIntStream();
// Unfortunately, it seems like we cannot easily fix InlineAPI components, so we will have to live with "an unknown entity"
component.put(iota.createString("entityId"), iota.createIntList(uuid));
component.put(iota.createString("isPlayer"), iota.createBoolean(true));
break;
case "hexcasting:boolean", "hexcasting:double":
component.put(iota.createString("value"), iotaData);
break;
case "hexcasting:list":
component.put(iota.createString("list"),
iota.createList(iotaData.asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData)));
break;
case "hexcasting:pattern":
component.put(iota.createString("value"), hexCasting$mapPattern(iotaData));
break;
case "hexcasting:vec3":
component.put(iota.createString("value"), hexCasting$mapVec3(iotaData));
break;
case "hexcasting:continuation":
component.put(iota.createString("value"),
iota.createList(iotaData.asStream().map(MixinItemStackComponentizationFix::hexCasting$mapContinuationFrame)));
break;
case "hexcasting:null", "hexcasting:garbage":
default:
break;
}
return iota.createMap(component);
}

@Unique
private static final String[] hexCasting$hexDir = {"NORTH_EAST", "EAST", "SOUTH_EAST", "SOUTH_WEST", "WEST", "NORTH_WEST"};
@Unique
private static final String[] hexCasting$hexAngle = {"w", "e", "d", "s", "a", "q"};
@Unique
private static Dynamic<?> hexCasting$mapPattern(Dynamic<?> pattern) {
Map<Dynamic<?>, Dynamic<?>> patternComponent = new HashMap<>();
byte startDir = pattern.get("start_dir").asByte((byte) 0);
List<String> angles = pattern.get("angles").asStream()
.map(a -> hexCasting$hexAngle[a.asByte((byte) 0)])
.toList();
patternComponent.put(pattern.createString(HexPattern.TAG_START_DIR), pattern.createString(hexCasting$hexDir[startDir]));
patternComponent.put(pattern.createString(HexPattern.TAG_ANGLES), pattern.createString(String.join("", angles)));
return pattern.createMap(patternComponent);
}

@Unique
private static Dynamic<?> hexCasting$mapVec3(Dynamic<?> iotaData) {
double x = iotaData.get("x").asDouble(0);
double y = iotaData.get("y").asDouble(0);
double z = iotaData.get("z").asDouble(0);
return iotaData.createList(Stream.of(iotaData.createDouble(x), iotaData.createDouble(y), iotaData.createDouble(z)));
}

@Unique
private static Dynamic<?> hexCasting$mapContinuationFrame(Dynamic<?> frame) {
String type = frame.get(HEX_TYPE).asString("");
Dynamic<?> frameData = frame.get(HEX_DATA).orElseEmptyMap();
Map<Dynamic<?>, Dynamic<?>> component = new HashMap<>();
component.put(frame.createString("type"), frame.createString(type));
switch (type) {
case "hexcasting:evaluate":
component.put(frame.createString("patterns"),
frame.createList(frameData.get("patterns").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData)));
component.put(frame.createString("isMetacasting"),
frame.createBoolean(frameData.get("isMetacasting").asBoolean(false)));
break;
case "hexcasting:foreach":
component.put(frame.createString("data"),
frame.createList(frameData.get("data").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData)));
component.put(frame.createString("code"),
frame.createList(frameData.get("code").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData)));
component.put(frame.createString("context"),
frame.createList(frameData.get("base").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData)));
component.put(frame.createString("stashed"),
frame.createList(Stream.of()));
component.put(frame.createString("accumulator"),
frame.createList(frameData.get("accumulator").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData)));
break;
case "hexcasting:end":
default:
break;
}
return frame.createMap(component);
}

@Unique
private static Dynamic<?> hexCasting$stringToPlainComponent(Dynamic<?> string) {
return string.createMap(Map.of(string.createString("text"), string));
}

@Unique
private static void hexCasting$fixScroll(ItemStackData itemStackData) {
itemStackData.fixSubTag("pattern", true, MixinItemStackComponentizationFix::hexCasting$mapPattern);

itemStackData.moveTagToComponent("pattern", "hexcasting:pattern");
itemStackData.moveTagToComponent("op_id", "hexcasting:op_id");
itemStackData.moveTagToComponent("recalc_warning", "hexcasting:recalc_warning");
itemStackData.moveTagToComponent("needs_purchase", "hexcasting:needs_purchase");
}

@Unique
private static void hexCasting$fixSpellbook(ItemStackData itemStackData) {
itemStackData.moveTagToComponent("page_idx", "hexcasting:page_idx");

itemStackData.fixSubTag("page_names", true, d0 ->
d0.createMap(d0.asMap(Function.identity(), MixinItemStackComponentizationFix::hexCasting$stringToPlainComponent)));
itemStackData.moveTagToComponent("page_names", "hexcasting:page_names");

itemStackData.fixSubTag("pages", true, d0 ->
d0.createMap(d0.asMap(Function.identity(), MixinItemStackComponentizationFix::hexCasting$mapIotaData)));
itemStackData.moveTagToComponent("pages", "hexcasting:pages");

itemStackData.moveTagToComponent("sealed_pages", "hexcasting:sealed_pages");
}

@Unique
private static void hexCasting$fixPackagedHex(ItemStackData itemStackData, Dynamic<?> dynamic) {
Stream<Dynamic<?>> patterns = itemStackData.removeTag("patterns").asStream()
.map(MixinItemStackComponentizationFix::hexCasting$mapIotaData);
Dynamic<?> pigment = itemStackData.removeTag("pigment").orElseEmptyMap();
Dynamic<?> hexHolder = dynamic.createMap(Map.of(
dynamic.createString("hex"), dynamic.createList(patterns),
dynamic.createString("pigment"), pigment));
itemStackData.setComponent("hexcasting:hex_holder", hexHolder);
}
}
2 changes: 2 additions & 0 deletions Common/src/main/resources/hexplat.accesswidener
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ accessible method net/minecraft/world/item/crafting/Ingredient <init> (Ljava/uti
accessible method net/minecraft/world/item/context/UseOnContext <init> (Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/phys/BlockHitResult;)V
accessible method net/minecraft/world/damagesource/DamageSources source (Lnet/minecraft/resources/ResourceKey;)Lnet/minecraft/world/damagesource/DamageSource;
accessible method net/minecraft/world/damagesource/DamageSources source (Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/world/entity/Entity;)Lnet/minecraft/world/damagesource/DamageSource;
accessible class net/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData
accessible field net/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData item Ljava/lang/String;
3 changes: 2 additions & 1 deletion Common/src/main/resources/hexplat.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"accessor.AccessorLivingEntity",
"accessor.AccessorLootTable",
"accessor.AccessorUseOnContext",
"accessor.AccessorVillager"
"accessor.AccessorVillager",
"datafixer.MixinItemStackComponentizationFix"
],
"client": [
"accessor.client.AccessorBlockEntityRenderDispatcher",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import at.petrak.hexcasting.api.addldata.*;
import at.petrak.hexcasting.common.entities.EntityWallScroll;
import at.petrak.hexcasting.common.lib.HexDataComponents;
import at.petrak.hexcasting.fabric.cc.adimpl.*;
import net.fabricmc.fabric.api.lookup.v1.item.ItemApiLookup;
import net.minecraft.server.level.ServerPlayer;
Expand All @@ -16,14 +15,12 @@
import org.ladysnake.cca.api.v3.entity.EntityComponentFactoryRegistry;
import org.ladysnake.cca.api.v3.entity.EntityComponentInitializer;
import org.ladysnake.cca.api.v3.entity.RespawnCopyStrategy;
import org.ladysnake.cca.api.v3.item.ItemComponentInitializer;
import org.ladysnake.cca.api.v3.item.ItemComponentMigrationRegistry;

import java.util.function.Function;

import static at.petrak.hexcasting.api.HexAPI.modLoc;

public class HexCardinalComponents implements EntityComponentInitializer, ItemComponentInitializer {
public class HexCardinalComponents implements EntityComponentInitializer {
// entities
public static final ComponentKey<CCBrainswept> BRAINSWEPT = ComponentRegistry.getOrCreate(modLoc("brainswept"),
CCBrainswept.class);
Expand Down Expand Up @@ -88,21 +85,6 @@ public void registerEntityComponentFactories(EntityComponentFactoryRegistry regi
wrapItemEntityDelegate(ItemDelegatingEntityIotaHolder.ToWallScroll::new));
}

@Override
public void registerItemComponentMigrations(ItemComponentMigrationRegistry registry) {
registry.registerMigration(modLoc("pigment"), HexDataComponents.PIGMENT.get());

registry.registerMigration(modLoc("iota_holder"), HexDataComponents.IOTA_HOLDER_IOTA.get());
// oh havoc, you think you're so funny
// the worst part is you're /right/

registry.registerMigration(modLoc("media_holder"), HexDataComponents.MEDIA.get());

registry.registerMigration(modLoc("hex_holder"), HexDataComponents.HEX_HOLDER_PATTERNS.get());

registry.registerMigration(modLoc("variant_item"), HexDataComponents.ITEM_VARIANT.get());
}

private <E extends Entity> ComponentFactory<E, CCEntityIotaHolder.Wrapper> wrapItemEntityDelegate(Function<E,
ItemDelegatingEntityIotaHolder> make) {
return e -> new CCEntityIotaHolder.Wrapper(make.apply(e));
Expand Down
Loading