Skip to content

Instantly share code, notes, and snippets.

@jeremysmitherman
Created September 7, 2021 21:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeremysmitherman/4412a21cef2e877f952606b207fde53c to your computer and use it in GitHub Desktop.
Save jeremysmitherman/4412a21cef2e877f952606b207fde53c to your computer and use it in GitHub Desktop.
package events
import (
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"strconv"
"strings"
"time"
)
type NetworkStartsCastingEvent struct {
NetworkEvent
TargetID []byte
TargetName string
AbilityID []byte
AbilityName string
}
func (e *NetworkStartsCastingEvent) FromLogLine(tokens []string) error {
ts, err := time.Parse(DATEFORMAT, tokens[1])
if err != nil { return err }
sourceID, err := hex.DecodeString(tokens[2])
if err != nil { return err }
abilityID, err := hex.DecodeString(fmt.Sprintf("%08s", tokens[4]))
if err != nil { return err }
targetID, err := hex.DecodeString(tokens[6])
if err != nil { return err }
e.Timestamp = ts
e.SourceID = sourceID
e.SourceName = tokens[3]
e.AbilityID = abilityID
e.AbilityName = tokens[5]
e.TargetID = targetID
e.TargetName = tokens[7]
return err
}
func (e *NetworkStartsCastingEvent) ToString() string {
return fmt.Sprintf("%s begins casting %s", e.SourceName, e.AbilityName)
}
func (e *NetworkStartsCastingEvent) GetEventID() int16 {
return 20
}
type NetworkAbilityEvent struct {
NetworkEvent
TargetID []byte
TargetName string
AbilityID []byte
AbilityName string
Flags uint32
DamageFlags []byte
Damage uint32
HitType HitType
TargetMaxHP uint32
TargetCurrHP uint32
CasterMaxHP uint32
CasterCurrHP uint32
IsAOE bool
}
func (e *NetworkAbilityEvent) FromLogLine(tokens []string) error {
ts, err := time.Parse(DATEFORMAT, tokens[1])
if err != nil { return err }
sourceID, err := hex.DecodeString(tokens[2])
if err != nil { return err }
abilityID, err := hex.DecodeString(fmt.Sprintf("%08s", tokens[4]))
if err != nil { return err }
targetID, err := hex.DecodeString(tokens[6])
if err != nil { return err }
damageFlags, err := strconv.ParseUint(tokens[8], 16, 32)
if err != nil { return err }
damage, err := strconv.ParseUint(tokens[9], 16, 32)
if err != nil { return err }
e.Timestamp = ts
e.SourceID = sourceID
e.SourceName = tokens[3]
e.AbilityID = abilityID
e.AbilityName = tokens[5]
e.TargetID = targetID
e.TargetName = tokens[7]
// Check instant death attack
if e.HitType == 0 && (damageFlags & 0x000000FF) == 0x00000033 {
e.HitType = DEATH
}
// Check crit variants
switch damageFlags & 0x00000F00 {
case 0x00000300:
e.HitType = CRITDIRECT
case 0x00000200:
e.HitType = DIRECT
case 0x00000100:
e.HitType = CRIT
}
// Check regular hit and heal variants
if e.HitType == 0 {
switch damageFlags & 0x0000000F {
case 0x00000001:
e.HitType = DODGE
case 0x00000003:
e.HitType = HIT
case 0x00000005:
e.HitType = BLOCK
case 0x00000006:
e.HitType = PARRY
case 0x00000004:
if damageFlags & 0x000F0000 == 0x00010000 {
e.HitType = CRITHEAL
} else {
e.HitType = HEAL
}
}
}
// Check big damage flag
if (damage & 0x0000F000) == 0x00004000 && (damage & 0x00000F00) == 0x00000000 {
buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, uint32(damage))
bigDamageBuf := make([]byte, 4)
bigDamageBuf[0] = buf[3]
bigDamageBuf[1] = buf[0]
bigDamageBuf[2] = buf[1] - buf[3]
bigDamage := binary.BigEndian.Uint32(bigDamageBuf)
e.Damage = bigDamage >> 8
} else {
e.Damage = uint32(damage >> 16)
}
return err
}
func (e *NetworkAbilityEvent) ToString() string {
return fmt.Sprintf("%s casts %s", e.SourceName, e.AbilityName)
}
func (e *NetworkAbilityEvent) GetEventID() int16 {
return 21
}
func EventFromLogLine(logLine string) (LogEvent, error) {
tokens := strings.Split(logLine, "|")
if len(tokens) == 0 {
return nil, errors.New(fmt.Sprintf("Invalid log line: %s", logLine))
}
eventID, err := strconv.Atoi(tokens[0])
if err != nil {
return nil, err
}
var e LogEvent
switch eventID {
case 20:
e = new(NetworkStartsCastingEvent)
case 21:
e = new(NetworkAbilityEvent)
case 22:
event := new(NetworkAbilityEvent)
event.IsAOE = true
e = event
default:
return nil, errors.New(fmt.Sprintf("Invalid log event prefix: %d", eventID))
}
err = e.FromLogLine(tokens)
return e, err
}
func EntityIDIsPlayerCharacter(entityID []byte) (bool, error) {
if len(entityID) != 4 {
return false, errors.New("invalid Source ID, expected 4 bytes")
}
if entityID[0] == 0x10 { return true, nil } else { return false, nil}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment