Skip to content

Commit

Permalink
Implement mapping from enchantments to modifiers
Browse files Browse the repository at this point in the history
TODO: add tags for common ones from other mods
  • Loading branch information
KnightMiner committed Jan 4, 2023
1 parent c72210a commit bcafa06
Show file tree
Hide file tree
Showing 6 changed files with 283 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"minecraft:unbreaking": "tconstruct:reinforced",
"minecraft:protection": "tconstruct:protection",
"minecraft:fire_protection": "tconstruct:fire_protection",
"minecraft:blast_protection": "tconstruct:blast_protection",
"minecraft:projectile_protection": "tconstruct:projectile_protection",
"minecraft:feather_falling": "tconstruct:feather_falling",
"minecraft:respiration": "tconstruct:respiration",
"minecraft:aqua_affinity": "tconstruct:aqua_affinity",
"minecraft:thorns": "tconstruct:thorns",
"minecraft:frost_walker": "tconstruct:frost_walker",
"minecraft:soul_speed": "tconstruct:soulspeed",
"minecraft:sharpness": "tconstruct:sharpness",
"minecraft:smite": "tconstruct:smite",
"minecraft:bane_of_arthropods": "tconstruct:bane_of_sssss",
"minecraft:knockback": "tconstruct:knockback",
"minecraft:fire_aspect": "tconstruct:fiery",
"minecraft:looting": "tconstruct:looting",
"minecraft:sweeping": "tconstruct:sweeping_edge",
"minecraft:impaling": "tconstruct:antiaquatic",
"minecraft:efficiency": "tconstruct:haste",
"minecraft:silk_touch": "tconstruct:silky",
"minecraft:fortune": "tconstruct:fortune",
"minecraft:power": "tconstruct:power",
"minecraft:punch": "tconstruct:punch",
"minecraft:flame": "tconstruct:fiery",
"minecraft:infinity": "tconstruct:crystalshot",
"minecraft:multishot": "tconstruct:multishot",
"minecraft:quick_charge": "tconstruct:quick_charge",
"minecraft:piercing": "tconstruct:impaling"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package slimeknights.tconstruct.library.data.tinkering;

import com.google.gson.JsonObject;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.HashCache;
import net.minecraft.server.packs.PackType;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.enchantment.Enchantment;
import slimeknights.mantle.data.GenericDataProvider;
import slimeknights.tconstruct.TConstruct;
import slimeknights.tconstruct.library.modifiers.ModifierId;

import java.io.IOException;
import java.util.Objects;

