implement comma separated rules for packet parser
This commit is contained in:
parent
fcb6a82135
commit
35fc2b667b
@ -68,6 +68,37 @@ StatTypes []uint8 `eq2:"int8,len=5"`
|
||||
StatValues []any `eq2:"int32,type2=float,type2criteria=stat_type_%i!=6"`
|
||||
```
|
||||
|
||||
### Comma-separated conditions
|
||||
Multiple variables can be checked in a single condition using comma-separated lists:
|
||||
|
||||
```go
|
||||
// Parse only if NONE of the listed variables are set
|
||||
NumEffects uint8 `eq2:"int8,ifvariablenotset=header_info_header_unknown_0_0,header_unknown_0"`
|
||||
|
||||
// Parse if ANY of the listed variables are set
|
||||
BonusData []byte `eq2:"char,len=20,ifvariableset=has_bonus,has_special,has_extra"`
|
||||
|
||||
// Parse if ANY of the listed flags are set
|
||||
OptionalField uint32 `eq2:"int32,ifflag=debug_mode,test_mode,dev_mode"`
|
||||
|
||||
// Parse if ALL of the listed flags are NOT set
|
||||
ProductionData []byte `eq2:"char,len=50,ifflagnotset=debug_mode,test_mode"`
|
||||
|
||||
// Multiple equals conditions (ANY must be true)
|
||||
TypeData any `eq2:"int32,ifequals=type=1,category=special"`
|
||||
|
||||
// Multiple not-equals conditions (ALL must be true)
|
||||
Value uint16 `eq2:"int16,ifnotequals=status=disabled,flag=hidden"`
|
||||
```
|
||||
|
||||
**Comma-separated logic rules:**
|
||||
- `ifvariableset` - TRUE if ANY variable is set
|
||||
- `ifvariablenotset` - TRUE if ALL variables are NOT set
|
||||
- `ifflag` - TRUE if ANY flag is set
|
||||
- `ifflagnotset` - TRUE if ALL flags are NOT set
|
||||
- `ifequals` - TRUE if ANY condition matches
|
||||
- `ifnotequals` - TRUE if ALL conditions are true (none match)
|
||||
|
||||
### Type switching (when EQ2 reuses the same bytes for different things)
|
||||
```go
|
||||
// Normally parse as int32, but if StatType != 6, parse as float instead
|
||||
@ -135,6 +166,12 @@ type CharacterData struct {
|
||||
Buffs []BuffData `eq2:"array,arraysize=BuffCount"`
|
||||
// Only parse extended data if first buff exists
|
||||
ExtendedBuffData []byte `eq2:"char,len=20,ifvariableset=buffs_0"`
|
||||
|
||||
// Comma-separated conditions example
|
||||
HeaderFlags uint8 `eq2:"int8"`
|
||||
// Parse effects only if neither unknown field is set
|
||||
NumEffects uint8 `eq2:"int8,ifvariablenotset=header_info_header_unknown_0_0,header_unknown_0"`
|
||||
Effects []EffectData `eq2:"array,arraysize=NumEffects"`
|
||||
}
|
||||
|
||||
type InventoryItem struct {
|
||||
@ -157,6 +194,11 @@ type BuffData struct {
|
||||
BuffID uint32 `eq2:"int32"`
|
||||
Duration uint16 `eq2:"int16"`
|
||||
}
|
||||
|
||||
type EffectData struct {
|
||||
Effect common.EQ2String16 `eq2:"string16"`
|
||||
Percentage uint8 `eq2:"int8"`
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced conditional patterns
|
||||
@ -179,6 +221,14 @@ type ComplexPacket struct {
|
||||
PlayerName string `eq2:"string16"`
|
||||
ShortName string `eq2:"string8,if=player_name!<=8"`
|
||||
LongDesc string `eq2:"string32,if=player_name!>15"`
|
||||
|
||||
// Comma-separated multi-condition examples
|
||||
DebugInfo []byte `eq2:"char,len=100,ifflag=debug_mode,test_mode,dev_mode"`
|
||||
ProdData []byte `eq2:"char,len=50,ifflagnotset=debug_mode,test_mode,dev_mode"`
|
||||
|
||||
// Multiple variable checks
|
||||
OptionalData []byte `eq2:"char,len=20,ifvariableset=has_optional,has_extended"`
|
||||
CleanupData []byte `eq2:"char,len=10,ifvariablenotset=dirty_flag,temp_flag,cache_flag"`
|
||||
}
|
||||
```
|
||||
|
||||
@ -191,6 +241,8 @@ If you've got EQ2's XML packet definitions, the conversion is pretty straightfor
|
||||
| `Type="int32"` | `eq2:"int32"` |
|
||||
| `ArraySizeVariable="count"` | `arraysize=Count` |
|
||||
| `IfVariableSet="flag"` | `ifvariableset=Flag` |
|
||||
| `IfVariableNotSet="var1,var2"` | `ifvariablenotset=var1,var2` |
|
||||
| `IfFlag="flag1,flag2"` | `ifflag=flag1,flag2` |
|
||||
| `Size="5"` | `len=5` |
|
||||
| `Type2Criteria="field!=value"` | `type2criteria=Field!=value` |
|
||||
| `Type2Criteria="name!>10"` | `type2criteria=name!>10` |
|
||||
|
@ -12,32 +12,30 @@ func (p *Parser) evaluateAllConditions(fieldTag *FieldTag, _ reflect.Value) bool
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldTag.IfVariableSet != "" && !p.isVariableSet(fieldTag.IfVariableSet) {
|
||||
if fieldTag.IfVariableSet != "" && !p.evaluateVariableSetCondition(fieldTag.IfVariableSet) {
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldTag.IfVariableNotSet != "" && p.isVariableSet(fieldTag.IfVariableNotSet) {
|
||||
if fieldTag.IfVariableNotSet != "" && !p.evaluateVariableNotSetCondition(fieldTag.IfVariableNotSet) {
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldTag.IfFlag != "" && !p.flags[fieldTag.IfFlag] {
|
||||
if fieldTag.IfFlag != "" && !p.evaluateFlagCondition(fieldTag.IfFlag) {
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldTag.IfFlagNotSet != "" && p.flags[fieldTag.IfFlagNotSet] {
|
||||
if fieldTag.IfFlagNotSet != "" && !p.evaluateFlagNotSetCondition(fieldTag.IfFlagNotSet) {
|
||||
return false
|
||||
}
|
||||
|
||||
if fieldTag.IfEquals != "" {
|
||||
parts := strings.Split(fieldTag.IfEquals, "=")
|
||||
if len(parts) == 2 && !p.evaluateEqualsCondition(parts[0], parts[1]) {
|
||||
if !p.evaluateEqualsConditions(fieldTag.IfEquals) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if fieldTag.IfNotEquals != "" {
|
||||
parts := strings.Split(fieldTag.IfNotEquals, "=")
|
||||
if len(parts) == 2 && p.evaluateEqualsCondition(parts[0], parts[1]) {
|
||||
if !p.evaluateNotEqualsConditions(fieldTag.IfNotEquals) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -45,6 +43,96 @@ func (p *Parser) evaluateAllConditions(fieldTag *FieldTag, _ reflect.Value) bool
|
||||
return true
|
||||
}
|
||||
|
||||
// evaluateVariableSetCondition handles comma-separated variable set conditions
|
||||
func (p *Parser) evaluateVariableSetCondition(variables string) bool {
|
||||
varList := p.splitCommaSeparated(variables)
|
||||
// Return true if ANY variable is set
|
||||
for _, variable := range varList {
|
||||
if p.isVariableSet(variable) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// evaluateVariableNotSetCondition handles comma-separated variable not set conditions
|
||||
func (p *Parser) evaluateVariableNotSetCondition(variables string) bool {
|
||||
varList := p.splitCommaSeparated(variables)
|
||||
// Return true if ALL variables are not set
|
||||
for _, variable := range varList {
|
||||
if p.isVariableSet(variable) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// evaluateFlagCondition handles comma-separated flag conditions
|
||||
func (p *Parser) evaluateFlagCondition(flags string) bool {
|
||||
flagList := p.splitCommaSeparated(flags)
|
||||
// Return true if ANY flag is set
|
||||
for _, flag := range flagList {
|
||||
if p.flags[flag] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// evaluateFlagNotSetCondition handles comma-separated flag not set conditions
|
||||
func (p *Parser) evaluateFlagNotSetCondition(flags string) bool {
|
||||
flagList := p.splitCommaSeparated(flags)
|
||||
// Return true if ALL flags are not set
|
||||
for _, flag := range flagList {
|
||||
if p.flags[flag] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// evaluateEqualsConditions handles comma-separated equals conditions
|
||||
func (p *Parser) evaluateEqualsConditions(conditions string) bool {
|
||||
conditionList := p.splitCommaSeparated(conditions)
|
||||
// Return true if ANY condition is true
|
||||
for _, condition := range conditionList {
|
||||
parts := strings.Split(condition, "=")
|
||||
if len(parts) == 2 && p.evaluateEqualsCondition(strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// evaluateNotEqualsConditions handles comma-separated not equals conditions
|
||||
func (p *Parser) evaluateNotEqualsConditions(conditions string) bool {
|
||||
conditionList := p.splitCommaSeparated(conditions)
|
||||
// Return true if ALL conditions are true (all not equal)
|
||||
for _, condition := range conditionList {
|
||||
parts := strings.Split(condition, "=")
|
||||
if len(parts) == 2 {
|
||||
if p.evaluateEqualsCondition(strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])) {
|
||||
return false // This condition is false (they are equal)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// splitCommaSeparated splits a comma-separated string and trims whitespace
|
||||
func (p *Parser) splitCommaSeparated(input string) []string {
|
||||
if input == "" {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
parts := strings.Split(input, ",")
|
||||
result := make([]string, len(parts))
|
||||
for i, part := range parts {
|
||||
result[i] = strings.TrimSpace(part)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// evaluateCondition evaluates conditions for conditional fields
|
||||
func (p *Parser) evaluateCondition(condition *FieldCondition) bool {
|
||||
if condition.Type == "simple" {
|
||||
|
Loading…
x
Reference in New Issue
Block a user