Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c78bc7fa5 | ||
|
|
4e30a04619 | ||
|
|
42a1c8a532 | ||
|
|
2a2c528981 | ||
|
|
58e0fa32fb | ||
|
|
62b4a2a897 | ||
|
|
d9d1c41d9e | ||
|
|
cb427de440 |
No files matched your search
@@ -57,7 +57,7 @@ public class dbNPCHandler extends dbHandlerBase {
|
|||||||
runeSets.put(runeSetID, runeList);
|
runeSets.put(runeSetID, runeList);
|
||||||
} else {
|
} else {
|
||||||
ArrayList<Integer> runeList = runeSets.get(runeSetID);
|
ArrayList<Integer> runeList = runeSets.get(runeSetID);
|
||||||
runeList.add(runeSetID);
|
runeList.add(runeBaseID);
|
||||||
runeSets.put(runeSetID, runeList);
|
runeSets.put(runeSetID, runeList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,11 +62,10 @@ public class MakeItemCmd extends AbstractDevCmd {
|
|||||||
ItemTemplate template;
|
ItemTemplate template;
|
||||||
try {
|
try {
|
||||||
templateID = Integer.parseInt(words[0]);
|
templateID = Integer.parseInt(words[0]);
|
||||||
template = ItemTemplate.templates.get(words[0].toLowerCase());
|
template = ItemTemplate.templates.get(templateID);
|
||||||
|
|
||||||
if (template == null) {
|
if (template == null) {
|
||||||
throwbackError(pc, "Supplied type " + words[0]
|
throwbackError(pc, "No item template with id " + words[0]);
|
||||||
+ " failed to parse to an Integer");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -480,6 +480,11 @@ public enum NPCManager {
|
|||||||
npc.runes.add(shopkeeper);
|
npc.runes.add(shopkeeper);
|
||||||
if (NPCManager._runeSetMap.containsKey(npc.runeSetID)) {
|
if (NPCManager._runeSetMap.containsKey(npc.runeSetID)) {
|
||||||
for (int runeID : _runeSetMap.get(npc.runeSetID)) {
|
for (int runeID : _runeSetMap.get(npc.runeSetID)) {
|
||||||
|
|
||||||
|
// Shopkeeper is already applied above and most rune sets repeat it
|
||||||
|
if (runeID == 252620)
|
||||||
|
continue;
|
||||||
|
|
||||||
RuneBase rb = RuneBase.getRuneBase(runeID);
|
RuneBase rb = RuneBase.getRuneBase(runeID);
|
||||||
if (rb != null) {
|
if (rb != null) {
|
||||||
CharacterRune toApply = new CharacterRune(rb, npc.getObjectUUID());
|
CharacterRune toApply = new CharacterRune(rb, npc.getObjectUUID());
|
||||||
|
|||||||
@@ -498,7 +498,7 @@ public class Warehouse {
|
|||||||
if (playerCharacter == null)
|
if (playerCharacter == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ItemTemplate template = ItemTemplate.templates.get(resourceType);
|
ItemTemplate template = ItemTemplate.templates.get(resourceType.templateID);
|
||||||
|
|
||||||
if (template == null)
|
if (template == null)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+235
@@ -0,0 +1,235 @@
|
|||||||
|
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||||
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||||
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||||
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||||
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||||
|
// Magicbane Emulator Project © 2013 - 2026
|
||||||
|
// https://www.magicbane.com
|
||||||
|
|
||||||
|
package engine.parsers.cache;
|
||||||
|
|
||||||
|
import engine.mbEnums;
|
||||||
|
import engine.parsers.objects.CObjectTemplate;
|
||||||
|
import engine.parsers.objects.DeedTemplate;
|
||||||
|
import engine.parsers.objects.ItemTemplate;
|
||||||
|
import engine.parsers.objects.PowerGrant;
|
||||||
|
import engine.parsers.objects.RuneTemplate;
|
||||||
|
import engine.parsers.objects.UserPowerAction;
|
||||||
|
import engine.util.Hasher;
|
||||||
|
import org.pmw.tinylog.Logger;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
// Lookups across the ITEM, DEED and RUNE cache templates.
|
||||||
|
// The JSON references runes, skills and powers by name; the server and DB use ids and tokens.
|
||||||
|
// Build once after all three parsers have loaded. Read only afterwards.
|
||||||
|
|
||||||
|
public class CObjectIndex {
|
||||||
|
|
||||||
|
private static final EnumMap<mbEnums.MonsterType, ArrayList<Integer>> raceRuneIds = new EnumMap<>(mbEnums.MonsterType.class);
|
||||||
|
private static final EnumMap<mbEnums.ClassType, Integer> classRuneIds = new EnumMap<>(mbEnums.ClassType.class);
|
||||||
|
private static final EnumMap<mbEnums.DisciplineType, Integer> disciplineRuneIds = new EnumMap<>(mbEnums.DisciplineType.class);
|
||||||
|
private static final HashMap<Integer, ArrayList<RuneTemplate>> runesBySubTypeToken = new HashMap<>();
|
||||||
|
private static final HashMap<String, Integer> skillTokens = new HashMap<>();
|
||||||
|
private static final HashMap<Integer, String> skillNames = new HashMap<>();
|
||||||
|
private static final HashMap<String, Integer> powerTokens = new HashMap<>();
|
||||||
|
private static final HashMap<Integer, String> powerNames = new HashMap<>();
|
||||||
|
|
||||||
|
// Same order as the client's id space checks (JSON-Refactor-Plan D1).
|
||||||
|
|
||||||
|
public static CObjectTemplate lookup(int templateId) {
|
||||||
|
|
||||||
|
CObjectTemplate template;
|
||||||
|
|
||||||
|
template = ItemTemplate._items.get(templateId);
|
||||||
|
|
||||||
|
if (template == null)
|
||||||
|
template = DeedTemplate._deeds.get(templateId);
|
||||||
|
|
||||||
|
if (template == null)
|
||||||
|
template = RuneTemplate._runes.get(templateId);
|
||||||
|
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Male and female runes share a race, so most races return two ids.
|
||||||
|
|
||||||
|
public static ArrayList<Integer> getRaceRuneIds(mbEnums.MonsterType race) {
|
||||||
|
return raceRuneIds.getOrDefault(race, new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getClassRuneId(mbEnums.ClassType classType) {
|
||||||
|
return classRuneIds.get(classType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getDisciplineRuneId(mbEnums.DisciplineType discipline) {
|
||||||
|
return disciplineRuneIds.get(discipline);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DB race and class tokens are SBStringHash(rune_sub_type). Mob and talent runes share sub types.
|
||||||
|
|
||||||
|
public static ArrayList<RuneTemplate> getRunesBySubTypeToken(int token) {
|
||||||
|
return runesBySubTypeToken.getOrDefault(token, new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getSkillToken(String skillName) {
|
||||||
|
return skillTokens.get(skillName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSkillName(int token) {
|
||||||
|
return skillNames.get(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getPowerToken(String powerName) {
|
||||||
|
return powerTokens.get(powerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPowerName(int token) {
|
||||||
|
return powerNames.get(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void build() {
|
||||||
|
|
||||||
|
int overlapCount = 0;
|
||||||
|
|
||||||
|
for (Integer templateId : RuneTemplate._runes.keySet())
|
||||||
|
if (ItemTemplate._items.containsKey(templateId) || DeedTemplate._deeds.containsKey(templateId))
|
||||||
|
overlapCount++;
|
||||||
|
|
||||||
|
for (Integer templateId : DeedTemplate._deeds.keySet())
|
||||||
|
if (ItemTemplate._items.containsKey(templateId))
|
||||||
|
overlapCount++;
|
||||||
|
|
||||||
|
if (overlapCount > 0)
|
||||||
|
Logger.warn(overlapCount + " template ids exist in more than one of ITEM/DEED/RUNE");
|
||||||
|
|
||||||
|
for (RuneTemplate rune : RuneTemplate._runes.values()) {
|
||||||
|
indexRuneName(rune);
|
||||||
|
indexSubTypeToken(rune);
|
||||||
|
indexRuneNames(rune);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ItemTemplate item : ItemTemplate._items.values()) {
|
||||||
|
addSkill(item.item_skill_used);
|
||||||
|
addSkill(item.item_skill_mastery_used);
|
||||||
|
indexItemFields(item.item_skill_req, item.item_user_power_action, item.item_power_grant, item.item_power_action);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DeedTemplate deed : DeedTemplate._deeds.values()) {
|
||||||
|
addSkill(deed.item_skill_used);
|
||||||
|
addSkill(deed.item_skill_mastery_used);
|
||||||
|
indexItemFields(deed.item_skill_req, deed.item_user_power_action, deed.item_power_grant, deed.item_power_action);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.info("Indexed " + raceRuneIds.size() + " races, " + classRuneIds.size() + " classes, "
|
||||||
|
+ disciplineRuneIds.size() + " disciplines, " + runesBySubTypeToken.size() + " rune sub type tokens, "
|
||||||
|
+ skillTokens.size() + " skills, " + powerTokens.size() + " powers");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void indexRuneName(RuneTemplate rune) {
|
||||||
|
|
||||||
|
Integer previousId;
|
||||||
|
|
||||||
|
if (rune.rune_type == null || rune.rune_sub_type.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (rune.rune_type) {
|
||||||
|
case RACE:
|
||||||
|
// Mob runes reuse race sub types; only creation races map to player race ids
|
||||||
|
if (rune.rune_is_standard_character_creation)
|
||||||
|
raceRuneIds.computeIfAbsent(CacheParserUtil.readEnum(mbEnums.MonsterType.class, rune.rune_sub_type, rune.template_id, "rune_sub_type"),
|
||||||
|
k -> new ArrayList<>()).add(rune.template_id);
|
||||||
|
break;
|
||||||
|
case CLASS:
|
||||||
|
previousId = classRuneIds.put(CacheParserUtil.readEnum(mbEnums.ClassType.class, rune.rune_sub_type, rune.template_id, "rune_sub_type"), rune.template_id);
|
||||||
|
if (previousId != null)
|
||||||
|
Logger.warn(rune.template_id + ": class " + rune.rune_sub_type + " already indexed by " + previousId);
|
||||||
|
break;
|
||||||
|
case DISCIPLINE:
|
||||||
|
previousId = disciplineRuneIds.put(CacheParserUtil.readEnum(mbEnums.DisciplineType.class, rune.rune_sub_type, rune.template_id, "rune_sub_type"), rune.template_id);
|
||||||
|
if (previousId != null)
|
||||||
|
Logger.warn(rune.template_id + ": discipline " + rune.rune_sub_type + " already indexed by " + previousId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// The Pet class rune has no ClassType
|
||||||
|
Logger.warn(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void indexSubTypeToken(RuneTemplate rune) {
|
||||||
|
|
||||||
|
int token;
|
||||||
|
|
||||||
|
if (!rune.rune_sub_type.isEmpty())
|
||||||
|
token = Hasher.SBStringHash(rune.rune_sub_type);
|
||||||
|
else if (rune.rune_sub_type_hash != 0)
|
||||||
|
token = rune.rune_sub_type_hash;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
runesBySubTypeToken.computeIfAbsent(token, k -> new ArrayList<>()).add(rune);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void indexRuneNames(RuneTemplate rune) {
|
||||||
|
|
||||||
|
for (RuneTemplate.SkillGrant grant : rune.rune_skill_grant) {
|
||||||
|
addSkill(grant.skill_type);
|
||||||
|
grant.skill_granted_skills.keySet().forEach(CObjectIndex::addSkill);
|
||||||
|
grant.skill_granted_powers.keySet().forEach(CObjectIndex::addPower);
|
||||||
|
}
|
||||||
|
|
||||||
|
rune.rune_skill_adj.keySet().forEach(CObjectIndex::addSkill);
|
||||||
|
addSkill(rune.item_skill_used);
|
||||||
|
addSkill(rune.item_skill_mastery_used);
|
||||||
|
indexItemFields(rune.item_skill_req, rune.item_user_power_action, rune.item_power_grant, rune.item_power_action);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void indexItemFields(Map<String, Integer> skillReq, ArrayList<UserPowerAction> userPowerActions,
|
||||||
|
ArrayList<PowerGrant> powerGrants, Map<String, ArrayList<int[]>> powerActions) {
|
||||||
|
|
||||||
|
skillReq.keySet().forEach(CObjectIndex::addSkill);
|
||||||
|
|
||||||
|
for (UserPowerAction action : userPowerActions)
|
||||||
|
addPower(action.power);
|
||||||
|
|
||||||
|
for (PowerGrant grant : powerGrants) {
|
||||||
|
addPower(grant.power_type);
|
||||||
|
grant.power_granted_skills.keySet().forEach(CObjectIndex::addSkill);
|
||||||
|
grant.power_granted_powers.keySet().forEach(CObjectIndex::addPower);
|
||||||
|
}
|
||||||
|
|
||||||
|
powerActions.keySet().forEach(CObjectIndex::addPower);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addSkill(String skillName) {
|
||||||
|
addName(skillName, skillTokens, skillNames, "skill");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addPower(String powerName) {
|
||||||
|
addName(powerName, powerTokens, powerNames, "power");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addName(String name, HashMap<String, Integer> tokens, HashMap<Integer, String> names, String kind) {
|
||||||
|
|
||||||
|
int token;
|
||||||
|
String previousName;
|
||||||
|
|
||||||
|
// readHashLabel keeps unresolved hashes as decimal strings; those are not names
|
||||||
|
if (name == null || name.isEmpty() || name.matches("-?\\d+") || tokens.containsKey(name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
token = Hasher.SBStringHash(name);
|
||||||
|
tokens.put(name, token);
|
||||||
|
previousName = names.putIfAbsent(token, name);
|
||||||
|
|
||||||
|
if (previousName != null)
|
||||||
|
Logger.warn(kind + " token " + token + " shared by '" + previousName + "' and '" + name + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
-1
@@ -35,7 +35,7 @@ public class CacheParserUtil {
|
|||||||
public static File[] listJsonFiles(String folderPath) {
|
public static File[] listJsonFiles(String folderPath) {
|
||||||
|
|
||||||
File folder = new File(folderPath);
|
File folder = new File(folderPath);
|
||||||
File[] jsonFiles = folder.listFiles((dir, name) -> name.endsWith(".json"));
|
File[] jsonFiles = folder.listFiles((dir, name) -> name.endsWith(".json") && hasTemplateId(name));
|
||||||
|
|
||||||
if (jsonFiles == null) {
|
if (jsonFiles == null) {
|
||||||
Logger.error("Cache folder not found: " + folder.getAbsolutePath());
|
Logger.error("Cache folder not found: " + folder.getAbsolutePath());
|
||||||
@@ -45,6 +45,22 @@ public class CacheParserUtil {
|
|||||||
return jsonFiles;
|
return jsonFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Template ids are 32-bit. The client cache has RUNE/10788957847552, which is
|
||||||
|
// 2512 << 32 (the Huntress id in the high word); files like it are skipped.
|
||||||
|
|
||||||
|
private static boolean hasTemplateId(String fileName) {
|
||||||
|
|
||||||
|
String idText = fileName.substring(0, fileName.length() - ".json".length());
|
||||||
|
|
||||||
|
try {
|
||||||
|
Integer.parseInt(idText);
|
||||||
|
return true;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Logger.warn("Skipping " + fileName + ": name is not a 32-bit template id");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static int templateIdFromFile(File jsonFile) {
|
public static int templateIdFromFile(File jsonFile) {
|
||||||
|
|
||||||
String fileName = jsonFile.getName();
|
String fileName = jsonFile.getName();
|
||||||
|
|||||||
+118
@@ -0,0 +1,118 @@
|
|||||||
|
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||||
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||||
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||||
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||||
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||||
|
// Magicbane Emulator Project © 2013 - 2026
|
||||||
|
// https://www.magicbane.com
|
||||||
|
|
||||||
|
package engine.parsers.cache;
|
||||||
|
|
||||||
|
import engine.gameManager.ConfigManager;
|
||||||
|
import engine.gameManager.DbManager;
|
||||||
|
import engine.mbEnums;
|
||||||
|
import engine.objects.AbstractGameObject;
|
||||||
|
import engine.objects.BaseClass;
|
||||||
|
import engine.parsers.objects.RuneTemplate;
|
||||||
|
import org.pmw.tinylog.Logger;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
// Dev-only check that compares DB-built objects with the cache JSON before a loader is switched.
|
||||||
|
// Enabled by the optional env var MB_PARITY_CHECK; not in the ConfigManager enum, which requires every entry.
|
||||||
|
|
||||||
|
public class ParityCheck {
|
||||||
|
|
||||||
|
private static final String FLAG_NAME = "MB_PARITY_CHECK";
|
||||||
|
private static final LinkedHashMap<String, Consumer<ParityCheck>> comparators = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
private final String table;
|
||||||
|
private int comparedCount = 0;
|
||||||
|
private int differenceCount = 0;
|
||||||
|
private int missingCount = 0;
|
||||||
|
|
||||||
|
static {
|
||||||
|
register("static_rune_baseclass", ParityCheck::compareBaseClasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ParityCheck(String table) {
|
||||||
|
this.table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEnabled() {
|
||||||
|
return ConfigManager.configMap.getOrDefault(FLAG_NAME, "false").equalsIgnoreCase("true");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register(String table, Consumer<ParityCheck> comparator) {
|
||||||
|
comparators.put(table, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void run() {
|
||||||
|
|
||||||
|
ParityCheck check;
|
||||||
|
|
||||||
|
for (String table : comparators.keySet()) {
|
||||||
|
check = new ParityCheck(table);
|
||||||
|
|
||||||
|
try {
|
||||||
|
comparators.get(table).accept(check);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Logger.error("Parity: " + table + ": comparator failed: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.info("Parity: " + table + ": " + check.comparedCount + " compared, "
|
||||||
|
+ check.differenceCount + " differences, " + check.missingCount + " missing in json");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns false when the row has no JSON counterpart, so the comparator can skip its fields.
|
||||||
|
|
||||||
|
public boolean compareRow(int id, Object jsonObject) {
|
||||||
|
|
||||||
|
comparedCount++;
|
||||||
|
|
||||||
|
if (jsonObject == null) {
|
||||||
|
missingCount++;
|
||||||
|
Logger.warn("Parity: " + table + "/" + id + ": missing in json");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void compareField(int id, String field, Object dbValue, Object jsonValue) {
|
||||||
|
|
||||||
|
if (Objects.equals(dbValue, jsonValue))
|
||||||
|
return;
|
||||||
|
|
||||||
|
differenceCount++;
|
||||||
|
Logger.warn("Parity: " + table + "/" + id + "/" + field + ": db=" + dbValue + " json=" + jsonValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void compareBaseClasses(ParityCheck check) {
|
||||||
|
|
||||||
|
ConcurrentHashMap<Integer, AbstractGameObject> cache;
|
||||||
|
BaseClass baseClass;
|
||||||
|
RuneTemplate rune;
|
||||||
|
|
||||||
|
cache = DbManager.getMap(mbEnums.GameObjectType.BaseClass);
|
||||||
|
|
||||||
|
if (cache == null) {
|
||||||
|
Logger.warn("Parity: static_rune_baseclass: no BaseClass objects loaded");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (AbstractGameObject cached : cache.values()) {
|
||||||
|
baseClass = (BaseClass) cached;
|
||||||
|
rune = RuneTemplate._runes.get(baseClass.getObjectUUID());
|
||||||
|
|
||||||
|
if (!check.compareRow(baseClass.getObjectUUID(), rune))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
check.compareField(baseClass.getObjectUUID(), "name", baseClass.getName(), rune.obj_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||||
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||||
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||||
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||||
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||||
|
// Magicbane Emulator Project © 2013 - 2026
|
||||||
|
// https://www.magicbane.com
|
||||||
|
|
||||||
|
package engine.parsers.objects;
|
||||||
|
|
||||||
|
// Common type for ITEM, DEED and RUNE cache templates, which share one id space.
|
||||||
|
// Shared obj_/combat_/item_ getters arrive with JSON-Refactor-Plan Task 1.1.
|
||||||
|
|
||||||
|
public interface CObjectTemplate {
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@ import java.util.LinkedHashMap;
|
|||||||
//
|
//
|
||||||
// Read only once loaded.
|
// Read only once loaded.
|
||||||
|
|
||||||
public class DeedTemplate {
|
public class DeedTemplate implements CObjectTemplate {
|
||||||
|
|
||||||
public static HashMap<Integer, DeedTemplate> _deeds = new HashMap<>();
|
public static HashMap<Integer, DeedTemplate> _deeds = new HashMap<>();
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import java.util.LinkedHashMap;
|
|||||||
// Not to be confused with engine.objects.ItemTemplate, which is loaded
|
// Not to be confused with engine.objects.ItemTemplate, which is loaded
|
||||||
// from the database. Read only once loaded.
|
// from the database. Read only once loaded.
|
||||||
|
|
||||||
public class ItemTemplate {
|
public class ItemTemplate implements CObjectTemplate {
|
||||||
|
|
||||||
public static HashMap<Integer, ItemTemplate> _items = new HashMap<>();
|
public static HashMap<Integer, ItemTemplate> _items = new HashMap<>();
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import java.util.LinkedHashMap;
|
|||||||
//
|
//
|
||||||
// Read only once loaded.
|
// Read only once loaded.
|
||||||
|
|
||||||
public class RuneTemplate {
|
public class RuneTemplate implements CObjectTemplate {
|
||||||
|
|
||||||
public static HashMap<Integer, RuneTemplate> _runes = new HashMap<>();
|
public static HashMap<Integer, RuneTemplate> _runes = new HashMap<>();
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import engine.net.client.ClientConnection;
|
|||||||
import engine.net.client.ClientConnectionManager;
|
import engine.net.client.ClientConnectionManager;
|
||||||
import engine.net.client.msg.login.*;
|
import engine.net.client.msg.login.*;
|
||||||
import engine.objects.*;
|
import engine.objects.*;
|
||||||
|
import engine.parsers.cache.CObjectIndex;
|
||||||
import engine.parsers.cache.DeedParser;
|
import engine.parsers.cache.DeedParser;
|
||||||
import engine.parsers.cache.ItemParser;
|
import engine.parsers.cache.ItemParser;
|
||||||
import engine.parsers.cache.RuneParser;
|
import engine.parsers.cache.RuneParser;
|
||||||
@@ -314,6 +315,9 @@ public class LoginServer {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.info("Indexing Cache Templates");
|
||||||
|
CObjectIndex.build();
|
||||||
|
|
||||||
Logger.info("Initializing Network");
|
Logger.info("Initializing Network");
|
||||||
Network.init();
|
Network.init();
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,10 @@ import engine.net.client.ClientConnectionManager;
|
|||||||
import engine.net.client.msg.UpdateStateMsg;
|
import engine.net.client.msg.UpdateStateMsg;
|
||||||
import engine.net.client.msg.chat.ChatSystemMsg;
|
import engine.net.client.msg.chat.ChatSystemMsg;
|
||||||
import engine.objects.*;
|
import engine.objects.*;
|
||||||
|
import engine.parsers.cache.CObjectIndex;
|
||||||
import engine.parsers.cache.DeedParser;
|
import engine.parsers.cache.DeedParser;
|
||||||
import engine.parsers.cache.ItemParser;
|
import engine.parsers.cache.ItemParser;
|
||||||
|
import engine.parsers.cache.ParityCheck;
|
||||||
import engine.parsers.cache.RuneParser;
|
import engine.parsers.cache.RuneParser;
|
||||||
import engine.parsers.objects.DeedTemplate;
|
import engine.parsers.objects.DeedTemplate;
|
||||||
import engine.parsers.objects.RuneTemplate;
|
import engine.parsers.objects.RuneTemplate;
|
||||||
@@ -333,6 +335,9 @@ public class WorldServer {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.info("Indexing Cache Templates");
|
||||||
|
CObjectIndex.build();
|
||||||
|
|
||||||
Logger.info("Loading PromotionClasses");
|
Logger.info("Loading PromotionClasses");
|
||||||
DbManager.PromotionQueries.GET_ALL_PROMOTIONS();
|
DbManager.PromotionQueries.GET_ALL_PROMOTIONS();
|
||||||
|
|
||||||
@@ -391,6 +396,11 @@ public class WorldServer {
|
|||||||
mbEnums.RaceType.initRaceTypeTables();
|
mbEnums.RaceType.initRaceTypeTables();
|
||||||
Race.loadAllRaces();
|
Race.loadAllRaces();
|
||||||
|
|
||||||
|
if (ParityCheck.isEnabled()) {
|
||||||
|
Logger.info("Running DB/JSON parity check");
|
||||||
|
ParityCheck.run();
|
||||||
|
}
|
||||||
|
|
||||||
Logger.info("Loading building slot/stuck location data.");
|
Logger.info("Loading building slot/stuck location data.");
|
||||||
BuildingLocation.loadBuildingLocations();
|
BuildingLocation.loadBuildingLocations();
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user