/** Data generator for mappings from enchantments to modifiers */
public abstract class AbstractEnchantmentToModifierProvider extends GenericDataProvider {
/** Compiled JSON to save, no need to do anything fancier, it already does merging for us */
private final JsonObject enchantmentMap = new JsonObject();

public AbstractEnchantmentToModifierProvider(DataGenerator generator) {
super(generator, PackType.SERVER_DATA, "tinkering");
}

/** Add any mappings */
protected abstract void addEnchantmentMappings();

@Override
public void run(HashCache pCache) throws IOException {
enchantmentMap.entrySet().clear();
addEnchantmentMappings();
saveThing(pCache, TConstruct.getResource("enchantments_to_modifiers"), enchantmentMap);
}

/* Helpers */

/** Adds the given enchantment */
protected void add(Enchantment enchantment, ModifierId modifierId) {
String key = Objects.requireNonNull(enchantment.getRegistryName()).toString();
if (enchantmentMap.has(key)) {
throw new IllegalArgumentException("Duplicate enchantment " + key);
}
enchantmentMap.addProperty(key, modifierId.toString());
}

/** Adds the given enchantment tag */
protected void add(TagKey<Enchantment> tag, ModifierId modifierId) {
String key = "#" + tag.location();
if (enchantmentMap.has(key)) {
throw new IllegalArgumentException("Duplicate enchantment tag " + tag.location());
}
enchantmentMap.addProperty(key, modifierId.toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
import net.minecraft.tags.Tag;
import net.minecraft.tags.TagKey;
import net.minecraft.tags.TagLoader;
import net.minecraft.util.GsonHelper;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.common.crafting.conditions.ICondition;
Expand All @@ -34,14 +36,18 @@
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.ForgeRegistries;
import slimeknights.mantle.data.GenericLoaderRegistry;
import slimeknights.mantle.util.JsonHelper;
import slimeknights.mantle.util.RegistryHelper;
import slimeknights.tconstruct.TConstruct;
import slimeknights.tconstruct.library.json.JsonRedirect;
import slimeknights.tconstruct.library.utils.GenericTagUtil;
import slimeknights.tconstruct.library.utils.JsonUtils;

import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand All @@ -50,6 +56,7 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand All @@ -60,6 +67,8 @@ public class ModifierManager extends SimpleJsonResourceReloadListener {
public static final String FOLDER = "tinkering/modifiers";
/** Location of modifier tags */
public static final String TAG_FOLDER = "tinkering/tags/modifiers";

public static final ResourceLocation ENCHANTMENT_MAP = TConstruct.getResource("tinkering/enchantments_to_modifiers.json");
/** Registry key to make tag keys */
private static final ResourceKey<? extends Registry<Modifier>> REGISTRY_KEY = ResourceKey.createRegistryKey(TConstruct.getResource("modifiers"));

Expand Down Expand Up @@ -94,6 +103,11 @@ public class ModifierManager extends SimpleJsonResourceReloadListener {
/** Map from modifier to tags on the modifier */
private Map<ModifierId,Set<TagKey<Modifier>>> reverseTags = Collections.emptyMap();

/** List of tag to modifier mappings to try */
private Collection<EnchantmentTagMapping> enchantmentTagMap = Collections.emptyList();
/** Mapping from enchantment to modifiers, for conversions */
private Map<Enchantment,Modifier> enchantmentMap = Collections.emptyMap();

/** If true, dynamic modifiers have been loaded from datapacks, so its safe to fetch dynamic modifiers */
@Getter
boolean dynamicModifiersLoaded = false;
Expand All @@ -112,7 +126,7 @@ private ModifierManager() {
public void init() {
FMLJavaModLoadingContext.get().getModEventBus().addListener(EventPriority.NORMAL, false, FMLCommonSetupEvent.class, e -> e.enqueueWork(this::fireRegistryEvent));
MinecraftForge.EVENT_BUS.addListener(EventPriority.NORMAL, false, AddReloadListenerEvent.class, this::addDataPackListeners);
MinecraftForge.EVENT_BUS.addListener(EventPriority.NORMAL, false, OnDatapackSyncEvent.class, e -> JsonUtils.syncPackets(e, new UpdateModifiersPacket(this.dynamicModifiers, this.tags)));
MinecraftForge.EVENT_BUS.addListener(EventPriority.NORMAL, false, OnDatapackSyncEvent.class, e -> JsonUtils.syncPackets(e, new UpdateModifiersPacket(this.dynamicModifiers, this.tags, this.enchantmentMap, this.enchantmentTagMap)));
}

/** Fires the modifier registry event */
Expand Down Expand Up @@ -166,6 +180,7 @@ protected void apply(Map<ResourceLocation,JsonElement> splashList, ResourceManag
dynamicModifiersLoaded = true;
long timeStep = System.nanoTime();
log.info("Loaded {} dynamic modifiers and {} modifier redirects in {} ms", modifierSize, redirects.size(), (timeStep - time) / 1000000f);
time = timeStep;

// load modifier tags
TagLoader<Modifier> tagLoader = new TagLoader<>(id -> {
Expand All @@ -177,7 +192,52 @@ protected void apply(Map<ResourceLocation,JsonElement> splashList, ResourceManag
}, TAG_FOLDER);
this.tags = tagLoader.loadAndBuild(pResourceManager);
this.reverseTags = GenericTagUtil.reverseTags(REGISTRY_KEY, Modifier::getId, tags);
log.info("Loaded {} modifier tags for {} modifiers in {} ms", tags.size(), this.reverseTags.size(), (System.nanoTime() - timeStep) / 1000000f);
timeStep = System.nanoTime();
log.info("Loaded {} modifier tags for {} modifiers in {} ms", tags.size(), this.reverseTags.size(), (timeStep - time) / 1000000f);

// load modifier to enchantment mapping
enchantmentMap = new HashMap<>();
Map<ResourceLocation,EnchantmentTagMapping> tagMappings = new HashMap<>();
try {
for (Resource resource : pResourceManager.getResources(ENCHANTMENT_MAP)) {
JsonObject enchantmentJson = JsonHelper.getJson(resource);
if (enchantmentJson != null) {
for (Entry<String,JsonElement> entry : enchantmentJson.entrySet()) {
try {
// parse the modifier first, its the same in both cases
String key = entry.getKey();
ModifierId modifierId = new ModifierId(JsonHelper.convertToResourceLocation(entry.getValue(), "modifier"));
Modifier modifier = get(modifierId);
if (modifier == defaultValue) {
throw new JsonSyntaxException("Unknown modifier " + modifierId + " for enchantment " + key);
}

// if it starts with #, it's a tag
if (key.startsWith("#")) {
ResourceLocation tagId = ResourceLocation.tryParse(key.substring(1));
if (tagId == null) {
throw new JsonSyntaxException("Invalid enchantment tag ID " + key.substring(1));
}
tagMappings.put(tagId, new EnchantmentTagMapping(TagKey.create(Registry.ENCHANTMENT_REGISTRY, tagId), modifier));
} else {
// assume its an ID
ResourceLocation enchantId = ResourceLocation.tryParse(key);
if (enchantId == null || !ForgeRegistries.ENCHANTMENTS.containsKey(enchantId)) {
throw new JsonSyntaxException("Invalid enchantment ID " + key);
}
enchantmentMap.put(ForgeRegistries.ENCHANTMENTS.getValue(enchantId), modifier);
}
} catch (JsonSyntaxException e) {
log.info("Invalid enchantment to modifier mapping", e);
}
}
}
}
} catch (IOException e) {
log.info("Failed to get enchantment map from {}", enchantmentMap);
}
this.enchantmentTagMap = tagMappings.values();
log.info("Loaded {} enchantment to modifier mappings in {} ms", enchantmentMap.size() + tagMappings.size(), (System.nanoTime() - timeStep) / 1000000f);

MinecraftForge.EVENT_BUS.post(new ModifiersLoadedEvent());
}
Expand Down Expand Up @@ -217,11 +277,13 @@ private Modifier loadModifier(ResourceLocation key, JsonElement element, Map<Mod
}

/** Updates the modifiers from the server */
void updateModifiersFromServer(Map<ModifierId,Modifier> modifiers, Map<ResourceLocation,Tag<Modifier>> tags) {
void updateModifiersFromServer(Map<ModifierId,Modifier> modifiers, Map<ResourceLocation,Tag<Modifier>> tags, Map<Enchantment,Modifier> enchantmentMap, Collection<EnchantmentTagMapping> enchantmentTagMappings) {
this.dynamicModifiers = modifiers;
this.dynamicModifiersLoaded = true;
this.tags = tags;
this.reverseTags = GenericTagUtil.reverseTags(REGISTRY_KEY, Modifier::getId, tags);
this.enchantmentMap = enchantmentMap;
this.enchantmentTagMap = enchantmentTagMappings;
MinecraftForge.EVENT_BUS.post(new ModifiersLoadedEvent());
}

Expand Down Expand Up @@ -254,6 +316,26 @@ public Modifier get(ModifierId id) {
return dynamicModifiers.getOrDefault(id, defaultValue);
}

/**
* Gets the modifier for a given enchantment. Not currently synced to client side
* @param enchantment Enchantment
* @return Closest modifier to the enchantment, or null if no match
*/
@Nullable
public Modifier get(Enchantment enchantment) {
// if we saw it before, return the last value
if (enchantmentMap.containsKey(enchantment)) {
return enchantmentMap.get(enchantment);
}
// did not find, check the tags
for (EnchantmentTagMapping mapping : enchantmentTagMap) {
if (mapping.test(enchantment)) {
return mapping.modifier;
}
}
return null;
}

/** Gets a list of all modifier IDs */
public Stream<ResourceLocation> getAllLocations() {
// filter out redirects (redirects are any modifiers where the ID does not match the key
Expand Down Expand Up @@ -415,4 +497,12 @@ public boolean shouldDisplay(boolean advanced) {
return false;
}
}

/** Record representing a mapping from tag to modifier */
record EnchantmentTagMapping(TagKey<Enchantment> tag, Modifier modifier) implements Predicate<Enchantment> {
@Override
public boolean test(Enchantment enchantment) {
return RegistryHelper.contains(Registry.ENCHANTMENT, this.tag, enchantment);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@
import com.google.common.collect.ImmutableMap;
import io.netty.handler.codec.DecoderException;
import lombok.RequiredArgsConstructor;
import net.minecraft.core.Registry;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.Tag;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraftforge.network.NetworkEvent.Context;
import net.minecraftforge.registries.ForgeRegistries;
import slimeknights.mantle.network.packet.IThreadsafePacket;
import slimeknights.tconstruct.library.modifiers.ModifierManager.EnchantmentTagMapping;
import slimeknights.tconstruct.library.utils.GenericTagUtil;

import java.util.Collection;
Expand All @@ -27,6 +32,10 @@ public class UpdateModifiersPacket implements IThreadsafePacket {
private Collection<Modifier> modifiers;
/** Map of modifier redirect ID pairs */
private Map<ModifierId,ModifierId> redirects;
/** Map of enchantment to modifier pair */
private final Map<Enchantment,Modifier> enchantmentMap;
/** Collection of all enchantment tag mappings */
private final Collection<EnchantmentTagMapping> enchantmentTagMappings;

/** Ensures both the modifiers and redirects lists are calculated, allows one packet to be used multiple times without redundant work */
private void ensureCalculated() {
Expand Down Expand Up @@ -77,6 +86,24 @@ public UpdateModifiersPacket(FriendlyByteBuf buffer) {
}
this.allModifiers = modifiers;
this.tags = GenericTagUtil.decodeTags(buffer, id -> getModifier(modifiers, new ModifierId(id)));

// read in enchantment to modifier mapping
ImmutableMap.Builder<Enchantment,Modifier> enchantmentBuilder = ImmutableMap.builder();
size = buffer.readVarInt();
for (int i = 0; i < size; i++) {
enchantmentBuilder.put(
buffer.readRegistryIdUnsafe(ForgeRegistries.ENCHANTMENTS),
getModifier(modifiers, new ModifierId(buffer.readResourceLocation())));
}
enchantmentMap = enchantmentBuilder.build();
ImmutableList.Builder<EnchantmentTagMapping> enchantmentTagBuilder = ImmutableList.builder();
size = buffer.readVarInt();
for (int i = 0; i < size; i++) {
enchantmentTagBuilder.add(new EnchantmentTagMapping(
TagKey.create(Registry.ENCHANTMENT_REGISTRY, buffer.readResourceLocation()),
getModifier(modifiers, new ModifierId(buffer.readResourceLocation()))));
}
enchantmentTagMappings = enchantmentTagBuilder.build();
}

@Override
Expand All @@ -95,10 +122,22 @@ public void encode(FriendlyByteBuf buffer) {
buffer.writeResourceLocation(entry.getValue());
}
GenericTagUtil.encodeTags(buffer, Modifier::getId, this.tags);

// enchantment mapping
buffer.writeVarInt(enchantmentMap.size());
for (Entry<Enchantment,Modifier> entry : enchantmentMap.entrySet()) {
buffer.writeRegistryIdUnsafe(ForgeRegistries.ENCHANTMENTS, entry.getKey());
buffer.writeResourceLocation(entry.getValue().getId());
}
buffer.writeVarInt(enchantmentTagMappings.size());
for (EnchantmentTagMapping mapping : enchantmentTagMappings) {
buffer.writeResourceLocation(mapping.tag().location());
buffer.writeResourceLocation(mapping.modifier().getId());
}
}

@Override
public void handleThreadsafe(Context context) {
ModifierManager.INSTANCE.updateModifiersFromServer(allModifiers, tags);
ModifierManager.INSTANCE.updateModifiersFromServer(allModifiers, tags, enchantmentMap, enchantmentTagMappings);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import slimeknights.tconstruct.library.tools.capability.PersistentDataCapability;
import slimeknights.tconstruct.library.tools.capability.TinkerDataCapability;
import slimeknights.tconstruct.library.tools.capability.TinkerDataKeys;
import slimeknights.tconstruct.tools.data.EnchantmentToModifierProvider;
import slimeknights.tconstruct.tools.data.ModifierProvider;
import slimeknights.tconstruct.tools.data.ModifierRecipeProvider;
import slimeknights.tconstruct.tools.data.SpillingFluidProvider;
Expand Down Expand Up @@ -556,6 +557,7 @@ void gatherData(final GatherDataEvent event) {
generator.addProvider(new ModifierRecipeProvider(generator));
generator.addProvider(new SpillingFluidProvider(generator));
generator.addProvider(new ModifierTagProvider(generator, event.getExistingFileHelper()));
generator.addProvider(new EnchantmentToModifierProvider(generator));
}
}
}

0 comments on commit bcafa06

Please sign in to comment.