Files
Server/src/engine/parsers/cache/ItemParser.java
T

248 lines
13 KiB
Java
Raw Normal View History

2026-10-17 09:51:20 -04:00
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.parsers.cache;
import engine.gameManager.ConfigManager;
import engine.mbEnums;
import engine.parsers.objects.ItemTemplate;
import org.json.JSONArray;
import org.json.JSONObject;
import org.pmw.tinylog.Logger;
import java.io.File;
import java.util.HashMap;
// Loads ITEM templates from the client cache JSON (COBJECTS/ITEM/<id>.json).
public class ItemParser {
private static final String itemPath = ConfigManager.DEFAULT_DATA_DIR + "COBJECTS/ITEM/";
public static HashMap<Integer, ItemTemplate> parseItemFolder() {
HashMap<Integer, ItemTemplate> itemTemplates = new HashMap<>();
File[] itemFiles = CacheParserUtil.listJsonFiles(itemPath);
int templateId;
JSONObject itemJson;
int failedCount = 0;
for (File itemFile : itemFiles) {
try {
templateId = CacheParserUtil.templateIdFromFile(itemFile);
itemJson = CacheParserUtil.readJsonFile(itemFile);
itemTemplates.put(templateId, parseItemEntry(templateId, itemJson));
} catch (Exception e) {
Logger.error(itemFile.getName() + ": " + e);
failedCount++;
}
}
Logger.info("Loaded " + itemTemplates.size() + " of " + itemFiles.length + " item templates");
// Partial item data is never usable; null tells the caller to abort
if (failedCount > 0)
return null;
return itemTemplates;
}
private static ItemTemplate parseItemEntry(int templateId, JSONObject itemJson) {
ItemTemplate item = new ItemTemplate();
JSONObject raceReq;
JSONObject classReq;
JSONObject discReq;
JSONArray itemFlags;
JSONArray useFlags;
String flag;
Object stubJson;
JSONArray stubHolder;
item.template_id = templateId;
// obj_
item.obj_name = itemJson.getString("obj_name");
item.obj_pickable = itemJson.getBoolean("obj_pickable");
item.obj_gravity = itemJson.getFloat("obj_gravity");
item.obj_cull_distance = itemJson.getFloat("obj_cull_distance");
item.obj_scale = CacheParserUtil.readVector3(itemJson.getJSONArray("obj_scale"));
item.obj_render_object = itemJson.getInt("obj_render_object");
item.obj_double_fusion = itemJson.getBoolean("obj_double_fusion");
item.obj_forward_vector = CacheParserUtil.readVector3(itemJson.getJSONArray("obj_forward_vector"));
item.obj_tracking_name = itemJson.getString("obj_tracking_name");
item.obj_max_tracking_distance = itemJson.getFloat("obj_max_tracking_distance");
item.obj_icon = itemJson.getInt("obj_icon");
item.obj_gravity_f = itemJson.getFloat("obj_gravity_f");
item.obj_sound_events.putAll(CacheParserUtil.readStringValueMap(itemJson.getJSONArray("obj_sound_events"), "sound_type", "sound_event"));
item.obj_arc_hardpoint_list = itemJson.getJSONArray("obj_arc_hardpoint_list");
item.obj_sparse_data.putAll(CacheParserUtil.readSparseData(itemJson.getJSONObject("obj_sparse_data")));
item.obj_render_object_low_detail = itemJson.getInt("obj_render_object_low_detail");
item.obj_default_alignment = CacheParserUtil.readVector3(itemJson.getJSONArray("obj_default_alignment"));
item.obj_sound_table = CacheParserUtil.readHashLabel(itemJson, "obj_sound_table", templateId);
// combat_
item.combat_health_current = itemJson.getFloat("combat_health_current");
item.combat_health_full = itemJson.getFloat("combat_health_full");
item.combat_attack_resist.putAll(CacheParserUtil.readEnumFloatMap(mbEnums.DamageType.class, itemJson.getJSONObject("combat_attack_resist"),
templateId, "combat_attack_resist"));
item.combat_powers = itemJson.getJSONArray("combat_powers");
// item_
item.item_type = CacheParserUtil.readEnum(mbEnums.ItemType.class, itemJson.getString("item_type"), templateId, "item_type");
item.item_eq_slots_value = itemJson.getInt("item_eq_slots_value");
item.item_eq_slots_type = itemJson.getBoolean("item_eq_slots_type");
// The exporter writes ["NONE"] for an empty slot mask
item.item_eq_slots_or.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, itemJson.getJSONArray("item_eq_slots_or"), templateId, "item_eq_slots_or"));
item.item_eq_slots_or.remove(mbEnums.EquipSlotType.NONE);
item.item_eq_slots_and.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, itemJson.getJSONArray("item_eq_slots_and"), templateId, "item_eq_slots_and"));
item.item_eq_slots_and.remove(mbEnums.EquipSlotType.NONE);
item.item_takeable = itemJson.getBoolean("item_takeable");
item.item_value = itemJson.getInt("item_value");
item.item_wt = itemJson.getInt("item_wt");
item.item_passive_defense_mod = itemJson.getFloat("item_passive_defense_mod");
item.item_base_name = itemJson.getString("item_base_name");
item.item_dsc = itemJson.getString("item_dsc");
item.item_render_object_female = itemJson.getInt("item_render_object_female");
item.item_health_full = itemJson.getFloat("item_health_full");
item.item_skill_used = CacheParserUtil.readHashLabel(itemJson, "item_skill_used", templateId);
item.item_skill_mastery_used = CacheParserUtil.readHashLabel(itemJson, "item_skill_mastery_used", templateId);
item.item_parry_anim_id = itemJson.getInt("item_parry_anim_id");
item.item_offering_info.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, itemJson.getJSONArray("item_offering_info"),
"offering_type", "offering_value", templateId, "item_offering_info"));
// The client reads these blocks by item type, not by key presence
if (item.item_type == mbEnums.ItemType.WEAPON) {
item.item_weapon = parseWeapon(templateId, itemJson.getJSONObject("item_weapon"));
item.item_primary_attr = CacheParserUtil.readEnum(mbEnums.AttributeType.class, itemJson.getString("item_primary_attr"), templateId, "item_primary_attr");
item.item_secondary_attr = CacheParserUtil.readEnum(mbEnums.AttributeType.class, itemJson.getString("item_secondary_attr"), templateId, "item_secondary_attr");
}
if (item.item_type == mbEnums.ItemType.ARMOR) {
item.item_bulk_factor = itemJson.getFloat("item_bulk_factor");
item.item_defense_rating = itemJson.getInt("item_defense_rating");
}
// "None" is bit 0 in the client's flag tables, not a real flag
itemFlags = itemJson.getJSONArray("item_flags");
for (int i = 0; i < itemFlags.length(); i++) {
flag = itemFlags.getString(i);
if (flag.equals("None"))
continue;
item.item_flags.add(CacheParserUtil.readEnum(mbEnums.ItemFlags.class, flag, templateId, "item_flags"));
}
useFlags = itemJson.getJSONArray("item_use_flags");
for (int i = 0; i < useFlags.length(); i++) {
flag = useFlags.getString(i);
if (flag.equals("NONE"))
continue;
item.item_use_flags.add(CacheParserUtil.readEnum(mbEnums.ItemUseFlags.class, flag, templateId, "item_use_flags"));
}
item.item_post_item_id = itemJson.getInt("item_post_item_id");
item.item_initial_charges = itemJson.getInt("item_initial_charges");
item.item_book_arcana = itemJson.getInt("item_book_arcana");
item.item_skill_req.putAll(CacheParserUtil.readStringValueMap(itemJson.getJSONArray("item_skill_req"), "skill_type", "skill_level"));
raceReq = itemJson.getJSONObject("item_race_req");
item.item_race_req_restrict = raceReq.getBoolean("restrict");
item.item_race_req.addAll(CacheParserUtil.readEnumSet(mbEnums.MonsterType.class, raceReq.getJSONArray("races"), templateId, "item_race_req"));
classReq = itemJson.getJSONObject("item_class_req");
item.item_class_req_restrict = classReq.getBoolean("restrict");
item.item_class_req.addAll(CacheParserUtil.readEnumSet(mbEnums.ClassType.class, classReq.getJSONArray("classes"), templateId, "item_class_req"));
discReq = itemJson.getJSONObject("item_disc_req");
item.item_disc_req_restrict = discReq.getBoolean("restrict");
item.item_disc_req.addAll(CacheParserUtil.readEnumSet(mbEnums.DisciplineType.class, discReq.getJSONArray("discs"), templateId, "item_disc_req"));
item.item_attr_req.putAll(CacheParserUtil.readEnumValueMap(mbEnums.AttributeType.class, itemJson.getJSONArray("item_attr_req"),
"attr_type", "attr_value", templateId, "item_attr_req"));
item.item_level_req = itemJson.getInt("item_level_req");
item.item_rank_req = itemJson.getInt("item_rank_req");
item.item_sex_req = CacheParserUtil.readEnum(mbEnums.SexType.class, itemJson.getString("item_sex_req"), templateId, "item_sex_req");
item.item_user_power_action.addAll(CacheParserUtil.readUserPowerActions(itemJson.getJSONArray("item_user_power_action")));
item.item_power_grant.addAll(CacheParserUtil.readPowerGrants(itemJson.getJSONArray("item_power_grant"), templateId));
item.item_power_action.putAll(CacheParserUtil.readPowerActions(itemJson.getJSONArray("item_power_action")));
item.item_sheathable = itemJson.getBoolean("item_sheathable");
if (item.item_sheathable) {
item.item_sheath_slot = CacheParserUtil.readEnum(mbEnums.SheathSlot.class, itemJson.getString("item_sheath_slot"), templateId, "item_sheath_slot");
item.item_sheath_offset = CacheParserUtil.readVector3(itemJson.getJSONArray("item_sheath_offset"));
item.item_sheath_rotation = CacheParserUtil.readVector3(itemJson.getJSONArray("item_sheath_rotation"));
}
stubJson = itemJson.get("item_has_stub");
if (stubJson instanceof JSONArray) {
stubHolder = (JSONArray) stubJson;
item.item_has_stub = true;
item.item_stub_flag = stubHolder.getBoolean(0);
item.item_stub_id = stubHolder.getInt(1);
} else {
item.item_has_stub = itemJson.getBoolean("item_has_stub");
}
item.item_offering_adjustments.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, itemJson.getJSONArray("item_offering_adjustments"),
"offering_type", "offering_value", templateId, "item_offering_adjustments"));
item.item_resource_costs.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ResourceType.class, itemJson.getJSONArray("item_resource_costs"),
"resource_type", "resource_value", templateId, "item_resource_costs"));
item.item_bane_rank = itemJson.getInt("item_bane_rank");
item.item_ignore_saved_actions = itemJson.getBoolean("item_ignore_saved_actions");
return item;
}
private static ItemTemplate.Weapon parseWeapon(int templateId, JSONObject weaponJson) {
ItemTemplate.Weapon weapon = new ItemTemplate.Weapon();
JSONArray damageJson;
JSONObject damageEntry;
ItemTemplate.Damage damage;
weapon.weapon_wepspeed = weaponJson.getFloat("weapon_wepspeed");
weapon.weapon_max_range = weaponJson.getFloat("weapon_max_range");
weapon.weapon_projectile_id = weaponJson.getInt("weapon_projectile_id");
weapon.weapon_projectile_speed = weaponJson.getFloat("weapon_projectile_speed");
weapon.weapon_combat_idle_anim = weaponJson.getInt("weapon_combat_idle_anim");
damageJson = weaponJson.getJSONArray("weapon_damage");
for (int i = 0; i < damageJson.length(); i++) {
damageEntry = damageJson.getJSONObject(i);
damage = new ItemTemplate.Damage();
damage.damage_type = CacheParserUtil.readEnum(mbEnums.DamageType.class, damageEntry.getString("damage_type"), templateId, "weapon_damage");
damage.damage_min = damageEntry.getInt("damage_min");
damage.damage_max = damageEntry.getInt("damage_max");
weapon.weapon_damage.add(damage);
}
weapon.weapon_attack_anim_right.addAll(CacheParserUtil.readIntArrays(weaponJson.getJSONArray("weapon_attack_anim_right")));
weapon.weapon_attack_anim_left.addAll(CacheParserUtil.readIntArrays(weaponJson.getJSONArray("weapon_attack_anim_left")));
return weapon;
}
}