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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/main/java/net/tfminecraft/magic/gear/GearItemBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ private static void copyGearPdc(ItemStack from, ItemStack to) {
toMeta.getPersistentDataContainer().set(
GearKeys.parts(), org.bukkit.persistence.PersistentDataType.STRING, parts);
}
String craftInputs = fromMeta.getPersistentDataContainer().get(
GearKeys.craftInputs(), org.bukkit.persistence.PersistentDataType.STRING);
if (craftInputs != null) {
toMeta.getPersistentDataContainer().set(
GearKeys.craftInputs(), org.bukkit.persistence.PersistentDataType.STRING, craftInputs);
}
toMeta.getPersistentDataContainer().set(
GearKeys.archetype(),
org.bukkit.persistence.PersistentDataType.STRING,
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/net/tfminecraft/magic/gear/GearKeys.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ public static NamespacedKey parts() {
return new NamespacedKey(Magic.plugin, "gear_parts");
}

/** Materials actually charged when the weapon was crafted, as a JSON map of item path to amount. */
public static NamespacedKey craftInputs() {
return new NamespacedKey(Magic.plugin, "gear_craft_inputs");
}

public static NamespacedKey socketsLocked() {
return new NamespacedKey(Magic.plugin, "gear_sockets_locked");
}
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/net/tfminecraft/magic/gear/GearProvenance.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
package net.tfminecraft.magic.gear;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;

import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;

public final class GearProvenance {

private static final Gson GSON = new Gson();
private static final Type INPUTS_TYPE = new TypeToken<LinkedHashMap<String, Integer>>() {}.getType();

private GearProvenance() {}

public static void stamp(ItemStack stack, GearType type, Collection<PartDef> parts) {
Expand Down Expand Up @@ -38,6 +48,33 @@ public static void stamp(ItemStack stack, GearType type, Collection<PartDef> par
stack.setItemMeta(meta);
}

/** Records what the craft actually charged. Empty when staff bypassed the cost. */
public static void stampInputs(ItemStack stack, Map<String, Integer> charged) {
if (stack == null || !stack.hasItemMeta()) {
return;
}
ItemMeta meta = stack.getItemMeta();
meta.getPersistentDataContainer().set(
GearKeys.craftInputs(), PersistentDataType.STRING, GSON.toJson(charged == null ? Map.of() : charged));
stack.setItemMeta(meta);
}

/** Materials charged at craft time, or null for weapons crafted before this was recorded. */
public static Map<String, Integer> readInputs(ItemStack stack) {
if (stack == null || !stack.hasItemMeta()) {
return null;
}
String json = stack.getItemMeta().getPersistentDataContainer().get(GearKeys.craftInputs(), PersistentDataType.STRING);
if (json == null) {
return null;
}
try {
return GSON.fromJson(json, INPUTS_TYPE);
} catch (JsonParseException ex) {
return null;
}
}

public static int majorityOf(ItemStack stack) {
if (stack == null || !stack.hasItemMeta()) {
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ private static void copyGearPdc(ItemStack from, ItemStack to) {
ItemMeta fromMeta = from.getItemMeta();
ItemMeta toMeta = to.getItemMeta();
copyString(fromMeta, toMeta, GearKeys.parts());
copyString(fromMeta, toMeta, GearKeys.craftInputs());
copyString(fromMeta, toMeta, GearKeys.archetype());
copyString(fromMeta, toMeta, GearKeys.orphans());
Integer archetypeRevision = fromMeta.getPersistentDataContainer().get(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import net.tfminecraft.magic.gear.GearCosts;
import net.tfminecraft.magic.gear.GearItemBuilder;
import net.tfminecraft.magic.gear.GearKeys;
import net.tfminecraft.magic.gear.GearProvenance;
import net.tfminecraft.magic.gear.GearStationStore;
import net.tfminecraft.magic.gear.GearType;
import net.tfminecraft.magic.gear.PartDef;
Expand Down Expand Up @@ -290,6 +291,7 @@ private void tryPrepare(Player player) {
boolean staffBypass = GearCosts.bypasses(player);
Map<String, Integer> charged = staffBypass ? Map.of() : GearCosts.total(parts);
GearCosts.take(player, parts);
GearProvenance.stampInputs(prepared, charged);
GearStationStore.occupy(station, prepared, player.getUniqueId(), charged);
OpenStationManager.clear(player);
player.closeInventory();
Expand Down
9 changes: 9 additions & 0 deletions src/test/java/net/tfminecraft/magic/GearItemCoverageTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,15 @@ void socketRewriteKeepsIdentityAndLocksFirstAttunement() throws Exception {
minimal,
dest);
assertEquals(GearType.STAFF, GearProvenance.archetypeOf(dest));
assertNull(GearProvenance.readInputs(dest));
GearProvenance.stampInputs(minimal, Map.of("v.gold", 3));
invoke(
GearItemBuilder.class,
"copyGearPdc",
new Class[] {ItemStack.class, ItemStack.class},
minimal,
dest);
assertEquals(Map.of("v.gold", 3), GearProvenance.readInputs(dest));
for (ItemStack[] pair :
new ItemStack[][] {
{null, dest},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ void unstampedItemsAndMissingMetadataAreSafe() {
assertTrue(GearProvenance.socketsLocked(item));
}

@Test
void craftInputsRecordWhatWasChargedAndReadBack() {
for (ItemStack item : Arrays.asList(null, new ItemStack(Material.AIR))) {
GearProvenance.stampInputs(item, Map.of("v.gold", 1));
assertNull(GearProvenance.readInputs(item));
}
var item = item();
assertNull(GearProvenance.readInputs(item), "Weapons crafted before the record have none");
GearProvenance.stampInputs(item, null);
assertEquals(Map.of(), GearProvenance.readInputs(item));
GearProvenance.stampInputs(item, Map.of("m.materials.steel_ingot", 4, "v.gold", 2));
assertEquals(Map.of("m.materials.steel_ingot", 4, "v.gold", 2), GearProvenance.readInputs(item));
tag(item, GearKeys.craftInputs(), PersistentDataType.STRING, "{not json");
assertNull(GearProvenance.readInputs(item));
}

@Test
void stampingTracksPartAndArchetypeRevisions() {
var item = item();
Expand Down
Loading