Share the static rune list and its serializer between NPCs and mobs

Moves staticRuneIDs, getStaticRunesByKind and the CZONE rune serializer
from NPC to AbstractCharacter, with the race rune object type as a
parameter, so static mobs (World Boot Plan 3.3) can send the same list.
No wire change for NPCs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MagicBotandClaude Opus 5.5 committed 2026-10-28 10:37:48 -04:00
1 parent eb495218ad
commit 820177529d
2 files changed
+46 -46

No files matched your search

+44
View File
@@ -129,6 +129,8 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
public CopyOnWriteArrayList<Integer> minions = new CopyOnWriteArrayList();
public ArrayList<CharacterRune> runes;
// Static zone mobiles (World Boot Plan 3.2, 3.3): the CZONE rune list as given
public final ArrayList<Integer> staticRuneIDs = new ArrayList<>();
public mbEnums.MonsterType absRace;
@@ -414,6 +416,38 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
//TODO INPUT SWITCH CASE ON GAME OBJECTS TO CALL SPECIFIC METHODS.
}
// Static zone mobiles send the CZONE rune list ordered by kind, as live (World Boot Plan findings §5, Task 3.1)
protected static void serializeStaticRunes(AbstractCharacter character, GameObjectType raceRuneType, int ownerID, ByteBufferWriter writer) {
ArrayList<Integer> runeIDs = character.getStaticRunesByKind();
GameObjectType[] otherRuneTypes = {GameObjectType.NPCClassRune, GameObjectType.NPCClassRuneTwo,
GameObjectType.NPCClassRuneThree, GameObjectType.NPCExtraRune};
GameObjectType runeObjectType;
RuneTemplate rune;
int otherRunes = 0;
writer.putInt(runeIDs.size());
for (int runeID : runeIDs) {
rune = RuneTemplate._runes.get(runeID);
// Each rune object needs its own type, since all share the character's ID
if (rune.rune_type == RuneType.RACE)
runeObjectType = raceRuneType;
else if (runeID == NPC.SHOPKEEPER_RUNE)
runeObjectType = GameObjectType.NPCShopkeeperRune;
else
runeObjectType = otherRuneTypes[Math.min(otherRunes++, otherRuneTypes.length - 1)];
writer.putInt(rune.rune_type.mobileRuneKind);
writer.putInt(0);
writer.putInt(runeID);
writer.putInt(runeObjectType.ordinal());
writer.putInt(ownerID);
}
}
public static final void serializeForTrack(AbstractCharacter abstractCharacter, final ByteBufferWriter writer, boolean isGroup) {
writer.putInt(abstractCharacter.getObjectType().ordinal());
writer.putInt(abstractCharacter.getObjectUUID());
@@ -1217,6 +1251,16 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
}
}
// Stable sort: CZONE order within a kind
public ArrayList<Integer> getStaticRunesByKind() {
ArrayList<Integer> runeIDs = new ArrayList<>(this.staticRuneIDs);
runeIDs.sort((first, second) -> Integer.compare(RuneTemplate._runes.get(first).rune_type.mobileRuneKind,
RuneTemplate._runes.get(second).rune_type.mobileRuneKind));
return runeIDs;
}
public String getFirstName() {
return this.firstName;
}
+2 -46
View File
@@ -28,7 +28,6 @@ import engine.parsers.objects.CObjectTemplate;
import engine.parsers.objects.CZoneDrop;
import engine.parsers.objects.CZoneMobile;
import engine.parsers.objects.CZonePlacement;
import engine.parsers.objects.RuneTemplate;
import engine.server.MBServerStatics;
import org.joda.time.DateTime;
import org.pmw.tinylog.Logger;
@@ -79,8 +78,7 @@ public class NPC extends AbstractCharacter {
public int parentZoneUUID;
public int equipmentSetID = 0;
private int repairCost = 5;
// Static zone trainers (World Boot Plan 3.2): the CZONE rune list as given, and worn equipment
public final ArrayList<Integer> staticRuneIDs = new ArrayList<>();
// Static zone trainers (World Boot Plan 3.2): worn equipment
private ArrayList<CZoneDrop> staticEquipment = null;
// New NPC constructor. Fill in the blanks and then call
@@ -207,7 +205,7 @@ public class NPC extends AbstractCharacter {
if (npc.staticRuneIDs.isEmpty())
serializeContractRunes(npc, writer);
else
serializeStaticRunes(npc, writer);
serializeStaticRunes(npc, GameObjectType.NPCRaceRune, npc.currentID, writer);
//Send Stats
writer.putInt(5);
@@ -453,38 +451,6 @@ public class NPC extends AbstractCharacter {
}
// Static trainers send the CZONE rune list ordered by kind, as live (World Boot Plan findings §5, Task 3.1)
private static void serializeStaticRunes(NPC npc, ByteBufferWriter writer) {
ArrayList<Integer> runeIDs = npc.getStaticRunesByKind();
GameObjectType[] otherRuneTypes = {GameObjectType.NPCClassRune, GameObjectType.NPCClassRuneTwo,
GameObjectType.NPCClassRuneThree, GameObjectType.NPCExtraRune};
GameObjectType runeObjectType;
RuneTemplate rune;
int otherRunes = 0;
writer.putInt(runeIDs.size());
for (int runeID : runeIDs) {
rune = RuneTemplate._runes.get(runeID);
// Each rune object needs its own type, since all share the NPC's ID
if (rune.rune_type == RuneType.RACE)
runeObjectType = GameObjectType.NPCRaceRune;
else if (runeID == SHOPKEEPER_RUNE)
runeObjectType = GameObjectType.NPCShopkeeperRune;
else
runeObjectType = otherRuneTypes[Math.min(otherRunes++, otherRuneTypes.length - 1)];
writer.putInt(rune.rune_type.mobileRuneKind);
writer.putInt(0);
writer.putInt(runeID);
writer.putInt(runeObjectType.ordinal());
writer.putInt(npc.currentID);
}
}
private static int serializeExtraRune(NPC npc, int runeID, int cnt, ByteBufferWriter writer) {
writer.putInt(5);
@@ -651,16 +617,6 @@ public class NPC extends AbstractCharacter {
return 0;
}
// Stable sort: CZONE order within a kind
public ArrayList<Integer> getStaticRunesByKind() {
ArrayList<Integer> runeIDs = new ArrayList<>(this.staticRuneIDs);
runeIDs.sort((first, second) -> Integer.compare(RuneTemplate._runes.get(first).rune_type.mobileRuneKind,
RuneTemplate._runes.get(second).rune_type.mobileRuneKind));
return runeIDs;
}
public boolean isStatic() {
return this.isStatic;
}