Remove internal phase comments and format code
Strip all Phase references, TODO/FUTURE roadmap notes, and internal planning comments from the codebase. Run Prettier for consistent formatting across all Java files.
This commit is contained in:
@@ -137,12 +137,18 @@ public class DataDrivenBondageItem extends AbstractV2BondageItem {
|
||||
IV2BondageEquipment equip = V2EquipmentHelper.getEquipment(entity);
|
||||
if (equip != null) {
|
||||
int maxDifficulty = -1;
|
||||
for (Map.Entry<BodyRegionV2, ItemStack> entry : equip.getAllEquipped().entrySet()) {
|
||||
for (Map.Entry<BodyRegionV2, ItemStack> entry : equip
|
||||
.getAllEquipped()
|
||||
.entrySet()) {
|
||||
ItemStack stack = entry.getValue();
|
||||
if (stack.getItem() == this) {
|
||||
DataDrivenItemDefinition def = DataDrivenItemRegistry.get(stack);
|
||||
DataDrivenItemDefinition def =
|
||||
DataDrivenItemRegistry.get(stack);
|
||||
if (def != null) {
|
||||
maxDifficulty = Math.max(maxDifficulty, def.escapeDifficulty());
|
||||
maxDifficulty = Math.max(
|
||||
maxDifficulty,
|
||||
def.escapeDifficulty()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,12 +163,18 @@ public class DataDrivenBondageItem extends AbstractV2BondageItem {
|
||||
@Override
|
||||
public void notifyStruggle(LivingEntity entity) {
|
||||
// Play a generic chain sound for data-driven items
|
||||
entity.level().playSound(
|
||||
null, entity.getX(), entity.getY(), entity.getZ(),
|
||||
net.minecraft.sounds.SoundEvents.CHAIN_STEP,
|
||||
net.minecraft.sounds.SoundSource.PLAYERS,
|
||||
0.4f, 1.0f
|
||||
);
|
||||
entity
|
||||
.level()
|
||||
.playSound(
|
||||
null,
|
||||
entity.getX(),
|
||||
entity.getY(),
|
||||
entity.getZ(),
|
||||
net.minecraft.sounds.SoundEvents.CHAIN_STEP,
|
||||
net.minecraft.sounds.SoundSource.PLAYERS,
|
||||
0.4f,
|
||||
1.0f
|
||||
);
|
||||
}
|
||||
|
||||
// ===== DISPLAY NAME =====
|
||||
@@ -189,7 +201,9 @@ public class DataDrivenBondageItem extends AbstractV2BondageItem {
|
||||
public static ItemStack createStack(ResourceLocation itemId) {
|
||||
if (V2BondageItems.DATA_DRIVEN_ITEM == null) return ItemStack.EMPTY;
|
||||
ItemStack stack = new ItemStack(V2BondageItems.DATA_DRIVEN_ITEM.get());
|
||||
stack.getOrCreateTag().putString(DataDrivenItemRegistry.NBT_ITEM_ID, itemId.toString());
|
||||
stack
|
||||
.getOrCreateTag()
|
||||
.putString(DataDrivenItemRegistry.NBT_ITEM_ID, itemId.toString());
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,8 @@ public record DataDrivenItemDefinition(
|
||||
* Optional per-item overrides for the movement style's default values.
|
||||
* Requires {@code movementStyle} to be non-null (ignored otherwise).
|
||||
*/
|
||||
@Nullable com.tiedup.remake.v2.bondage.movement.MovementModifier movementModifier,
|
||||
@Nullable
|
||||
com.tiedup.remake.v2.bondage.movement.MovementModifier movementModifier,
|
||||
|
||||
/**
|
||||
* Per-animation bone whitelist. Maps animation name (e.g. "idle", "struggle")
|
||||
|
||||
@@ -52,7 +52,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
*/
|
||||
public final class DataDrivenItemParser {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("DataDrivenItems");
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
"DataDrivenItems"
|
||||
);
|
||||
|
||||
private DataDrivenItemParser() {}
|
||||
|
||||
@@ -64,7 +66,10 @@ public final class DataDrivenItemParser {
|
||||
* @return the parsed definition, or null if the file is invalid
|
||||
*/
|
||||
@Nullable
|
||||
public static DataDrivenItemDefinition parse(InputStream input, ResourceLocation fileId) {
|
||||
public static DataDrivenItemDefinition parse(
|
||||
InputStream input,
|
||||
ResourceLocation fileId
|
||||
) {
|
||||
try {
|
||||
JsonObject root = JsonParser.parseReader(
|
||||
new InputStreamReader(input, StandardCharsets.UTF_8)
|
||||
@@ -72,7 +77,11 @@ public final class DataDrivenItemParser {
|
||||
|
||||
return parseObject(root, fileId);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("[DataDrivenItems] Failed to parse JSON {}: {}", fileId, e.getMessage());
|
||||
LOGGER.error(
|
||||
"[DataDrivenItems] Failed to parse JSON {}: {}",
|
||||
fileId,
|
||||
e.getMessage()
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -85,19 +94,28 @@ public final class DataDrivenItemParser {
|
||||
* @return the parsed definition, or null if validation fails
|
||||
*/
|
||||
@Nullable
|
||||
public static DataDrivenItemDefinition parseObject(JsonObject root, ResourceLocation fileId) {
|
||||
public static DataDrivenItemDefinition parseObject(
|
||||
JsonObject root,
|
||||
ResourceLocation fileId
|
||||
) {
|
||||
// Validate type field
|
||||
String type = getStringOrNull(root, "type");
|
||||
if (!"tiedup:bondage_item".equals(type)) {
|
||||
LOGGER.error("[DataDrivenItems] Skipping {}: invalid or missing type '{}' (expected 'tiedup:bondage_item')",
|
||||
fileId, type);
|
||||
LOGGER.error(
|
||||
"[DataDrivenItems] Skipping {}: invalid or missing type '{}' (expected 'tiedup:bondage_item')",
|
||||
fileId,
|
||||
type
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Required: display_name
|
||||
String displayName = getStringOrNull(root, "display_name");
|
||||
if (displayName == null || displayName.isEmpty()) {
|
||||
LOGGER.error("[DataDrivenItems] Skipping {}: missing 'display_name'", fileId);
|
||||
LOGGER.error(
|
||||
"[DataDrivenItems] Skipping {}: missing 'display_name'",
|
||||
fileId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -107,33 +125,63 @@ public final class DataDrivenItemParser {
|
||||
// Required: model
|
||||
String modelStr = getStringOrNull(root, "model");
|
||||
if (modelStr == null || modelStr.isEmpty()) {
|
||||
LOGGER.error("[DataDrivenItems] Skipping {}: missing 'model'", fileId);
|
||||
LOGGER.error(
|
||||
"[DataDrivenItems] Skipping {}: missing 'model'",
|
||||
fileId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
ResourceLocation modelLocation = ResourceLocation.tryParse(modelStr);
|
||||
if (modelLocation == null) {
|
||||
LOGGER.error("[DataDrivenItems] Skipping {}: invalid model ResourceLocation '{}'", fileId, modelStr);
|
||||
LOGGER.error(
|
||||
"[DataDrivenItems] Skipping {}: invalid model ResourceLocation '{}'",
|
||||
fileId,
|
||||
modelStr
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Optional: slim_model
|
||||
ResourceLocation slimModelLocation = parseOptionalResourceLocation(root, "slim_model", fileId);
|
||||
ResourceLocation slimModelLocation = parseOptionalResourceLocation(
|
||||
root,
|
||||
"slim_model",
|
||||
fileId
|
||||
);
|
||||
|
||||
// Optional: texture
|
||||
ResourceLocation texturePath = parseOptionalResourceLocation(root, "texture", fileId);
|
||||
ResourceLocation texturePath = parseOptionalResourceLocation(
|
||||
root,
|
||||
"texture",
|
||||
fileId
|
||||
);
|
||||
|
||||
// Optional: animation_source
|
||||
ResourceLocation animationSource = parseOptionalResourceLocation(root, "animation_source", fileId);
|
||||
ResourceLocation animationSource = parseOptionalResourceLocation(
|
||||
root,
|
||||
"animation_source",
|
||||
fileId
|
||||
);
|
||||
|
||||
// Required: regions (non-empty)
|
||||
Set<BodyRegionV2> occupiedRegions = parseRegions(root, "regions", fileId);
|
||||
Set<BodyRegionV2> occupiedRegions = parseRegions(
|
||||
root,
|
||||
"regions",
|
||||
fileId
|
||||
);
|
||||
if (occupiedRegions == null || occupiedRegions.isEmpty()) {
|
||||
LOGGER.error("[DataDrivenItems] Skipping {}: missing or empty 'regions'", fileId);
|
||||
LOGGER.error(
|
||||
"[DataDrivenItems] Skipping {}: missing or empty 'regions'",
|
||||
fileId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Optional: blocked_regions (defaults to regions)
|
||||
Set<BodyRegionV2> blockedRegions = parseRegions(root, "blocked_regions", fileId);
|
||||
Set<BodyRegionV2> blockedRegions = parseRegions(
|
||||
root,
|
||||
"blocked_regions",
|
||||
fileId
|
||||
);
|
||||
if (blockedRegions == null || blockedRegions.isEmpty()) {
|
||||
blockedRegions = occupiedRegions;
|
||||
}
|
||||
@@ -148,13 +196,25 @@ public final class DataDrivenItemParser {
|
||||
boolean lockable = getBooleanOrDefault(root, "lockable", true);
|
||||
|
||||
// Optional: supports_color (default false)
|
||||
boolean supportsColor = getBooleanOrDefault(root, "supports_color", false);
|
||||
boolean supportsColor = getBooleanOrDefault(
|
||||
root,
|
||||
"supports_color",
|
||||
false
|
||||
);
|
||||
|
||||
// Optional: tint_channels (default empty)
|
||||
Map<String, Integer> tintChannels = parseTintChannels(root, "tint_channels", fileId);
|
||||
Map<String, Integer> tintChannels = parseTintChannels(
|
||||
root,
|
||||
"tint_channels",
|
||||
fileId
|
||||
);
|
||||
|
||||
// Optional: icon (item model ResourceLocation for inventory sprite)
|
||||
ResourceLocation icon = parseOptionalResourceLocation(root, "icon", fileId);
|
||||
ResourceLocation icon = parseOptionalResourceLocation(
|
||||
root,
|
||||
"icon",
|
||||
fileId
|
||||
);
|
||||
|
||||
// Optional: movement_style (requires valid MovementStyle name)
|
||||
MovementStyle movementStyle = null;
|
||||
@@ -162,14 +222,21 @@ public final class DataDrivenItemParser {
|
||||
if (movementStyleStr != null && !movementStyleStr.isEmpty()) {
|
||||
movementStyle = MovementStyle.fromName(movementStyleStr);
|
||||
if (movementStyle == null) {
|
||||
LOGGER.warn("[DataDrivenItems] In {}: unknown movement_style '{}', ignoring",
|
||||
fileId, movementStyleStr);
|
||||
LOGGER.warn(
|
||||
"[DataDrivenItems] In {}: unknown movement_style '{}', ignoring",
|
||||
fileId,
|
||||
movementStyleStr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Optional: movement_modifier (requires movement_style to be set)
|
||||
MovementModifier movementModifier = null;
|
||||
if (movementStyle != null && root.has("movement_modifier") && root.get("movement_modifier").isJsonObject()) {
|
||||
if (
|
||||
movementStyle != null &&
|
||||
root.has("movement_modifier") &&
|
||||
root.get("movement_modifier").isJsonObject()
|
||||
) {
|
||||
JsonObject modObj = root.getAsJsonObject("movement_modifier");
|
||||
Float speedMul = getFloatOrNull(modObj, "speed_multiplier");
|
||||
Boolean jumpDis = getBooleanOrNull(modObj, "jump_disabled");
|
||||
@@ -177,14 +244,22 @@ public final class DataDrivenItemParser {
|
||||
movementModifier = new MovementModifier(speedMul, jumpDis);
|
||||
}
|
||||
} else if (movementStyle == null && root.has("movement_modifier")) {
|
||||
LOGGER.warn("[DataDrivenItems] In {}: movement_modifier ignored because movement_style is absent",
|
||||
fileId);
|
||||
LOGGER.warn(
|
||||
"[DataDrivenItems] In {}: movement_modifier ignored because movement_style is absent",
|
||||
fileId
|
||||
);
|
||||
}
|
||||
|
||||
// Required: animation_bones (per-animation bone whitelist)
|
||||
Map<String, Set<String>> animationBones = parseAnimationBones(root, fileId);
|
||||
Map<String, Set<String>> animationBones = parseAnimationBones(
|
||||
root,
|
||||
fileId
|
||||
);
|
||||
if (animationBones == null) {
|
||||
LOGGER.error("[DataDrivenItems] Skipping {}: missing or invalid 'animation_bones'", fileId);
|
||||
LOGGER.error(
|
||||
"[DataDrivenItems] Skipping {}: missing or invalid 'animation_bones'",
|
||||
fileId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -200,14 +275,30 @@ public final class DataDrivenItemParser {
|
||||
if (idPath.endsWith(".json")) {
|
||||
idPath = idPath.substring(0, idPath.length() - 5);
|
||||
}
|
||||
ResourceLocation id = new ResourceLocation(fileId.getNamespace(), idPath);
|
||||
ResourceLocation id = new ResourceLocation(
|
||||
fileId.getNamespace(),
|
||||
idPath
|
||||
);
|
||||
|
||||
return new DataDrivenItemDefinition(
|
||||
id, displayName, translationKey, modelLocation, slimModelLocation,
|
||||
texturePath, animationSource, occupiedRegions, blockedRegions,
|
||||
posePriority, escapeDifficulty,
|
||||
lockable, supportsColor, tintChannels, icon,
|
||||
movementStyle, movementModifier, animationBones
|
||||
id,
|
||||
displayName,
|
||||
translationKey,
|
||||
modelLocation,
|
||||
slimModelLocation,
|
||||
texturePath,
|
||||
animationSource,
|
||||
occupiedRegions,
|
||||
blockedRegions,
|
||||
posePriority,
|
||||
escapeDifficulty,
|
||||
lockable,
|
||||
supportsColor,
|
||||
tintChannels,
|
||||
icon,
|
||||
movementStyle,
|
||||
movementModifier,
|
||||
animationBones
|
||||
);
|
||||
}
|
||||
|
||||
@@ -223,7 +314,11 @@ public final class DataDrivenItemParser {
|
||||
}
|
||||
}
|
||||
|
||||
private static int getIntOrDefault(JsonObject obj, String key, int defaultValue) {
|
||||
private static int getIntOrDefault(
|
||||
JsonObject obj,
|
||||
String key,
|
||||
int defaultValue
|
||||
) {
|
||||
if (!obj.has(key) || obj.get(key).isJsonNull()) return defaultValue;
|
||||
try {
|
||||
return obj.get(key).getAsInt();
|
||||
@@ -232,7 +327,11 @@ public final class DataDrivenItemParser {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean getBooleanOrDefault(JsonObject obj, String key, boolean defaultValue) {
|
||||
private static boolean getBooleanOrDefault(
|
||||
JsonObject obj,
|
||||
String key,
|
||||
boolean defaultValue
|
||||
) {
|
||||
if (!obj.has(key) || obj.get(key).isJsonNull()) return defaultValue;
|
||||
try {
|
||||
return obj.get(key).getAsBoolean();
|
||||
@@ -263,13 +362,20 @@ public final class DataDrivenItemParser {
|
||||
|
||||
@Nullable
|
||||
private static ResourceLocation parseOptionalResourceLocation(
|
||||
JsonObject obj, String key, ResourceLocation fileId
|
||||
JsonObject obj,
|
||||
String key,
|
||||
ResourceLocation fileId
|
||||
) {
|
||||
String value = getStringOrNull(obj, key);
|
||||
if (value == null || value.isEmpty()) return null;
|
||||
ResourceLocation loc = ResourceLocation.tryParse(value);
|
||||
if (loc == null) {
|
||||
LOGGER.warn("[DataDrivenItems] In {}: invalid ResourceLocation for '{}': '{}'", fileId, key, value);
|
||||
LOGGER.warn(
|
||||
"[DataDrivenItems] In {}: invalid ResourceLocation for '{}': '{}'",
|
||||
fileId,
|
||||
key,
|
||||
value
|
||||
);
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
@@ -279,7 +385,11 @@ public final class DataDrivenItemParser {
|
||||
* Unknown region names are logged as warnings and skipped.
|
||||
*/
|
||||
@Nullable
|
||||
private static Set<BodyRegionV2> parseRegions(JsonObject obj, String key, ResourceLocation fileId) {
|
||||
private static Set<BodyRegionV2> parseRegions(
|
||||
JsonObject obj,
|
||||
String key,
|
||||
ResourceLocation fileId
|
||||
) {
|
||||
if (!obj.has(key) || !obj.get(key).isJsonArray()) return null;
|
||||
|
||||
JsonArray arr = obj.getAsJsonArray(key);
|
||||
@@ -293,12 +403,20 @@ public final class DataDrivenItemParser {
|
||||
if (region != null) {
|
||||
regions.add(region);
|
||||
} else {
|
||||
LOGGER.warn("[DataDrivenItems] In {}: unknown region '{}' in '{}', skipping",
|
||||
fileId, name, key);
|
||||
LOGGER.warn(
|
||||
"[DataDrivenItems] In {}: unknown region '{}' in '{}', skipping",
|
||||
fileId,
|
||||
name,
|
||||
key
|
||||
);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("[DataDrivenItems] In {}: invalid element in '{}': {}",
|
||||
fileId, key, e.getMessage());
|
||||
LOGGER.warn(
|
||||
"[DataDrivenItems] In {}: invalid element in '{}': {}",
|
||||
fileId,
|
||||
key,
|
||||
e.getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,18 +439,29 @@ public final class DataDrivenItemParser {
|
||||
* @param fileId the source file for error messages
|
||||
* @return an unmodifiable map of channel names to RGB ints, or empty map if absent
|
||||
*/
|
||||
private static Map<String, Integer> parseTintChannels(JsonObject obj, String key, ResourceLocation fileId) {
|
||||
private static Map<String, Integer> parseTintChannels(
|
||||
JsonObject obj,
|
||||
String key,
|
||||
ResourceLocation fileId
|
||||
) {
|
||||
if (!obj.has(key) || !obj.get(key).isJsonObject()) return Map.of();
|
||||
JsonObject channels = obj.getAsJsonObject(key);
|
||||
Map<String, Integer> result = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, JsonElement> entry : channels.entrySet()) {
|
||||
try {
|
||||
String hex = entry.getValue().getAsString();
|
||||
int color = Integer.parseInt(hex.startsWith("#") ? hex.substring(1) : hex, 16);
|
||||
int color = Integer.parseInt(
|
||||
hex.startsWith("#") ? hex.substring(1) : hex,
|
||||
16
|
||||
);
|
||||
result.put(entry.getKey(), color);
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.warn("[DataDrivenItems] In {}: invalid hex color '{}' for tint channel '{}'",
|
||||
fileId, entry.getValue(), entry.getKey());
|
||||
LOGGER.warn(
|
||||
"[DataDrivenItems] In {}: invalid hex color '{}' for tint channel '{}'",
|
||||
fileId,
|
||||
entry.getValue(),
|
||||
entry.getKey()
|
||||
);
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableMap(result);
|
||||
@@ -340,7 +469,12 @@ public final class DataDrivenItemParser {
|
||||
|
||||
/** Valid PlayerAnimator bone names for animation_bones validation. */
|
||||
private static final Set<String> VALID_BONE_NAMES = Set.of(
|
||||
"head", "body", "rightArm", "leftArm", "rightLeg", "leftLeg"
|
||||
"head",
|
||||
"body",
|
||||
"rightArm",
|
||||
"leftArm",
|
||||
"rightLeg",
|
||||
"leftLeg"
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -364,14 +498,23 @@ public final class DataDrivenItemParser {
|
||||
* @return unmodifiable map of animation name to bone set, or null if absent/invalid
|
||||
*/
|
||||
@Nullable
|
||||
private static Map<String, Set<String>> parseAnimationBones(JsonObject obj, ResourceLocation fileId) {
|
||||
if (!obj.has("animation_bones") || !obj.get("animation_bones").isJsonObject()) {
|
||||
private static Map<String, Set<String>> parseAnimationBones(
|
||||
JsonObject obj,
|
||||
ResourceLocation fileId
|
||||
) {
|
||||
if (
|
||||
!obj.has("animation_bones") ||
|
||||
!obj.get("animation_bones").isJsonObject()
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JsonObject bonesObj = obj.getAsJsonObject("animation_bones");
|
||||
if (bonesObj.size() == 0) {
|
||||
LOGGER.error("[DataDrivenItems] In {}: 'animation_bones' is empty", fileId);
|
||||
LOGGER.error(
|
||||
"[DataDrivenItems] In {}: 'animation_bones' is empty",
|
||||
fileId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -381,8 +524,11 @@ public final class DataDrivenItemParser {
|
||||
JsonElement value = entry.getValue();
|
||||
|
||||
if (!value.isJsonArray()) {
|
||||
LOGGER.warn("[DataDrivenItems] In {}: animation_bones['{}'] is not an array, skipping",
|
||||
fileId, animName);
|
||||
LOGGER.warn(
|
||||
"[DataDrivenItems] In {}: animation_bones['{}'] is not an array, skipping",
|
||||
fileId,
|
||||
animName
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -394,29 +540,41 @@ public final class DataDrivenItemParser {
|
||||
if (VALID_BONE_NAMES.contains(boneName)) {
|
||||
bones.add(boneName);
|
||||
} else {
|
||||
LOGGER.warn("[DataDrivenItems] In {}: animation_bones['{}'] contains unknown bone '{}', skipping",
|
||||
fileId, animName, boneName);
|
||||
LOGGER.warn(
|
||||
"[DataDrivenItems] In {}: animation_bones['{}'] contains unknown bone '{}', skipping",
|
||||
fileId,
|
||||
animName,
|
||||
boneName
|
||||
);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("[DataDrivenItems] In {}: invalid element in animation_bones['{}']",
|
||||
fileId, animName);
|
||||
LOGGER.warn(
|
||||
"[DataDrivenItems] In {}: invalid element in animation_bones['{}']",
|
||||
fileId,
|
||||
animName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!bones.isEmpty()) {
|
||||
result.put(animName, Collections.unmodifiableSet(bones));
|
||||
} else {
|
||||
LOGGER.warn("[DataDrivenItems] In {}: animation_bones['{}'] resolved to empty set, skipping",
|
||||
fileId, animName);
|
||||
LOGGER.warn(
|
||||
"[DataDrivenItems] In {}: animation_bones['{}'] resolved to empty set, skipping",
|
||||
fileId,
|
||||
animName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isEmpty()) {
|
||||
LOGGER.error("[DataDrivenItems] In {}: 'animation_bones' has no valid entries", fileId);
|
||||
LOGGER.error(
|
||||
"[DataDrivenItems] In {}: 'animation_bones' has no valid entries",
|
||||
fileId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,7 +29,10 @@ public final class DataDrivenItemRegistry {
|
||||
* Volatile reference to an unmodifiable map. Reload builds a new map
|
||||
* and swaps atomically; consumer threads always see a consistent snapshot.
|
||||
*/
|
||||
private static volatile Map<ResourceLocation, DataDrivenItemDefinition> DEFINITIONS = Map.of();
|
||||
private static volatile Map<
|
||||
ResourceLocation,
|
||||
DataDrivenItemDefinition
|
||||
> DEFINITIONS = Map.of();
|
||||
|
||||
private DataDrivenItemRegistry() {}
|
||||
|
||||
@@ -39,7 +42,9 @@ public final class DataDrivenItemRegistry {
|
||||
*
|
||||
* @param newDefs the new definitions map (will be defensively copied)
|
||||
*/
|
||||
public static void reload(Map<ResourceLocation, DataDrivenItemDefinition> newDefs) {
|
||||
public static void reload(
|
||||
Map<ResourceLocation, DataDrivenItemDefinition> newDefs
|
||||
) {
|
||||
DEFINITIONS = Collections.unmodifiableMap(new HashMap<>(newDefs));
|
||||
}
|
||||
|
||||
@@ -53,8 +58,12 @@ public final class DataDrivenItemRegistry {
|
||||
*
|
||||
* @param newDefs the definitions to merge (will overwrite existing entries with same key)
|
||||
*/
|
||||
public static void mergeAll(Map<ResourceLocation, DataDrivenItemDefinition> newDefs) {
|
||||
Map<ResourceLocation, DataDrivenItemDefinition> merged = new HashMap<>(DEFINITIONS);
|
||||
public static void mergeAll(
|
||||
Map<ResourceLocation, DataDrivenItemDefinition> newDefs
|
||||
) {
|
||||
Map<ResourceLocation, DataDrivenItemDefinition> merged = new HashMap<>(
|
||||
DEFINITIONS
|
||||
);
|
||||
merged.putAll(newDefs);
|
||||
DEFINITIONS = Collections.unmodifiableMap(merged);
|
||||
}
|
||||
@@ -81,7 +90,9 @@ public final class DataDrivenItemRegistry {
|
||||
if (stack.isEmpty()) return null;
|
||||
CompoundTag tag = stack.getTag();
|
||||
if (tag == null || !tag.contains(NBT_ITEM_ID)) return null;
|
||||
ResourceLocation id = ResourceLocation.tryParse(tag.getString(NBT_ITEM_ID));
|
||||
ResourceLocation id = ResourceLocation.tryParse(
|
||||
tag.getString(NBT_ITEM_ID)
|
||||
);
|
||||
if (id == null) return null;
|
||||
return DEFINITIONS.get(id);
|
||||
}
|
||||
|
||||
@@ -21,50 +21,80 @@ import org.apache.logging.log4j.Logger;
|
||||
* <p>Follows the same pattern as {@link com.tiedup.remake.client.animation.context.ContextGlbRegistry}:
|
||||
* prepare phase is a no-op, apply phase scans + parses + atomic-swaps the registry.</p>
|
||||
*/
|
||||
public class DataDrivenItemReloadListener extends SimplePreparableReloadListener<Void> {
|
||||
public class DataDrivenItemReloadListener
|
||||
extends SimplePreparableReloadListener<Void>
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("DataDrivenItems");
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
"DataDrivenItems"
|
||||
);
|
||||
|
||||
/** Resource directory containing item definition JSON files. */
|
||||
private static final String DIRECTORY = "tiedup_items";
|
||||
|
||||
@Override
|
||||
protected Void prepare(ResourceManager resourceManager, ProfilerFiller profiler) {
|
||||
protected Void prepare(
|
||||
ResourceManager resourceManager,
|
||||
ProfilerFiller profiler
|
||||
) {
|
||||
// No preparation needed — parsing happens in apply phase
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void apply(Void nothing, ResourceManager resourceManager, ProfilerFiller profiler) {
|
||||
Map<ResourceLocation, DataDrivenItemDefinition> newDefs = new HashMap<>();
|
||||
protected void apply(
|
||||
Void nothing,
|
||||
ResourceManager resourceManager,
|
||||
ProfilerFiller profiler
|
||||
) {
|
||||
Map<ResourceLocation, DataDrivenItemDefinition> newDefs =
|
||||
new HashMap<>();
|
||||
|
||||
Map<ResourceLocation, Resource> resources = resourceManager.listResources(
|
||||
DIRECTORY, loc -> loc.getPath().endsWith(".json")
|
||||
);
|
||||
Map<ResourceLocation, Resource> resources =
|
||||
resourceManager.listResources(DIRECTORY, loc ->
|
||||
loc.getPath().endsWith(".json")
|
||||
);
|
||||
|
||||
int skipped = 0;
|
||||
|
||||
for (Map.Entry<ResourceLocation, Resource> entry : resources.entrySet()) {
|
||||
for (Map.Entry<
|
||||
ResourceLocation,
|
||||
Resource
|
||||
> entry : resources.entrySet()) {
|
||||
ResourceLocation fileId = entry.getKey();
|
||||
Resource resource = entry.getValue();
|
||||
|
||||
try (InputStream input = resource.open()) {
|
||||
DataDrivenItemDefinition def = DataDrivenItemParser.parse(input, fileId);
|
||||
DataDrivenItemDefinition def = DataDrivenItemParser.parse(
|
||||
input,
|
||||
fileId
|
||||
);
|
||||
|
||||
if (def != null) {
|
||||
// Check for duplicate IDs
|
||||
if (newDefs.containsKey(def.id())) {
|
||||
LOGGER.warn("[DataDrivenItems] Duplicate item ID '{}' from file '{}' — overwriting previous definition",
|
||||
def.id(), fileId);
|
||||
LOGGER.warn(
|
||||
"[DataDrivenItems] Duplicate item ID '{}' from file '{}' — overwriting previous definition",
|
||||
def.id(),
|
||||
fileId
|
||||
);
|
||||
}
|
||||
|
||||
newDefs.put(def.id(), def);
|
||||
LOGGER.debug("[DataDrivenItems] Loaded: {} -> '{}'", def.id(), def.displayName());
|
||||
LOGGER.debug(
|
||||
"[DataDrivenItems] Loaded: {} -> '{}'",
|
||||
def.id(),
|
||||
def.displayName()
|
||||
);
|
||||
} else {
|
||||
skipped++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("[DataDrivenItems] Failed to read resource {}: {}", fileId, e.getMessage());
|
||||
LOGGER.error(
|
||||
"[DataDrivenItems] Failed to read resource {}: {}",
|
||||
fileId,
|
||||
e.getMessage()
|
||||
);
|
||||
skipped++;
|
||||
}
|
||||
}
|
||||
@@ -73,7 +103,11 @@ public class DataDrivenItemReloadListener extends SimplePreparableReloadListener
|
||||
// overwrite client-only definitions on integrated server
|
||||
DataDrivenItemRegistry.mergeAll(newDefs);
|
||||
|
||||
LOGGER.info("[DataDrivenItems] Loaded {} item definitions ({} skipped) from {} JSON files",
|
||||
newDefs.size(), skipped, resources.size());
|
||||
LOGGER.info(
|
||||
"[DataDrivenItems] Loaded {} item definitions ({} skipped) from {} JSON files",
|
||||
newDefs.size(),
|
||||
skipped,
|
||||
resources.size()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,50 +23,80 @@ import org.apache.logging.log4j.Logger;
|
||||
* <p>Registered via {@link net.minecraftforge.event.AddReloadListenerEvent} in
|
||||
* {@link com.tiedup.remake.core.TiedUpMod.ForgeEvents}.</p>
|
||||
*/
|
||||
public class DataDrivenItemServerReloadListener extends SimplePreparableReloadListener<Void> {
|
||||
public class DataDrivenItemServerReloadListener
|
||||
extends SimplePreparableReloadListener<Void>
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("DataDrivenItems");
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
"DataDrivenItems"
|
||||
);
|
||||
|
||||
/** Resource directory containing item definition JSON files (under data/). */
|
||||
private static final String DIRECTORY = "tiedup_items";
|
||||
|
||||
@Override
|
||||
protected Void prepare(ResourceManager resourceManager, ProfilerFiller profiler) {
|
||||
protected Void prepare(
|
||||
ResourceManager resourceManager,
|
||||
ProfilerFiller profiler
|
||||
) {
|
||||
// No preparation needed -- parsing happens in apply phase
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void apply(Void nothing, ResourceManager resourceManager, ProfilerFiller profiler) {
|
||||
Map<ResourceLocation, DataDrivenItemDefinition> newDefs = new HashMap<>();
|
||||
protected void apply(
|
||||
Void nothing,
|
||||
ResourceManager resourceManager,
|
||||
ProfilerFiller profiler
|
||||
) {
|
||||
Map<ResourceLocation, DataDrivenItemDefinition> newDefs =
|
||||
new HashMap<>();
|
||||
|
||||
Map<ResourceLocation, Resource> resources = resourceManager.listResources(
|
||||
DIRECTORY, loc -> loc.getPath().endsWith(".json")
|
||||
);
|
||||
Map<ResourceLocation, Resource> resources =
|
||||
resourceManager.listResources(DIRECTORY, loc ->
|
||||
loc.getPath().endsWith(".json")
|
||||
);
|
||||
|
||||
int skipped = 0;
|
||||
|
||||
for (Map.Entry<ResourceLocation, Resource> entry : resources.entrySet()) {
|
||||
for (Map.Entry<
|
||||
ResourceLocation,
|
||||
Resource
|
||||
> entry : resources.entrySet()) {
|
||||
ResourceLocation fileId = entry.getKey();
|
||||
Resource resource = entry.getValue();
|
||||
|
||||
try (InputStream input = resource.open()) {
|
||||
DataDrivenItemDefinition def = DataDrivenItemParser.parse(input, fileId);
|
||||
DataDrivenItemDefinition def = DataDrivenItemParser.parse(
|
||||
input,
|
||||
fileId
|
||||
);
|
||||
|
||||
if (def != null) {
|
||||
// Check for duplicate IDs
|
||||
if (newDefs.containsKey(def.id())) {
|
||||
LOGGER.warn("[DataDrivenItems] Server: Duplicate item ID '{}' from file '{}' -- overwriting previous definition",
|
||||
def.id(), fileId);
|
||||
LOGGER.warn(
|
||||
"[DataDrivenItems] Server: Duplicate item ID '{}' from file '{}' -- overwriting previous definition",
|
||||
def.id(),
|
||||
fileId
|
||||
);
|
||||
}
|
||||
|
||||
newDefs.put(def.id(), def);
|
||||
LOGGER.debug("[DataDrivenItems] Server loaded: {} -> '{}'", def.id(), def.displayName());
|
||||
LOGGER.debug(
|
||||
"[DataDrivenItems] Server loaded: {} -> '{}'",
|
||||
def.id(),
|
||||
def.displayName()
|
||||
);
|
||||
} else {
|
||||
skipped++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("[DataDrivenItems] Server: Failed to read resource {}: {}", fileId, e.getMessage());
|
||||
LOGGER.error(
|
||||
"[DataDrivenItems] Server: Failed to read resource {}: {}",
|
||||
fileId,
|
||||
e.getMessage()
|
||||
);
|
||||
skipped++;
|
||||
}
|
||||
}
|
||||
@@ -75,7 +105,11 @@ public class DataDrivenItemServerReloadListener extends SimplePreparableReloadLi
|
||||
// definitions aren't overwritten on integrated server
|
||||
DataDrivenItemRegistry.mergeAll(newDefs);
|
||||
|
||||
LOGGER.info("[DataDrivenItems] Server loaded {} item definitions ({} skipped) from {} JSON files",
|
||||
newDefs.size(), skipped, resources.size());
|
||||
LOGGER.info(
|
||||
"[DataDrivenItems] Server loaded {} item definitions ({} skipped) from {} JSON files",
|
||||
newDefs.size(),
|
||||
skipped,
|
||||
resources.size()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user