feat(D-01/A): config-driven components + tooltip hook (A1, A2, A3)
- ResistanceComponent: resistanceId delegates to SettingsAccessor at runtime, fallback to hardcoded base for backward compat - GaggingComponent: material field delegates to GagMaterial enum from ModConfig, explicit comprehension/range overrides take priority - IItemComponent: add default appendTooltip() method - ComponentHolder: iterate components for tooltip contribution - 6 components implement appendTooltip (lockable, resistance, gagging, shock, gps, choking) - DataDrivenBondageItem: call holder.appendTooltip() in appendHoverText()
This commit is contained in:
@@ -1,6 +1,13 @@
|
|||||||
package com.tiedup.remake.v2.bondage.component;
|
package com.tiedup.remake.v2.bondage.component;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component: choking effect for data-driven items.
|
* Component: choking effect for data-driven items.
|
||||||
@@ -43,4 +50,9 @@ public class ChokingComponent implements IItemComponent {
|
|||||||
public boolean isNonLethalForMaster() {
|
public boolean isNonLethalForMaster() {
|
||||||
return nonLethalForMaster;
|
return nonLethalForMaster;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appendTooltip(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
|
||||||
|
tooltip.add(Component.translatable("item.tiedup.tooltip.choking").withStyle(ChatFormatting.DARK_PURPLE));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,13 @@ package com.tiedup.remake.v2.bondage.component;
|
|||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public final class ComponentHolder {
|
public final class ComponentHolder {
|
||||||
@@ -58,6 +62,12 @@ public final class ComponentHolder {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void appendTooltip(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
|
||||||
|
for (IItemComponent c : components.values()) {
|
||||||
|
c.appendTooltip(stack, level, tooltip, flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return components.isEmpty();
|
return components.isEmpty();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,94 @@
|
|||||||
package com.tiedup.remake.v2.bondage.component;
|
package com.tiedup.remake.v2.bondage.component;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.tiedup.remake.core.TiedUpMod;
|
||||||
|
import com.tiedup.remake.util.GagMaterial;
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component: gagging behavior for data-driven items.
|
* Component: gagging behavior for data-driven items.
|
||||||
*
|
*
|
||||||
* JSON config: {@code "gagging": {"comprehension": 0.2, "range": 10.0}}
|
* <p>Config-driven: {@code "gagging": {"material": "ball"}} delegates to
|
||||||
|
* {@link GagMaterial} for comprehension/range from ModConfig at runtime.</p>
|
||||||
|
*
|
||||||
|
* <p>Override: {@code "gagging": {"comprehension": 0.15, "range": 8.0}} uses
|
||||||
|
* explicit values that take priority over the material lookup.</p>
|
||||||
*/
|
*/
|
||||||
public class GaggingComponent implements IItemComponent {
|
public class GaggingComponent implements IItemComponent {
|
||||||
|
|
||||||
private final double comprehension;
|
private final @Nullable String material;
|
||||||
private final double range;
|
private final double comprehensionOverride;
|
||||||
|
private final double rangeOverride;
|
||||||
|
|
||||||
private GaggingComponent(double comprehension, double range) {
|
private GaggingComponent(@Nullable String material, double comprehensionOverride, double rangeOverride) {
|
||||||
this.comprehension = comprehension;
|
this.material = material;
|
||||||
this.range = range;
|
this.comprehensionOverride = comprehensionOverride;
|
||||||
|
this.rangeOverride = rangeOverride;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IItemComponent fromJson(JsonObject config) {
|
public static IItemComponent fromJson(JsonObject config) {
|
||||||
double comprehension = 0.2;
|
String material = null;
|
||||||
double range = 10.0;
|
double comprehension = -1;
|
||||||
|
double range = -1;
|
||||||
if (config != null) {
|
if (config != null) {
|
||||||
|
if (config.has("material")) {
|
||||||
|
material = config.get("material").getAsString();
|
||||||
|
}
|
||||||
if (config.has("comprehension")) {
|
if (config.has("comprehension")) {
|
||||||
comprehension = config.get("comprehension").getAsDouble();
|
comprehension = Math.max(0.0, Math.min(1.0, config.get("comprehension").getAsDouble()));
|
||||||
}
|
}
|
||||||
if (config.has("range")) {
|
if (config.has("range")) {
|
||||||
range = config.get("range").getAsDouble();
|
range = Math.max(0.0, config.get("range").getAsDouble());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
comprehension = Math.max(0.0, Math.min(1.0, comprehension));
|
return new GaggingComponent(material, comprehension, range);
|
||||||
range = Math.max(0.0, range);
|
|
||||||
return new GaggingComponent(comprehension, range);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** How much of the gagged speech is comprehensible (0.0 = nothing, 1.0 = full). */
|
/** How much of the gagged speech is comprehensible (0.0 = nothing, 1.0 = full). */
|
||||||
public double getComprehension() {
|
public double getComprehension() {
|
||||||
return comprehension;
|
if (comprehensionOverride >= 0) return comprehensionOverride;
|
||||||
|
GagMaterial gag = getMaterial();
|
||||||
|
if (gag != null) return gag.getComprehension();
|
||||||
|
return 0.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Maximum range in blocks where muffled speech can be heard. */
|
/** Maximum range in blocks where muffled speech can be heard. */
|
||||||
public double getRange() {
|
public double getRange() {
|
||||||
return range;
|
if (rangeOverride >= 0) return rangeOverride;
|
||||||
|
GagMaterial gag = getMaterial();
|
||||||
|
if (gag != null) return gag.getTalkRange();
|
||||||
|
return 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The gag material enum, or null if not configured or invalid. */
|
||||||
|
public @Nullable GagMaterial getMaterial() {
|
||||||
|
if (material == null) return null;
|
||||||
|
try {
|
||||||
|
return GagMaterial.valueOf(material.toUpperCase());
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
TiedUpMod.LOGGER.warn("[GaggingComponent] Unknown gag material: {}", material);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The raw material string from JSON, or null. */
|
||||||
|
public @Nullable String getMaterialName() {
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appendTooltip(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
|
||||||
|
if (material != null) {
|
||||||
|
tooltip.add(Component.translatable("item.tiedup.tooltip.gag_material", material)
|
||||||
|
.withStyle(ChatFormatting.RED));
|
||||||
|
} else {
|
||||||
|
tooltip.add(Component.translatable("item.tiedup.tooltip.gagging").withStyle(ChatFormatting.RED));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
package com.tiedup.remake.v2.bondage.component;
|
package com.tiedup.remake.v2.bondage.component;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component: GPS tracking and safe zone for data-driven items.
|
* Component: GPS tracking and safe zone for data-driven items.
|
||||||
@@ -42,4 +49,14 @@ public class GpsComponent implements IItemComponent {
|
|||||||
public boolean isPublicTracking() {
|
public boolean isPublicTracking() {
|
||||||
return publicTracking;
|
return publicTracking;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appendTooltip(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
|
||||||
|
tooltip.add(Component.translatable("item.tiedup.tooltip.gps_tracking")
|
||||||
|
.withStyle(ChatFormatting.AQUA));
|
||||||
|
if (safeZoneRadius > 0) {
|
||||||
|
tooltip.add(Component.translatable("item.tiedup.tooltip.gps_zone_radius", safeZoneRadius)
|
||||||
|
.withStyle(ChatFormatting.DARK_AQUA));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
package com.tiedup.remake.v2.bondage.component;
|
package com.tiedup.remake.v2.bondage.component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A reusable behavior module for data-driven bondage items.
|
* A reusable behavior module for data-driven bondage items.
|
||||||
@@ -16,4 +21,6 @@ public interface IItemComponent {
|
|||||||
default boolean blocksUnequip(ItemStack stack, LivingEntity entity) {
|
default boolean blocksUnequip(ItemStack stack, LivingEntity entity) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void appendTooltip(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
package com.tiedup.remake.v2.bondage.component;
|
package com.tiedup.remake.v2.bondage.component;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component: lockable behavior for data-driven items.
|
* Component: lockable behavior for data-driven items.
|
||||||
@@ -41,4 +48,13 @@ public class LockableComponent implements IItemComponent {
|
|||||||
public int getLockResistance() {
|
public int getLockResistance() {
|
||||||
return lockResistance;
|
return lockResistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appendTooltip(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
|
||||||
|
tooltip.add(Component.translatable("item.tiedup.tooltip.lockable").withStyle(ChatFormatting.GOLD));
|
||||||
|
if (flag.isAdvanced()) {
|
||||||
|
tooltip.add(Component.translatable("item.tiedup.tooltip.lock_resistance", lockResistance)
|
||||||
|
.withStyle(ChatFormatting.DARK_GRAY));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,70 @@
|
|||||||
package com.tiedup.remake.v2.bondage.component;
|
package com.tiedup.remake.v2.bondage.component;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.tiedup.remake.core.SettingsAccessor;
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component: struggle resistance for data-driven items.
|
* Component: struggle resistance for data-driven items.
|
||||||
*
|
*
|
||||||
* JSON config: {@code "resistance": {"base": 150}}
|
* <p>Config-driven: {@code "resistance": {"id": "rope"}} delegates to
|
||||||
|
* {@link SettingsAccessor#getBindResistance(String)} at runtime.</p>
|
||||||
|
*
|
||||||
|
* <p>Legacy/override: {@code "resistance": {"base": 150}} uses a hardcoded value.</p>
|
||||||
*/
|
*/
|
||||||
public class ResistanceComponent implements IItemComponent {
|
public class ResistanceComponent implements IItemComponent {
|
||||||
|
|
||||||
private final int baseResistance;
|
private final @Nullable String resistanceId;
|
||||||
|
private final int fallbackBase;
|
||||||
|
|
||||||
private ResistanceComponent(int baseResistance) {
|
private ResistanceComponent(@Nullable String resistanceId, int fallbackBase) {
|
||||||
this.baseResistance = baseResistance;
|
this.resistanceId = resistanceId;
|
||||||
|
this.fallbackBase = fallbackBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IItemComponent fromJson(JsonObject config) {
|
public static IItemComponent fromJson(JsonObject config) {
|
||||||
|
String id = null;
|
||||||
int base = 100;
|
int base = 100;
|
||||||
if (config != null && config.has("base")) {
|
if (config != null) {
|
||||||
base = config.get("base").getAsInt();
|
if (config.has("id")) {
|
||||||
|
id = config.get("id").getAsString();
|
||||||
|
}
|
||||||
|
if (config.has("base")) {
|
||||||
|
base = config.get("base").getAsInt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
base = Math.max(0, base);
|
base = Math.max(0, base);
|
||||||
return new ResistanceComponent(base);
|
return new ResistanceComponent(id, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the base resistance for this item.
|
* Get the base resistance for this item.
|
||||||
|
* If a {@code resistanceId} is configured, delegates to server config at runtime.
|
||||||
|
* Otherwise returns the hardcoded fallback value.
|
||||||
*/
|
*/
|
||||||
public int getBaseResistance() {
|
public int getBaseResistance() {
|
||||||
return baseResistance;
|
if (resistanceId != null) {
|
||||||
|
return SettingsAccessor.getBindResistance(resistanceId);
|
||||||
|
}
|
||||||
|
return fallbackBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The config key used for runtime resistance lookup, or null if hardcoded. */
|
||||||
|
public @Nullable String getResistanceId() {
|
||||||
|
return resistanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appendTooltip(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
|
||||||
|
if (flag.isAdvanced()) {
|
||||||
|
tooltip.add(Component.translatable("item.tiedup.tooltip.resistance", getBaseResistance())
|
||||||
|
.withStyle(ChatFormatting.DARK_GRAY));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
package com.tiedup.remake.v2.bondage.component;
|
package com.tiedup.remake.v2.bondage.component;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component: shock collar behavior for data-driven items.
|
* Component: shock collar behavior for data-driven items.
|
||||||
@@ -49,4 +56,16 @@ public class ShockComponent implements IItemComponent {
|
|||||||
public boolean hasAutoShock() {
|
public boolean hasAutoShock() {
|
||||||
return autoInterval > 0;
|
return autoInterval > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appendTooltip(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
|
||||||
|
if (hasAutoShock()) {
|
||||||
|
float seconds = autoInterval / 20.0f;
|
||||||
|
tooltip.add(Component.translatable("item.tiedup.tooltip.shock_auto", String.format("%.1f", seconds))
|
||||||
|
.withStyle(ChatFormatting.DARK_RED));
|
||||||
|
} else {
|
||||||
|
tooltip.add(Component.translatable("item.tiedup.tooltip.shock_manual")
|
||||||
|
.withStyle(ChatFormatting.DARK_RED));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,6 +246,12 @@ public class DataDrivenBondageItem extends AbstractV2BondageItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Component tooltips
|
||||||
|
ComponentHolder holder = DataDrivenItemRegistry.getComponents(stack);
|
||||||
|
if (holder != null) {
|
||||||
|
holder.appendTooltip(stack, level, tooltip, flag);
|
||||||
|
}
|
||||||
|
|
||||||
// Lock status + escape difficulty (from AbstractV2BondageItem)
|
// Lock status + escape difficulty (from AbstractV2BondageItem)
|
||||||
super.appendHoverText(stack, level, tooltip, flag);
|
super.appendHoverText(stack, level, tooltip, flag);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user