Skip to content

Commit

Permalink
Migrate rebalanced to modifier modules
Browse files Browse the repository at this point in the history
Decided for this one to make it two modules, one for the base slots/name/data, and one to handle the penalties, named bonus here. Idea being you could use it to add penalties that are not just the opposite of the slot added, or to add additional slots when a certain type is chosen
When the full composable between datapacks functionality is done, will also let addons with new slot types add their own penalties without overwriting rebalanced
  • Loading branch information
KnightMiner committed Jun 7, 2023
1 parent 85494b7 commit 0d6e87c
Show file tree
Hide file tree
Showing 7 changed files with 272 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
{
"type": "tconstruct:swappable_extra_slot",
"slots": 1,
"always_show": false,
"penalize": {
"abilities": "upgrades"
}
"type": "tconstruct:composable",
"level_display": "tconstruct:no_levels",
"tooltip_display": "tinker_station",
"priority": 50,
"modules": [
{
"type": "tconstruct:swappable_slot",
"slots": 1
},
{
"type": "tconstruct:swappable_bonus_slot",
"match": "abilities",
"bonus": "upgrades",
"slots": -1
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import slimeknights.tconstruct.TConstruct;
import slimeknights.tconstruct.library.modifiers.Modifier;
import slimeknights.tconstruct.library.modifiers.impl.NoLevelsModifier;
import slimeknights.tconstruct.library.modifiers.modules.SwappableSlotModule;
import slimeknights.tconstruct.library.tools.SlotType;
import slimeknights.tconstruct.library.tools.context.ToolRebuildContext;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;
Expand All @@ -24,9 +25,8 @@
import java.util.Map;
import java.util.Map.Entry;

/**
* Modifier that grants slot type based on an NBT tag
*/
/** @deprecated use {@link SwappableSlotModule} */
@Deprecated
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class SwappableExtraSlotModifier extends NoLevelsModifier {
/** Format key for swappable variant */
Expand Down Expand Up @@ -83,6 +83,11 @@ public void addVolatileData(ToolRebuildContext context, int level, ModDataNBT vo
}
}

@Override
public void onRemoved(IToolStackView tool) {
tool.getPersistentData().remove(getId());
}

@Override
public IGenericLoader<? extends Modifier> getLoader() {
return LOADER;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import slimeknights.mantle.data.GenericLoaderRegistry.IGenericLoader;
import slimeknights.mantle.util.JsonHelper;
import slimeknights.tconstruct.library.modifiers.Modifier;
import slimeknights.tconstruct.library.modifiers.ModifierHook;
import slimeknights.tconstruct.library.modifiers.TinkerHooks;
import slimeknights.tconstruct.library.modifiers.hook.DisplayNameModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.EffectiveLevelModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.build.ModifierRemovalHook;
import slimeknights.tconstruct.library.modifiers.impl.IncrementalModifier;
import slimeknights.tconstruct.library.modifiers.util.ModuleWithKey;
import slimeknights.tconstruct.library.recipe.modifiers.ModifierRecipeLookup;
import slimeknights.tconstruct.library.tools.nbt.INamespacedNBTView;
import slimeknights.tconstruct.library.tools.nbt.IToolContext;
Expand All @@ -30,7 +30,7 @@
* @param neededPerLevel If zero, modifier is incremental with no max set and will fetch if from the recipe.
* If greater than zero, modifier will have a fixed max.
*/
public record IncrementalModule(@Nullable ResourceLocation key, int neededPerLevel) implements EffectiveLevelModifierHook, DisplayNameModifierHook, ModifierRemovalHook, ModifierModule {
public record IncrementalModule(@Nullable ResourceLocation key, int neededPerLevel) implements EffectiveLevelModifierHook, DisplayNameModifierHook, ModifierRemovalHook, ModifierModule, ModuleWithKey {
private static final List<ModifierHook<?>> DEFAULT_HOOKS = List.of(TinkerHooks.EFFECTIVE_LEVEL, TinkerHooks.DISPLAY_NAME, TinkerHooks.REMOVE);

/** Recipe controlled incremental modifier with no extra settings */
Expand All @@ -44,14 +44,6 @@ public static IncrementalModule create(@Nullable ResourceLocation key, int neede
return new IncrementalModule(key, neededPerLevel);
}

/** Gets the key to use for incremental data */
private ResourceLocation getKey(Modifier modifier) {
if (key != null) {
return key;
}
return modifier.getId();
}

/** Gets the number needed per level */
private int getNeededPerLevel(ResourceLocation key) {
if (neededPerLevel > 0) {
Expand Down Expand Up @@ -112,10 +104,7 @@ public IGenericLoader<? extends ModifierModule> getLoader() {
public static final IGenericLoader<IncrementalModule> LOADER = new IGenericLoader<>() {
@Override
public IncrementalModule deserialize(JsonObject json) {
ResourceLocation key = null;
if (json.has("key")) {
key = JsonHelper.getResourceLocation(json, "key");
}
ResourceLocation key = ModuleWithKey.parseKey(json);
int neededPerLevel = JsonUtils.getIntMin(json, "needed_per_level", 0);
return IncrementalModule.create(key, neededPerLevel);
}
Expand All @@ -132,22 +121,14 @@ public void serialize(IncrementalModule object, JsonObject json) {

@Override
public IncrementalModule fromNetwork(FriendlyByteBuf buffer) {
ResourceLocation key = null;
if (buffer.readBoolean()) {
key = buffer.readResourceLocation();
}
ResourceLocation key = ModuleWithKey.fromNetwork(buffer);
int neededPerLevel = buffer.readVarInt();
return IncrementalModule.create(key, neededPerLevel);
}

@Override
public void toNetwork(IncrementalModule object, FriendlyByteBuf buffer) {
if (object.key != null) {
buffer.writeBoolean(true);
buffer.writeResourceLocation(object.key);
} else {
buffer.writeBoolean(false);
}
ModuleWithKey.toNetwork(object.key, buffer);
buffer.writeVarInt(object.neededPerLevel);
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package slimeknights.tconstruct.library.modifiers.modules;

import com.google.gson.JsonObject;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import slimeknights.mantle.data.GenericLoaderRegistry.IGenericLoader;
import slimeknights.tconstruct.TConstruct;
import slimeknights.tconstruct.library.modifiers.Modifier;
import slimeknights.tconstruct.library.modifiers.ModifierEntry;
import slimeknights.tconstruct.library.modifiers.ModifierHook;
import slimeknights.tconstruct.library.modifiers.TinkerHooks;
import slimeknights.tconstruct.library.modifiers.hook.DisplayNameModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.build.ModifierRemovalHook;
import slimeknights.tconstruct.library.modifiers.hook.build.VolatileDataModifierHook;
import slimeknights.tconstruct.library.modifiers.util.ModuleWithKey;
import slimeknights.tconstruct.library.tools.SlotType;
import slimeknights.tconstruct.library.tools.context.ToolRebuildContext;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;
import slimeknights.tconstruct.library.tools.nbt.ModDataNBT;

import javax.annotation.Nullable;
import java.util.List;

/**
* Module for a extra slot modifier with multiple variants based on the slot type
* @param key Persistent data key containing the slot name. If null, uses the modifier ID.
* Presently, changing this makes it incompatible with the swappable modifier recipe, this is added for future proofing.
* @param slotCount Number of slots to grant
*/
public record SwappableSlotModule(@Nullable ResourceLocation key, int slotCount) implements VolatileDataModifierHook, DisplayNameModifierHook, ModifierRemovalHook, ModifierModule, ModuleWithKey {
private static final List<ModifierHook<?>> DEFAULT_HOOKS = List.of(TinkerHooks.VOLATILE_DATA, TinkerHooks.DISPLAY_NAME, TinkerHooks.REMOVE);
/** Format key for swappable variant */
private static final String FORMAT = TConstruct.makeTranslationKey("modifier", "extra_modifier.type_format");

public SwappableSlotModule(int slotCount) {
this(null, slotCount);
}

@Override
public Component getDisplayName(IToolStackView tool, Modifier modifier, int level, Component name) {
String slotName = tool.getPersistentData().getString(getKey(modifier));
if (!slotName.isEmpty()) {
SlotType type = SlotType.getIfPresent(slotName);
if (type != null) {
return new TranslatableComponent(FORMAT, name.plainCopy(), type.getDisplayName()).withStyle(style -> style.withColor(type.getColor()));
}
}
return name;
}

@Override
public void addVolatileData(ToolRebuildContext context, ModifierEntry modifier, ModDataNBT volatileData) {
String slotName = context.getPersistentData().getString(getKey(modifier.getModifier()));
if (!slotName.isEmpty()) {
SlotType type = SlotType.getIfPresent(slotName);
if (type != null) {
volatileData.addSlots(type, slotCount);
}
}
}

@Nullable
@Override
public Component onRemoved(IToolStackView tool, Modifier modifier) {
tool.getPersistentData().remove(modifier.getId());
return null;
}

@Override
public List<ModifierHook<?>> getDefaultHooks() {
return DEFAULT_HOOKS;
}

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

/** Loader instance */
public static final IGenericLoader<SwappableSlotModule> LOADER = new IGenericLoader<>() {
@Override
public SwappableSlotModule deserialize(JsonObject json) {
ResourceLocation key = ModuleWithKey.parseKey(json);
int slotCount = GsonHelper.getAsInt(json, "slots");
return new SwappableSlotModule(key, slotCount);
}

@Override
public void serialize(SwappableSlotModule object, JsonObject json) {
if (object.key != null) {
json.addProperty("key", object.key.toString());
}
json.addProperty("slots", object.slotCount);
}

@Override
public SwappableSlotModule fromNetwork(FriendlyByteBuf buffer) {
ResourceLocation key = ModuleWithKey.fromNetwork(buffer);
int slotCount = buffer.readInt();
return new SwappableSlotModule(key, slotCount);
}

@Override
public void toNetwork(SwappableSlotModule object, FriendlyByteBuf buffer) {
ModuleWithKey.toNetwork(object.key, buffer);
buffer.writeInt(object.slotCount);
}
};

/** Module to add (or remove) additional slots based on the given swappable slot type */
public record BonusSlot(@Nullable ResourceLocation key, SlotType match, SlotType bonus, int slotCount) implements VolatileDataModifierHook, ModifierModule, ModuleWithKey {
private static final List<ModifierHook<?>> DEFAULT_HOOKS = List.of(TinkerHooks.VOLATILE_DATA);

public BonusSlot(SlotType match, SlotType penalty, int slotCount) {
this(null, match, penalty, slotCount);
}

@Override
public void addVolatileData(ToolRebuildContext context, ModifierEntry modifier, ModDataNBT volatileData) {
String slotName = context.getPersistentData().getString(getKey(modifier.getModifier()));
if (!slotName.isEmpty() && match.getName().equals(slotName)) {
volatileData.addSlots(bonus, slotCount);
}
}

@Override
public List<ModifierHook<?>> getDefaultHooks() {
return DEFAULT_HOOKS;
}

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

public static final IGenericLoader<BonusSlot> LOADER = new IGenericLoader<>() {
@Override
public BonusSlot deserialize(JsonObject json) {
ResourceLocation key = ModuleWithKey.parseKey(json);
SlotType match = SlotType.getOrCreate(GsonHelper.getAsString(json, "match"));
SlotType bonus = SlotType.getOrCreate(GsonHelper.getAsString(json, "bonus"));
int slotCount = GsonHelper.getAsInt(json, "slots");
return new BonusSlot(key, match, bonus, slotCount);
}

@Override
public void serialize(BonusSlot object, JsonObject json) {
if (object.key != null) {
json.addProperty("key", object.key.toString());
}
json.addProperty("match", object.match.getName());
json.addProperty("bonus", object.bonus.getName());
json.addProperty("slots", object.slotCount);
}

@Override
public BonusSlot fromNetwork(FriendlyByteBuf buffer) {
ResourceLocation key = ModuleWithKey.fromNetwork(buffer);
SlotType match = SlotType.read(buffer);
SlotType bonus = SlotType.read(buffer);
int slots = buffer.readInt();
return new BonusSlot(key, match, bonus, slots);
}

@Override
public void toNetwork(BonusSlot object, FriendlyByteBuf buffer) {
ModuleWithKey.toNetwork(object.key, buffer);
object.match.write(buffer);
object.bonus.write(buffer);
buffer.writeInt(object.slotCount);
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package slimeknights.tconstruct.library.modifiers.util;

import com.google.gson.JsonObject;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import slimeknights.mantle.util.JsonHelper;
import slimeknights.tconstruct.library.modifiers.Modifier;

import javax.annotation.Nullable;

/**
* Shared boilerplate for a module with a nullable key that can alternatively be the modifier ID
*/
public interface ModuleWithKey {
/** Gets the key for the module */
default ResourceLocation getKey(Modifier modifier) {
ResourceLocation key = key();
if (key != null) {
return key;
}
return modifier.getId();
}

/** Gets the key field from the record */
@Nullable
ResourceLocation key();

/**
* Parses the key from JSON
* @param json Json object
* @return Key, or null if not present
*/
@Nullable
static ResourceLocation parseKey(JsonObject json) {
if (json.has("key")) {
return JsonHelper.getResourceLocation(json, "key");
}
return null;
}

/** Reads the key from the network */
@Nullable
static ResourceLocation fromNetwork(FriendlyByteBuf buffer) {
if (buffer.readBoolean()) {
return buffer.readResourceLocation();
}
return null;
}

/** Writes the key to the network */
static void toNetwork(@Nullable ResourceLocation key, FriendlyByteBuf buffer) {
if (key != null) {
buffer.writeBoolean(true);
buffer.writeResourceLocation(key);
} else {
buffer.writeBoolean(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import slimeknights.tconstruct.library.modifiers.modules.ModifierModule;
import slimeknights.tconstruct.library.modifiers.modules.ModifierSlotModule;
import slimeknights.tconstruct.library.modifiers.modules.RarityModule;
import slimeknights.tconstruct.library.modifiers.modules.SwappableSlotModule;
import slimeknights.tconstruct.library.modifiers.modules.ToolActionsModule;
import slimeknights.tconstruct.library.modifiers.modules.ToolStatModule;
import slimeknights.tconstruct.library.modifiers.modules.VolatileFlagModule;
Expand Down Expand Up @@ -596,6 +597,8 @@ void registerSerializers(RegistryEvent.Register<RecipeSerializer<?>> event) {
ModifierModule.LOADER.register(TConstruct.getResource("constant_enchantment"), EnchantmentModule.Constant.LOADER);
ModifierModule.LOADER.register(TConstruct.getResource("looting"), LootingModule.LOADER);
ModifierModule.LOADER.register(TConstruct.getResource("modifier_slot"), ModifierSlotModule.LOADER);
ModifierModule.LOADER.register(TConstruct.getResource("swappable_slot"), SwappableSlotModule.LOADER);
ModifierModule.LOADER.register(TConstruct.getResource("swappable_bonus_slot"), SwappableSlotModule.BonusSlot.LOADER);
ModifierModule.LOADER.register(TConstruct.getResource("mob_effect"), MobEffectModule.LOADER);

ModifierPredicate.LOADER.register(TConstruct.getResource("and"), ModifierPredicate.AND);
Expand Down

0 comments on commit 0d6e87c

Please sign in to comment.