Created
September 7, 2021 21:17
-
-
Save jeremysmitherman/4412a21cef2e877f952606b207fde53c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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