Skip to content

Commit

Permalink
Implement depth strider modifier and JSON enchantment modifier
Browse files Browse the repository at this point in the history
The thing holding enchantments back before was grindstones, as we had no way to prevent grindstone disenchanting leading to an XP dupe. Now we have a way
The hook is still not as ideal as the 1.19 hook, but I wanted as modifiers, whether it works or not depends on the enchantment implementation
  • Loading branch information
KnightMiner committed Jan 4, 2023
1 parent ce3ea5c commit 5c65b94
Show file tree
Hide file tree
Showing 24 changed files with 256 additions and 111 deletions.
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ minecraft_version=1.18.2
minecraft_range=[1.18.2,1.19)

# Forge Version Information
forge_version=40.1.21
forge_version=40.1.92
loader_range=[39.0,)
forge_range=[40.1.21,)
forge_range=[40.1.88,)
parchment_version=2022.03.13

# Build Dependencies
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"type": "tconstruct:modifier_salvage",
"tools": {
"tag": "tconstruct:modifiable/armor/boots"
},
"slots": {
"upgrades": 1
},
"modifier": "tconstruct:depth_strider",
"min_level": 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"type": "tconstruct:modifier",
"inputs": [
{
"tag": "minecraft:fishes"
},
{
"item": "minecraft:prismarine_bricks"
},
{
"tag": "minecraft:fishes"
}
],
"tools": {
"tag": "tconstruct:modifiable/armor/boots"
},
"slots": {
"upgrades": 1
},
"allow_crystal": true,
"result": {
"name": "tconstruct:depth_strider",
"level": 1
},
"max_level": 3
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"minecraft:respiration": "tconstruct:respiration",
"minecraft:aqua_affinity": "tconstruct:aqua_affinity",
"minecraft:thorns": "tconstruct:thorns",
"minecraft:depth_strider": "tconstruct:depth_strider",
"minecraft:frost_walker": "tconstruct:frost_walker",
"minecraft:soul_speed": "tconstruct:soulspeed",
"minecraft:sharpness": "tconstruct:sharpness",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "tconstruct:enchantment",
"level_display": "tconstruct:default",
"enchantment": {
"name": "minecraft:depth_strider",
"level": 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package slimeknights.tconstruct.library.modifiers.dynamic;

import com.google.gson.JsonObject;
import lombok.RequiredArgsConstructor;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraftforge.registries.ForgeRegistries;
import slimeknights.mantle.data.GenericLoaderRegistry.IGenericLoader;
import slimeknights.mantle.util.JsonHelper;
import slimeknights.tconstruct.library.modifiers.Modifier;
import slimeknights.tconstruct.library.modifiers.util.ModifierLevelDisplay;
import slimeknights.tconstruct.library.tools.helper.ModifierUtil;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;
import slimeknights.tconstruct.library.utils.RestrictedCompoundTag;

import java.util.Objects;

/**
* Modifier that adds an enchantment. The current implementation is a bit of a hack, and will clobber enchantments from other sources.
* TODO 1.19: switch to new hook to make this less of a hack
*/
@RequiredArgsConstructor
public class EnchantmentModifier extends Modifier {
private final Enchantment enchantment;
private final int enchantmentLevel;
private final ModifierLevelDisplay levelDisplay;

@Override
public Component getDisplayName(int level) {
return levelDisplay.nameForLevel(this, level);
}

@Override
public void addRawData(IToolStackView tool, int level, RestrictedCompoundTag tag) {
// first, find the enchantment tag
ListTag enchantments;
if (tag.contains(ModifierUtil.TAG_ENCHANTMENTS, Tag.TAG_LIST)) {
enchantments = tag.getList(ModifierUtil.TAG_ENCHANTMENTS, Tag.TAG_COMPOUND);
} else {
enchantments = new ListTag();
tag.put(ModifierUtil.TAG_ENCHANTMENTS, enchantments);
}
// first, see if it already exists, if so we need to replace it
String id = Objects.requireNonNull(enchantment.getRegistryName()).toString();
for (int i = 0; i < enchantments.size(); i++) {
CompoundTag enchantmentTag = enchantments.getCompound(i);
if (id.equals(enchantmentTag.getString("id"))) {
EnchantmentHelper.setEnchantmentLevel(enchantmentTag, level * enchantmentLevel);
return;
}
}
// none of the existing tags match the enchant, so add it
enchantments.add(EnchantmentHelper.storeEnchantment(enchantment.getRegistryName(), level * enchantmentLevel));
}

@Override
public void beforeRemoved(IToolStackView tool, RestrictedCompoundTag tag) {
// when removing the modifier, remove the enchant
// this will clobber anyone else trying to remove it, not much we can do
if (tag.contains(ModifierUtil.TAG_ENCHANTMENTS, Tag.TAG_LIST)) {
ListTag enchantments = tag.getList(ModifierUtil.TAG_ENCHANTMENTS, Tag.TAG_COMPOUND);
String id = Objects.requireNonNull(enchantment.getRegistryName()).toString();
for (int i = 0; i < enchantments.size(); i++) {
CompoundTag enchantmentTag = enchantments.getCompound(i);
if (id.equals(enchantmentTag.getString("id"))) {
enchantments.remove(i);
if (enchantments.isEmpty()) {
tag.remove(ModifierUtil.TAG_ENCHANTMENTS);
}
break;
}
}
}
}

@Override
public IGenericLoader<? extends Modifier> getLoader() {
return LOADER;
}

public static final IGenericLoader<EnchantmentModifier> LOADER = new IGenericLoader<>() {
@Override
public EnchantmentModifier deserialize(JsonObject json) {
JsonObject enchantmentJson = GsonHelper.getAsJsonObject(json, "enchantment");
Enchantment enchantment = JsonHelper.getAsEntry(ForgeRegistries.ENCHANTMENTS, enchantmentJson, "name");
int level = GsonHelper.getAsInt(enchantmentJson, "level", 1);
ModifierLevelDisplay display = ModifierLevelDisplay.LOADER.getAndDeserialize(json, "level_display");
return new EnchantmentModifier(enchantment, level, display);
}

@Override
public void serialize(EnchantmentModifier object, JsonObject json) {
json.add("level_display", ModifierLevelDisplay.LOADER.serialize(object.levelDisplay));
JsonObject enchantmentJson = new JsonObject();
enchantmentJson.addProperty("name", Objects.requireNonNull(object.enchantment.getRegistryName()).toString());
enchantmentJson.addProperty("level", object.enchantmentLevel);
json.add("enchantment", enchantmentJson);
}

@Override
public EnchantmentModifier fromNetwork(FriendlyByteBuf buffer) {
Enchantment enchantment = buffer.readRegistryIdUnsafe(ForgeRegistries.ENCHANTMENTS);
int level = buffer.readVarInt();
ModifierLevelDisplay display = ModifierLevelDisplay.LOADER.fromNetwork(buffer);
return new EnchantmentModifier(enchantment, level, display);
}

@Override
public void toNetwork(EnchantmentModifier object, FriendlyByteBuf buffer) {
buffer.writeRegistryIdUnsafe(ForgeRegistries.ENCHANTMENTS, object.enchantment);
buffer.writeVarInt(object.enchantmentLevel);
ModifierLevelDisplay.LOADER.toNetwork(object.levelDisplay, buffer);
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public LootModifier deserialize(JsonObject json) {
if (json.has("enchantment")) {
JsonObject enchantmentJson = GsonHelper.getAsJsonObject(json, "enchantment");
enchantment = JsonHelper.getAsEntry(ForgeRegistries.ENCHANTMENTS, enchantmentJson, "name");
enchantmentLevel = GsonHelper.getAsInt(enchantmentJson, "level");
enchantmentLevel = GsonHelper.getAsInt(enchantmentJson, "level", 1);
}
int looting = GsonHelper.getAsInt(json, "looting", 0);
ModifierLevelDisplay display = ModifierLevelDisplay.LOADER.getAndDeserialize(json, "level_display");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,11 @@ public static void addModifierNames(ItemStack stack, IToolStackView tool, List<C
CompoundTag enchantmentTag = enchantments.getCompound(i);
// TODO: tag to whitelist/blacklist enchantments in the tooltip, depends on which ones we reimplement and which work on their own
Registry.ENCHANTMENT.getOptional(ResourceLocation.tryParse(enchantmentTag.getString("id")))
.ifPresent(enchantment -> tooltips.add(enchantment.getFullname(enchantmentTag.getInt("lvl"))));
.ifPresent(enchantment -> {
if (enchantment.isCurse()) {
tooltips.add(enchantment.getFullname(enchantmentTag.getInt("lvl")));
}
});
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import slimeknights.tconstruct.library.tools.context.ToolRebuildContext;
import slimeknights.tconstruct.library.tools.definition.PartRequirement;
import slimeknights.tconstruct.library.tools.definition.ToolDefinition;
import slimeknights.tconstruct.library.tools.helper.ModifierUtil;
import slimeknights.tconstruct.library.tools.helper.ToolBuildHandler;
import slimeknights.tconstruct.library.tools.helper.TooltipUtil;
import slimeknights.tconstruct.library.tools.item.IModifiable;
Expand Down Expand Up @@ -72,7 +71,7 @@ public class ToolStack implements IToolStackView {
public static final String TAG_HIDE_FLAGS = "HideFlags";

/** List of tags to disallow editing for the relevant modifier hooks, disallows all tags we touch. Ignores unbreakable as we only look at that tag for vanilla compat */
private static final Set<String> RESTRICTED_TAGS = ImmutableSet.of(TAG_MATERIALS, TAG_STATS, TAG_MULTIPLIERS, TAG_PERSISTENT_MOD_DATA, TAG_VOLATILE_MOD_DATA, TAG_UPGRADES, TAG_MODIFIERS, TAG_BROKEN, TAG_DAMAGE, ModifierUtil.TAG_ENCHANTMENTS, TAG_HIDE_FLAGS);
private static final Set<String> RESTRICTED_TAGS = ImmutableSet.of(TAG_MATERIALS, TAG_STATS, TAG_MULTIPLIERS, TAG_PERSISTENT_MOD_DATA, TAG_VOLATILE_MOD_DATA, TAG_UPGRADES, TAG_MODIFIERS, TAG_BROKEN, TAG_DAMAGE, TAG_HIDE_FLAGS);

/** Item representing this tool */
@Getter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import slimeknights.tconstruct.library.modifiers.ModifierManager;
import slimeknights.tconstruct.library.modifiers.dynamic.ConditionalDamageModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.ConditionalMiningSpeedModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.EnchantmentModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.ExtraModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.InventoryMenuModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.LootModifier;
Expand Down Expand Up @@ -536,6 +537,7 @@ void registerSerializers(RegistryEvent.Register<RecipeSerializer<?>> event) {
ModifierManager.MODIFIER_LOADERS.register(TConstruct.getResource("conditional_damage"), ConditionalDamageModifier.LOADER);
ModifierManager.MODIFIER_LOADERS.register(TConstruct.getResource("conditional_mining_speed"), ConditionalMiningSpeedModifier.LOADER);
ModifierManager.MODIFIER_LOADERS.register(TConstruct.getResource("loot"), LootModifier.LOADER);
ModifierManager.MODIFIER_LOADERS.register(TConstruct.getResource("enchantment"), EnchantmentModifier.LOADER);
ModifierManager.MODIFIER_LOADERS.register(TConstruct.getResource("inventory_with_menu"), InventoryMenuModifier.LOADER);
// specialized
ModifierManager.MODIFIER_LOADERS.register(TConstruct.getResource("tool_belt"), ToolBeltModifier.LOADER);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ protected void addEnchantmentMappings() {
add(Enchantments.RESPIRATION, TinkerModifiers.respiration.getId());
add(Enchantments.AQUA_AFFINITY, TinkerModifiers.aquaAffinity.getId());
add(Enchantments.THORNS, TinkerModifiers.thorns.getId());
// TODO: depth strider
add(Enchantments.DEPTH_STRIDER, ModifierIds.depthStrider);
add(Enchantments.FROST_WALKER, TinkerModifiers.frostWalker.getId());
add(Enchantments.SOUL_SPEED, TinkerModifiers.soulspeed.getId());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ public class ModifierIds {
public static final ModifierId stepUp = id("step_up");
public static final ModifierId speedy = id("speedy");
public static final ModifierId toolBelt = id("tool_belt");
// boots
public static final ModifierId depthStrider = id("depth_strider");

// internal
public static final ModifierId overslimeFriend = id("overslime_friend");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import slimeknights.tconstruct.library.modifiers.ModifierId;
import slimeknights.tconstruct.library.modifiers.dynamic.ConditionalDamageModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.ConditionalMiningSpeedModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.EnchantmentModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.ExtraModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.InventoryMenuModifier;
import slimeknights.tconstruct.library.modifiers.dynamic.LootModifier;
Expand Down Expand Up @@ -178,6 +179,8 @@ protected void addModifiers() {
addRedirect(id("pocket_chain"), redirect(TinkerModifiers.shieldStrap.getId()));
addModifier(ModifierIds.stepUp, StatBoostModifier.builder().attribute("tconstruct.modifier.step_up", ForgeMod.STEP_HEIGHT_ADDITION.get(), Operation.ADDITION, 0.5f, armorSlots).build());
addModifier(ModifierIds.speedy, StatBoostModifier.builder().attribute("tconstruct.modifier.speedy", Attributes.MOVEMENT_SPEED, Operation.MULTIPLY_TOTAL, 0.1f, armorSlots).build());
// boots
addModifier(ModifierIds.depthStrider, new EnchantmentModifier(Enchantments.DEPTH_STRIDER, 1, ModifierLevelDisplay.DEFAULT));

// internal
addModifier(ModifierIds.overslimeFriend, StatBoostModifier.builder().addFlag(OverslimeModifier.KEY_OVERSLIME_FRIEND).modifierDisplay(ModifierDisplay.NEVER).build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,15 @@ private void addModifierRecipes(Consumer<FinishedRecipe> consumer) {
.setMaxLevel(3)
.saveSalvage(consumer, prefix(TinkerModifiers.soulspeed, upgradeSalvage))
.save(consumer, prefix(TinkerModifiers.soulspeed, upgradeFolder));
ModifierRecipeBuilder.modifier(ModifierIds.depthStrider)
.setTools(TinkerTags.Items.BOOTS)
.addInput(ItemTags.FISHES)
.addInput(Blocks.PRISMARINE_BRICKS)
.addInput(ItemTags.FISHES)
.setSlots(SlotType.UPGRADE, 1)
.setMaxLevel(3)
.saveSalvage(consumer, prefix(ModifierIds.depthStrider, upgradeSalvage))
.save(consumer, prefix(ModifierIds.depthStrider, upgradeFolder));
IncrementalModifierRecipeBuilder.modifier(TinkerModifiers.lightspeedArmor)
.setTools(TinkerTags.Items.BOOTS)
.setInput(Tags.Items.DUSTS_GLOWSTONE, 1, 64)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraftforge.event.GrindstoneEvent;
import net.minecraftforge.event.entity.ProjectileImpactEvent;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingDamageEvent;
Expand Down Expand Up @@ -430,4 +431,12 @@ static void projectileHit(ProjectileImpactEvent event) {
}
}
}

@SubscribeEvent
static void onGrindstoneChange(GrindstoneEvent.OnPlaceItem event) {
// no removing enchantments from tools, you must use the modifier to remove them
if (event.getTopItem().is(TinkerTags.Items.MODIFIABLE) || event.getBottomItem().is(TinkerTags.Items.MODIFIABLE)) {
event.setCanceled(true);
}
}
}

0 comments on commit 5c65b94

Please sign in to comment.