1
0
Fork 0
mirror of https://github.com/Luzifer/sii.git synced 2024-10-18 05:14:19 +00:00
sii/datatypes.go

123 lines
2.6 KiB
Go
Raw Normal View History

package sii
import (
"bytes"
"regexp"
"strings"
"github.com/pkg/errors"
)
// See https://modding.scssoft.com/wiki/Documentation/Engine/Units
// string => native type string
// float => native type float
// float2-4 => [2]float - [4]float
var placementRegexp = regexp.MustCompile(`^\(([0-9.-]+|&[0-9a-f]+), ([0-9.-]+|&[0-9a-f]+), ([0-9.-]+|&[0-9a-f]+)\) \(([0-9.-]+|&[0-9a-f]+); ([0-9.-]+|&[0-9a-f]+), ([0-9.-]+|&[0-9a-f]+), ([0-9.-]+|&[0-9a-f]+)\)$`)
// Placement contains 7 floats: (x, y, z) (w; x, y, z)
type Placement [7]float32
func (p Placement) MarshalSII() ([]byte, error) {
var siiFloats = make([][]byte, 7)
for i, f := range p {
b, err := float2sii(f)
if err != nil {
return nil, errors.Wrap(err, "Unable to encode float")
}
siiFloats[i] = b
}
var buf = new(bytes.Buffer)
buf.Write([]byte("("))
buf.Write(bytes.Join(siiFloats[0:3], []byte(", ")))
buf.Write([]byte(") ("))
buf.Write(siiFloats[3])
buf.Write([]byte("; "))
buf.Write(bytes.Join(siiFloats[4:7], []byte(", ")))
buf.Write([]byte(")"))
return buf.Bytes(), nil
}
func (p *Placement) UnmarshalSII(in []byte) error {
if !placementRegexp.Match(in) {
return errors.New("Input data does not match expected format")
}
grps := placementRegexp.FindSubmatch(in)
var err error
for i := 0; i < 7; i++ {
if p[i], err = sii2float(grps[i+1]); err != nil {
return errors.Wrap(err, "Unable to decode float")
}
}
return nil
}
// fixed => native type int
// fixed2-4 => [2]int - [4]int
// int2 => [2]int
// quaternion => [4]float
// s16, s32, s64 => int16, int32, int64
// u16, u32, u64 => uint16, uint32, uint64
// bool => native type bool
// token => native type string
type Ptr struct {
Target string
unit *Unit
}
func (p Ptr) IsNull() bool { return p.Target == "null" || strings.TrimSpace(p.Target) == "" }
func (p Ptr) MarshalSII() []byte { return []byte(p.Target) }
func (p Ptr) Resolve() Block {
if p.Target == "null" {
return nil
}
for _, b := range p.unit.Entries {
if b.Name() == p.Target {
return b
}
}
return nil
}
func (p *Ptr) UnmarshalSII(in []byte) error {
p.Target = string(in)
return nil
}
// resource_tie => native type string
// RawValue is used in places where a key can has multiple types and
// clean parsing into Go types is no longer possible. Sadly even parsing
// into interface{} is not possible as even for that the type of the value
// must be known
type RawValue []byte
func (r RawValue) MarshalSII() ([]byte, error) { return r, nil }
func (r *RawValue) UnmarshalSII(in []byte) error {
*r = in
return nil
}
// TODO: Add converter functions from / to RawValue