bring in more common types from emu

This commit is contained in:
Sky Johnson 2025-07-29 22:23:29 -05:00
parent d337309b17
commit 9c35904ecf
4 changed files with 269 additions and 54 deletions

View File

@ -2,32 +2,33 @@ package common
type EQ2DataType int
// Constants matching data_struct.hpp exactly
const (
TypeUint8 EQ2DataType = iota
TypeUint16
TypeUint32
TypeUint64
TypeNone EQ2DataType = iota
TypeInt8
TypeInt16
TypeInt32
TypeInt64
TypeChar
TypeFloat
TypeDouble
TypeColor
TypeSInt8
TypeSInt16
TypeSInt32
TypeChar
TypeString8
TypeString16
TypeString32
TypeColor
TypeEquipment
TypeItem
TypeArray
TypeItem
TypeSInt64
)
// Core EQ2 structures
type EQ2Color struct {
Red uint8
Green uint8
Blue uint8
Red int8
Green int8
Blue int8
}
type EQ2EquipmentItem struct {
@ -37,16 +38,189 @@ type EQ2EquipmentItem struct {
}
type EQ2String8 struct {
Size uint8
Size int8
Data string
}
type EQ2String16 struct {
Size uint16
Size int16
Data string
}
type EQ2String32 struct {
Size uint32
Size int32
Data string
}
const (
SlotPrimary = iota
SlotSecondary
SlotHead
SlotChest
SlotShoulders
SlotForearms
SlotHands
SlotLegs
SlotFeet
SlotLeftRing
SlotRightRing
SlotEars
SlotNeck
SlotLeftWrist
SlotRightWrist
SlotRanged
SlotAmmo
SlotWaist
SlotActivate1
SlotActivate2
SlotTextures
SlotHair
SlotBeard
SlotNakedChest
SlotNakedLegs
)
type EQ2Equipment struct {
EquipID [25]int16 // Equipment item IDs for each slot
Color [25]EQ2Color // Primary colors for each equipment slot
Highlight [25]EQ2Color // Highlight colors for each equipment slot
}
type CharFeatures struct {
HairType int16 // Hair style type
HairFaceType int16 // Facial hair type
WingType int16 // Wing type (for races with wings)
ChestType int16 // Chest appearance type
LegsType int16 // Leg appearance type
EyeType [3]int8 // Eye shape variations
EarType [3]int8 // Ear shape variations
EyeBrowType [3]int8 // Eyebrow shape variations
CheekType [3]int8 // Cheek shape variations
LipType [3]int8 // Lip shape variations
ChinType [3]int8 // Chin shape variations
NoseType [3]int8 // Nose shape variations
BodySize int8 // Body size modifier
BodyAge int8 // Body age appearance
SogaEyeType [3]int8 // SOGA eye shape variations
SogaEarType [3]int8 // SOGA ear shape variations
SogaEyeBrowType [3]int8 // SOGA eyebrow shape variations
SogaCheekType [3]int8 // SOGA cheek shape variations
SogaChestType int16 // SOGA chest appearance type
SogaLegsType int16 // SOGA leg appearance type
SogaLipType [3]int8 // SOGA lip shape variations
SogaChinType [3]int8 // SOGA chin shape variations
SogaNoseType [3]int8 // SOGA nose shape variations
SogaBodySize int8 // SOGA body size modifier
SogaBodyAge int8 // SOGA body age appearance
SogaHairType int16 // SOGA hair style type
SogaHairFaceType int16 // SOGA facial hair type
CombatVoice int16 // Combat voice type
EmoteVoice int16 // Emote voice type
MountModelType int16 // Mount model type
MountSaddleColor EQ2Color // Mount saddle color
MountColor EQ2Color // Mount body color
SkinColor EQ2Color // Skin color
EyeColor EQ2Color // Eye color
HairTypeColor EQ2Color // Primary hair color
HairTypeHighlightColor EQ2Color // Hair highlight color
HairFaceColor EQ2Color // Facial hair color
HairFaceHighlightColor EQ2Color // Facial hair highlight color
HairHighlightColor EQ2Color // Hair highlight color
WingColor1 EQ2Color // Wing primary color
WingColor2 EQ2Color // Wing secondary color
ShirtColor EQ2Color // Shirt color
PantsColor EQ2Color // Pants color
HairColor1 EQ2Color // Hair primary color
HairColor2 EQ2Color // Hair secondary color
SogaSkinColor EQ2Color // SOGA skin color
SogaEyeColor EQ2Color // SOGA eye color
SogaHairColor1 EQ2Color // SOGA hair primary color
SogaHairColor2 EQ2Color // SOGA hair secondary color
SogaHairTypeColor EQ2Color // SOGA primary hair color
SogaHairTypeHighlightColor EQ2Color // SOGA hair highlight color
SogaHairFaceColor EQ2Color // SOGA facial hair color
SogaHairFaceHighlightColor EQ2Color // SOGA facial hair highlight color
SogaHairHighlightColor EQ2Color // SOGA hair highlight color
ModelColor EQ2Color // Model color
SogaModelColor EQ2Color // SOGA model color
}
type PositionData struct {
GridID int32 // Current grid identifier
BadGridID int32 // Invalid grid identifier
Speed1 int8 // Primary speed value
Speed2 int8 // Secondary speed value
Dir1 int16 // Primary direction
Dir2 int16 // Secondary direction
Pitch1 int16 // Primary pitch angle
Pitch2 int16 // Secondary pitch angle
Roll int16 // Roll angle
X float32 // X coordinate
Y float32 // Y coordinate
Z float32 // Z coordinate
X2 float32 // Secondary X coordinate
Y2 float32 // Secondary Y coordinate
Z2 float32 // Secondary Z coordinate
X3 float32 // Tertiary X coordinate
Y3 float32 // Tertiary Y coordinate
Z3 float32 // Tertiary Z coordinate
SpawnOrigX float32 // Original spawn X coordinate
SpawnOrigY float32 // Original spawn Y coordinate
SpawnOrigZ float32 // Original spawn Z coordinate
SpawnOrigHeading float32 // Original spawn heading
SpawnOrigPitch float32 // Original spawn pitch
SpawnOrigRoll float32 // Original spawn roll
SpeedX float32 // X-axis speed
SpeedY float32 // Y-axis speed
SpeedZ float32 // Z-axis speed
SideSpeed float32 // Lateral movement speed
VertSpeed float32 // Vertical movement speed
ClientHeading1 float32 // Client-side heading (primary)
ClientHeading2 float32 // Client-side heading (secondary)
ClientPitch float32 // Client-side pitch
CollisionRadius int16 // Collision detection radius
State int16 // Current movement state
}
type AppearanceData struct {
Pos PositionData // Position and movement data
ModelType int16 // 3D model type identifier
SogaModelType int16 // SOGA model type identifier
ActivityStatus int16 // Current activity status
VisualState int16 // Visual state flags
ActionState int16 // Action state flags
MoodState int16 // Mood/emotion state
EmoteState int16 // Current emote state
Attackable int8 // Whether entity can be attacked
Icon int8 // Icon type to display
HideHood int8 // Whether to hide hood graphics
ShowLevel int8 // Whether to show level
LockedNoLoot int8 // Locked status with no loot
QuestFlag int8 // Quest-related flag
HeroicFlag int8 // Heroic opportunity flag
ShowCommandIcon int8 // Whether to show command icon
DisplayHandIcon int8 // Whether to show hand cursor icon
PlayerFlag int8 // Player character flag
Targetable int8 // Whether entity can be targeted
DisplayName int8 // Whether to display name
SubTitle [255]byte // Subtitle text (Guild name)
DisplayHP int32 // Health percentage (0 = 100%)
PowerLeft int32 // Power remaining (bar hidden if >=100)
AdventureClass int8 // Adventure class identifier
TradeskillClass int8 // Tradeskill class identifier
Level int8 // Character level
TradeskillLevel int8 // Tradeskill level
MinLevel int8 // Minimum level for encounters
MaxLevel int8 // Maximum level for encounters
Difficulty int8 // Encounter difficulty rating
Visible int16 // Visibility state (02 = normal, 15 = shadow)
Name [128]byte // Entity name
LastName [64]byte // Last name (for players)
PrefixTitle [128]byte // Title prefix
SuffixTitle [128]byte // Title suffix
Race int8 // Race identifier
Gender int8 // Gender identifier
Randomize int32 // Randomization seed
LuaRaceID int8 // Lua script race identifier
}

View File

@ -26,6 +26,7 @@ func NewContext(data []byte, version uint32, flags uint64) *ParseContext {
}
}
// Unsigned integer readers
func (ctx *ParseContext) readUint8() uint8 {
val := ctx.data[ctx.offset]
ctx.offset++
@ -50,6 +51,32 @@ func (ctx *ParseContext) readUint64() uint64 {
return val
}
// Signed integer readers
func (ctx *ParseContext) readSint8() int8 {
val := int8(ctx.data[ctx.offset])
ctx.offset++
return val
}
func (ctx *ParseContext) readSint16() int16 {
val := int16(binary.LittleEndian.Uint16(ctx.data[ctx.offset:]))
ctx.offset += 2
return val
}
func (ctx *ParseContext) readSint32() int32 {
val := int32(binary.LittleEndian.Uint32(ctx.data[ctx.offset:]))
ctx.offset += 4
return val
}
func (ctx *ParseContext) readSint64() int64 {
val := int64(binary.LittleEndian.Uint64(ctx.data[ctx.offset:]))
ctx.offset += 8
return val
}
// Oversized readers
func (ctx *ParseContext) readOversizedUint8(threshold int) uint8 {
if ctx.data[ctx.offset] == byte(threshold) {
ctx.offset++
@ -74,22 +101,17 @@ func (ctx *ParseContext) readOversizedUint32(threshold int) uint32 {
return uint32(ctx.readUint16())
}
func (ctx *ParseContext) readString8() string {
length := ctx.readUint8()
str := string(ctx.data[ctx.offset : ctx.offset+int(length)])
ctx.offset += int(length)
return str
func (ctx *ParseContext) readOversizedSint16(threshold int) int16 {
val := int8(ctx.data[ctx.offset])
if val == int8(threshold) || val == int8(-threshold) {
ctx.offset++
return ctx.readSint16()
}
func (ctx *ParseContext) readString16() string {
length := ctx.readUint16()
str := string(ctx.data[ctx.offset : ctx.offset+int(length)])
ctx.offset += int(length)
return str
return int16(ctx.readSint8())
}
func (ctx *ParseContext) readEQ2String8() common.EQ2String8 {
size := ctx.readUint8()
size := ctx.readSint8()
data := string(ctx.data[ctx.offset : ctx.offset+int(size)])
ctx.offset += int(size)
return common.EQ2String8{
@ -99,7 +121,7 @@ func (ctx *ParseContext) readEQ2String8() common.EQ2String8 {
}
func (ctx *ParseContext) readEQ2String16() common.EQ2String16 {
size := ctx.readUint16()
size := ctx.readSint16()
data := string(ctx.data[ctx.offset : ctx.offset+int(size)])
ctx.offset += int(size)
return common.EQ2String16{
@ -109,7 +131,7 @@ func (ctx *ParseContext) readEQ2String16() common.EQ2String16 {
}
func (ctx *ParseContext) readEQ2String32() common.EQ2String32 {
size := ctx.readUint32()
size := ctx.readSint32()
data := string(ctx.data[ctx.offset : ctx.offset+int(size)])
ctx.offset += int(size)
return common.EQ2String32{
@ -120,9 +142,9 @@ func (ctx *ParseContext) readEQ2String32() common.EQ2String32 {
func (ctx *ParseContext) readEQ2Color() common.EQ2Color {
return common.EQ2Color{
Red: ctx.readUint8(),
Green: ctx.readUint8(),
Blue: ctx.readUint8(),
Red: ctx.readSint8(),
Green: ctx.readSint8(),
Blue: ctx.readSint8(),
}
}
@ -326,7 +348,7 @@ func (ctx *ParseContext) evaluateComparison(varName, valueStr, op string) bool {
func (ctx *ParseContext) hasVar(name string) bool {
if val, exists := ctx.vars[name]; exists {
switch v := val.(type) {
case uint8, uint16, uint32, uint64:
case uint8, uint16, uint32, uint64, int8, int16, int32, int64:
return ctx.getVarValue(name) != 0
case string:
return v != ""
@ -354,6 +376,14 @@ func (ctx *ParseContext) getVarValue(name string) uint64 {
return uint64(v)
case uint64:
return v
case int8:
return uint64(v)
case int16:
return uint64(v)
case int32:
return uint64(v)
case int64:
return uint64(v)
}
}
return 0

View File

@ -55,16 +55,16 @@ type Parser struct {
fieldNames []string
}
// Type mapping for efficient lookup
// Type mapping using corrected type constants
var typeMap = map[string]common.EQ2DataType{
"u8": common.TypeUint8,
"u16": common.TypeUint16,
"u32": common.TypeUint32,
"u64": common.TypeUint64,
"i8": common.TypeInt8,
"i16": common.TypeInt16,
"i32": common.TypeInt32,
"i64": common.TypeInt64,
"u8": common.TypeInt8,
"u16": common.TypeInt16,
"u32": common.TypeInt32,
"u64": common.TypeInt64,
"i8": common.TypeSInt8,
"i16": common.TypeSInt16,
"i32": common.TypeSInt32,
"i64": common.TypeSInt64,
"f32": common.TypeFloat,
"f64": common.TypeDouble,
"double": common.TypeDouble,
@ -151,24 +151,24 @@ func getDataType(tag string) (common.EQ2DataType, bool) {
case 'u':
switch tag {
case "u8":
return common.TypeUint8, true
return common.TypeInt8, true
case "u16":
return common.TypeUint16, true
return common.TypeInt16, true
case "u32":
return common.TypeUint32, true
return common.TypeInt32, true
case "u64":
return common.TypeUint64, true
return common.TypeInt64, true
}
case 'i':
switch tag {
case "i8":
return common.TypeInt8, true
return common.TypeSInt8, true
case "i16":
return common.TypeInt16, true
return common.TypeSInt16, true
case "i32":
return common.TypeInt32, true
return common.TypeSInt32, true
case "i64":
return common.TypeInt64, true
return common.TypeSInt64, true
}
case 's':
switch tag {

View File

@ -47,23 +47,34 @@ func (def *PacketDef) parseStruct(ctx *ParseContext) (map[string]any, error) {
func (def *PacketDef) parseField(ctx *ParseContext, field FieldDesc, fieldType common.EQ2DataType, fieldName string) any {
switch fieldType {
case common.TypeInt8, common.TypeUint8:
case common.TypeInt8:
if field.Oversized > 0 {
return ctx.readOversizedUint8(field.Oversized)
}
return ctx.readUint8()
case common.TypeInt16, common.TypeUint16:
case common.TypeInt16:
if field.Oversized > 0 {
return ctx.readOversizedUint16(field.Oversized)
}
return ctx.readUint16()
case common.TypeInt32, common.TypeUint32:
case common.TypeInt32:
if field.Oversized > 0 {
return ctx.readOversizedUint32(field.Oversized)
}
return ctx.readUint32()
case common.TypeInt64, common.TypeUint64:
case common.TypeInt64:
return ctx.readUint64()
case common.TypeSInt8:
return ctx.readSint8()
case common.TypeSInt16:
if field.Oversized > 0 {
return ctx.readOversizedSint16(field.Oversized)
}
return ctx.readSint16()
case common.TypeSInt32:
return ctx.readSint32()
case common.TypeSInt64:
return ctx.readSint64()
case common.TypeString8:
return ctx.readEQ2String8()
case common.TypeString16: